Coordinate coding agents with nothing but GitHub.

Rallypoint installs eight roles, a label state machine and an atomic claim into your repository. Agents never message each other: they read and write issues, branches, labels and pull requests — and no agent approves its own work.

npx rallypoint@latest add loop

#142 Retry failed webhook deliveries

Illustrative run · real commands

OpenIssue #142prio:p1
No pull request yet

Planner planner-2b80Step 1 of 7

gh issue create --title "Retry failed webhook deliveries" --label prio:p1

No hold label, no assignee: the issue is claimable the moment it is filed. There is no readiness label to forget.

One claim per issue, decided by GitHub.

Assignment is not a lock. Before a worker touches an issue, claim.mjs creates a reservation ref. GitHub creates a ref exactly once — so when two sessions reach for the same issue, one gets it and the other moves on.

Two workers race to claim issue 142worker-a3f9 creates refs/heads/rallypoint-claims/issue-142 first and claims issue 142. worker-7c21 tries to create the same ref, GitHub refuses the second creation, and it moves on to issue 143 without touching 142.create ref — once onlyrefs/heads/rallypoint-claims/issue-142Refused:reference already existsworker-a3f91st to arriveworker-7c212nd to arrive#142 status:claimedthen the label, the assignee, the branch#143 next candidate#142 never touchedTwo workers race to claim issue 142worker-a3f9 creates the reservation ref first and claims issue 142. worker-7c21 is refused and moves on to issue 143.create ref — once onlyrefs/heads/rallypoint-claims/issue-1422nd create refused:reference already existsworker-a3f9worker-7c21#142 claimed#143 next
Several sessions may share one GitHub identity, so an assignee proves nothing about who arrived first. The ref does: claim.mjs reserves before it mutates, and skips a contended issue without touching it.

Labels are the state machine.

There is no side-channel database. An issue’s labels say whether it can be claimed, who holds it, and what it is waiting on; a pull request’s labels carry the verdict. Every agent reads the same board.

Issue

  1. Claimable

    Open, no assignee, no hold label. Filing an issue makes it claimable.

  2. status:claimed

    Set by claim.mjs only after the reservation ref exists. release-claim.mjs returns it to the pool.

  3. Closed

    Closes #N lands, the claim is released. Refs #N releases it and leaves the issue open.

Held out of the pool

  • status:blockedOnly with a Blocked-By: #41 trailer; clears itself when the last blocker closes.
  • status:deferredA deliberate hold that will not clear on its own.
  • needs:humanAn owner decision. No automated writer may remove it.

Pull request

  1. Ready for review

    One branch, agent/<issue>-<slug>, body says Closes #N.

  2. status:changes-requested

    The fixer pushes to the same branch; the head moves, the verdict stops binding, review runs again.

  3. review:approved

    Applied only by review.mjs, bound to one head SHA, never from the author’s own session.

  4. Merged

    The merger checks CI itself and that the head has not moved since the verdict.

Flagged, never hidden

  • merged:unreviewedMerged without an approve verdict at its head.
Rallypoint labels, their config keys, and meanings
LabelConfig keyOnMeaning
status:claimedclaimedissueReserved by one worker right now.
status:blockedblockedissueWaiting on another issue, named in a Blocked-By: trailer.
status:deferreddeferredissueA deliberate hold that will not clear on its own.
needs:humanhumanissue or PRRequires an owner decision or a protected action.
review:approvedapprovedpull requestReviewer verdict on a pull request, bound to its head SHA.
status:changes-requestedchangesRequestedpull requestA reviewer asked for changes and they are outstanding.
merged:unreviewedmergedUnreviewedpull requestMerged without an approve verdict at its head.
prio:p1prio:p0 … prio:p9issuePriority. claim.mjs orders the claimable pool by this number and nothing else.

Eight roles. None approves its own work.

Every session adopts exactly one role and works inside its boundary. Each role is one plain file under .rallypoint/roles/, so prompting an agent into it is one sentence.

The eight Rallypoint roles, whether each claims issues or reviews, and what it is responsible for
RoleClaims issuesReviewsResponsibilityContract
OrchestratorNoNoReads repository state and recommends what to run next.Contract
PlannerNoNoKeeps an ordered, well-scoped backlog.Contract
WorkerExactly oneNever own workShips one issue as one pull request.Contract
ReviewerNoYesJudges the current revision against the issue and repository rules.Contract
TesterIts own filed gapNoFinds the weakest coverage area and closes one gap.Contract
FixerNoNoAddresses review feedback on an existing pull request branch.Contract
JanitorNoNoRepairs GitHub coordination state: stale claims, orphaned refs, leases.Contract
MergerNoNoVerifies CI and the verdict, merges, and reconciles the claim.Contract

UTON OS was built through this loop.

A studio booking platform with payments, delivered by agents in Claude Code, Codex and OpenCode with GitHub as the only source of truth: 1,328 pull requests opened and 1,256 merged in eight weeks. Payments, credentials and auth stayed on human-only approval paths.

1,328 pull requests opened on UTON OS, one square each; 1,256 filled squares were merged.1,328 pull requests opened on UTON OS, one square each; 1,256 filled squares were merged.
1,256 mergedopened, not mergedOne square per pull request · 1,328 opened in eight weeks

Two commands. Then it is your code.

Rallypoint’s zero-dependency CLI reads its own checksummed manifest, refuses conflicting writes, and leaves an existing AGENTS.md untouched.

1 Write the loop into your repository

npx rallypoint@latest add loop

Writes the loop with Rallypoint’s own conflict-safe CLI. Add the dry-run flag to plan without writing.

2 Bring GitHub up to date

npx rallypoint@latest init

Needs an authenticated gh. Syncs the integration branch to your default branch, creates the labels the loop reads and writes, and reports — without changing — branch protection.

What lands in the repository

  • AGENTS.md
  • AGENTIC_LOOP.md
  • docs/AGENT_LOOP.md
  • .rallypoint/LICENSE
  • .rallypoint/config.json
  • .rallypoint/roles/orchestrator.md
  • .rallypoint/roles/planner.md
  • .rallypoint/roles/worker.md
  • .rallypoint/roles/reviewer.md
  • .rallypoint/roles/tester.md
  • .rallypoint/roles/fixer.md
  • .rallypoint/roles/janitor.md
  • .rallypoint/roles/merger.md
  • .rallypoint/scripts/claim.mjs
  • .rallypoint/scripts/review.mjs
  • .rallypoint/scripts/report.mjs
  • .rallypoint/scripts/janitor-pass.mjs

…and the rest of the scripts. view loop lists every file with its checksum.

Plain text, fully yours to edit
Every installed file is plain text — roles, config, scripts. Edit it, delete it, rewrite it. There is no proprietary format to work around.
Downloaded once, not rented
“add loop” writes real files into your repository once. From that moment they are yours to change, not a subscription you keep paying for.
Runs where your code runs
Every role runs inside your repository, your CI, your credentials. Nothing calls home, because there is no Rallypoint server to call.
MIT, permanently
What gets installed is MIT-licensed, permanently and non-exclusively. If Rallypoint disappeared tomorrow, what is already in your repository keeps working.