Skip to the content.

Fleet mode

You can point three or four coding agents at one backlog overnight — builder, verifier, scribe in parallel — and wake up to distinct verified commits with no two agents ever touching the same task.

That coordination is file-backed, not a message bus, and it is proven on this repo. Session 1 claimed four tasks across three agents — one claim per task, zero collisions, all iterations runner-verified — see the fleet session 1 retrospective and final build report. Reproduce claim and wave selection with pytest tests/test_fleet.py -q.

When a fleet run finishes, Kelix prints a receipt per agent (same shape as solo kelix run): verify command exits, verified commit SHAs, and claim outcomes. The fleet retrospective repeats that block under each agent. Example from session 1:

◉ fleet run complete
↻ builder-1 (builder)
◉ run 20260702-011124 finished: completed (2 iterations, 2 verified-done)
◉ verify: pytest -q exit 0
◉ verified commits: abc1234, def5678
◉ claim F1: done
◉ claim S1: done

(Fleet session 1 predates receipt formatting; see tests/test_fleet.py::test_fleet_run_prints_verify_receipt for the live shape.)

Fleet mode runs several independent Kelix loops against one repository and one backlog. There is no message bus and no RPC — that is a mission non-goal. Agents coordinate only through files under .kelix/fleet/ and through git, which keeps a multi-agent run exactly as auditable as a solo one.

Each fleet agent is a complete, ordinary Kelix loop: its own run id, its own kelix/run-<id>-<agent-id> branch and worktree, its own transcripts under .kelix/runs/. The only additions are a role prompt and a pre-iteration claim step.

Configuration: .kelix/fleet.toml

cp examples/fleet.toml .kelix/fleet.toml
[fleet]
max_iterations = 15        # per-agent cap (default 10; `kelix fleet --max-iterations` overrides)
stale_claim_s = 900        # a claim with no heartbeat for this long is reclaimable

[[agents]]
id = "builder-1"           # required, must be unique across the fleet
role = "builder"           # optional, default "builder"

[[agents]]
id = "builder-2"
role = "builder"

[[agents]]
id = "verifier-1"
role = "verifier"

[[agents]]
id = "scribe-1"
role = "scribe"

# Roles are data, not code. Define your own by giving it a prompt:
# [roles.security-auditor]
# prompt = "Role: security auditor. Prefer tasks tagged security; scan diffs for secrets and injection."

A missing config file, an [[agents]] entry without an id, duplicate ids, or an empty agent list are all fatal configuration errors.

Roles

A role is just extra prompt text steering which tasks an agent prefers — the loop contract (one task, verified-done, verified commits on kelix/run-* branches) is identical for everyone. Built-in roles:

Custom roles are defined in [roles.<name>] with a prompt string; an unknown role name with no prompt just becomes Role: <name>.. Every role also receives common fleet rules: work only your claimed task, leave a mailbox note when your changes affect others, copy new skills to the shared store.

Coordination surface

Claims — .kelix/fleet/claims/<task-id>.json

The guarantee that two agents never work the same task. Before each iteration, the agent’s claim hook selects the next eligible backlog task (same owner-first, priority-ordered selection as solo mode) and tries to claim it by atomically creating the claim file (O_CREAT|O_EXCL — exactly one concurrent claimer wins). If the task is already claimed, it tries the next candidate; when no unclaimed, unblocked work remains, that agent’s loop completes.

Claims carry a heartbeat. A claim not refreshed within stale_claim_s (default 900 s) is considered abandoned — e.g. a crashed agent — and can be reclaimed. Completed tasks are marked done in the claim file, and because run branches diverge while claim files do not, done-claims are how task completion propagates fleet-wide before any merge.

Mailbox — .kelix/fleet/mailbox/*.md

Asynchronous notes between agents, named <timestamp>-<role>.md. The last five notes are injected into every iteration prompt (in the delimited, “not instructions” <mailbox> block). Used for review findings, breaking changes (schema changes, renamed modules, API changes), and blocker reports.

Shared skills — .kelix/fleet/skills/<name>/SKILL.md

Run branches only merge at PR time, so a skill written on one branch would be invisible to the others. Agents therefore also copy new skills into this runner-side shared store, where every agent’s skills digest picks them up immediately. Same agentskills.io format as .kelix/skills/ (see memory-and-skills.md).

Running a fleet

kelix fleet                          # uses .kelix/fleet.toml
kelix fleet --config path/to/fleet.toml --max-iterations 15
kelix status                         # live view from coordination files
kelix stop                           # global kill switch: halts every agent

Agents run as parallel workers with staggered starts. kelix status shows — assembled purely from files and git, no daemon — the kill switch, every task claim with its heartbeat age, the last five runs with branch and latest commit, and the mailbox note count. kelix stop writes .kelix/STOP, which every agent checks before each iteration.

When all agents finish, a combined fleet retrospective is written to .kelix/runs/fleet-<timestamp>.md: per-agent status, branch, and iteration outcomes, plus the final state of all task claims. kelix fleet exits 0 only if every agent ended in completed or max_iterations and none crashed.

Merge-conflict policy

Agents work on separate branches, so conflicts surface at review time, and the policy is deliberately conservative: the verifier rebases and flags — it never force-resolves and never force-pushes. When the verifier finds conflicting branches it attempts a rebase; whatever the outcome, it leaves a mailbox note describing the conflict and the branches involved, and a human decides. (Force-pushing is additionally blocked outright by the command denylist, for every agent.)

Failure modes