Writing Agents

How to define, configure, and tune agents in swarm.

Overview

Agents are the core unit of work in swarm. Each agent runs in its own git worktree with its own backend session, system prompt, and permissions. You define agents in ~/.swarm/settings.json under the agents array of your project configuration.

Step 1: Create the Settings File

If you haven't already, initialize the configuration:

swarm init --path /path/to/your-project

This creates ~/.swarm/settings.json with a skeleton project config. Open it in your editor.

Step 2: Define a Provider

Providers specify how swarm connects to a model API. At minimum, you need one provider:

{
  "version": 2,
  "/home/user/my-project": {
    "providers": {
      "default": {
        "type": "anthropic",
        "api_key_env": "ANTHROPIC_API_KEY"
      }
    }
  }
}

Provider fields:

FieldTypeRequiredDefaultDescription
typeStringYesProvider type ("anthropic")
api_key_envStringNo"ANTHROPIC_API_KEY"Environment variable holding the API key
base_urlStringNonullCustom API base URL
max_retriesu32NonullMax retries for transient errors
timeoutu64NonullRequest timeout in seconds

You can define multiple providers and reference them by name in agent or defaults config.

Step 3: Set Project Defaults

The defaults section provides fallback values for all agents:

{
  "defaults": {
    "model": "sonnet",
    "provider": "default",
    "commit_interval": 300,
    "max_consecutive_errors": 5,
    "max_total_errors": 20,
    "liveness": {
      "enabled": true,
      "idle_nudge_after_secs": 120,
      "idle_nudge_interval_secs": 300,
      "max_nudges": 3
    }
  }
}

Key defaults:

FieldDefaultDescription
model"sonnet"Default model identifier
provider"default"Default provider name
session_timeoutnullPer-session timeout (seconds)
commit_interval300Auto-commit interval (seconds)
max_consecutive_errors5Errors before an agent stops
max_total_errors20Lifetime errors before an agent stops

Step 4: Define Agents

Each agent needs a name and a prompt. All other fields are optional:

{
  "agents": [
    {
      "name": "backend",
      "prompt": "You are a senior backend engineer. Focus on API design, database schemas, and server-side logic. Write tests for all new endpoints.",
      "model": "sonnet"
    },
    {
      "name": "frontend",
      "prompt": "@prompts/frontend.md",
      "model": "sonnet"
    },
    {
      "name": "reviewer",
      "prompt": "You are a code reviewer. Read changes from other agents and provide feedback via messages.",
      "model": "sonnet"
    }
  ]
}

Agent fields:

FieldTypeRequiredDefaultDescription
nameStringYesUnique identifier ([a-z][a-z0-9-]*)
promptStringYesSystem prompt text or @path/to/file
modelStringNodefaults.modelModel identifier
providerStringNodefaults.providerProvider name reference
permissionsPermissionsConfigNonullAgent-level permission overrides
modeStringNoSee cascadeAgent execution mode

Prompt Loading

Prompts can be specified in two ways:

  • Inline: Write the prompt directly as a string value
  • File reference: Use @path/to/file to load from a file relative to the project root

File references are useful for long prompts and allow version-controlling prompts alongside your code:

prompts/
  backend.md
  frontend.md
  reviewer.md

Name Rules

Agent names must:

  • Start with a lowercase letter
  • Contain only lowercase letters, digits, and hyphens
  • Be unique within the project

Invalid names cause a ValidationError at startup.

Step 5: Configure Permissions

Permissions control what tools each agent can use. They're defined at the project level and optionally overridden per agent.

Project-Level Permissions

{
  "permissions": {
    "allow": ["Read(*)", "Glob(*)", "Grep(*)"],
    "deny": ["Bash(rm -rf *)"],
    "default_mode": "default"
  }
}

Agent-Level Overrides

{
  "name": "frontend",
  "prompt": "...",
  "permissions": {
    "allow": ["Bash(npm *)"],
    "deny": ["Bash(rm *)"]
  }
}

Agent permissions are evaluated after project permissions. See Permissions for the full evaluation order.

Rule Format

Rules follow the pattern Tool(specifier):

ExampleMeaning
Read(*)Allow reading any file
Bash(npm *)Allow any npm command
Bash(rm *)Match any rm command
Edit(src/*.rs)Match editing Rust files in src/

Step 6: Choose Agent Modes

The mode field controls how an agent interacts with tools and the operator. Available modes:

ModeDescription
defaultStandard mode — tools require permission checks
accept-editsAuto-accept file edits without confirmation
planPlanning mode — agent proposes changes but doesn't execute
dont-askSkip all permission prompts (auto-allow)
bypass-permissionsBypass the permission system entirely

Set a default mode for all agents:

{
  "defaults": {
    "mode": "dont-ask"
  }
}

Or override per agent:

{
  "name": "reviewer",
  "prompt": "...",
  "mode": "plan"
}

Step 7: Add a Supervisor (Optional)

The supervisor generates the final merge commit message when stopping with --merge or --squash:

{
  "supervisor": {
    "prompt": "Summarize all agent changes into a concise merge commit message.",
    "model": "sonnet"
  }
}

If omitted, swarm uses a built-in merge prompt.

Complete Example

A full three-agent configuration:

{
  "version": 2,
  "/home/user/my-project": {
    "providers": {
      "default": {
        "type": "anthropic",
        "api_key_env": "ANTHROPIC_API_KEY"
      }
    },
    "defaults": {
      "model": "sonnet",
      "commit_interval": 300,
      "max_consecutive_errors": 5,
      "max_total_errors": 20,
      "mode": "dont-ask",
      "liveness": {
        "enabled": true,
        "idle_nudge_after_secs": 120,
        "idle_nudge_interval_secs": 300,
        "max_nudges": 3,
        "stall_timeout_secs": 900
      }
    },
    "agents": [
      {
        "name": "backend",
        "prompt": "@prompts/backend.md",
        "model": "sonnet"
      },
      {
        "name": "frontend",
        "prompt": "@prompts/frontend.md",
        "model": "sonnet",
        "permissions": {
          "allow": ["Bash(npm *)", "Bash(npx *)"],
          "deny": ["Bash(rm -rf *)"]
        }
      },
      {
        "name": "reviewer",
        "prompt": "@prompts/reviewer.md",
        "model": "sonnet",
        "mode": "plan"
      }
    ],
    "supervisor": {
      "prompt": "@prompts/supervisor.md"
    },
    "permissions": {
      "allow": ["Read(*)", "Glob(*)", "Grep(*)"],
      "default_mode": "default"
    }
  }
}

Troubleshooting

"config validation failed: agent names must be unique"

Two agents have the same name. Each agent must have a distinct name.

"config validation failed: agents list cannot be empty"

You must define at least one agent in the agents array.

"config file not found"

Run swarm init to create the settings file, or verify the path in ~/.swarm/settings.json matches your project's canonicalized absolute path.

Agent keeps entering CoolingDown state

Check the agent's logs with swarm logs <name>. Common causes:

  • Invalid API key (check the api_key_env environment variable)
  • Model name not recognized by the provider
  • Prompt too large for the model context window

The backoff formula is min(2000 * 2^(n-1), 60000) ms, where n is consecutive errors. After max_consecutive_errors (default 5), the agent stops.