Refusals
Part of team up — what stops a run before its first step, and who may start one.
What a dry run returns
up.no-launch, this call has no way to reach herdr (src/commands/up.ts:712)up.run-lock, another run holds the session (src/commands/up.ts:726)up.lobby, the lobby could not be created (src/commands/up.ts:742)up.clear, a stopped session this team records did not clear (src/commands/up.ts:758)up.pending, a seat left short of ready;up.server, the server did not start;up.watch, the watch did not start, including a watch that would not read this file (src/commands/up.ts:981-984)
The delegate gate
A pane of another session the approved file's delegates section names may run up when that
entry's commands list names it. The ordinary rule above refuses such a caller first, and only
then — the section is in the file — does the delegate gate decide, against the live file and the
approved copy, never a cached team: refused, the gate's own words replace the ordinary refusal
(same list, same dry-run line, same exit); passed, the run is the delegate's. The section is read
from the folder's own default file, never one the caller names: a delegated run never has
--session or --file — both are the owner's, the gate refuses them before the file or the
session they name is read, and a refused run answers in the gate's words without reading the
flagged target at all. A delegated run writes delegate [delegate] <pane> up to
.agents/team.log before its first effect — a dry run writes nothing. With no delegates
section in the default file none of this exists: the ordinary order, the ordinary refusal, the
same words, the same exit.
The ordinary rule that paragraph names — only the owner, from a terminal outside herdr — is on the team up page.
A seat is not the owner
A seat is not the owner, so it can read a plan but not start a team:
team up ; echo "exit $?"
team up: only the owner runs `up`, from a terminal outside herdr; this call is claude-beacon
exit 1Every refusal
The MISS row's in the lines above means the line table on the records page.
A real run stops before the first step, prints one team up: <reason> per reason and exits 1:
| Reason |
|---|
only the owner runs `up`, from a terminal outside herdr; this call is <caller> — the owner without a terminal is not refused: it runs, and never prompts. With a delegates section in the file, this refusal is the delegate gate's to say, in its own words below |
only the owner or the approved delegate runs `up`; this call is <caller> — the delegate gate: the file's delegates section names panes, and this caller is none of them |
--<flag> is the owner's; the approved delegate cannot use it — the delegate gate, for --session and --file on a delegated run, refused before the file or the session the flag names is read |
the delegate gate's other refusals, each in its own words — no verified approval in force on this machine, the approved copy unreadable, the live file drifted from the approved copy, the caller's placement in its pane unproven, or the caller's entry not naming up in commands — printed like every refusal here, and on a dry run above the plan |
the file was never approved on this machine: run `team approve` |
approved before records were signed: run `team approve` once — the record was written by an earlier team |
the record <case>: run `team approve` once — a signed record that does not verify |
the file is not the approved one (<differences>): run `team approve` |
a MISS finding from team doctor — herdr or a CLI not installed, or a CLI not logged in. A launch that names another model than the file, or that names none, is a warning, so up still starts the seat; a seat's own launch line is not this — it leaves that seat out alone, in the lines above. After the idle wait, a screen that shows a different model leaves that seat at launched, not named |
the load is 1.2 per core, above 1 / free memory is 8%, below 25% / free disk is 3.0 GB, below 10.0 GB / free swap is 1.0 GB, below 2.0 GB |
herdr doesn't answer |
session beacon is stopped — herdr lists it stopped and this team's state does not record it, so up does not clear it |
session <session> is stopped and did not clear — herdr lists it stopped, this team's state records it, and the clear did not happen |
session beacon has 2 agents this file's state doesn't record: `up` never touches a running team — an agent on a pane no record names, or on a pane this state records for a seat at another stage: a seat at named or ready whose pane now holds a foreign agent is refused here, with the whole team. An agent on the pane this state records for a seat left at launched — the run stopped after its pane was made and before its rename — is not refused: it is the run's own half-finished seat, and this run finishes it, the idle wait and the rename like any launched seat |
the file is legacy: migrate trust to absolute paths including the lobby ~/.config/team/lobby: ... — followed by the whole trust: block to paste: every entry the next up requires, one line saying which key of the file each entry comes from, and, for an entry a rule of trust refuses, one line naming the key that forces it |
the lobby ~/.config/team/lobby: <check> — gate check failed (symbolic link, permissions, mode, not empty, inside git repo) |
the lobby <path>: failed to create <component>: <code> — the run had to make an absent lobby, and the make itself failed at <component>: a component that cannot be written, or one another process took first. The read-only check above found the lobby missing and made nothing; the make runs under the run lock, after a delegated run's audit line and before any seat's own effect, and the run stops here (exit 1) |
seat beacon-qa would start in live, inside the protected checkout live; a seat that isn't `mode: shared` never starts in one — the folder the file gives it, or its lobby, is a protected checkout |
another session-mutating run is holding session <session> (pid <pid>); try again when it is done — another run holds the session's mutator lock, the one lock up, add, down and remove share: this run stopped before its first step, and a delegated run gets the same line. The line names no command, because the lock is shared and its token records only a pid. --dry-run takes no lock and never shows it |
another session-mutating run may be holding session <session>, and its lock cannot be read; if no run is using it, delete <state dir>/seat-locks/<session>/.run — the lock file does not read as a token (empty, corrupt, unreadable), so its holder is unknown: a run that cannot be proven finished counts as running, the same as a lock left by a run whose pid is still alive, and only the owner clears it — the line names the file |
A watch that has not run, or whose heartbeat is old, is not a reason to refuse: up starts the
watch itself.
An approval that drifted
An owner section changed in the file needs a new approval, and the plan says so before the run:
format: 1
project: beacon
coordinator: claude-keeper
operator: claude-keeper
trust:
- ~/.config/team/lobby
- ~/Code/beacon
limits:
seats: 4
workspace:
mode: shared
seats:
- role: coordinator
name: claude-keeper
label: coordinator
cli: claude-code
vendor: anthropic
model: Claude Opus
version: "5.5"
launch: claude --model claude-opus-5-5
- role: implementer
name: claude-beacon
label: implementer
cli: claude-code
vendor: anthropic
model: Claude Opus
version: "5.5"
launch: claude --model claude-opus-5-5
- role: reviewer
name: gemini-qa
label: reviewer
cli: antigravity
vendor: google
model: Gemini
version: "3"
launch: agy
stopped: true team up --dry-run ; echo "exit $?"
! up would refuse: the file is not the approved one (`limits` changed): run `team approve`
! up would refuse: run `team approve`: `limits` changed
skip claude-keeper: already ready; left as it is; a relaunch records its process: team down, then team up (to restart the whole team)
skip claude-beacon: already ready; left as it is; a relaunch records its process: team remove claude-beacon --keep, then team add claude-beacon (or team down, then team up, for the whole team)
skip gemini-qa: stopped in the file; start it with `team add gemini-qa`
dry run: nothing was run
exit 1The real run goes no further than the refusal — it never touches a team the file doesn't match:
team up ; echo "exit $?"
team up: the file is not the approved one (`limits` changed): run `team approve`
team up: run `team approve`: `limits` changed
exit 1