Plugins

SwarmClaw has an extensible plugin system for adding custom logic at key points in the agent lifecycle. Plugins from OpenClaw are also natively supported, and built-in capabilities now share the same canonical plugin-family IDs used by the Plugins UI, agent configs, approvals, and policy rules.

Installing Plugins

Need a step-by-step walkthrough? See Plugin Tutorial.

Three ways to add plugins:

Marketplace

Browse and install approved plugins directly from Settings:

  1. Go to SettingsPluginsMarketplace tab
  2. Browse available plugins and click Install
  3. The plugin source is downloaded, saved to data/plugins/, and enabled automatically

The marketplace registry is hosted at swarmclaw.ai/registry/plugins.json and sourced from swarmclawai/swarmforge. The hosted file is a generated mirror. Refresh it before deploying the site with npm run sync:plugin-registry.

SwarmClaw also normalizes legacy swarmclawai/plugins URLs during install, so older entries continue to work without manual fixes.

Marketplace Sources

SwarmClaw now records both the publisher/source of a plugin and the install channel used to fetch it. In practice that means the UI can show combinations like:

  • SwarmForge via SwarmClaw Site — first-party plugin published from swarmforge and installed from the hosted site mirror
  • ClawHub — external catalog entries installed from ClawHub
  • Direct URL — manually installed over HTTPS

Treat the sources like this:

  • SwarmForge is the canonical first-party registry/repo
  • SwarmClaw Site hosts the public mirror at swarmclaw.ai/registry/plugins.json
  • ClawHub is an external marketplace
  • Manual URL is the direct install path when no registry is involved

Install from URL

Install any plugin from an HTTPS URL:

  1. Go to SettingsPluginsInstall from URL tab
  2. Paste the URL to a .js or .mjs plugin file
  3. Choose a filename and click Install Plugin

Manual

Drop .js or .mjs files directly into data/plugins/. SwarmClaw hot-reloads plugin files, so installs and edits are usually visible without a restart.

If a plugin needs third-party npm packages, SwarmClaw can also manage it in a per-plugin workspace with a package.json manifest.

Trust Model

External plugins run as server-side code inside the SwarmClaw app process. Install code you trust, pin plugin URLs to stable sources when possible, and review plugin settings before enabling them on autonomous agents.

Stability & Recovery

To protect runtime stability, SwarmClaw tracks consecutive plugin failures during:

  • Plugin load/startup
  • Lifecycle hooks
  • Plugin tool execution
  • Inbound/outbound text transform hooks

If a plugin keeps failing repeatedly, SwarmClaw auto-disables it, writes failure metadata to data/plugin-failures.json, and emits a warning notification in the Notification Center with a link to the Plugins page.

You can tune the threshold with:

SWARMCLAW_PLUGIN_FAILURE_THRESHOLD=3

Default is 3 consecutive failures. Users can re-enable a disabled plugin manually from Settings → Plugins.

Plugin Format (SwarmClaw)

SwarmClaw supports CommonJS (module.exports = { ... }) and .mjs/ESM default exports. The example below uses CommonJS because it is the simplest format for local plugins.

// data/plugins/my-plugin.js
module.exports = {
  name: "my-plugin",
  description: "What this plugin does",
  hooks: {
    beforeAgentStart({ session, message }) {
      // Called before an agent begins processing a message
    },
    afterAgentComplete({ session, response }) {
      // Called after an agent finishes generating a response
    },
    beforeToolExec({ toolName, input }) {
      // Called before a tool is executed.
      // Return a replacement object to rewrite tool input.
      return { ...input, traced: true };
    },
    afterToolExec({ session, toolName, input, output }) {
      // Called after a tool completes execution
    },
    afterChatTurn({ session, message, response, source, internal }) {
      // Called after a full chat turn completes
    },
    getAgentContext({ session, enabledPlugins, message, history }) {
      // Return markdown context injected into the agent prompt
      return `Workspace mode: ${session.cwd || "default"}`;
    },
    getCapabilityDescription() {
      // Return one capability line injected into the system prompt
      return "I can annotate pull requests with deployment risk tags.";
    },
    getOperatingGuidance() {
      // Return one or more guidance lines injected into runtime hints
      return ["Prefer dry-run mode before write actions."];
    },
    onTaskComplete({ taskId, result }) {
      // Called when an agent successfully completes a task
    },
    onAgentDelegation({ sourceAgentId, targetAgentId, task }) {
      // Called when an orchestrator delegates to a sub-agent
    },
  },
  // Plugins can also define custom tools that agents can use
  tools: [
    {
      name: "my_custom_tool",
      description: "Does something amazing",
      parameters: {
        type: "object",
        properties: {
          query: { type: "string" }
        },
        required: ["query"]
      },
      execute: async (args, ctx) => {
        return "Result: " + args.query;
      }
    }
  ],
  // Optional plugin settings rendered in Settings -> Plugins detail panel
  ui: {
    settingsFields: [
      { key: "webhookUrl", label: "Webhook URL", type: "text", placeholder: "https://...", required: true },
      { key: "debug", label: "Debug Mode", type: "boolean", defaultValue: false },
      { key: "token", label: "API Token", type: "secret" },
    ],
  },
};

Hook signatures of note:

  • beforeToolExec({ toolName, input }) may return a replacement input object.
  • afterToolExec({ session, toolName, input, output }) observes completed tool executions.
  • transformInboundMessage({ session, text }) and transformOutboundMessage({ session, text }) run sequentially across enabled plugins.
  • ui.settingsFields values are available through getPluginSettings(pluginId) and type: "secret" values are encrypted at rest.

OpenClaw Plugin Compatibility

SwarmClaw natively supports the OpenClaw plugin format. Drop an OpenClaw plugin into data/plugins/ and it works automatically — lifecycle hooks are mapped at load time:

OpenClaw HookSwarmClaw Hook
onAgentStartbeforeAgentStart
onAgentCompleteafterAgentComplete
onToolCallbeforeToolExec
onToolResultafterToolExec
onMessageonMessage
onAgentContext / agent:contextgetAgentContext

OpenClaw plugins use the activate(ctx) pattern:

module.exports = {
  name: "my-openclaw-plugin",
  version: "1.0.0",
  activate(ctx) {
    ctx.onAgentStart((data) => { /* ... */ });
    ctx.onToolCall((data) => { /* ... */ });
  },
  deactivate() { /* cleanup */ },
};

This means plugins written for OpenClaw work in SwarmClaw with zero changes, and vice versa for plugins that use the hook mapping.

Available Hooks

HookTriggerCan Modify
beforeAgentStartAgent receives a messageAgent config, chat context
afterAgentCompleteAgent finishes responseNothing (observation only)
beforeToolExecBefore a tool runsTool input (by returning a replacement input object)
afterToolExecAfter a tool completesNothing (observation only)
afterChatTurnFull chat turn completesNothing (observation only)
transformInboundMessageUser text enters runtimeInbound text
transformOutboundMessageAssistant text leaves runtimeOutbound text
getAgentContextPrompt context assemblyAdditional markdown context block
getCapabilityDescriptionPrompt capability assemblyCapability line in system prompt
getOperatingGuidancePrompt guidance assemblyRuntime guidance lines
onTaskCompleteWhen a task status becomes "completed"Nothing (observation only)
onAgentDelegationWhen an orchestrator delegates to a sub-agentNothing (observation only)

Plugin Settings Fields

Plugins can declare ui.settingsFields so users can configure plugin-specific values in the plugin detail sheet.

  • Values are stored in app settings under pluginSettings[pluginId]
  • Unknown keys are ignored on write
  • Fields with type: secret are encrypted at rest
  • Read/write API:
    • GET /api/plugins/settings?pluginId=<pluginId>
    • PUT /api/plugins/settings?pluginId=<pluginId>
  • Supported field types: text, number, boolean, select, secret

Plugin Workspaces & Dependencies

Plugins that need runtime dependencies can be backed by a workspace under data/plugins/.workspaces/<plugin>/.

  • Add a package.json manifest for the plugin
  • Use the Install / Refresh action in the Plugins detail sheet
  • Or call POST /api/plugins/dependencies with { "filename": "plugin.mjs", "packageManager": "npm" }

SwarmClaw tracks dependency install status, package manager, error state, and last-installed time in the plugin metadata shown by the UI and API.

Lifecycle Management

  • Versioning: Plugins support semantic versioning metadata (for example v1.2.3).
  • Updates: External plugins installed from a recorded source URL can be updated individually or in bulk from the Plugins manager. Built-ins update with the app release.
  • Hot Reload: Changes inside data/plugins/ invalidate the plugin registry automatically.
  • Stability Guardrails: Consecutive plugin failures are tracked in data/plugin-failures.json; failing external plugins are auto-disabled and surfaced in Notifications.
  • Source Metadata: Marketplace and URL installs record normalized source URL and source hash metadata in data/plugins.json.

Built-In Plugin Families

SwarmClaw ships a growing set of built-in plugin families. Some of the most useful ones for autonomous work:

  • mailbox: IMAP/SMTP inbox access with list_messages, read_message, reply, download_attachment, and durable wait_for_email.
  • ask_human: Human-loop requests and approvals with request_input, request_approval, wait_for_reply, wait_for_approval, list_mailbox, and ack_mailbox.
  • document: Parse PDFs, Office docs, HTML, OCR-able images, CSV/TSV/XLSX, ZIP listings, and plain text files, then optionally store searchable document text.
  • extract: Turn raw text or local files into validated JSON with schema-driven extraction using the current session model.
  • table: Read, filter, sort, group, pivot, dedupe, join, summarize, and export tabular data without dropping to shell scripts.
  • crawl: Crawl multi-page sites, follow pagination, dedupe crawled pages, and batch-extract structured results.
  • browser: Reusable browser profiles plus higher-level actions such as read_page, extract_links, extract_form_fields, submit_form, download_file, and complete_web_task.
  • schedule_wake / monitor: Durable watch jobs for time, HTTP, file, task, webhook, page, mailbox, and approval waits.
  • delegate / spawn_subagent: Handle-based long-running delegation with persisted resume/checkpoint metadata.

Plugin API

GET  /api/plugins              # List installed plugins
POST /api/plugins              # Toggle plugin enabled/disabled
GET  /api/plugins/marketplace  # Browse marketplace registry
POST /api/plugins/install      # Install from URL { url, filename }
POST /api/plugins/dependencies # Install/refresh workspace deps { filename, packageManager? }
GET  /api/plugins/settings     # Read per-plugin settings (?pluginId=...)
PUT  /api/plugins/settings     # Write per-plugin settings (?pluginId=...)

GET /api/plugins includes failure metadata for operational debugging (failureCount, lastFailureAt, lastFailureStage, lastFailureError, autoDisabled).

Examples

Logging plugin — log all tool executions:

module.exports = {
  name: "tool-logger",
  description: "Logs all tool executions to console",
  hooks: {
    beforeToolExec({ toolName, input }) {
      console.log(`[tool] executing ${toolName}`, input);
    },
    afterToolExec({ toolName, output }) {
      console.log(`[tool] ${toolName} completed`);
    },
  },
};

Guard plugin — flag dangerous shell commands:

module.exports = {
  name: "shell-gate",
  description: "Flags dangerous shell commands",
  hooks: {
    beforeToolExec({ toolName, input }) {
      if (toolName === "shell" && /rm\s+-rf\s+\//.test(input.command)) {
        console.warn("Potentially dangerous shell command detected", input.command);
      }
    },
  },
};