Coordinate agents

Keep experiments in sandbox lanes

Let agents try work on lane branches that run checks against main but never merge into it.

A lane is a set of refs, such as refs/heads/research/*, for work that must never reach main. A change you open in a lane runs its checks against main like any change. Then bay refuses to merge it, and hands back the verdicts. Agents can try ideas and see the check results, and main stays untouched.

bay also keeps lane work out of other changes. It refuses a change whose history reaches lane commits. The agent hook denies Git commands that copy from a lane ref. bay cannot see bytes copied by hand, such as an editor paste.

When to use lanes

  • Research spikes: an agent tries an approach and learns whether the checks pass.
  • Prototypes: work you plan to rewrite before it reaches main.
  • Risky experiments: work you want checked against today's main, but never merged.
  • Keep it apart: bay refuses to merge another change that carries lane commits.

Declare a lane

Add one [[lane]] per lane to .bay/config.toml on main. name is 1 to 64 characters of a-z, 0-9 and -. refs lists full ref names under refs/, each with at most one *. A * matches any run of characters, slashes too. A pattern never matches main, and never lies under refs/bay/. bay also reads a branch pattern under its remote-tracking name, such as refs/remotes/origin/research/*.

toml
[[lane]]
name = "research"
refs = ["refs/heads/research/*"]
window_s = 3600                    # keep an ended lane change's view for one hour

Start a lane change

bay start --lane <name> opens a change in that lane. The lane must be one that main's .bay/config.toml declares, or bay creates nothing. The result names the lane in detail.lane, and bay status shows it on the change.

sh
bay start CARD-17 --lane research --paths src/search/

Run its checks

Run bay land as for any change. bay builds the candidate on the current main and runs its checks. A lane change takes no place in the queue, and a red main does not hold it. Then bay refuses it with LANE_NEVER_LANDS, and detail.checks lists each check's verdict. detail.check_refusal names the code the checks gave, such as CHECK_FAILED, else null. A conflict, or a check that no worker could run, comes back as its own refusal instead.

sh
bay land --wait --json | jq '.detail.checks'

Keep lane work out of other changes

At bay land, bay fetches the lane refs and reads the history of a change outside any lane. It reads the frozen draft, the view's HEAD, and any merge or cherry-pick under way there. When that history reaches lane commits that are not on main, bay refuses with LANE_LEAK. detail.leaks names each lane ref and up to 20 of its commits. To repair, reset the view to the change's base and redo the work, or start it in the lane.

Hook denials

In the view of a change outside any lane, the agent hook denies Git commands that copy lane work. Each denial is SHELL_DENIED, and names the shape it matched. The hook reads a lane ref as a full name, or as Git completes a short one. It also reads commands inside a shell wrapper such as bash -c.

DeniedExample
git merge of a lane refgit merge origin/research/x
git cherry-pick of a lane refgit cherry-pick main..research/x
git checkout <lane ref> -- <paths>git checkout research/x -- src/a.rs
git restore --source <lane ref>git restore --source research/x src/a.rs

Lane work merged outside bay

A forge merge can still bring lane commits onto main. bay status names that merge under detail.unattributed, with lane and lane_leak on its row. lane_leaks counts the merges that name a lane, and the fleet map lists the same. Outside a view, bay watch adds lane and lane_leak to that merge's unattributed_landing event. bay names only merge commits this way. A fast-forward or a cherry-pick shows as a plain outside row.

When a lane view goes

A lane change ends when bay refuses it with LANE_NEVER_LANDS. A later bay start removes its view once the lane's window_s has passed. window_s defaults to one day, or to the retention window when that is shorter. It must be shorter than [retention] window_s, or the config does not load.

What lanes cannot do

  • A lane change never merges. No flag or retry changes that.
  • bay cannot detect bytes copied by hand, such as a paste or a file from another clone.
  • The hook judges only the four Git shapes above.
  • bay land catches only copies that carry lane history.

Refusals

Each refusal is blocked and exits 10. The Results page lists what to do next for each one.

CodeMeaning
LANE_NEVER_LANDSA lane change ran its checks and never merges. detail.checks carries the verdicts. On a host from bay host init with a key registry, the hook refuses its merge too.
LANE_LEAKThe change's history reaches lane commits that are not on main. detail.leaks names the lane refs and commits.
SHELL_DENIEDThe agent hook denied a Git command that copies from a lane ref.

Limits

  • Tips: one check reads at most 64 lane tips, and detail.tips_truncated says when it stopped.
  • Commits: one leak names at most 20 commits, and counts them all.
  • View: an ended lane change keeps its view for window_s, at most one day by default.