Guide

Swarms as an agent tool

Your agent hands a task to a swarm and applies the patch that comes back. It does this by running the acyclic CLI, the same way it runs git or your tests.

Use the CLI when the agent works on a local checkout: --dir . sends the swarm your working files. If your agent has no shell and the code is in a public repository, connect it over MCP instead.

1. Set up once

Do this yourself, not through the agent: the login prints a link and a code, and a person has to approve it. The session lasts 90 days.

npm install -g @acyclic-labs/cli
acyclic swarm login --site https://acyclic.dev --no-browser
acyclic swarm whoami

For CI, log in once and give the job your ~/.acyclic directory as a secret. It holds a login to your account, so revoke it from the dashboard if it leaks.

2a. Agents with a shell

Claude Code, Codex and Cursor need no wrapper. Add this to the project's CLAUDE.md or AGENTS.md. llms.txt walks the agent through the rest.

## Swarms
For a large task that splits into parts (a migration, a failing
test suite, a wide refactor), hand it to an Acyclic swarm by
following https://acyclic.dev/llms.txt.
Before uploading, run `acyclic swarm run --dir . --dry-run`
and check the file list.
After `acyclic swarm pull <id> --apply`, read `git diff --cached`
and run the tests before committing.

2b. Your own harness

Wrap five commands as tools. Each one runs acyclic swarm … and hands its output to the model, which passes the swarm id from one call to the next.

Toolacyclic swarm …Gives back
swarm_startrun --task … --dir . --idempotency-key …The swarm id, sw_…
swarm_waitwatch <id>Exits when the swarm ends: 0 succeeded, 2 failed, 3 canceled, 1 CLI error
swarm_statusshow <id> --jsonState, agent tree, open questions, spend, result
swarm_answeranswer <id> --option <n>Answers a question the swarm asked
swarm_applypull <id> --applyStages the patch in the checkout

The definition the model sees for the first tool:

{
  "name": "swarm_start",
  "description": "Hand a coding task to an Acyclic swarm: several agents, each in its own cloud sandbox, working on a copy of the current directory. Returns a swarm id. Call swarm_wait with it next.",
  "input_schema": {
    "type": "object",
    "required": ["task"],
    "properties": {
      "task": {
        "type": "string",
        "maxLength": 4000,
        "description": "The goal, the constraints, and how to check the result."
      }
    }
  }
}

And the code behind the first two. Pass arguments as a list, not through a shell, so a task with quotes in it arrives intact. A swarm takes minutes, so give the wait a long timeout and let the model fall back to swarm_status.

import { execFile } from "node:child_process";
import { promisify } from "node:util";

const acyclic = (args: string[], timeout = 60_000) =>
  promisify(execFile)("acyclic", ["swarm", ...args], { timeout, maxBuffer: 16 << 20 });

// key: your tool call's id, so retrying the same call reuses the swarm it started.
export async function swarmStart({ task }: { task: string }, key: string) {
  const { stdout } = await acyclic(["run", "--task", task, "--dir", ".", "--idempotency-key", key]);
  return stdout.trim(); // sw_...
}

export async function swarmWait({ swarm_id }: { swarm_id: string }) {
  try {
    await acyclic(["watch", swarm_id], 30 * 60_000);
    return "succeeded";
  } catch (error: any) {
    if (error.killed) return "still running: call swarm_status";
    if (error.code === 2) return "failed";
    if (error.code === 3) return "canceled";
    return `error: ${error.stderr}`;
  }
}

3. Write the task like a ticket

Give the goal, what not to touch, and how to check the result, in at most 4,000 characters. For example: "Fix the failing tests in tests/api. Don't edit the tests. Done when pytest passes." Longer instructions go in a SKILL.md passed with --skill.

Good to know

  • --dir leaves out .git, .env*, keys and ignored files. run --dir . --dry-run lists what would go up without sending anything.
  • Retrying a start after a timeout? Reuse its --idempotency-key. You get the swarm that already started, not a second bill.
  • A swarm may ask a question, but it never waits for the answer. It carries on with the option it thinks best, so your harness can answer or ignore it.
  • pull --apply stages the change: review it with git diff --cached, since a plain git diff shows nothing.
  • --pull-request opens a GitHub pull request instead. It needs --repo and a linked GitHub account. --tool gives the swarm one of your saved MCP servers.
  • Every extra agent is another sandbox you pay for. Leave --width at the default unless the task really splits into parts.
  • On acyclic.dev the CLI refuses --model, --verify, --from, --boxes and --merge-requires. Those only work against a host you run yourself.
  • Errors end with [X-Trace-Id: …]. Log it, and quote it if you contact us.