Plugin Tutorial

This tutorial walks through building a real SwarmClaw plugin from scratch, enabling it, testing it, and shipping it in a way that still behaves well under autonomous agent load.

What You'll Build

A plugin that:

  • Adds one custom tool (release_guard)
  • Rewrites tool input with beforeToolExec
  • Exposes plugin settings in Settings → Plugins
  • Demonstrates safe install, test, update, and recovery flows

Prerequisites

  • SwarmClaw running locally
  • Access to data/plugins/
  • Basic JavaScript familiarity

Plugin File Format

SwarmClaw supports both:

  • CommonJS: module.exports = { ... }
  • ESM: export default { ... } in a .mjs file

For a first plugin, CommonJS is the easiest path.

Step 1: Create the Plugin File

Create data/plugins/release-guard.js:

module.exports = {
  name: "release-guard",
  version: "1.0.0",
  description: "Adds a guarded release checklist tool and traces risky shell usage.",

  hooks: {
    getCapabilityDescription() {
      return "I can run guarded release checks with `release_guard` and annotate risky shell calls."
    },

    getOperatingGuidance() {
      return [
        "Prefer dry-run or preview modes before write actions.",
        "If a release tool would publish externally, confirm the target first.",
      ]
    },

    beforeToolExec({ toolName, input }) {
      if (toolName !== "shell" || !input || typeof input !== "object") return input
      if (typeof input.command !== "string") return input
      if (!/npm publish|git push|docker push/i.test(input.command)) return input

      return {
        ...input,
        command: `echo "[release-guard] traced command"; ${input.command}`,
      }
    },

    afterToolExec({ toolName, output }) {
      if (toolName === "shell") {
        console.log("[release-guard] shell completed", String(output).slice(0, 160))
      }
    },
  },

  tools: [
    {
      name: "release_guard",
      description: "Return a compact release checklist for a package, app, or deployment target.",
      parameters: {
        type: "object",
        properties: {
          target: { type: "string" },
          environment: { type: "string", enum: ["dev", "staging", "prod"] },
        },
        required: ["target"],
      },
      async execute(args, ctx) {
        return {
          ok: true,
          target: args.target,
          environment: args.environment || "prod",
          cwd: ctx.session.cwd,
          checklist: [
            "Verify tests or smoke checks are green",
            "Confirm release target and credentials",
            "Review rollback path before publish",
          ],
        }
      },
    },
  ],

  ui: {
    settingsFields: [
      {
        key: "defaultEnvironment",
        label: "Default Environment",
        type: "select",
        options: [
          { label: "Development", value: "dev" },
          { label: "Staging", value: "staging" },
          { label: "Production", value: "prod" },
        ],
        defaultValue: "staging",
      },
      {
        key: "releaseToken",
        label: "Release Token",
        type: "secret",
      },
    ],
  },
}

Step 2: Understand the Important Parts

  • hooks.beforeToolExec can return a replacement input object. Use that only for deliberate input shaping, not silent policy surprises.
  • hooks.getCapabilityDescription helps the agent understand what the plugin adds.
  • hooks.getOperatingGuidance adds concise runtime hints.
  • tools[].execute(args, ctx) receives normalized JSON input plus the current session context.
  • ui.settingsFields renders a settings form in the Plugins sheet. Fields with type: "secret" are encrypted at rest.

Step 3: Enable the Plugin

  1. Open Settings → Plugins
  2. Confirm release-guard appears in the installed list
  3. Toggle it on
  4. Open the plugin detail sheet and save any settings you declared

SwarmClaw hot-reloads plugin files, so a restart is usually unnecessary after editing code under data/plugins/.

Step 4: Test the Plugin Tool

Ask an agent to call:

  • Tool: release_guard
  • Input: { "target": "npm package", "environment": "staging" }

You should get a JSON result with:

  • ok: true
  • target
  • environment
  • checklist

Step 5: Test Hook Behavior

Ask an agent to run a shell command that includes something risky, for example a publish or push command. Because beforeToolExec returns a replacement input object, the tool input is rewritten before execution.

Good uses for beforeToolExec:

  • Adding tracing or dry-run flags
  • Injecting plugin-controlled defaults
  • Enforcing a small number of explicit safety wrappers

Bad uses:

  • Silently changing the user’s intent
  • Hiding destructive behavior inside a plugin

Step 6: Read and Write Plugin Settings

The plugin sheet uses:

  • GET /api/plugins/settings?pluginId=<pluginId>
  • PUT /api/plugins/settings?pluginId=<pluginId>

Use settings for values that should not live in source code, such as:

  • API base URLs
  • Project defaults
  • Tokens or credentials

Unknown keys are ignored on write, and secret values are encrypted before storage.

Step 7: Install From URL and Update Safely

Once the plugin works locally, you can host it on HTTPS and install it from Settings → Plugins → Install from URL.

SwarmClaw records normalized source metadata for URL-installed plugins, which enables future updates from the Plugins manager. Built-in plugins update with the app release; external plugins update from their recorded source URL.

Step 8: Add Dependencies When You Need Them

If your plugin needs third-party npm packages, give it a package.json manifest and let SwarmClaw manage a per-plugin workspace.

Typical flow:

  1. Attach a package.json manifest to the plugin
  2. Open the plugin detail sheet in Settings → Plugins
  3. Use Install / Refresh in the Dependencies card

The same operation is available over the API:

curl -X POST http://localhost:3456/api/plugins/dependencies \
  -H "Content-Type: application/json" \
  -d '{"filename":"release-guard.js","packageManager":"npm"}'

SwarmClaw records dependency status, install errors, package manager, and last install time in plugin metadata so operators can see whether the workspace is ready.

Step 9: Failure Recovery

To test stability guardrails, temporarily throw an error from one of your hooks:

beforeToolExec() {
  throw new Error("intentional failure")
}

SwarmClaw tracks consecutive failures across plugin load, hooks, and tool execution. If a plugin keeps failing, it can be auto-disabled based on SWARMCLAW_PLUGIN_FAILURE_THRESHOLD.

Recovery flow:

  1. Fix the plugin code
  2. Re-enable the plugin in Settings → Plugins
  3. Re-run a safe test tool call

Failure metadata is stored in data/plugin-failures.json.

Common Patterns

  • Build one plugin around one responsibility
  • Keep tool outputs structured when possible
  • Use plugin settings instead of hardcoding secrets
  • Use hooks for guidance or light shaping, not heavy hidden control flow
  • Prefer a dedicated tool over overloading a lifecycle hook when the agent needs explicit intent

Common Mistakes

  • Returning prose when the agent really needs JSON
  • Doing expensive work in every hook invocation
  • Storing credentials in source instead of settingsFields
  • Installing unreviewed remote plugin code on production agents
  • Forgetting that external plugins execute as server-side code with app-level access

Next Steps

  • Use Plugins for the full hook and API reference
  • Add UI extensions (sidebarItems, headerWidgets, chatInputActions) after your tool contract is stable
  • Combine plugin tools with the built-in document, extract, table, and crawl families when you want structured autonomous workflows without writing shell scripts