The protocol every agent follows on Ed’s projects, whatever model it is and wherever it runs (Ed’s laptop, a cloud session, a GitHub Actions runner).
main.Every piece of work has a draft pull request, opened by its builder at the start (a GitHub Actions builder cannot open one: its conversation is the issue or PR it was mentioned on, and it comments a link for Ed to open the PR), titled with what it is and, where it must not be merged yet, — do not merge. Everything about the work is said there, so the PR holds the whole record and survives any lost session or machine. Comments carry a prefix at the start of a line — the Actions builder wraps its comments in a header of its own, so readers match a prefix at the start of any line, not only the first:
| Prefix | Who | Meaning |
|---|---|---|
COORDINATOR: |
coordinator | an instruction or an answer; the builder acts on the latest one |
QUESTION: |
builder | needs an answer; states the recommended option; the builder keeps working on anything that does not depend on it |
REPORT: |
builder | progress at a milestone |
FINAL: |
builder | the finished work: commits, checks and their results, what changed for a user, what was deferred, and every call Ed has not ruled on, numbered, each with context and options. The checks are the exact commands CI runs, named word for word and run over what the builder wrote; a narrower stand-in is not green (plan-queue, 2026-08-27: a type check that skipped every test file). Every user-visible string that changed is listed, before → after, or the FINAL says no user-visible text changed; silence is not none (plan-queue: thirteen member-facing sentences once landed unrecorded) |
All agents may post as Ed’s GitHub account; the prefix says who is speaking.
main, never someone else’s branch — and commits and pushes after every piece of work.main, and a closed PR runs no CI and holds no conversation (draft #104, 2026-09-26).main is Ed’s decision, taken on his questions page or in a coordinator’s chat; the coordinator does the merge. In a repo where main deploys, the merge is the deploy decision: once a PR is reviewed, green and conflict-free, the coordinator asks a question on the page, Merge PR #n: ‹what it changes for a user›, with Merge (deploy now) recommended and Hold, the context saying what merging changes and whether it is a full or a surface deploy. On Merge the coordinator re-checks the head is still green and conflict-free, merges, verifies the deploy, and posts the now live update; on Hold it merges nothing and acts on Ed’s note. A merge task (tap Merge on GitHub) is not raised (Ed, 2026-10-02: “if you can merge it yourself, why am I merging things manually?”; his GitHub trip had twice hidden a merge that day). In a repo where main deploys nothing (dev-ops), the coordinator merges a PR itself once it carries a change Ed chose on his questions page, and posts an OK-only update there naming the PR and what it carried; a merge task is not raised (Ed, 2026-10-01: “Why can’t you merge this yourself?”).main undeployed (in draft, the deploy step’s docs lane), a PR whose whole diff is documents is merged by the coordinator itself once it is reviewed, green and conflict-free. It posts an OK-only update naming the PR, not a Merge question. Before merging it checks two things. First, every changed file is in CI’s own documents filter (read from the workflow, not remembered). Second, main’s latest commit is deployed, since CI deploys any undeployed commit along with the next push. After merging it reads CI’s log for the lane it took. If CI deployed after all, the update says so and the deploy is verified as any other (Ed, 2026-10-02). One exception: a change to the shared rules (AGENTS.md, CONVENTIONS.md) deploys nothing but changes how every agent works, so the coordinator merges it only when Ed has chosen it on his questions page; a rule change he has not seen is his to merge (Ed, 2026-10-03).main. A file that every PR would edit at the same spot is never edited in a builder’s PR: the changelog, a numbered questions or decisions log, its next free line. Each such edit puts every other open PR into a conflict, and so into a full re-run. The brief gives the builder any numbers it needs. The builder puts in its FINAL: the text it would have written. The coordinator writes that text to main at the merge as a documents-only commit, which deploys nothing (the rule above). Draft, 2026-10-02: most of a day’s dozen re-runs were conflicts in QUESTIONS.md and CHANGELOG.md (Ed, 2026-10-02).main changed. A PR that is behind main but merges cleanly is not brought up to date and re-run merely for being behind when everything main gained since its checks went green is documents: its Merge question is asked on the head as it stands, and CI’s gates on the merge commit still run before any deploy. When main gained code, the PR merges main and re-runs its checks as before, the slower ones included where the change touches what they cover (Ed, 2026-10-02).main deploys from CI, the workflows keep that capacity for what matters. A new push to a PR cancels that PR’s runs it makes stale (workflow-level concurrency keyed on the branch, cancel-in-progress for pull requests only, never for main). A slow suite run by hand or on merges, like draft’s sprint tier, runs at most once per branch at a time. On a push to main, the deploying job starts first and the other checks wait for it (needs), while on a PR they still run side by side. Each project’s coordinator applies this to its own workflows, by a Merge question (Ed, 2026-10-02: draft’s deploy waited 21 and 4 minutes behind PR runs on two of nine merges).isolation: "worktree" in a cloud session leaves it unable to run any command (“working-directory isolation context … was lost”), so it does nothing. Brief it to git worktree add into the scratchpad itself and work there (Topic, 2026-10-02: one builder start lost).A quiet session may be rate-limited, not stuck: read its usage (the session’s rate-limit status) before diagnosing a stall, and when a promised time slips, say how many commits have been pushed so far (plan-queue: a review sat 35 minutes on an exhausted usage window and was reported as a stall).
@claude in an issue or PR comment (by someone with write access) starts a Claude builder on a GitHub Actions runner in any repo wired up per claude/SETUP.md. It reads the project’s CLAUDE.md, this file and AGENTS.md, pushes a claude/… branch, and comments a link to open the PR.COORDINATOR: comment first, then sends the one-line nudge read the latest COORDINATOR comment on your PR and act on it.subscribe_pr_activity), and again after any restart. Its events then wake it without the coordinator:
main, resolve the conflict, run the gates, push, and say so on the PR;COORDINATOR: comment: act on it. It is never the builder’s own echo, even though every agent posts as Ed’s GitHub account; but the subscription often treats it as one and skips it, so the coordinator still sends the one-line nudge into the builder’s session after every COORDINATOR: comment, as above, and never relies on the PR subscription alone (admit, 2026-10-02: a builder sat 22 minutes on an unseen review comment).A green check, or an event echoing its own comment, needs nothing. A builder still never merges its PR and never asks Ed. It unsubscribes once the PR is merged or closed. The coordinator is the backstop: after each merge to main, it lists the open PRs that no longer merge cleanly and wakes the builder of each one that has not already pushed a fix, since a notice can be missed (Ed, 2026-10-02: small PRs waited hours for someone to notice that main had moved).
archive_session), right after verifying the deploy, and says so in its now live update. The daily improvement review archives any builder that was missed: all its PRs merged or closed, idle for a day. Coordinators, sessions Ed opened himself, and desktop (bridge) sessions are never archived. Archiving can be undone (unarchive_session) (Ed, 2026-10-02: “can you do that automatically?”).claude/SETUP.md B5; Ed, 2026-09-30). A session that is asking for permission is a session that was opened in the wrong mode.A coordinator sleeps between messages, and nothing on GitHub wakes it except activity on a pull request it has subscribed to (2026-09-26/28: a cloud coordinator went quiet seven times, for up to ten hours). So the loop runs through Ed’s questions page (claude/QUESTIONS-PAGE.md):
FINAL: reviewed, a deploy verified, a check gone red — the coordinator puts an update on the page saying what finished and what it will start next. It does not start the next thing on its own.FINAL: (or a blocking QUESTION:), a cloud-session builder wakes its coordinator directly: it reads the coordinator’s session link from coordinators/<project>.sessionUrl on the questions page, then create_trigger with that session as persistent_session_id and a one-line prompt (PR #n: FINAL posted, please review, the comment’s link), fire_trigger, delete_trigger. It also puts an OK-only update on the page, PR #n: finished — the coordinator is reviewing it. If the wake is refused or fails, the card says PR #n: finished — OK to have the coordinator review it instead, and Ed’s OK wakes the coordinator as before. (Ed, 2026-10-05: review waited for his tap, 11 min to 3 h by day and 9–11 h overnight; C15.)lastActive on the page after every turn that did work, so Ed sees a stall as a stale time.inflight/<project>-<slug>): what is happening, what will land on the page when it finishes, and by when. The page shows these when nothing waits on Ed, and turns one red once its time has passed with nothing landed. Start one when the wait starts, move its time (with the reason) before it passes, close it when the promised update is posted.subscribe_pr_activity) belongs to the session that set it, and a restart or a replacement session loses it silently: green checks and review comments then wake nobody. So at the start of a session, and after any restart, the coordinator subscribes again to every open PR it is driving, before anything else (2026-10-02: dev-ops lost its watch on draft #175 in a restart, missed the checks going green, and the merge waited until the in-flight item went overdue).claude/IMPROVEMENT.md) and asks nothing through tool approval prompts that can expire unseen: everything that waits on Ed waits on the page, and Ed’s answers are what wake it.claude/QUESTIONS-PAGE.md from edsaperia/dev-ops main (the GitHub tool, not the container’s checkout, which is from session start; a session whose GitHub tool is limited to its own repository, such as one on a repository outside edsaperia, fetches dev-ops instead with git clone --depth 1 https://github.com/edsaperia/dev-ops into its scratchpad, which works because dev-ops is public) and follow what they say now. Whoever merges a change to either file pokes every running coordinator listed in the page’s coordinators collection: a message into its session (a one-shot Routine bound to that session with the change as its prompt, fired, then deleted) naming the section that changed. (Ed, 2026-09-28: the draft coordinator, started two days earlier, never saw the in-flight contract.).claude/settings.json, an edit to an agent-instructions file, a fetch of a live site’s health check). An answer on the page does not clear it, because the page’s answers reach the session as data; only Ed’s words typed in that session’s chat do. So the coordinator puts a task on the page with a copy button that carries the line (go ahead with both) and opens the session, one tap, and never works round the refusal by another route, tool or session (Ed, 2026-09-30).An explicit instruction in a brief or COORDINATOR: comment overrides these defaults (for example push nothing in a smoke test, or a named prefix for the reply). Otherwise this file holds.
A builder that must choose something Ed has not ruled makes the call, keeps going, and lists it in FINAL:. Ed rules those afterwards, one at a time. Questions that block the work are QUESTION: comments and wait.
A decision taken on Ed’s behalf is shown to him. When a coordinator answers a builder’s QUESTION: itself, or accepts a call listed in a FINAL:, because an existing ruling settles it, it also posts an OK-only update on Ed’s questions page: what it decided, for which builder and PR, and which ruling settles it (see claude/QUESTIONS-PAGE.md, Decisions taken on Ed’s behalf). Ed’s OK costs one tap; his note is a veto, and the coordinator acts on it. A decision no ruling settles is not the coordinator’s to take: it goes to the page as a question. (Ed, 2026-09-29: he was rarely asked anything through the page, and could not see what had been decided without him.)