Development Workflow
Set up your local development environment for Volt extensions
Development Workflow
Learn how to set up your local environment for developing and testing Volt extensions.
Project Setup
Create Extension Directory
Create a new directory for your extension:
mkdir my-extension
cd my-extensionInitialize Project Structure
Create the essential files:
{
"id": "my-extension",
"name": "My Extension",
"version": "1.0.0",
"description": "My awesome extension",
"author": { "name": "Your Name" },
"main": "index.ts",
"category": "utilities",
"minVoltVersion": "0.4.0",
"permissions": []
}Optional: Set up TypeScript (for IDE support)
While Volt handles TypeScript compilation, you can set up a tsconfig.json for better IDE support:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"noEmit": true
},
"include": ["*.ts", "**/*.ts"]
}{
"name": "my-extension",
"private": true,
"devDependencies": {
"typescript": "^5.3.0"
}
}Type Definitions
Create a types.ts file for better TypeScript support:
// Plugin interfaces (copied from Volt's type system)
export interface Plugin {
id: string;
name: string;
description: string;
enabled: boolean;
canHandle(context: PluginContext): boolean;
match(context: PluginContext): Promise<PluginResult[]> | PluginResult[] | null;
execute(result: PluginResult): Promise<void> | void;
}
export interface PluginContext {
query: string;
settings?: Record<string, unknown>;
}
export interface PluginResult {
id: string;
type: PluginResultType;
title: string;
subtitle?: string;
icon?: string;
badge?: string;
score: number;
data?: Record<string, unknown>;
pluginId?: string;
}
export enum PluginResultType {
Calculator = "calculator",
WebSearch = "websearch",
SystemCommand = "systemcommand",
FileExplorer = "fileexplorer",
Timer = "timer",
SystemMonitor = "systemmonitor",
Steam = "steam",
Game = "game",
Clipboard = "clipboard",
Emoji = "emoji",
Info = "info",
Password = "password",
}
// VoltAPI type definition for IDE support
export interface VoltAPI {
types: {
PluginResultType: typeof PluginResultType;
};
utils: {
fuzzyScore(query: string, target: string): number;
copyToClipboard(text: string): Promise<boolean>;
openUrl(url: string): Promise<void>;
formatNumber(num: number): string;
};
invoke<T>(cmd: string, args?: Record<string, unknown>): Promise<T>;
events: {
emit(event: string, detail?: unknown): void;
on(event: string, handler: (detail: unknown) => void): () => void;
};
notify(message: string, type?: "info" | "success" | "error"): void;
}
// Declare global VoltAPI
declare global {
interface Window {
VoltAPI: VoltAPI;
}
}Local Testing
Method 1: Dev Mode (Recommended)
Like Raycast!
Link your extension folder directly to Volt for instant testing with hot reload. No packaging required!
Open Volt Settings
- Press
Ctrl+Shift+Spaceto open Volt - Type
settingsand press Enter - Go to Extensions tab
Link Your Extension
- Click "Link Dev Extension"
- Select your extension folder (e.g.,
D:\dev\my-extension) - Your extension is instantly loaded with a DEV badge!
Test and Iterate
- Type your trigger keyword to test
- Edit your code and save
- Press
Ctrl+Rto refresh Volt - Changes are immediately visible!
Dev Mode Commands:
| Command | Description |
|---|---|
| Link Dev Extension | Link a local folder |
| Unlink Dev Extension | Remove a dev extension |
| Refresh Dev Extension | Reload from disk |
Hot Reload
Dev extensions automatically re-read manifest.json on each query, so metadata changes are
instant. For code changes, use Refresh or Ctrl+R.
Method 2: Install from ZIP
For testing the final packaged version:
Package Your Extension
Create a ZIP file with your extension files:
Compress-Archive -Path .\* -DestinationPath ..\my-extension-v1.0.0.zipzip -r ../my-extension-v1.0.0.zip .Install in Volt
- Open Volt
- Go to Settings → Extensions
- Click Install from file
- Select your ZIP file
Test Your Extension
Type your trigger keyword in Volt to test the extension.
Method 3: Direct Folder Installation
For manual installation (advanced):
Find Extension Directory
Volt stores extensions in the app data directory:
%APPDATA%\volt\extensions\~/Library/Application Support/volt/extensions/~/.config/volt/extensions/Copy Your Extension
Copy your extension folder directly:
# Example for Windows
cp -r ./my-extension "$env:APPDATA/volt/extensions/"Update installed.json
Add your extension to installed.json in the extensions directory:
{
"extensions": [
{
"id": "my-extension",
"name": "My Extension",
"version": "1.0.0",
"enabled": true,
"installedAt": "2024-01-01T00:00:00Z"
}
]
}Reload Volt
Restart Volt or use the reload command to load your extension.
Debugging
Browser DevTools
Volt runs in a Tauri webview, which supports Chrome DevTools:
Enable DevTools
In development builds, press F12 or Ctrl+Shift+I to open DevTools.
View Console Output
Your console.log() statements will appear in the Console tab.
canHandle(context: PluginContext): boolean {
console.log('Query received:', context.query);
return context.query.startsWith('my ');
}Debug Errors
Check the Console for any errors in your extension code.
Common Debugging Techniques
class MyPlugin implements Plugin {
// ...
canHandle(context: PluginContext): boolean {
// Debug: Log every query
console.log("[MyPlugin] canHandle called with:", context.query);
const result = context.query.startsWith("my ");
console.log("[MyPlugin] canHandle result:", result);
return result;
}
match(context: PluginContext): PluginResult[] {
console.log("[MyPlugin] match called");
try {
// Your matching logic
const results = this.generateResults(context);
console.log("[MyPlugin] Generated results:", results);
return results;
} catch (error) {
console.error("[MyPlugin] Error in match:", error);
return [];
}
}
async execute(result: PluginResult): Promise<void> {
console.log("[MyPlugin] execute called with:", result);
try {
// Your execution logic
await this.performAction(result);
console.log("[MyPlugin] Action completed successfully");
} catch (error) {
console.error("[MyPlugin] Error in execute:", error);
window.VoltAPI.notify("An error occurred", "error");
}
}
}Extension Loading Process
Understanding how Volt loads extensions helps with debugging:
1. Volt starts
↓
2. Backend reads installed.json
↓
3. For each enabled extension:
a. Read all source files (.ts, .js, .json)
b. Bundle files into single JavaScript
c. Transform TypeScript → JavaScript (via Sucrase)
d. Transform imports/exports to module system
e. Execute the bundle
f. Get default export (your Plugin class)
g. Instantiate and register with Plugin Registry
↓
4. Extension ready to handle queriesKey Points
TypeScript Transformation
Your TypeScript is automatically compiled to JavaScript. You don't need a build step. However, only TypeScript syntax is supported—not Node.js APIs.
- Entry point: The file specified in
manifest.main - Default export: Must be a class implementing
Plugin - No Node.js: Browser APIs only (no
fs,path, etc.) - Web Crypto: Use
crypto.getRandomValues()instead of Node'scrypto
Troubleshooting
Development Tips
1. Start Simple
Begin with a minimal extension and add features incrementally:
class MinimalPlugin implements Plugin {
id = "minimal";
name = "Minimal";
description = "A minimal extension";
enabled = true;
canHandle(context: PluginContext): boolean {
return context.query === "test";
}
match(context: PluginContext): PluginResult[] {
return [
{
id: "1",
type: window.VoltAPI.types.PluginResultType.Info,
title: "It works!",
score: 100,
},
];
}
execute(): void {
window.VoltAPI.notify("Executed!", "success");
}
}
export default MinimalPlugin;2. Use Descriptive Logging
const LOG_PREFIX = "[MyExtension]";
console.log(`${LOG_PREFIX} Initializing...`);
console.log(`${LOG_PREFIX} Query: "${context.query}"`);
console.error(`${LOG_PREFIX} Error:`, error);3. Handle Errors Gracefully
match(context: PluginContext): PluginResult[] {
try {
return this.generateResults(context);
} catch (error) {
console.error('Error generating results:', error);
return [{
id: 'error',
type: window.VoltAPI.types.PluginResultType.Info,
title: 'An error occurred',
subtitle: 'Check console for details',
icon: '⚠️',
score: 0
}];
}
}4. Test Edge Cases
- Empty query
- Very long queries
- Special characters
- Unicode input
- Rapid typing (debouncing)
Using the Extension Templates
Clone the official templates for a quick start:
# Clone the volt-extensions repository
git clone https://github.com/VoltLaunchr/volt-extensions.git
# Copy a template
cp -r volt-extensions/templates/typescript-plugin ./my-extension
# Start developing
cd my-extensionThe template includes:
- Pre-configured
manifest.json - Type definitions
- Example plugin structure
- README template