Volt LogoVolt
Extension Development

Extension Examples

Real-world extension implementations and use cases

Extension Examples

Learn from real examples

These production-ready extension implementations demonstrate best practices and common patterns using the VoltAPI.

Password Generator

A secure password generator with multiple modes:

// Password Generator Extension
// Trigger: "pass", "password", "pwd"

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 = ['pass', 'password', 'pwd'];
const CHARSET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&\*';

function generatePassword(length: number): string {
const array = new Uint32Array(length);
crypto.getRandomValues(array);
return Array.from(array, (num) => CHARSET[num % CHARSET.length]).join('');
}

function calculateStrength(length: number): string {
if (length >= 20) return 'Very Strong';
if (length >= 16) return 'Strong';
if (length >= 12) return 'Good';
return 'Weak';
}

class PasswordGeneratorPlugin implements Plugin {
id = 'password-generator';
name = 'Password Generator';
description = 'Generate cryptographically secure passwords';
enabled = true;

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

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

    // Parse length from query (e.g., "pass 20")
    const parts = query.split(/\s+/);
    const lengthArg = parts.find(p => /^\d+$/.test(p));
    const length = lengthArg ? Math.min(128, Math.max(8, parseInt(lengthArg))) : 16;

    const password = generatePassword(length);
    const strength = calculateStrength(length);

    return [{
      id: 'password',
      type: PluginResultType.Password,
      title: password,
      subtitle: `${length} chars • ${strength} • Enter to copy`,
      icon: '🔐',
      score: 100,
      data: { password, length }
    }];

}

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

    if (success) {
      window.VoltAPI.notify('Password copied!', 'success');
    } else {
      window.VoltAPI.notify('Failed to copy', 'error');
    }

}
}

export default PasswordGeneratorPlugin;
{
  "id": "password-generator",
  "name": "Password Generator",
  "version": "1.0.0",
  "description": "Generate cryptographically secure passwords",
  "author": { "name": "Volt Community" },
  "main": "index.ts",
  "category": "utilities",
  "keywords": ["password", "security", "generator"],
  "minVoltVersion": "0.4.0",
  "permissions": ["clipboard"]
}

Usage:

  • pass → 16-character password
  • pass 24 → 24-character password
  • password 32 → 32-character password

Search multiple search engines:

// Web Search Extension
// Trigger: "?", "search ", "web "

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;
}

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

const TRIGGERS = ['?', 'search ', 'web ', 'google ', 'bing '];

const SEARCH_ENGINES = [
{ id: 'google', name: 'Google', url: 'https://google.com/search?q=', icon: '🔍' },
{ id: 'duckduckgo', name: 'DuckDuckGo', url: 'https://duckduckgo.com/?q=', icon: '🦆' },
{ id: 'bing', name: 'Bing', url: 'https://bing.com/search?q=', icon: '🅱️' },
];

class WebSearchPlugin implements Plugin {
id = 'web-search';
name = 'Web Search';
description = 'Search the web with various search engines';
enabled = true;

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

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

    // Extract search query
    let searchQuery = context.query;
    for (const trigger of TRIGGERS) {
      if (searchQuery.toLowerCase().startsWith(trigger)) {
        searchQuery = searchQuery.slice(trigger.length).trim();
        break;
      }
    }

    if (!searchQuery) {
      return [{
        id: 'hint',
        type: PluginResultType.Info,
        title: 'Type your search query',
        subtitle: 'Example: ? what is volt launcher',
        icon: '💡',
        score: 50
      }];
    }

    return SEARCH_ENGINES.map((engine, i) => ({
      id: engine.id,
      type: PluginResultType.WebSearch,
      title: `Search "${searchQuery}"`,
      subtitle: `Open in ${engine.name}`,
      icon: engine.icon,
      score: 100 - i,
      data: {
        url: engine.url + encodeURIComponent(searchQuery),
        engine: engine.name
      }
    }));

}

async execute(result: PluginResult): Promise<void> {
const url = result.data?.url as string;
if (url) {
await window.VoltAPI.utils.openUrl(url);
}
}
}

export default WebSearchPlugin;
{
  "id": "web-search",
  "name": "Web Search",
  "version": "1.0.0",
  "description": "Search the web with various search engines",
  "author": { "name": "Volt Community" },
  "main": "index.ts",
  "category": "utilities",
  "keywords": ["search", "web", "google", "bing"],
  "minVoltVersion": "0.4.0",
  "permissions": ["network"]
}

Usage:

  • ?what is typescript → Search all engines
  • search weather → Search for weather
  • google react docs → Search Google

Calculator

Evaluate mathematical expressions:

// Calculator Extension
// Trigger: Mathematical expressions

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;
}

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

// Simple math expression regex
const MATH_REGEX = /^[\d\s+\-*/().,%^]+$/;

function evaluate(expression: string): number {
// Remove spaces and replace common symbols
const cleaned = expression
.replace(/\s/g, '')
.replace(/,/g, '')
.replace(/%/g, '/100')
.replace(/\^/g, '\*\*');

// Use Function constructor for safe evaluation
// Only allows mathematical operations
const fn = new Function(`return (${cleaned})`);
return fn();
}

function formatResult(num: number): string {
if (Number.isInteger(num)) {
return num.toLocaleString();
}
// Round to 10 decimal places to avoid floating point issues
return parseFloat(num.toFixed(10)).toLocaleString(undefined, {
maximumFractionDigits: 10
});
}

class CalculatorPlugin implements Plugin {
id = 'calculator';
name = 'Calculator';
description = 'Evaluate mathematical expressions';
enabled = true;

canHandle(context: PluginContext): boolean {
const query = context.query.trim();
// Must contain at least one digit and one operator
return MATH_REGEX.test(query) &&
/\d/.test(query) &&
/[+\-*/.^%]/.test(query);
}

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

    try {
      const result = evaluate(query);

      if (!isFinite(result)) {
        return [{
          id: 'error',
          type: PluginResultType.Calculator,
          title: 'Invalid calculation',
          subtitle: 'Division by zero or invalid expression',
          icon: '⚠️',
          score: 50
        }];
      }

      const formatted = formatResult(result);

      return [{
        id: 'result',
        type: PluginResultType.Calculator,
        title: formatted,
        subtitle: `${query} = ${formatted} • Enter to copy`,
        icon: '🔢',
        score: 100,
        data: { result: formatted, expression: query }
      }];
    } catch (error) {
      return [];
    }

}

async execute(result: PluginResult): Promise<void> {
const value = result.data?.result as string;
if (value) {
const success = await window.VoltAPI.utils.copyToClipboard(value);
if (success) {
window.VoltAPI.notify('Result copied!', 'success');
}
}
}
}

export default CalculatorPlugin;
{
  "id": "calculator",
  "name": "Calculator",
  "version": "1.0.0",
  "description": "Evaluate mathematical expressions",
  "author": { "name": "Volt Community" },
  "main": "index.ts",
  "category": "utilities",
  "keywords": ["calculator", "math", "compute"],
  "minVoltVersion": "0.4.0",
  "permissions": ["clipboard"]
}

Usage:

  • 2 + 2 → 4
  • 100 * 1.15 → 115
  • (50 + 25) / 3 → 25
  • 2^10 → 1,024

Timer

Create timers with notifications:

// Timer Extension
// Trigger: "timer", "remind"

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;
}

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

const TIME_REGEX = /^(?:timer|remind)\s+(\d+)\s\*(s|sec|seconds?|m|min|minutes?|h|hours?)?$/i;

function parseTime(amount: number, unit: string): number {
const u = (unit || 's').toLowerCase();
if (u.startsWith('h')) return amount _ 3600;
if (u.startsWith('m')) return amount _ 60;
return amount;
}

function formatDuration(seconds: number): string {
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
const s = seconds % 60;

const parts = [];
if (h > 0) parts.push(`${h}h`);
if (m > 0) parts.push(`${m}m`);
if (s > 0 || parts.length === 0) parts.push(`${s}s`);

return parts.join(' ');
}

class TimerPlugin implements Plugin {
id = 'timer';
name = 'Timer';
description = 'Create timers and reminders';
enabled = true;

canHandle(context: PluginContext): boolean {
const query = context.query.toLowerCase().trim();
return query.startsWith('timer') || query.startsWith('remind');
}

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

    const match = TIME_REGEX.exec(query);
    if (!match) {
      return [{
        id: 'hint',
        type: PluginResultType.Timer,
        title: 'Set a timer',
        subtitle: 'Example: timer 5m, timer 30s, timer 1h',
        icon: '⏱️',
        score: 50
      }];
    }

    const [, amountStr, unit] = match;
    const amount = parseInt(amountStr);
    const seconds = parseTime(amount, unit);
    const formatted = formatDuration(seconds);

    return [{
      id: 'timer',
      type: PluginResultType.Timer,
      title: `Set ${formatted} timer`,
      subtitle: 'Press Enter to start',
      icon: '⏱️',
      score: 100,
      data: { seconds, display: formatted }
    }];

}

async execute(result: PluginResult): Promise<void> {
const seconds = result.data?.seconds as number;
const display = result.data?.display as string;

    if (!seconds) return;

    window.VoltAPI.notify(`Timer set for ${display}`, 'success');

    // Start the timer
    setTimeout(() => {
      // Show notification when timer completes
      if ('Notification' in window && Notification.permission === 'granted') {
        new Notification('Timer Complete!', {
          body: `Your ${display} timer has finished`,
          icon: '⏱️'
        });
      }
      window.VoltAPI.notify(`Timer complete! (${display})`, 'info');
    }, seconds * 1000);

}
}

export default TimerPlugin;
{
  "id": "timer",
  "name": "Timer",
  "version": "1.0.0",
  "description": "Create timers and reminders",
  "author": { "name": "Volt Community" },
  "main": "index.ts",
  "category": "utilities",
  "keywords": ["timer", "reminder", "countdown"],
  "minVoltVersion": "0.4.0",
  "permissions": ["notifications"]
}

Usage:

  • timer 30s → 30 second timer
  • timer 5m → 5 minute timer
  • timer 1h → 1 hour timer

UUID Generator

Generate unique identifiers:

// UUID Generator Extension
// Trigger: "uuid", "guid"

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;
}

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

function generateUUID(): string {
// Use crypto.randomUUID if available (modern browsers)
if (typeof crypto.randomUUID === 'function') {
return crypto.randomUUID();
}

// Fallback implementation
const array = new Uint8Array(16);
crypto.getRandomValues(array);

// Set version (4) and variant (10xx)
array[6] = (array[6] & 0x0f) | 0x40;
array[8] = (array[8] & 0x3f) | 0x80;

const hex = Array.from(array, b => b.toString(16).padStart(2, '0')).join('');
return `${hex.slice(0,8)}-${hex.slice(8,12)}-${hex.slice(12,16)}-${hex.slice(16,20)}-${hex.slice(20)}`;
}

class UUIDPlugin implements Plugin {
id = 'uuid-generator';
name = 'UUID Generator';
description = 'Generate unique identifiers';
enabled = true;

canHandle(context: PluginContext): boolean {
const query = context.query.toLowerCase().trim();
return query === 'uuid' || query === 'guid' || query.startsWith('uuid ');
}

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

    // Check if user wants multiple UUIDs
    const countMatch = query.match(/^uuid\s+(\d+)$/);
    const count = countMatch ? Math.min(10, parseInt(countMatch[1])) : 1;

    const results: PluginResult[] = [];

    for (let i = 0; i < count; i++) {
      const uuid = generateUUID();
      results.push({
        id: `uuid-${i}`,
        type: PluginResultType.Info,
        title: uuid,
        subtitle: 'Press Enter to copy',
        icon: '🔑',
        score: 100 - i,
        data: { uuid }
      });
    }

    return results;

}

async execute(result: PluginResult): Promise<void> {
const uuid = result.data?.uuid as string;
if (uuid) {
const success = await window.VoltAPI.utils.copyToClipboard(uuid);
if (success) {
window.VoltAPI.notify('UUID copied!', 'success');
}
}
}
}

export default UUIDPlugin;
{
  "id": "uuid-generator",
  "name": "UUID Generator",
  "version": "1.0.0",
  "description": "Generate unique identifiers",
  "author": { "name": "Volt Community" },
  "main": "index.ts",
  "category": "development",
  "keywords": ["uuid", "guid", "unique", "id"],
  "minVoltVersion": "0.4.0",
  "permissions": ["clipboard"]
}

Usage:

  • uuid → Generate one UUID
  • uuid 5 → Generate 5 UUIDs

Backend Plugin Example (Rust)

For system-level integrations, use Rust backend plugins:

use serde::{Deserialize, Serialize};
use std::path::PathBuf;

#[derive(Debug, Serialize, Deserialize)]
pub struct GameInfo {
    pub id: String,
    pub name: String,
    pub path: PathBuf,
    pub icon: Option<String>,
}

pub struct SteamPlugin {
    steam_path: PathBuf,
}

impl SteamPlugin {
    pub fn new() -> Self {
        let steam_path = Self::find_steam_path();
        Self { steam_path }
    }

    fn find_steam_path() -> PathBuf {
        #[cfg(target_os = "windows")]
        { PathBuf::from("C:\\Program Files (x86)\\Steam") }
        #[cfg(target_os = "macos")]
        { PathBuf::from("/Users/Shared/Steam") }
        #[cfg(target_os = "linux")]
        { PathBuf::from("~/.steam/steam") }
    }

    pub fn scan_games(&self) -> Vec<GameInfo> {
        let library_path = self.steam_path.join("steamapps");
        let mut games = Vec::new();

        if let Ok(entries) = std::fs::read_dir(&library_path) {
            for entry in entries.flatten() {
                if let Some(name) = entry.file_name().to_str() {
                    if name.starts_with("appmanifest_") && name.ends_with(".acf") {
                        if let Ok(game) = self.parse_manifest(&entry.path()) {
                            games.push(game);
                        }
                    }
                }
            }
        }

        games
    }

    fn parse_manifest(&self, path: &PathBuf) -> Result<GameInfo, Box<dyn std::error::Error>> {
        let content = std::fs::read_to_string(path)?;

        let id = Self::extract_value(&content, "appid")?;
        let name = Self::extract_value(&content, "name")?;
        let install_dir = Self::extract_value(&content, "installdir")?;

        Ok(GameInfo {
            id,
            name,
            path: self.steam_path.join("steamapps/common").join(&install_dir),
            icon: None,
        })
    }

    fn extract_value(content: &str, key: &str) -> Result<String, Box<dyn std::error::Error>> {
        let pattern = format!("\"{}\"\\s+\"([^\"]+)\"", key);
        let re = regex::Regex::new(&pattern)?;

        re.captures(content)
            .and_then(|c| c.get(1))
            .map(|m| m.as_str().to_string())
            .ok_or_else(|| "Key not found".into())
    }
}

// Tauri command to expose to frontend
#[tauri::command]
pub async fn scan_steam_games() -> Result<Vec<GameInfo>, String> {
    let plugin = SteamPlugin::new();
    Ok(plugin.scan_games())
}

More Examples

On this page