Coordinate agents
Require a person's approval
Hold a change to chosen paths until a person signs a yes for its exact checked candidate.
An approval check makes bay wait for a person before it merges a change to chosen paths. You list the paths in when_paths, such as billing/ or infra/. A change that touches them waits with APPROVAL_PENDING until an enrolled approver signs a yes. A change elsewhere merges without one.
An approval is a signed evidence record, not a comment or a button. It names the exact candidate that bay checked, so a later edit needs a new approval. Only a key in the registry's approver file can sign one that counts. bay is not a code-review tool. The approver decides how to review.
When to use approvals
- Risky paths: billing, auth or infrastructure code needs a person's yes before it merges.
- Agents at scale: agents merge most work alone, and a person signs off where it matters.
- Named approvers: only the people a check lists may approve its paths.
Add an approval check
Add a [[check]] with kind = "approval" to .bay/policy.toml on main. Every approval check needs when_paths. Use ["**"] to ask for an approval on every change. An approval check runs nothing, so it takes no command, adapter, expected_minimum or other run settings. It is never a post check. producers narrows which approvers may answer it. Every policy still needs a run check with expected_minimum above zero, unless it declares unchecked = true.
[[check]]
id = "billing-approval"
environment = "people"
kind = "approval" # a person answers; bay runs nothing
when_paths = ["billing/"] # the paths that need a yes
producers = ["alice"] # optional: only these approvers countEnrol an approver
Approvals need the key registry. Without one, no approval counts, and the refusal says so. Add the person's public key to the registry's approver file, as for any key. An approver name is never also an agent, producer or reviewer name. On the approver's machine, set bay.approverName and bay.approverKey in Git config.
git config bay.approverName alice
git config bay.approverKey ~/.ssh/bay-approver # a hardware key, such as ed25519-sk, is bestApprove a change
Read the waiting change with bay status <change> from your own clone. operation.approval names each owed check, who can approve it, and the candidate commit. Each owed check also carries record, the exact command to run. Review that candidate, then record your answer on that exact commit. --verdict pass approves, and --verdict product_failure rejects. bay signs the record with your approver key and pushes it.
candidate=$(bay status c7k2m4qa --json | jq -r '.detail.changes[0].operation.approval.commit')
bay evidence record --kind approval --check billing-approval --verdict pass --commit "$candidate"Merge after the approval
The agent runs bay land again. bay fetches the approvals first, then judges the change. With every required check passed and the approval in, bay merges it. A candidate with a different tree needs a new approval, such as one built on a newer main.
bay land --waitHow bay judges an approval
- bay reads the approval check from the policy on main, like every check.
- bay asks for an approval only once every other required check passed.
- An approval counts for the candidate's tree, under the policy that judges it.
- A change to the policy needs an approval under both policies.
bay evidence recordwrites one for each. - Only an
approvalrecord answers an approval check, and an approval never answers a run check. - A no from any approver, or two approvers who disagree, rejects the change.
What an approval cannot do
- An unsigned yes never counts. Without a key registry, no approval check can pass.
- A key of any other class never signs an approval that counts.
- On a host from
bay host initwith a registry, the hook refuses such a record. - An approver key signs
approvalrecords only, never a check record or a review. - A quarantine sets an approval check aside, like any check.
- bay never reviews the code. It records who said yes to which tree.
Refusals
Each refusal is blocked and exits 10. The Results page lists what to do next for each one.
| Code | Meaning |
|---|---|
APPROVAL_PENDING | Every other check passed, and an approval is still owed. detail.approval names the approvers and the candidate commit and tree. Without a registry, its why says that no approval can count. |
CHECK_FAILED | An approver rejected the candidate. detail.checks names each approver who said no. |
Limits
- Record size: one record is at most 64 KiB of JSON.
- Scope: one approval covers one tree under one policy.