Volt LogoVolt
Extension Development

Extension Development

Learn how to create extensions to extend Volt's functionality

Extension Development Guide

Build powerful extensions for Volt

Create extensions that integrate seamlessly with Volt's lightning-fast architecture. Extensions are distributed as ZIP files and can be shared via the official registry.

Welcome to the Volt extension development guide! This guide will help you create your own extensions to extend Volt's capabilities.

Quick Start

Create Extension Directory

Create a new folder for your extension:

manifest.json
index.ts

Create manifest.json

Every extension requires a manifest file:

manifest.json
{
  "id": "my-extension",
  "name": "My Extension",
  "version": "1.0.0",
  "description": "A custom Volt extension",
  "author": { "name": "Your Name" },
  "main": "index.ts",
  "category": "utilities",
  "minVoltVersion": "0.4.0",
  "permissions": []
}

Implement Your Plugin

Create the main plugin file:

index.ts
class MyExtensionPlugin implements Plugin {
  id = 'my-extension';
  name = 'My Extension';
  description = 'A custom Volt extension';
  enabled = true;

  canHandle(context: PluginContext): boolean {
    return context.query.toLowerCase().startsWith('my ');
  }

  match(context: PluginContext): PluginResult[] {
    const { PluginResultType } = window.VoltAPI.types;
    const query = context.query.slice(3); // Remove "my "

    return [{
      id: '1',
      type: PluginResultType.Info,
      title: `Process: ${query}`,
      subtitle: 'Press Enter to execute',
      icon: '⚡',
      score: 100,
      data: { query }
    }];
  }

  async execute(result: PluginResult): Promise<void> {
    window.VoltAPI.notify(`Executed with: ${result.data?.query}`, 'success');
  }
}

export default MyExtensionPlugin;

Test Your Extension (Dev Mode)

  1. Open Volt → SettingsExtensions
  2. Click "Link Dev Extension"
  3. Select your extension folder
  4. Type your trigger keyword to test!

Hot Reload

Edit your code, save, and press Ctrl+R to refresh. No packaging required!

See Development Workflow for more options.

Extension Architecture

Volt features a hybrid extension system with two layers:

Frontend Extensions

TypeScript - Handle UI and user interactions. Perfect for calculators, web searches, generators.

Backend Plugins

Rust - Handle system integrations. Perfect for game scanners, system monitors, file operations.

Frontend Extensions

  • Written in TypeScript
  • Run in browser context
  • Access to window.VoltAPI for utilities
  • 500ms timeout per query
  • Perfect for: calculators, web searches, generators, converters
class MyPlugin implements Plugin {
  id = 'my-plugin';
  name = 'My Plugin';
  description = 'Does something useful';
  enabled = true;

  canHandle(context: PluginContext): boolean {
    return context.query.startsWith('my ');
  }

  match(context: PluginContext): PluginResult[] {
    const { PluginResultType } = window.VoltAPI.types;
    return [{
      id: '1',
      type: PluginResultType.Info,
      title: 'Result',
      score: 100
    }];
  }

  async execute(result: PluginResult): Promise<void> {
    await window.VoltAPI.utils.copyToClipboard('copied!');
    window.VoltAPI.notify('Done!', 'success');
  }
}

export default MyPlugin;

Backend Plugins

  • Written in Rust
  • Full system access
  • Native performance
  • Perfect for: game scanners, system monitors, file operations
pub struct MyBackendPlugin;

impl VoltPluginAPI for MyBackendPlugin {
    fn name(&self) -> &str { "my-backend-plugin" }
    fn version(&self) -> &str { "1.0.0" }

    fn scan(&self) -> Result<Vec<PluginResult>, PluginError> {
        // Scan system resources
        Ok(vec![])
    }

    fn execute(&self, action: &str) -> Result<(), PluginError> {
        // Execute action
        Ok(())
    }
}

Architecture Diagram

┌─────────────────────────────────────────────────────────┐
│              Frontend (React/TypeScript)                │
│  ┌───────────────────────────────────────────────────┐  │
│  │              Extension Loader                      │  │
│  │  • Loads extensions from ZIP or dev folders       │  │
│  │  • Bundles TypeScript → JavaScript                │  │
│  │  • Injects VoltAPI                                │  │
│  └───────────────────────────────────────────────────┘  │
│              ↓                                          │
│  ┌───────────────────────────────────────────────────┐  │
│  │              Plugin Registry                       │  │
│  │  • Manages all plugins (built-in + extensions)    │  │
│  │  • Routes queries to plugins                      │  │
│  │  • Handles 500ms timeouts                         │  │
│  └───────────────────────────────────────────────────┘  │
│              ↓                                          │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐   │
│  │ Built-in│  │Extension│  │Extension│  │  DEV    │   │
│  │ Plugin  │  │    A    │  │    B    │  │Extension│   │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘   │
└─────────────────────────────────────────────────────────┘
                    ↕ Tauri IPC
┌─────────────────────────────────────────────────────────┐
│               Backend (Rust/Tauri)                      │
│  ┌───────────────────────────────────────────────────┐  │
│  │         Extension Management Commands              │  │
│  │  • install_extension() / uninstall_extension()    │  │
│  │  • link_dev_extension() / unlink_dev_extension()  │  │
│  │  • toggle_extension() / refresh_dev_extension()   │  │
│  │  • fetch_extension_registry()                     │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

VoltAPI - Global API

All extensions have access to the global window.VoltAPI object:

// Types
window.VoltAPI.types.PluginResultType; // Enum for result types

// Utilities
window.VoltAPI.utils.copyToClipboard(text); // Copy to clipboard
window.VoltAPI.utils.openUrl(url); // Open URL in browser
window.VoltAPI.utils.fuzzyScore(query, str); // Fuzzy matching
window.VoltAPI.utils.formatNumber(num); // Format numbers

// Backend communication
window.VoltAPI.invoke(command, args); // Call Tauri commands

// Events
window.VoltAPI.events.emit(event, data); // Emit custom event
window.VoltAPI.events.on(event, handler); // Subscribe to events

// Notifications
window.VoltAPI.notify(message, type); // Show notification

Full API Reference

See the API Reference for complete VoltAPI documentation.

Plugin Result Types

Extensions can return different types of results:

Prop

Type

Extension Distribution

Extensions are distributed as ZIP files via GitHub Releases:

  1. Package your extension files into a ZIP
  2. Create a GitHub Release with the ZIP as an asset
  3. Submit to the official registry for discoverability
my-extension-v1.0.0.zip
├── manifest.json
├── index.ts
├── types.ts
└── utils/
    └── helpers.ts

See the Publishing Guide for detailed instructions.

Complete Example

Here's a complete, production-ready extension:

index.ts
// Greeting Extension
// Responds to "hello" queries with personalized greetings

interface Plugin {
  id: string;
  name: string;
  description: string;
  enabled: boolean;
  canHandle(context: PluginContext): boolean;
  match(context: PluginContext): PluginResult[];
  execute(result: PluginResult): Promise<void>;
}

interface PluginContext {
  query: string;
  settings?: Record<string, unknown>;
}

interface PluginResult {
  id: string;
  type: any;
  title: string;
  subtitle?: string;
  icon?: string;
  score: number;
  data?: Record<string, unknown>;
}

const TRIGGERS = ["hello", "hi", "hey", "greet"];

class GreetingPlugin implements Plugin {
  id = "greeting";
  name = "Greeting";
  description = "Friendly greetings for everyone";
  enabled = true;

  canHandle(context: PluginContext): boolean {
    const query = context.query.toLowerCase().trim();
    return TRIGGERS.some((t) => query.startsWith(t));
  }

  match(context: PluginContext): PluginResult[] {
    const { PluginResultType } = window.VoltAPI.types;
    const query = context.query.trim();

    // Extract name if provided (e.g., "hello John")
    const parts = query.split(/\s+/);
    const name = parts.length > 1 ? parts.slice(1).join(" ") : "friend";

    const greetings = [`Hello, ${name}! 👋`, `Hey there, ${name}! ✨`, `Greetings, ${name}! 🌟`];

    return greetings.map((greeting, i) => ({
      id: `greeting-${i}`,
      type: PluginResultType.Info,
      title: greeting,
      subtitle: "Press Enter to copy",
      icon: "👋",
      score: 100 - i,
      data: { greeting },
    }));
  }

  async execute(result: PluginResult): Promise<void> {
    const greeting = result.data?.greeting as string;
    const success = await window.VoltAPI.utils.copyToClipboard(greeting);

    if (success) {
      window.VoltAPI.notify("Greeting copied!", "success");
    }
  }
}

export default GreetingPlugin;
manifest.json
{
  "id": "greeting",
  "name": "Greeting",
  "version": "1.0.0",
  "description": "Friendly greetings for everyone",
  "author": { "name": "Your Name" },
  "main": "index.ts",
  "category": "utilities",
  "keywords": ["hello", "greeting", "friendly"],
  "minVoltVersion": "0.4.0",
  "permissions": ["clipboard"]
}

Next Steps

On this page