Goals and milestones
The goal is split into milestones, and each has a check command that brindle
runs itself. A milestone is done only when its check exits 0, so progress is
verified, not just claimed. A milestone may name a profile, the
worker profile for its tasks, so a small milestone can run on a cheaper one.
The sidebar shows the goal and each milestone (✓ verified, ✗ failing, ○ not
checked yet).
<!-- .brindle/goals.md -->
# Settings page
## Settings API
check: uv run pytest tests/test_settings_api.py -q
## Settings UI
check: npm test -- settings
profile: developer-local
goals.md stays in sync
A session that loaded its goal from goals.md writes each
milestone's status back to that file after every check, as one line under the
milestone, for example status: passed at abc1234 (2026-09-29).
The rest of the file is left exactly as you wrote it, and since
goals.md may be committed, no session data ever goes in. A status
line is information only: a new session starts every milestone as pending and
re-runs the checks. A session stops writing when it's handed over, paused, or
has autopilot off.
Workers in parallel
The supervisor splits each milestone into tasks and starts workers on their
own branches, up to max_agents at once. Claude workers run the
task as a Claude Code /goal with a finish line, so they keep going
until it's met. A task can declare the files it expects to touch
(checked for overlap with other running workers) and depends_on
earlier tasks: it waits in a queue and starts on its own, from the updated
base, once those merge. list_tasks shows what's queued.
Plan-first workers
With plan_first (per task, or as a repo default), a worker
reads the code, proposes a short plan with submit_plan, and
waits. The supervisor approves it with approve_plan, or sends it
back with feedback. Claude workers can't edit files until the plan is
approved; other CLIs are told to wait.
The review-and-merge pipeline
When a worker reports, brindle starts a reviewer at once and runs your
checks in the background. Findings go straight back to the
worker to fix (up to review_rounds times). When the reviewer
approves that exact commit and the checks pass, brindle merges the branch,
removes the worktree, and sends the supervisor one message with the report
and the review. Anything it can't settle (a conflict, a failing check)
arrives as “needs you”. Check runs share the machine: at most
check_concurrency run at once across all branches (2 by
default), the rest wait their turn, and a run that goes far past its last
duration is reported to the supervisor.
It never merges into your default branch on its own. When
a reviewed branch's base is main (or whatever the default is), the
supervisor gets a “needs you” message and merge_workspace
merges it. Set merge_into to an integration branch to have workers
branch from and merge into it instead, or
auto_merge_default_branch: true for fully automatic merges.
The reviewer is your review_profile if set, else the repo's
reviewer (the built-in reviewer by default). brindle
never switches to a different model on its own: set reviewer or
review_profile to reviewer-codex or
reviewer-local for a second model's view. With
hosted learning on, brindle may
pick one of those instead when it can run here and has reviewed this kind of
work better.
It keeps going, and knows when to stop
If the supervisor stops while milestones are unverified and no worker is
running, brindle tells it to continue. It stops when every check passes, when
it needs a decision from you, or after three reminders with no progress.
Passing checks aren't the finish line yet. A check can
pass while the milestone isn't done: the test asserts too little, or checks
the wrong thing. So once every milestone passes, a read-only reviewer audits
the work since the goal was set against the goal and each milestone, looking
for anything missing, stubbed or weakly tested. Only its approval of that
commit finishes the goal; if it finds gaps, the supervisor gets them and keeps
working until a fresh audit approves. "goal_audit": false turns
it off.
Pausing for usage limits
When your Claude usage reaches usage_limit (90% by default),
autopilot pauses: its running Claude workers stop, with worktrees, branches,
queued messages and sessions kept, and the sidebar says “paused for usage
until <time>”. When the usage window resets, brindle restarts those
workers on its own and tells the supervisor what it resumed. To see your
usage, brindle gives the Claude Code agents it launches a status line that
records it (Claude.ai plans report it; API-key use doesn't), then prints
whatever your own status line prints.
Quieter messages
Messages from workers and the pipeline don't interrupt the supervisor
one by one. It gets a single notice (“brindle (16:25:03): 2 new messages
... Call read_messages.”) and reads them with read_messages when it's
ready; the sidebar shows the unread count. If a notice goes unread, the next
message or the end of the supervisor's turn sends a fresh one, at most once
every two minutes. "message_delivery": "push" restores the old
behaviour; messages you send skip the notice: they reach the agent as
written, as soon as it's idle.
Handing over to another branch
brindle start -b BRANCH (or -w PATH) runs the
supervisor in that branch's worktree, creating it if needed; a linked worktree
finds the repo's .brindle config through the main checkout.
brindle handover --to BRANCH (or the supervisor's
handover tool) moves the goal, milestones, workers, queued tasks
and a note to a new supervisor there, and pauses the old one.
Controlling it
brindle autopilot shows progress, brindle autopilot
check runs the checks now, and brindle autopilot off (or
on) hands the wheel back or takes it again. brindle
--no-autopilot, or "autopilot": false in the repo config,
starts without it.
Cost and history
Each Claude Code and local-model agent's token usage is read from its own
transcript (Codex and Antigravity don't report one) and shows in the
sidebar, in brindle ls, in each worker's report, and per row in
brindle history, a durable log of results, reviews, merges and
milestone checks that survives brindle prune. To spend fewer
tokens, workers run only the tests for their change, the full suite runs once
before merge and is cached by commit, and the supervisor makes small changes
itself.