team commits check
Checks a commit, or a range of commits, against the team file's rules: every commit must carry a
seat's signature where the file says, and no line of its message may match a forbidden pattern.
commits check is what a seat runs on its own branch before it reports, and what CI runs on
every push. The request to merge is a separate run, team pr check, which checks a pull
request's body alone and needs no git.
Synopsis
team commits check <ref> [--since <ref>] [--file <path>]
What it reads and writes
Reads the team file (or the one --file names), the ledger of this machine's store (every seat the
team has had here, so a removed seat's commits still pass), and the git history of <ref>. It
writes nothing: no state file, no log line, no store.
Who may run it
Anyone. It needs no herdr session, no terminal and no approval of its own; a seat runs it on its own branch and CI runs it on a push.
Flags
| Flag | Meaning |
|---|---|
<ref> | one commit, or a range when it holds .., passed to git as given (origin/main..HEAD) |
--since <ref> | skip this commit and everything reachable from it, for this run; overrides identity.since |
--file <path> | the team file, instead of .agents/team.yaml |
--help, -h | the usage, and exit 0 |
What it finds
Every offending commit is printed with its hash and subject, then one block per finding:
<sha> Tidy the logs
line 5: forbidden pattern ^Claude-Session:
Claude-Session: 8f21c4a9
| Finding | Meaning |
|---|---|
no signature: expected "Agent: {display} · {role}" in the final trailer block | the message carries no signature at all |
the signature is not in the final trailer block | a seat's signature is there, but not where the file's rule says |
the signature shares its paragraph with prose ("…"), so git reads no trailer block: put it in a paragraph of its own, with trailers only | the signature touches ordinary text, so git reads no trailer |
a signature no seat of this team has had (the model, the version and the role must all match one seat) | a signature-shaped line naming a model, version or role no seat has |
forbidden pattern <source> | the line matches one of the file's patterns, or one of the two defaults |
The summary says what was read — <n> commits checked, <n> by a human or a merge, <n> skipped (since <ref>) — and then ok, or 1 commit refused, or 2 commits refused.
Refusals
| Message | Exit |
|---|---|
team commits check: a <ref> is required (with the usage) | 2 |
team commits check: one <ref> at most (with the usage) | 2 |
team commits check: unknown option --<name> (with the usage) | 2 |
team commits check: --since needs a value (with the usage) | 2 |
team commits check: <path>, line <n>: <message> | 2 |
team commits check: not in a git repository | 2 |
team commits check: "<ref>" doesn't name a commit | 2 |
team commits check: the range "<ref>" can't be resolved | 2 |
team commits check: the range "<ref>" holds no commit | 2 |
team commits check: since "<ref>" doesn't name a commit here (a shallow clone doesn't hold the history it needs) | 2 |
team commits check: since "<ref>" is not reachable from "<ref>" | 2 |
The body's own refusals are team pr check's. The old spelling team check … still
runs all of this, one notice line first: team check.
Exit codes
0— every commit checked passes.1— at least one commit was refused.2— the check can't run: a bad invocation, a team file that can't be read, a ref that names nothing.
Examples
format: 1
project: beacon
coordinator: claude-keeper
operator: claude-keeper
identity:
humans: [[email protected]]
trust:
- ~/.config/team/lobby
- ~/Code/beacon
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-5A seat signs its commits in a trailer block of its own:
Sketch the layout
Agent: Claude Opus 5.5 · implementerThe person named in identity.humans never signs:
Review the copyThis one forgot, and this one signed but leaked a line the file forbids:
Add the metrics page
The counters come from the tracker's webhook, not from a poll.Tidy the logs
The reader printed one line too many, so the reports carried noise.
Claude-Session: 8f21c4a9
Agent: Claude Opus 5.5 · implementerThe commit a person wrote needs no signature:
team commits check HEAD~2 ; echo "exit $?"
team commits check: warning: line 3: `coordinator:` is now `leads: true` on the lead's seat, and is still read
team commits check: 1 commit checked, 1 by a human or a merge: ok
exit 0The newest commit signs, but leaks the forbidden line:
team commits check HEAD ; echo "exit $?"
team commits check: warning: line 3: `coordinator:` is now `leads: true` on the lead's seat, and is still read
<sha> Tidy the logs
line 5: forbidden pattern ^Claude-Session:
Claude-Session: 8f21c4a9
team commits check: 1 commit checked: 1 commit refused
exit 1A range reads newest first and reports every commit with findings:
team commits check HEAD~3..HEAD ; echo "exit $?"
team commits check: warning: line 3: `coordinator:` is now `leads: true` on the lead's seat, and is still read
<sha> Tidy the logs
line 5: forbidden pattern ^Claude-Session:
Claude-Session: 8f21c4a9
<sha> Add the metrics page
no signature: expected "Agent: {display} · {role}" in the final trailer block
team commits check: 3 commits checked, 1 by a human or a merge: 2 commits refused
exit 1--since leaves that commit and everything reachable from it out of the report:
team commits check HEAD~3..HEAD --since HEAD~1 ; echo "exit $?"
team commits check: warning: line 3: `coordinator:` is now `leads: true` on the lead's seat, and is still read
<sha> Tidy the logs
line 5: forbidden pattern ^Claude-Session:
Claude-Session: 8f21c4a9
team commits check: 1 commit checked, 2 skipped (since <sha>): 1 commit refused
exit 1A ref that names nothing can't be checked:
team commits check origin/main ; echo "exit $?"
team commits check: warning: line 3: `coordinator:` is now `leads: true` on the lead's seat, and is still read
team commits check: "origin/main" doesn't name a commit
exit 2