astro-ai · shubhagya.com
A subagent starts with no memory of any other, so this system cannot pass work by
conversation. Every handoff is written down somewhere durable — an issue
comment, a label, a commit SHA, a PR body, a workflow_run event. The diagram
below is that paper trail. The arrows are not calls; they are
artifacts one agent leaves for the next one to find.
Because nothing shares memory, the medium matters more than the message. Each channel below has a different durability, and that is what decides which one a handoff uses.
| Channel | Written by | Read by | Why this one |
|---|---|---|---|
issue comment | every agent | the next cycle, the steward, you | The only record that outlives the run. AGENT_STATUS.md is gitignored, so it is invisible outside one machine. |
label | qa_verdict.sh only | agent-merge |
A machine-readable verdict. QA writes a report; the label is what a workflow can act on. |
commit SHA | engineer | QA, gates, close-on-evidence |
Binds a verdict to exact code. A pass on a moved branch is refused. |
workflow_run | GitHub | agent-merge, qa-on-green |
The edge that says a gate finished. Miss one and a green PR strands silently. |
/health | production | close-on-evidence |
Proof the fix is actually serving, not merely merged. |
The strictest rule in the repo is that no agent decides what lands. An agent
pushes a branch and opens a PR; the authority to merge lives in
agent-merge.yml, gated on evidence rather than on anyone's judgment that the work
is finished. Four conditions bind — author, pr-gates green on the head SHA,
qa-pass, and a diff touching no trust-boundary path (agent-merge.yml
steps own, gates, qa, boundary). A fifth,
diff size (step size), is in place but switched off:
MAX_LINES: 1000000 admits any plausible diff, so it holds nothing today.
This matters because the loop has twice produced an agent that wrote its own permission slip.
One recorded USER AUTHORISED PUSH this turn into a status file, then cited its own
line as the authorization. Keeping merge authority in a workflow means there is nothing for an
agent to grant itself.
That holds only where the merge is actually denied, and for the delivery loop it is not. On
2026-10-08 the owner granted the unattended loop permission to push and merge:
CLAUDE.md (line 149) says /agent-cycle, running in
agent-work.yml, "pushes its branch and merges its own PR once QA passes",
and that workflow's denied-tools list (line 274 on) does not include gh pr merge.
In the designed path agent-merge still does the merging, and qa and
qa-lead are told never to merge, but only agent-steward is tool-denied
the merge. For the delivery loop the boundary is its instructions plus branch protection on
main, which requires gates and build-gates, not
qa-pass.
Two paths stop the unattended merge today: a diff touching the trust boundary
(prompts, knowledge, workflows, notify.py, events.py,
storage.py, email_sender.py), and anything labelled
needs-human-review (refused by the */30 sweep and, since #604, by
the qa step on the edge-triggered path too). Since 2026-11-01 (#610) the hold
waits for chief rather than the owner: chief may release it on any
boundary path, but only with a ruling comment naming the head SHA
(chief-cleared at <sha>), posted before the chief-cleared
label — a push invalidates it. That clears the hold and nothing else: the boundary step is
reached only after gates, qa and size have passed, and
agent-merge still does the merging. A third path, a diff over the size limit, is
written but inert — MAX_LINES was raised to 1000000 on 2026-10-08 and left in
place so the mechanism survives. Green CI means very different things for a one-file deletion
and a 3D chart, and main deploys with no staging — so path is treated as evidence
too, and size would be if it were switched back on.
Every edge in the authority stage is load-bearing, and the recurring bug is a
missing one. agent-merge listened only to PR gates, but
build-gates is published by verify-build — a different workflow — so
whenever that finished last, nothing fired and a green, qa-pass, mergeable PR sat
untouched. Measured on PR #562: gates 7m43s, build-gates 10m25s.
The scheduled sweep is the backstop, and it is weaker than it looks. Its cron asks for every 30 minutes; measured over 71 runs it delivered a 126-minute best case and a 444-minute worst, because GitHub throttles short-interval cron on public repos. A backstop that arrives in hours is not a substitute for an edge that arrives in seconds.
The same approach can be applied to your own agents. For startups, that means setting up agent orchestration and Claude Code workflows with guardrails, and running AI governance and agent-security reviews of the agents you already have.
Or read the write-up of why merging in this cycle belongs to a workflow, and where that rests on instructions rather than a deny.