Skills agent-swarm

IMPORTANT: OpenRouter is required. Routes tasks to the right model and always delegates work through sessions_spawn. Rejects prompt-injection patterns in task strings (v1.7.6+).

install
source · Clone the upstream repo
git clone https://github.com/openclaw/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/austindixson/agent-swarm" ~/.claude/skills/clawdbot-skills-agent-swarm && rm -rf "$T"
manifest: skills/austindixson/agent-swarm/SKILL.md
source content

Agent Swarm | OpenClaw Skill

Description

IMPORTANT: OpenRouter is required. Routes tasks to the right model and always delegates work through sessions_spawn.

Before installing

  • OPENCLAW_HOME: Not required. The skill uses
    OPENCLAW_HOME
    only if set; otherwise it defaults to
    ~/.openclaw
    . This is consistent in both metadata (
    _meta.json
    : listed in
    optionalEnv
    , not in
    env
    ) and behavior.
  • openclaw.json read access: The skill reads the local file
    openclaw.json
    (at
    $OPENCLAW_HOME/openclaw.json
    or
    ~/.openclaw/openclaw.json
    ). Only the fields
    tools.exec.host
    and
    tools.exec.node
    are used; no gateway secrets or API keys are read. Verify you are comfortable granting read access to that file before installing.

Examples

Single task

Router output:

{"task":"write a poem","model":"openrouter/moonshotai/kimi-k2.5","sessionTarget":"isolated"}

Then call:

sessions_spawn(task="write a poem", model="openrouter/moonshotai/kimi-k2.5", sessionTarget="isolated")

Parallel tasks

python3 workspace/skills/agent-swarm/scripts/router.py spawn --json --multi "fix bug and write poem"

This returns multiple spawn configs. Start one sub-agent per config.

Commands

Manual/CLI use only. The examples below pass the task as a single argument; for programmatic use with untrusted user input, always invoke the router via

subprocess.run(..., [..., user_message], ...)
with a list of arguments (see Security). Do not build a shell command string from user input.

python scripts/router.py default
python scripts/router.py classify "fix lint errors"
python scripts/router.py spawn --json "write a poem"
python scripts/router.py spawn --json --multi "fix bug and write poem"
python scripts/router.py models

What this skill does

Agent Swarm is a traffic cop for AI models. It picks the best model for each task, then starts a sub-agent to do the work.

IMPORTANT: OpenRouter is required

Required Platform Configuration:

  • OpenRouter API key: Must be configured in OpenClaw platform settings (not provided by this skill)
  • OPENCLAW_HOME (optional): Environment variable pointing to OpenClaw workspace root. If not set, defaults to
    ~/.openclaw
  • openclaw.json access: The router reads
    tools.exec.host
    and
    tools.exec.node
    from
    openclaw.json
    (located at
    $OPENCLAW_HOME/openclaw.json
    or
    ~/.openclaw/openclaw.json
    ). Only these two fields are accessed; no gateway secrets or API keys are read.

Model Requirements:

  • Model IDs must use
    openrouter/...
    prefix
  • If OpenRouter is not configured in OpenClaw, delegation will fail

Why this helps

  • Faster replies (cheap orchestrator, smart sub-agent routing)
  • Better quality (code tasks go to code models, writing tasks go to writing models)
  • Lower cost (you do not run every task on the most expensive model)

Core rule (non-negotiable)

For user tasks, the orchestrator must delegate. It must NOT answer the task itself.

Use this flow every time:

  1. Run router. From orchestrator code, use subprocess with a list of arguments (never shell interpolation with user input):
    import subprocess
    result = subprocess.run(
        ["python3", "/path/to/workspace/skills/agent-swarm/scripts/router.py", "spawn", "--json", user_message],
        capture_output=True,
        text=True
    )
    data = json.loads(result.stdout) if result.returncode == 0 else {}
    
    CLI only (manual testing; do not use from code with untrusted user input):
    python3 workspace/skills/agent-swarm/scripts/router.py spawn --json "your task here"

    Use
    OPENCLAW_HOME
    or absolute path for the script when not in workspace root.
  2. If
    needs_config_patch
    is true: stop and report that patch to the user.
  3. Otherwise call:
    sessions_spawn(task=..., model=..., sessionTarget=...)
  4. Wait for
    sessions_spawn
    result.
  5. Return the sub-agent result to the user.

If

sessions_spawn
fails, return only a delegation failure message. Do not do the task yourself.

Config basics

Edit

config.json
in the skill root (parent of
scripts/
) to change routing.

What you can change

WhatKeyPurpose
Orchestrator / session default
default_model
Main agent and new sessions (e.g. Gemini 2.5 Flash)
Task-specific model per tier
routing_rules.<TIER>.primary
Model used when a task matches that tier
Backup models if primary fails
routing_rules.<TIER>.fallback
Array of model IDs to try next

All task-specific tiers (change the model for each)

TierKey to change primaryTypical use
FAST
routing_rules.FAST.primary
Simple tasks: check, list, status, fetch
REASONING
routing_rules.REASONING.primary
Logic, math, step-by-step analysis
CREATIVE
routing_rules.CREATIVE.primary
Writing, stories, UI/UX, design
RESEARCH
routing_rules.RESEARCH.primary
Research, search, fact-finding
CODE
routing_rules.CODE.primary
Code, debug, refactor, implement
QUALITY
routing_rules.QUALITY.primary
Complex/architecture tasks
COMPLEX
routing_rules.COMPLEX.primary
Multi-step / complex system tasks
VISION
routing_rules.VISION.primary
Image analysis, screenshots, visual

To change all task-specific models: edit each

routing_rules.<TIER>.primary
above. Use model IDs from the
models
array in
config.json
(must start with
openrouter/
).

Simple config examples

Orchestrator only (keep defaults for tiers):

{
  "default_model": "openrouter/google/gemini-2.5-flash"
}

(Other keys like

routing_rules
and
models
can stay as in the shipped
config.json
.)

Change one tier (e.g. CODE to MiniMax):

"routing_rules": {
  "CODE": {
    "primary": "openrouter/minimax/minimax-m2.5",
    "fallback": ["openrouter/qwen/qwen3-coder-flash"]
  }
}

Change multiple tiers (primaries only):

"routing_rules": {
  "CREATIVE": { "primary": "openrouter/moonshotai/kimi-k2.5", "fallback": [] },
  "CODE":     { "primary": "openrouter/z-ai/glm-4.7-flash", "fallback": ["openrouter/minimax/minimax-m2.5"] },
  "RESEARCH": { "primary": "openrouter/x-ai/grok-4.1-fast", "fallback": [] }
}

Only include tiers you want to override; the rest are read from the full

config.json
.

Security

Input Validation

The router validates and sanitizes all inputs to prevent injection attacks:

  • Task strings: Validated for length (max 10KB), null bytes; rejects prompt-injection patterns (script tags,
    javascript:
    protocol, event-handler attributes). Invalid tasks raise
    ValueError
    with a clear message.
  • Config patches: Only allows modifications to
    tools.exec.host
    and
    tools.exec.node
    (whitelist approach)
  • Labels: Validated for length and null bytes

Safe Execution

Critical: When calling

router.py
from orchestrator code, always use
subprocess
with a list of arguments, never shell string interpolation:

# ✅ SAFE: Use subprocess with list arguments
import subprocess
result = subprocess.run(
    ["python3", "/path/to/router.py", "spawn", "--json", user_message],
    capture_output=True,
    text=True
)

# ❌ UNSAFE: Shell string interpolation (vulnerable to injection)
import os
os.system(f'python3 router.py spawn --json "{user_message}"')  # DON'T DO THIS

The router uses Python's

argparse
, which safely handles arguments when passed as a list. Shell string interpolation is vulnerable to command injection if the user message contains shell metacharacters.

Config Patch Safety

The

recommended_config_patch
only modifies safe fields:

  • tools.exec.host
    (must be 'sandbox' or 'node')
  • tools.exec.node
    (only when host is 'node')

All config patches are validated before being returned. The orchestrator should validate patches again before applying them to

openclaw.json
.

Prompt Injection Mitigation

The router rejects task strings that contain prompt-injection patterns (e.g.

<script>
,
javascript:
,
onclick=
). Rejected tasks raise
ValueError
; the orchestrator should surface a clear message and not pass the task to sub-agents. Additional layers:

  1. The orchestrator (validating task strings and handling rejections)
  2. The sub-agent LLM (resisting prompt injection)
  3. The OpenClaw platform (sanitizing
    sessions_spawn
    inputs)

File Access

Required File Access:

  • Read:
    openclaw.json
    (located via
    OPENCLAW_HOME
    environment variable or
    ~/.openclaw/openclaw.json
    )
    • Fields accessed:
      tools.exec.host
      and
      tools.exec.node
      only
    • Purpose: Determine execution environment for spawned sub-agents
    • Security: The router does NOT read gateway secrets, API keys, or any other sensitive configuration

Write Access:

  • Write: None (no files are written by this skill)
  • Config patches: The skill may return
    recommended_config_patch
    JSON that the orchestrator can apply, but the skill itself does not write to
    openclaw.json

Security Guarantees:

  • The router does not persist, upload, or transmit any tokens or credentials
  • Only
    tools.exec.host
    and
    tools.exec.node
    are accessed from
    openclaw.json
  • All file access is read-only except for validated config patches (whitelisted to
    tools.exec.*
    only)

Other Security Notes

  • This skill does not expose gateway secrets.
  • Use
    gateway-guard
    separately for gateway/auth management.
  • The router does not execute arbitrary code or modify files outside of config patches.
  • The phrase "saves tokens" in documentation refers to cost savings (using cheaper models for simple tasks), not token storage or collection.