Agent Fleets
Fan a dependency-ordered task DAG out to parallel worker agents in one shared tree, coordinated by cooperative file claims — with per-task worktree isolation as the opt-in, a SQLite ledger of every attempt and dollar, and an optional CI watch.
stella fleet runs many tasks at once — each task handled by a full
Stella worker. By default the workers share one tree: every worker runs
in the repository root, coordinated by cooperative file claims, so conflicts
surface at write time with the rival named, commits interleave on one
branch, and the build cache stays warm. A task marked
isolation = "isolated" instead gets its own git worktree on its own
branch, isolated from your working copy and from every other worker.
stella fleet \
"Add unit tests for the parser module" \
"Document every public function in src/api/" \
"Fix the clippy warnings in the store crate"How a fleet run works
- Plan. Task prompts (inline, or from a
--planfile) form a DAG: tasks withdepends_onwait for their dependencies. Plans are validated up front — a duplicate id, a self-dependency, an unknown dependency, or a dependency cycle is rejected before anything runs, with the offending task (or cycle path) named. - Share — or isolate. By default every worker runs directly in the
repository root under the cooperative claim discipline (see
file claims below). A task marked
isolation = "isolated"instead gets a fresh git worktree under.stella/worktrees/<slug>, branched from a pinned base commit (the currentHEAD, or--base-ref, resolved to a SHA at start so mid-run commits can't drift the base) onto afleet/<slug>-<hash>branch. The 16-hex-digit hash suffix keeps re-runs — which reuse task ids liket1— from colliding with branches and worktrees you kept from an earlier fleet. Isolated workers can't see each other's uncommitted work and can't touch your checkout. - Dispatch in waves. Dependency-ordered waves run up to
--max-concurrencytasks at once (default 4). A failed task does not unblock its dependents — they end the run asskipped— and nothing is retried automatically: the ledger records every attempt, but re-running is your call. - Work. Each worker is a full engine run — the
staged pipeline with the standard toolbelt,
honoring your agent-engine config.
Workers are headless by design: no MCP, no interactive prompts, nothing
that can block on stdin. Pass
--no-pipelineto run the raw step loop instead of the staged pipeline. - Record. Every attempt, commit, and dollar lands in the fleet ledger
at
.stella/fleet.db— local SQLite, like all Stella telemetry. Past runs (tasks, attempts, successes, commits) also surface on the Fleet runs card of the Observatory dashboard. - Review. Shared-tree work lands directly on your current branch as
interleaved commits. Isolated tasks' worktrees and
fleet/*branches are deliberately left in place — those branches are the work product. Inspect, test, and merge them on your terms;git worktree listshows them all.
Plan files
For anything beyond a handful of independent prompts, declare a plan
(.toml or .json):
[[tasks]]
id = "t1"
title = "Bump the version and changelog"
prompt = "Bump the workspace version to 1.4.0 and update CHANGELOG.md"
claims = ["Cargo.toml", "CHANGELOG.md"]
[[tasks]]
id = "t2"
title = "Update the release notes page"
prompt = "Update the release notes for 1.4.0 from the merged PRs"
depends_on = ["t1"]Each task carries an id, title, and prompt, plus optionally:
depends_on— ids that must succeed before this task dispatches (orders the waves).isolation—shared_tree(the default: run directly in the repo root under the cooperative claim discipline) orisolated(own worktree, own branch — the explicit opt-in for genuinely divergent work: best-of-N attempts producing competing versions of the same files, or tasks that mutate checkout state. Claims can't help there — the conflict is the point — and the costs are real: a cold build cache per tree, and conflicts deferred to integration time).claims— workspace-relative paths held as cooperative file locks.
File claims — cooperative locks
A task that declares claims (workspace-relative paths it intends to touch)
holds them as cooperative file locks for the attempt's duration. A second
task — or a second fleet run — that claims an already-held path fails that
dispatch by name instead of silently racing another agent into the same
file. The locks live in the file_locks table of .stella/store.db,
separate from the fleet ledger, so they coordinate across concurrent fleet
runs too.
Budget across a fleet
Budget comes from the global --budget flag (or STELLA_BUDGET), which
goes before the subcommand:
stella --budget 5 fleet --plan release-prep.toml
# equivalently: STELLA_BUDGET=5 stella fleet --plan release-prep.tomlIt is enforced twice: each child runs under its own guard — the aggregate cap
divided across the concurrency width (budget ÷ max-concurrency), so one
wave's in-flight children can't collectively overshoot — and the fleet stops
launching new waves once total metered spend crosses the cap. In-flight
siblings settle cleanly — never a mid-tool kill.
Watching CI: --watch
After the fan-out, --watch holds a fleet monitor on every branch that
carries successful work: it watches each branch's CI to completion via the
gh CLI, reconciles PR status live, and exits non-zero if any watched branch
ends red. It polls every 30 seconds, allows CI 10 minutes of startup grace to
appear, gives up on a branch after 20 minutes without progress, and caps the
whole watch at 2 hours of wall time.
stella fleet --plan release-prep.toml --max-concurrency 2 --watch--watch only has something to watch once branches are pushed — for
example when your task prompts push and open PRs. It requires an installed,
authenticated gh.
Flags
| Flag | Meaning |
|---|---|
<task>... | One or more task prompts. Required unless --plan is given. |
--plan <FILE> | A .json/.toml plan with [[tasks]] entries. |
--max-concurrency <N> | Max tasks running at once per wave. Default 4. |
--base-ref <ref> | Git ref the worktrees branch from. Default: current HEAD, pinned to a SHA at start so mid-run commits can't drift the base. |
--watch | Watch each successful branch's CI to completion after the fan-out. |
--no-pipeline | Workers run the raw step loop instead of the staged pipeline. |
Cleaning up
When you've merged (or rejected) the branches your isolated tasks left — the branch names carry a hash suffix, so list them rather than guessing:
git worktree list # what the fleet left in .stella/worktrees/
git worktree remove <path> # per worktree
git branch --list 'fleet/*' # the fleet branches
git branch -D fleet/<slug>-<hash> # per branch, exactly as listedGoal Mode
Run Stella in judged rounds until an independent judge model — routed to a different model family than the worker — confirms from evidence that your objective has been met.
Built-in Tools
The complete catalog of tools the Stella agent can call in every session, including which are read-only and which mutate your workspace.