conductorv2

Core

Plugin System

Every tool in Conductor is a plugin. 40+ built-in plugins cover developer workflows, communication, productivity, finance, and system monitoring. Write your own in a single JavaScript file.

The Plugin Interface

A plugin is a class implementing the Plugin interface. Plugins are lazily initialized — the first time an AI calls any tool from a plugin, initialize() is called with the full Conductor instance, giving access to config, database, AI manager, and other plugins.

TypeScript
interface Plugin {
  name: string;
  description: string;
  version: string;

  // Called once on first use. Receives the Conductor instance for
  // access to config, database, AI manager, and other plugins.
  initialize(conductor: Conductor): Promise<void>;

  // Return false to show as "not_configured" in plugin list.
  // Tools from unconfigured plugins are not registered with MCP.
  isConfigured(): boolean;

  // The tools this plugin exposes to the MCP server.
  getTools(): PluginTool[];

  // Optional: guided setup via `conductor plugins setup <name>`
  configSchema?: PluginConfigSchema;

  // Optional: called each reasoning cycle for proactive context.
  // Return a string to inject into the AI's system prompt.
  getContext?(): Promise<string | null>;

  // Optional: cleanup on plugin disable or server shutdown.
  onUnload?(): Promise<void>;
}

interface PluginTool {
  name: string;
  description: string;
  inputSchema: JSONSchema7;

  // Set true for irreversible operations (delete, send, publish).
  // The MCP client will prompt the user before execution.
  requiresApproval?: boolean;

  handler(
    args: unknown,
    conductor: Conductor
  ): Promise<ToolResult>;
}

Plugin Lifecycle

Plugins move through these states. A plugin in not_configured or init_failed state does not expose tools to MCP clients.

registered

Plugin class is registered with PluginManager. Not yet initialized.

not_configured

initialize() succeeded but isConfigured() returns false. Tools are not registered with MCP.

ready

Initialized and configured. All tools are active and callable.

init_failed

initialize() threw an error. Plugin is shown in startup summary with the error message.

disabled

Manually disabled via CLI. Not initialized, not shown to MCP clients.

Run conductor mcp start to see a startup summary showing each plugin's state. Failed plugins are shown with the error message so you can diagnose credential or network issues immediately.

Built-in Plugins

37 built-in plugins ship with Conductor. Plugins marked zero-config work immediately with no API keys or setup. Click any plugin name to see its full tool reference.

Utilities

PluginToolsAuthDescription
calculator3zero-configMath expressions, unit conversions, percentages
hash5zero-configMD5, SHA-1, SHA-256, SHA-512, bcrypt
text-tools6zero-configWord count, JSON format, diff, encode/decode
colors4zero-configHex/RGB/HSL/name conversion
timezone3zero-configConvert time between zones, list zones
url-tools4zero-configParse URLs, expand short links, encode/decode
cron2zero-configParse cron expressions, next run times
translate2zero-configText translation via LibreTranslate (free)

Developer

PluginToolsAuthDescription
shell4zero-configSafe shell command execution (whitelist-based)
github20partialIssues, PRs, code search, releases, forks, notifications
github-actions6credentialsTrigger workflows, view runs, download artifacts
linear9credentialsIssues, cycles, projects, team management
jira8credentialsIssues, transitions, projects, sprints
vercel7credentialsDeployments, domains, environment variables
docker8zero-configContainers, images, volumes, compose
n8n5credentialsTrigger workflows, list executions
figma5credentialsFiles, components, comments, exports

Communication

PluginToolsAuthDescription
slack6credentialsSend messages, read channels, manage threads
gmail7credentialsRead, send, search, label, archive emails
discord5credentialsSend messages, read channels, manage roles
twilio4credentialsSend SMS, make calls, check logs

Productivity

PluginToolsAuthDescription
notion8credentialsPages, databases, blocks, search
gcal6credentialsEvents, calendars, availability, scheduling
gdrive6credentialsFiles, folders, permissions, search
airtable6credentialsRecords, tables, views, formulas
todoist5credentialsTasks, projects, labels, filters
notes4zero-configLocal markdown notes in ~/.conductor/notes/
memory3zero-configLocal semantic memory stored in SQLite

Finance

PluginToolsAuthDescription
stripe9credentialsPayments, customers, subscriptions, refunds
shopify7credentialsProducts, orders, customers, inventory
crypto3zero-configCrypto prices via public CoinGecko API

System

PluginToolsAuthDescription
system5zero-configCPU, memory, disk, processes, uptime
network4zero-configDNS lookup, IP geolocation, ping, port check
weather3zero-configCurrent conditions and forecasts via Open-Meteo

Smart Home

PluginToolsAuthDescription
homekit6credentialsControl HomeKit devices, scenes, automations

Media

PluginToolsAuthDescription
spotify7credentialsPlayback, playlists, search, library

Social

PluginToolsAuthDescription
x5credentialsPost, search, read timeline, DMs

Managing Plugins

All plugin management is done through the CLI. Changes take effect immediately — no server restart required.

conductor plugins list
conductor plugins enable <name>
conductor plugins disable <name>
conductor plugins setup <name>
conductor plugins install <name>
conductor plugins uninstall <name>
conductor plugins onboard

Configuring Credentials

Plugins that require credentials define a configSchema. Running conductor plugins setup <name> walks through the fields interactively. Fields marked secret: true are stored in an encrypted local credential store (AES-256-GCM) — never in config.json.

terminal
$ conductor plugins setup github

? GitHub Personal Access Token: ghp_••••••••••••
? Default organization (optional): myorg

✓ Token stored in encrypted credential store
✓ github plugin configured — 20 tools now active

Writing a Plugin

Drop a .js file into ~/.conductor/plugins/ and enable it. The file must export a default class implementing the Plugin interface. Here is a complete, production-ready example:

~/.conductor/plugins/planetscale.js
// ~/.conductor/plugins/planetscale.js
// A complete plugin example with credentials, error handling, and multiple tools

export default class PlanetScalePlugin {
  name = "planetscale";
  description = "Query PlanetScale databases via the PS API";
  version = "1.0.0";

  #apiKey = null;
  #orgName = null;
  #baseUrl = "https://api.planetscale.com/v1";

  configSchema = {
    fields: [
      {
        key: "apiKey",
        label: "Service Token",
        type: "string",
        secret: true,     // stored in encrypted credential store
        required: true,
        hint: "Create at app.planetscale.com/settings/service-tokens",
      },
      {
        key: "orgName",
        label: "Organization name",
        type: "string",
        required: true,
      },
    ],
  };

  async initialize(conductor) {
    this.#apiKey = await conductor.config.getSecret("planetscale.apiKey");
    this.#orgName = await conductor.config.get("planetscale.orgName");
    this.logger = conductor.logger;
  }

  isConfigured() {
    return !!this.#apiKey && !!this.#orgName;
  }

  getTools() {
    return [
      {
        name: "planetscale_databases",
        description: "List all databases in your organization",
        inputSchema: { type: "object", properties: {} },
        handler: async () => this.#listDatabases(),
      },
      {
        name: "planetscale_branches",
        description: "List branches for a database",
        inputSchema: {
          type: "object",
          properties: {
            database: { type: "string", description: "Database name" },
          },
          required: ["database"],
        },
        handler: async ({ database }) => this.#listBranches(database),
      },
      {
        name: "planetscale_query",
        description: "Run a read-only SQL query",
        inputSchema: {
          type: "object",
          properties: {
            database: { type: "string" },
            branch: { type: "string", default: "main" },
            sql: { type: "string", description: "SELECT statement" },
          },
          required: ["database", "sql"],
        },
        handler: async ({ database, branch = "main", sql }) => {
          if (!sql.trim().toUpperCase().startsWith("SELECT")) {
            throw new Error("Only SELECT queries are permitted");
          }
          return this.#runQuery(database, branch, sql);
        },
      },
    ];
  }

  async #request(path) {
    const res = await fetch(`${this.#baseUrl}/${path}`, {
      headers: {
        Authorization: `Bearer ${this.#apiKey}`,
        Accept: "application/json",
      },
    });
    if (!res.ok) throw new Error(`PlanetScale API error: ${res.status}`);
    return res.json();
  }

  async #listDatabases() {
    const data = await this.#request(
      `organizations/${this.#orgName}/databases`
    );
    return {
      content: [{ type: "text", text: JSON.stringify(data.data, null, 2) }],
    };
  }

  async #listBranches(database) {
    const data = await this.#request(
      `organizations/${this.#orgName}/databases/${database}/branches`
    );
    return {
      content: [{ type: "text", text: JSON.stringify(data.data, null, 2) }],
    };
  }

  async #runQuery(database, branch, sql) {
    this.logger.info(`Querying ${database}/${branch}`);
    // implementation omitted for brevity
    return { content: [{ type: "text", text: "..." }] };
  }
}

Key patterns in the example above:

  • configSchema — defines the credentials the user needs to provide; secret fields go to encrypted credential store
  • initialize() — reads secrets from keychain; only runs once on first tool call
  • isConfigured() — returns false until credentials are set, keeping tools out of MCP
  • requiresApproval — set this to true on any tool that mutates state (write, delete, send)
  • Private methods — use # private class fields for API request helpers
terminal
conductor plugins enable planetscale
conductor plugins setup planetscale

Publishing to the Marketplace

Share your plugin with other Conductor users by publishing it to the marketplace. The marketplace is an npm registry namespace — publish your plugin as an npm package named @conductor-plugins/your-plugin-name.

terminal
# Publish to npm under the @conductor-plugins scope
npm publish --access public

# Users install your plugin with:
conductor plugins install planetscale

Scaffold a new plugin with the correct package.json, tsconfig, and entry point using: conductor plugin-create