relevo docs
Every verb, file and state relevo has, in the order a round meets them: the round, actors and runners, remote builders, the MasterMind, what relevo shows you, the daemon, between rounds, candidates and gates, the refusals, install.
First round
On a clean machine, relevo config init comes first: it writes the candidates,
policy and actors sections from the harnesses on PATH and installs the agent
definitions relevo ships. relevo doctor then preflights the plugin, the daemon,
each harness binary and the roles, and names anything still missing together with the literal fix command.
relevo config init
# candidates, policy and actors
relevo doctor
# names what is missing and prints the fix
Then, from the MasterMind session, in the repository you want worked on:
relevo bind --name api --no-feature
# start a builder on this tree
relevo send --name api --file plan.md
# hand it the plan
relevo wait --name api --timeout 10m
# 0 closed · 3 needs you · 5 halted
relevo done api
# stop relaying
The builder writes NNN-report.md when it has finished and then creates an
empty NNN-done as its last action. relevo closes the round on that marker:
the marker is the contract, not the report. A runner that exits with a report and no marker still
closes the round, flagged unmarked; one that leaves no report is noted
noreport. Nothing is read off a terminal and nothing is guessed.
relevo makes no judgement about what came back. When the report lands, run the project’s own check yourself and compare the diff against the plan before calling the round done. In Claude Code the wait runs as a background command and the session wakes with the report — see how reports arrive.
demonstrationauthored from relevo’s output formats · not a capture of a session
$ relevo send --name api --file plan.md --dry-run
would send round 5 to api
runner headless agy/google/gemini-3.8-flash-high
where /usr/bin/agy -p
tier edit
prompt /home/me/.local/state/relevo/api/005-prompt.md (staged from ./plan.md, 4.1 KiB)
report /home/me/.local/state/relevo/api/005-report.md
marker /home/me/.local/state/relevo/api/005-done
head relevo: round 5 · to runner "api" · from the MasterMind (not the human)
Your working tree is: /home/me/.worktrees/api
The round
relevo wait exits with meaning, so a shell can branch on it:
- 0
- closed on the marker, stdout is the report path
- 2
- closed without it (
unmarked, ornoreport— verify before trusting) - 3
- needs you, stdout says what it is waiting on
- 4
- the binding is DONE or was unbound
- 5
- closed, but the report says halted or blocked — read it before sending again
- 6
- the round was never sent, so nothing is in flight
- 124
- the
--timeoutelapsed.
On every exit but 4 and 124 the wait prints the pending report itself, marked delivered, so collecting a report never means typing into your session.
The report block. A runner ends its report with a fenced
relevo block: status, one of
done, halted, blocked or
deferred; then halted_at,
changed_paths, commands_run and
not_done. relevo reads the block for its shape, never for meaning: a
halted or blocked status is what puts
relevo wait on exit 5. A report with no usable block closes the round as
unstructured, without error.
Every mutating verb ends by listing, on stderr, every other binding that is waiting on a human — how long, and the verb that resolves it. The exit code is unchanged; it is a reminder, not a refusal.
What a round leaves on disk
An open round’s files sit under ~/.local/state/relevo/<name>/,
the state root resolving through $XDG_STATE_HOME. When the round closes, relevo
seals those files into relevo.db in the same transaction that closes the round,
and removes them, so the directory afterwards holds only the files of a round still open.
relevo show reads either: a live binding’s open round, or anything sealed or
archived.
- NNN-prompt.md
- The round’s plan, as the MasterMind handed it over. It opens
with an origin line:
relevo: round N · to runner "api" · from the MasterMind (not the human). - NNN-report.md
- The runner’s report, read back by the MasterMind. Instruction-shaped lines in it are flagged for the reader to see — never altered, never held back.
- NNN-done
- Empty. Its existence is the completion contract.
- NNN-runner.jsonl
- The harness’s own stream, one JSON event per line, plus the
supervisor’s exit trailer.
relevo show --transcriptrenders it for a human. When the harness’s stream carries times, each rendered line opens with the event’s clock and how long the step took (12:41:03 +4.2s ● Bash go test ./...); codex’s stream carries no time field and is never stamped. - NNN-diff.patch
- The round’s captured patch.
relevo show --diffprints it,--statthe summary,--driftwhat changed between rounds, and--anchorseach hunk and line with itspath:line. - NNN-question.md
- A blocked runner’s dialog, captured.
- NNN-gate.log
- The gate command’s own output, when the round runs one.
The binding itself, its round log and the configuration are rows in relevo.db,
not files. Nothing else in the state root is a source of truth.
Actors and runners
Three words, kept apart. An actor is a role — builder,
planner, reviewer. A candidate is one way to
fill it, named harness/provider/model; each actor holds an ordered candidate list
(see candidates, actors, gates). An actor entry also names a
placement — where its rounds run, most preferred first; local
is this machine and every other entry names a servers entry; absent or empty means
["local"]; bind probes the list in order and
--server/--local override it. The runner is the
process relevo starts for the round.
One fresh process per round. A runner is the harness’s non-interactive form —
claude -p …, agy -p …,
opencode run …, codex exec … — started in the
binding’s tree with the round’s prompt, writing its own stream to
NNN-runner.jsonl and returning when it is done. The daemon renders that stream as
it grows, so relevo status and relevo ui show the round
live, about two seconds behind. It also means no memory across rounds: a plan must carry its own context.
Reader actors
A reader runs like a builder — bind it, send it a plan — but its round reads and reports instead of writing.
relevo runs it in a throwaway scratch copy of the tree: it never edits the shared tree, and nothing it does is
committed. Its final message becomes the round’s output,
NNN-<actor>/<label>.md, and is queued to the MasterMind like any
report.
relevo bind --name webshop --no-feature --actor reviewer
relevo send --name webshop --file q.md
# q.md becomes the round's prompt
relevo show webshop --output
# the round's output file
The reader actors relevo ships are planner,
lite-planner, reviewer and
researcher. The output label follows the actor: a
reviewer writes findings.md, a
researcher notes.md, a planner
plan.md. relevo show <name> --output prints it,
and --artifacts lists the round’s other files.
relevo also ships security-reviewer, a second read-only consult that audits a
diff, area or question for exploitable issues and returns findings with severity,
file:line evidence and preconditions. relevo does not run it automatically — add a
security actor whose candidate list names the models, then bind
--actor security; the definition supports the two-round protocol (round one to one
model, its findings to a second model to confirm or refute each and hunt what the first missed), and it writes
findings.md like reviewer.
Planner actors
A planner is a reader actor too: bind a lite-planner, send it a seed, and read
its plan back from the round’s output.
relevo bind --name plan-x --no-feature --actor lite-planner
relevo send --name plan-x --file task.md
# the seed, at most 4 KiB
relevo show plan-x --output
# plan-x's plan.md
relevo send --name api --file ./plan.md
# the plan you reviewed, on to a builder
A planner round takes a seed, not a plan: the prompt is capped at 4 KiB and a larger one is refused
unless --force. Review the plan with
relevo show --output, then hand that output path to a builder. Reviewing is a human
or MasterMind step — relevo sends nothing automatically.
Several builders at once. relevo bind gives the MasterMind one builder over
the current tree. relevo bind --worktree attaches another, on its own git worktree,
so exactly one agent writes to any working tree. Each peer is an ordinary binding: its own round counter, round
log, captured diffs and budget, and its own name for every verb that takes one.
Remote builders
A remote binding is an ordinary binding whose builder runs on someone else’s machine, over a signed, pinned
HTTPS connection instead of a local process. It has no worktree of its own:
relevo send ships a bundle of your branch’s history alongside the plan, and the
daemon polls the server for the round’s state the same way it polls a local builder. Nothing else about the
round changes — plan out, report back, the marker closes it.
-
outbound.
relevo sendships001-plan.mdand a bundle ofrelevo/apito the server, over pinned HTTPS. -
The serve daemon runs a fresh headless builder in a worktree on
relevo/api. No MasterMind there. -
inbound. The closed round comes back as a fast-forward onto your own
refs/heads/relevo/api. -
Your daemon polls the server for the round’s state;
statusandwaitsync first, so a laptop closed overnight still collects the round.
Set up once, per machine
- 01
- On the server host:
relevo serve init --host <hostname>once — a server private key and a self-signed certificate — then share the SHA-256 fingerprint it prints. - 02
- Each client runs
relevo config server key: this machine’s remote-builder identity, an ed25519 keypair, and the enrollment line to hand the server’s admin. - 03
- The admin runs
relevo serve enroll --label <label> --key "<line>"on the server, one line per client. Nothing is enrolled until this happens. - 04
- The client records the server and pins its certificate:
relevo config server add zen https://… --fingerprint sha256:…— and, having a fingerprint to check it against, checks enrollment at once. - 05
relevo config server list— every configured server and this client’s standing on each:enrolled as <label>,not enrolled,unreachable,cert changed.
This release binds every request signature to the destination server’s identity. A client that pins the
fingerprint signs for it and needs nothing; a client that trusts the system CA
(--ca system) or runs over plain HTTP
(--insecure) signs for the URL’s host, so the server admin starts
relevo serve --public-host <that host> (repeatable; the port is dropped),
and a server with no accepted audience refuses every signed request. The two ends upgrade together: a
pre-upgrade client against an upgraded server gets HTTP 426, and
relevo config server list marks that server with
server rejected protocol version (426); an upgraded client against a
pre-upgrade server prints server predates audience-bound signatures; upgrade relevo
on the server. Upgrade both, then enrolled as <label>. A
bind --server overrides the actor’s placement, a plain
bind follows the placement list, and --local pins
this machine.
Then, from any repository
relevo bind --name api --server zen --no-feature
# the binding, and the local branch relevo/api
relevo send --name api --file plan.md
# ships plan.md and a bundle of relevo/api
relevo status
# round state comes from the server, polled
What comes back
The closed round is fetched into your repository’s own
refs/heads/relevo/<name> — fast-forward only, exactly like a local
builder’s worktree branch. Uncommitted changes on the server land on a side ref,
refs/relevo/<name>/round-<N>, and the report names it. Every
status and every wait syncs remote bindings
first, without needing the daemon, so a laptop closed overnight still collects the finished round on the
next relevo status.
What is refused, and what the server is not
relevo serve runs no MasterMind and takes no administrative verbs over the
network: administration happens on the server host. A remote builder cannot be changed in place —
bind --resume --rebind against one is refused, the same rule a local binding
follows; unbind and create it again. Tenants are protected from each other over the wire and from a
passive network — not from the server’s admin, and not from each other at the OS level, where every
builder runs as the same unix user.
The MasterMind
The MasterMind is the session you drive — the Claude Code or opencode session you run
relevo bind and relevo send from. relevo does not
pick its harness and does not start it. What relevo provides is the definition, so the same architect runs on
any kind; relevo config agents --agent architect installs it, and the harness’s
own flag starts it:
claude --agent architect --model opus
opencode --agent architect -m openrouter/deepseek/deepseek-v4-pro
The plugin
A Claude Code MasterMind installs relevo as a plugin. The plugin carries
relevo mcp — the MCP server that exposes status,
send, show, gate and
done as tools — and a
SessionStart hook that runs relevo mastermind init, so
relevo knows which session is calling. It also carries the slash commands
/relevo:status and /relevo:show beside the consent
commands, and the planner-loop skill that walks the send → wait → read → check →
done loop. The plugin ships with relevo’s releases.
/plugin marketplace add fuad-daoud/relevo
/plugin install relevo@relevo
Claude Code caches an installed plugin by version, so after upgrading relevo, update the plugin to match —
relevo doctor warns when the two differ:
claude plugin marketplace update relevo && claude plugin update relevo@relevo
Repository consent
relevo registers a session as a MasterMind only with your consent, and the slash commands answer for you:
/relevo:enable says yes for this session,
/relevo:enable-repo yes for this repository from now on,
/relevo:disable no for this session,
/relevo:disable-repo never in this repository, and
/relevo:reset asks the question again. They run
relevo mastermind enable, enable --repo,
disable, disable --repo and
reset. relevo mastermind list shows the records, and
relevo mastermind rename <id|name> <new-name> gives one a name of your
own. A round’s process is not a consent candidate: it runs with exactly one
RELEVO_RUNNER=<binding name> and relevo strips its own identity variables,
so a builder or reader session is never asked the repository consent question, never briefed and never
registered as a MasterMind.
How reports arrive
The background wait is the default. After each relevo send, the
MasterMind runs relevo wait --name <n> --timeout <budget> as a
background command and ends its turn. Claude Code wakes the session when the command exits, with the report
already in its output; an agy MasterMind is woken by the report itself, through credentials relevo refreshes
on every command. Nothing has to be typed into the session.
The channel is opt-in. With the channel enabled, reports and consult answers arrive as channel events
the moment the daemon has them, instead of being fetched by the wait. It is off unless you turn it on; a
relevo mcp server with no channel runs in tools mode, which is the background wait
described above.
A report therefore reaches the MasterMind by exactly one of four routes: the background
relevo wait, the channel, a deliverer for a harness that has one, or a
relevo wait you run by hand. Nothing is ever typed into a terminal. No verb
has to guess who is calling, because the plugin’s hook exports
RELEVO_MASTERMIND.
What relevo shows you
Three read surfaces, all text. relevo reports state and moves files; it never summarises a report or grades a round. Every specimen on this page is authored from relevo’s own output formats and labelled so — there is no capture of a real session here.
relevo status — one row per binding, attention first
demonstrationauthored from relevo’s output formats · not a capture of a session
$ relevo status
client /home/me/src/shop round 2 NEEDS YOU stale 23m
MasterMind architect-14 claude route wait
runner headless opencode blocked pid 48122 since 13:58 `glm-5.3-flash`
last 13:39:02 question to_planner round 2
pending question round 2 -> mastermind
docs /home/me/.local/state/relevo/.worktrees/docs round 3 PAUSED
MasterMind architect-14 claude route wait
runner headless claude idle pid 51204 since 14:31 `sonnet`
last 14:28:40 report to_planner round 3
pending --
api /home/me/src/shop round 4 ACTIVE +120/-30 in 6 quiet 40s ●new
MasterMind architect-14 claude route wait
runner headless opencode working pid 51777 since 14:02 `glm-5.3-flash`
last 14:02:11 report to_planner round 4
pending report round 4 -> mastermind
candidates
agy/google/gemini-3.8-flash-high rate-limited 13:58 until 15:30
1 done · relevo unbind --done to clear
Rows are ordered NEEDS YOU, PAUSED, ACTIVE, DONE — attention first, stale first inside a group, newest
last-event first — the same order relevo ui uses, so the two never disagree. DONE
rows are hidden by default and the footer counts them; --all includes them, so
--all is what shows the work you finished and not yet cleared. Naming a binding
shows only that one.
While a round is open, the row also carries the round’s live diff against its baseline
(+120/-30 in 6, or (shared tree) for a
--cwd binding), an ACTIVE row’s quiet <age>,
and ●new when the newest report has not been read.
--json adds the fields the prose does not spell out: branch,
waiting (cause, line, since, hint), last_seq,
live, quiet_for and unread.
relevo status --line — under the Claude Code prompt
demonstrationauthored from relevo’s output formats · not a capture of a session
> MasterMind architect-14
○ api r3 · builder · prompt sent 12m
○ plan r1 · planner ARTIFACT IN 4m
● client r1 · builder · question in NEEDS YOU 2m
One row per live binding of this MasterMind: ○ name rN · <actor>, plus
on <candidate>[@server] when the runner is remote, what the round is waiting
on, this round’s tokens, then the status column — ARTIFACT IN for a delivered
reader output, REPORT IN for a writer’s, QUESTION IN,
NEEDS YOU, or the round’s phase when there is none — and the clock, last, ticking
while the round runs and frozen once the report is in. ● marks a NEEDS YOU row. The
first line names the MasterMind, so each terminal says which one it is. It shows nothing on error and never
probes a builder. One line in ~/.claude/settings.json:
"statusLine": { "type": "command", "command": "relevo status --line", "refreshInterval": 1 }
relevo ui — the cockpit
demonstrationauthored from the reader’s own golden render · not a capture of a session
relevo 6 bindings · 1 needs you · 1 paused agy gated until 15:30 · 14:02
NEEDS YOU 1 │ atlas round 4 ACTIVE
▎ webshop r4 │ MasterMind architect-14 claude working
▎ question · 2m │ runner %11 opencode working
▎ dirty · 2 consults · $9.40 · 1 │ tree relevo/atlas
▎ opencode · relevo/webshop │ usage live · glm-5.3-flash · 4m · in 2k · cache 91k (95%) · write 3k · out 8k · $0.04
│ spend 1 round · $0.16 · 3.5M tok
PAUSED 1 │
docs r3 │ prompt report terminal diff log
released between rounds │ ──────────────────━━━━━━━━━━────────────────────────────────────────────────────────────────────────
claude · bind --resume │ %11 · captured 0s ago · 2 lines
│
ACTIVE 3 │ $ go test ./...
api r2 │ ok github.com/fuad-daoud/relevo/internal/ui 1.2s
working · quiet 23s │
opencode · relevo/api │
▸ atlas r4 │
working │
$0.16 · 3.5M tok · live $0.04 ·│
opencode · relevo/atlas │
worker r2 │
working │
opencode · relevo/worker │
│
DONE 1 │
ledger r3 │
done · 3h │
agy │
│
↑↓ move ⏎ open round tab next tab [ ] round 1-5 tab s sort: attention c compact : command q quit webshop NEEDS YOU
The views read live and archived data. The cockpit is not read-only: every action goes through an
explicit key and confirmation (x stop, D done,
u unbind, g gate, s send,
r retry, o shell, E editor,
b bind), and the :settings,
:actors, :candidates,
:agents and :servers sections are editable in place.
It still never types into a terminal. Its views are :fleet,
:rounds, :round,
:stats, :candidates,
:actors, :agents,
:servers, :settings,
:audit and :log.
:servers lists the configured servers and probes their health on demand
(r); you can add (a), edit
(e/enter) and delete
(d) a server there; the client key stays with
relevo config server key and the view never shows or edits it. Five tabs per round
— prompt, report, terminal, diff, log — and [ ] step
back through every round the binding has run. :rounds opens every round the
database has recorded, live or archived, with relevo history’s filter grammar on
top.
relevo show — one round, after the fact
relevo show <name> prints one section of one round:
--prompt (the default), --report,
--diff with --stat or
--anchors, --drift,
--log with --follow and
--after N, --transcript,
--gate, --findings,
--output or --artifacts,
--artifact <rel> (raw bytes) and --peek (read
without claiming the pending payload). A live binding is read from
its open round’s files; anything sealed or archived is read from the database and renders the same way.
relevo history -q "harness:agy outcome:halted since:30d" is round history across
every binding relevo has recorded, and --by regroups it.
The daemon
relevo daemon is the reconciler and the one process that opens
relevo.db; every other process reaches the database through the owner socket
$XDG_STATE_HOME/relevo/relevo.sock beside it, so a command that finds no daemon
starts one itself — the systemd user unit when installed, launchctl kickstart on
macOS, otherwise a relevo daemon of its own appending its output to
<state>/daemon.log. So the CLI works on its own: you never have to start the
daemon first, and reports are delivered even when you run a single verb by hand instead of
relevo wait. Run it in any spare terminal, or hand it to systemd or launchd:
relevo daemon
# the reconciler, in the foreground
relevo daemon --check
# exit 0 when one is running, 1 when not
relevo daemon --pprof <path>
# net/http/pprof on a 0600 unix socket; off by default
make service
# a systemd user unit, or a LaunchAgent on macOS
Only one daemon runs at a time. It takes an exclusive lock on
$XDG_STATE_HOME/relevo/.daemon.lock and refuses to start beside another, so a
second one started by hand is an error rather than two reconcilers racing. A running daemon moves onto a
newly installed binary by itself within a few seconds, and a round in flight is not interrupted.
The four states relevo status shows
- ACTIVE
- Someone is working. Nothing needs a human yet. A row may carry
stalled,exploringorquiet— observations, never actions: relevo never kills, nudges or switches on them. - NEEDS YOU
- relevo has stopped and a person must act: a dead builder process, a round past its budget, a binding at its round cap, a permission denial. relevo flags it and reports it; it never cleans it up.
- PAUSED
- The binding’s worktree was released between rounds, keeping the branch and the round log. Nothing needs a human,
unbind --doneleaves it alone, andrelevo bind --resumerestores it. - DONE
- You declared the work verified with
relevo done. Relaying stopped deliberately, not because anything went wrong: no reports are queued and no timeouts are flagged. A clean worktree is released so the branch is free to review.
Mid-round switching
The daemon can replace a builder while a round is open, in two cases: its process exits without writing a
report, or you gate its provider with relevo gate — which is how you tell relevo a
running builder hit its limit. It resolves builder again through the actor’s
ordered candidate list and the ledger, starts the pick in the same tree, and hands it the
same round’s plan. The round number does not change; the round clock restarts. A
switch entry in the log says what was tried and why. Bounded by
max_switches, default 2; after that the binding goes NEEDS YOU.
Hooks and webhooks
The daemon runs any executable in ~/.config/relevo/hooks/<event>.d/ —
state_changed.d/, round_started.d/,
builder_stalled.d/ and binding_stale.d/ — detached,
with a 10-second timeout and RELEVO_EVENT,
RELEVO_BINDING, RELEVO_STATE,
RELEVO_OLD_STATE and RELEVO_ROUND in the environment.
A directory is imported into the hooks section and removed; an event with no argv
list is a silent no-op. notify.webhooks in the policy section posts the same events
straight to a URL with no script required — a Slack incoming webhook, a Discord webhook, or any endpoint that
accepts a JSON POST, in the slack, discord or
json format, filtered by event.
Between rounds
Verbs for the space after one round closes and before the next opens. Each is the mechanical half of something the MasterMind used to type by hand, and each stops short of the decision.
The check
A binding can carry a gate command: a shell line relevo runs in the worktree the instant the
completion marker appears, against the tree exactly as the runner left it. Configure it with
--gate 'make check' on bind;
--no-gate opts a binding out of the policy section’s
gate.default, and omitting both flags falls back to it. The gate never decides
anything — it annotates. The round still closes on the marker, the report is still delivered, and the
human still judges the diff; the gate only adds a gate=<result> note, whose
result is one of pass, fail,
timeout or error.
demonstrationauthored from relevo’s output formats · not a capture of a session
Gate: make check -- FAIL (exit 2, 1m40s). Output: /home/me/.local/state/relevo/api/003-gate.log
ok github.com/example/pkg 0.01s
FAIL github.com/example/pkg2 0.02s
The gate’s full output and the supervisor’s exit trailer live in
NNN-gate.log beside the round, and
relevo show <name> --gate prints it. A failing gate’s payload line carries
the last few non-empty lines of that log, so the MasterMind sees why without opening the file.
The reviewer
relevo send --verify — or the policy section’s
verify.default — marks the round: when it closes, after the gate, so the reviewer
sees the gate’s own output, relevo runs a read-only reviewer over the finished round and records its
verdict. --no-verify overrides the policy default for one send; the two flags are
exclusive.
The reviewer is a headless, one-shot reader started at round close in a throwaway worktree at the
runner’s HEAD, removed once it reaches any terminal state. That isolation is what lets it run tests without
touching the builder’s tree or your own checkout. It ends its findings with
verdict: accepted or verdict: rejected; anything else —
no block, an unreadable one, a verdict that is neither word — is recorded as
unstructured and delivered as prose. A verdict decides nothing:
rejected does not reopen the round, stop the binding or summon a human, and the
report is delivered exactly as it always was.
Repair rounds. A failing gate does nothing on its own. A binding can opt into a repair round instead,
with --regate N on bind or
send, or with regate under
gate in the policy section. relevo then opens at most N more rounds, each naming
the failed check and the last 200 non-empty lines of its log, and telling the builder to fix only what the
check reports. 0, the default, turns the loop off.
Done and unbind
relevo stop <name> ends an open round on purpose. The runner has no stdin,
so there is nothing to ask it: the process is killed and the round closes without a report. A stop is not a
failure — it never charges a mid-round switch and never gates a candidate.
send --candidate is refused while a live round is open — except on a served
binding halted in NEEDS YOU, where stop is itself refused (the server answers
409 round_halted) and naming the candidate re-points that round.
relevo done <name> declares the work verified and stops relaying: when the
worktree is clean and no round is open, it releases the worktree so the branch is free to check out, and
relevo bind --resume --name <n> puts it back on the same branch at the same
path.
relevo unbind <name> forgets a binding, deleting its directory.
Archiving is the default where a binding is cleared in bulk:
relevo unbind --done clears every binding the MasterMind marked DONE in one pass,
archiving each, and --delete removes them instead. An archived binding keeps every
round, event and artifact, so relevo history and
relevo show still read it months later, and the name frees for a fresh binding.
--sweep clears the branches and refs of bindings that no longer exist, once each
is on a remote-tracking ref. A PAUSED binding is left alone: it is released but alive.
relevo deletes a branch in exactly two places: unbind --done and
unbind --sweep, for a relevo/<name> branch
relevo created, and only once its commit is on a remote-tracking ref; and a
bind --server rollback seconds old, when the server refuses the binding.
A branch adopted with --branch is never deleted — relevo did not create
it.
Candidates, actors, gates
A candidate is one way to run an actor, named by the token
harness/provider/model. harness and
provider are single segments and model is the rest, so
opencode/openrouter/z-ai/glm-5.3-flash is one token. Some harnesses take an
effort suffix on the model: claude reads opus:medium as
--model opus --effort medium, codex reads
gpt-5.6-terra:high as a reasoning effort, and opencode takes a variant as
model#variant. The suffix stays in the token, so two efforts are two candidates.
relevo ships no candidates. Which model you are entitled to run is a fact about your accounts, not
about relevo. Candidates, the actors and the policy live in relevo.db, not in a
file, and are read and changed with relevo config:
relevo config get candidates, relevo config set
actors.builder.candidates '[…]', or relevo config edit for the whole
document.
Each actor holds an ordered candidate list, most preferred first. Omit
--candidate and relevo takes the actor’s first candidate that is not gated; name
one and relevo starts exactly that, gated or not. When several candidates serve an actor and nothing orders
them, relevo refuses rather than picking, and says so as would refuse.
demonstrationauthored from relevo’s output formats · not a capture of a session
$ relevo config
builder (config actors)
1 gemini-3.8-flash-high order rate-limited until 20:28
2 sonnet order <- would pick
3 glm-5.3-flash order limited 2x around 14:00 (30d)
reviewer (config actors)
1 opus sole <- would pick
The marker is computed by the same code bind runs, so it cannot disagree with
what bind does next, and every pick is written down: one line on stderr and a
pick entry in the binding’s log.
Gates
A limit gates the provider — every candidate with that provider — because that is who enforces the
quota, not the model. Without --for it stays gated until you clear it, because
relevo does not know your provider’s reset schedule. relevo also records spawn failures itself, gating that one
candidate for ten minutes; those expire on their own. Name a gated candidate explicitly and relevo prints a
note: and proceeds — you named it.
relevo gate claude/anthropic/sonnet --reason "5-hour window"
relevo gate claude/anthropic/sonnet --for 2h
relevo gate --clear anthropic
The same command tells the daemon to replace a running builder that hit its limit: see
mid-round switching. relevo status gains a
candidates block only while something is gated, and
relevo config marks a gated row unavailable:.
relevo gate --serve acts on the local serve daemon’s gates.
What relevo refuses to do
relevo makes no judgements. It moves files, starts processes, and records what each round did. Whether a report is good, whether a question needs a human, whether the work is done — every one of those decisions stays with the MasterMind, or with you. Six structural refusals follow from that, and each has a reason.
It makes no judgements
relevo never summarises, rewrites, or decides that work is done. It reads a report for the shape of its block, never for meaning, and it grades nothing. The decision is the one thing it does not automate — that is the whole product.
The check annotates; it never decides
A gate result is a note on the round. A reviewer’s verdict is a note on the round. A round budget that runs out flags NEEDS YOU and kills nothing. relevo reads no agent’s claim for meaning, and the human still judges the diff.
The destructive verbs need a name
done and unbind act on one loop and take its
name, or --pick. Neither resolves the current directory for you, and a bare
verb never opens a picker: a bare done once ended a live loop by accident,
and the recovery is relevo bind --resume.
It refuses to guess a candidate
More than one candidate serving an actor with no order set is would refuse,
not a pick. relevo lists them and names the command that sets the order, rather than choosing for you.
It deletes a branch in exactly two places
unbind --done and unbind --sweep, for a
relevo/<name> branch relevo created and that is already on a
remote-tracking ref; and a bind --server rollback seconds old. A branch holds
commits, and commits are work; an adopted --branch is never deleted.
Nothing is typed into your session
A report reaches the MasterMind by the background wait, the channel, a harness deliverer, or a
relevo wait you run by hand — and by nothing else. relevo never writes into
the session you are talking to.
Also in the box
- bind
- Bind this MasterMind to a runner over the current working tree.
--worktreeattaches another on its own worktree,--serverruns it on a remote host,--cwdbinds an existing directory. A fresh bind names exactly one of--feature Land--no-feature, plus--ticket,--actor,--candidate,--tier,--gate,--no-gate,--regateand--local. - send
- Stage a plan file as the current round and start the runner:
--file,--candidate,--tier,--dry-run,--verify|--no-verify,--regate. - status
- One row per binding: round, state, the runner’s live status, and what
is pending.
--allincludes DONE rows,--lineis the status-line form,--nameshows one binding,--jsonthe machine-readable one. - history
- Round history as JSON across every binding, live or archived:
--here,--binding,--feature,--ticket,--mastermind,--since,--limit,-q QUERY,--by,--rows,--json. - show
- One round’s prompt, report, diff, drift, gate, findings, log, transcript
or output file, live or archived:
--round N,--diff [--stat|--anchors],--log [--follow --after N],--peek,--artifact <rel>,--json. - wait
- Block until a round closes or the binding needs you, then print the
pending report.
--timeout,--round,--any,--peek,--json. - ui
- The cockpit:
:fleet,:rounds [query],:round <binding> [N]. - done
- Mark a binding done; relaying stops.
--pickchooses it on screen. - stop
- Kill the runner process and close its round without a report, unless one is already on disk.
- unbind
- Forget a binding, deleting or archiving its directory.
--doneclears every binding the MasterMind marked DONE, with--deleteor--dry-run;--sweepclears the branches of bindings that no longer exist. - daemon
- Run the long-running reconciler:
--interval,--check,--pprof <path>. - mcp
- Run an MCP server over stdio for a Claude Code MasterMind:
status,send,show,gateanddoneas tools; in channel mode it also pushes reports and NEEDS YOU into the session. - doctor
- Preflight check: plugin, daemon, harness binaries, roles, the database and hooks. It reports; your shell acts.
- update
- Replace this release binary with the latest release, checksum-verified:
--check,--to vX.Y.Z,--release. - bugreport
- Assemble a local, redacted bug-report bundle — version, machine,
doctor’s checks, bindings, the last recorded failure — and print the
gh issue createline; nothing is sent automatically.--name/--round,--logs,--raw,--out,--stdout,--json,--gh. - config
- Show the actors, the current pick and the candidates, and read or
change the configuration document:
init,agents,edit,get,set,unset,export,import,server add|rm|list|key,secret set|rm|list. - mastermind
- Register this MasterMind, or re-attach an existing one, and list, rename or forget records.
- gate
- List this machine’s active gates; gate a provider with
relevo gate <token> [--for D] [--reason S]; clear one withrelevo gate --clear <provider|token>.relevo gate --serveacts on the local serve daemon’s gates. - serve
- Run the remote-builder server, listener and daemon. Server
administration, on the server host:
init,enroll,clients,revoke,fingerprint,status,ui,gc,unbind. - help
- Print the command list;
--jsonprints the registry document (verbs, flags, output documents, error codes). A failure is coded —relevo: <code>: <message>then anext:line. - version
- Print the relevo version.
Renamed commands. Every verb the housekeeping removed, and the form that replaces it. An
old name exits 2 and names its replacement: init →
relevo config init · candidates,
policy, roles →
relevo config · agent →
relevo config agents · client →
relevo config server · servers →
relevo config server list · add →
relevo bind --worktree · diff →
relevo show --diff · log →
relevo show --log · gc →
relevo unbind --done · pause →
relevo done, then relevo bind --resume ·
statusline → relevo status --line ·
pull → relevo wait, which prints the report ·
unavailable → relevo gate <token> ·
available → relevo gate --clear <provider> ·
db → relevo doctor, the database row.
Install
In Claude Code, as a plugin:
/plugin marketplace add fuad-daoud/relevo
/plugin install relevo@relevo
Then, once, on a clean machine:
relevo config init
# candidates, policy and actors
relevo doctor
# names what is missing and prints the fix
Or take the binary: a release tarball for Linux or macOS, amd64 or arm64, unpacked onto your
PATH — or, with a Go toolchain,
go install github.com/fuad-daoud/relevo/cmd/relevo@latest
A release binary updates itself with relevo update; a
go install gets its own command printed instead.
Requirements
- Two harnesses
- One for the MasterMind, one for the builder. relevo knows how to start
claude,opencode,agyandcodex; claude only plans, so it never gets a builder candidate. There is no terminal manager and no terminal multiplexer to install. - git
- Optional. Without it relevo works normally, but rounds capture no diffs.
- Linux or macOS
- Both are exercised in CI. Windows is not supported: the tree cross-compiles for
windows/amd64and refuses at runtime with a clear error rather than running without a state lock. - Go 1.25+
- To build from source. Not needed for the plugin or a release binary.
Upgrading
relevo update installs the latest release over the running binary by an atomic
rename, and --check prints what it would do without changing anything;
--to vX.Y.Z installs an exact tag, a downgrade included. A running daemon moves
onto the new binary by itself, and a round in flight is not interrupted.
Claude Code caches an installed plugin by version, so update it to match:
claude plugin marketplace update relevo && claude plugin update relevo@relevo
The remote ends upgrade together: a pre-upgrade client against an upgraded server gets HTTP 426, and an upgraded client against a pre-upgrade server is told the server predates audience-bound signatures.