The GitHub loop
With github.enabled (default false — zero GitHub calls until then), GitHub
Issues become a dispatch surface for the same queue the folder inbox feeds (see
how it works). Junco never executes a raw issue directly; it
always plans first, and the plan is reviewed on the issue itself.
The two-hop flow
Every sweep (default 60s), junco lists open issues carrying the trigger label in each watched repo.
- Dispatch → plan. An eligible issue — trigger label
juncopresent, no lifecycle label yet — is verified first: who applied the label, and do they have write access? A labeler without write access flips the issue tojunco:denied. Verified, the issue becomes a planning ticket: a read-only session at the mapped clone drafts a plan using the same authoring discipline as the bundled junco-dispatch skill. The issue flips tojunco:planning. - Plan → review. The plan posts as one issue comment — ordinary Markdown with a hidden
anchor so the bridge recovers it later — and the issue flips to
junco:plan-ready. - Approve → execute. A write+ collaborator applies
junco:approvedafter reading the plan. Junco verifies both that a write+ collaborator applied it and that the approval postdates the plan comment — a stale approval from before a re-plan cannot push an old plan through. The (possibly edited) comment text is read back into an execution ticket, and the normal pipeline runs: atomic claim, isolated worktree, supervised agent, verification, critic.junco:queued, thenjunco:working. - Finalize. One closing comment — PR link plus summary, or the failure reason — and the
issue flips to
junco:doneorjunco:failed. The draft PR body carriesCloses acme/reef-api#52, so merging auto-closes the issue.
Flow: a collaborator labels an issue junco; junco verifies the labeler and posts a plan as an editable issue comment (junco:plan-ready); a write-access collaborator applies junco:approved after the plan posted; an agent executes in a worktree with verification and a critic; a draft PR closes the issue and the label flips to junco:done.
With github.requireApproval = false, the plan executes automatically on the next
sweep — no human gate. Keep the default true anywhere but a private personal repo;
the full trust model is on the security page.
Lifecycle labels
junco- The trigger. A write+ collaborator applying it vouches for the issue body as it stands.
junco:planning- A planning session is drafting a plan from the raw issue.
junco:plan-ready- Plan posted as a comment — awaiting review and approval.
junco:approved- Applied by a write+ collaborator after reading the plan; authorizes execution. Removed once dispatched.
junco:queued- An execution (or Q&A) ticket is in the inbox, waiting for a worker slot.
junco:working- A session is on it right now.
junco:done- Finished — the closing comment carries the PR link or answer.
junco:failed- Failed — the closing comment carries the reason, planning or execution.
junco:denied- The trigger label was applied by someone without write access.
junco:ask- Added alongside the trigger: route to read-only Q&A instead of planning.
Editing and re-planning
The plan comment is the executable text at approval time. Edit it before approval and the edit is
what executes, not the model's original draft. Remove junco:plan-ready (leave the
trigger label on) and a fresh planning session runs — when multiple plan comments exist, the
latest wins. Remove junco:failed and the issue re-enters at the top: fresh plan,
fresh review, fresh approval. All gestures take effect on the next sweep; no restart.
junco:planning → junco:plan-ready
flip is lost offline after the plan comment posted, the issue strands in
junco:planning. Apply junco:plan-ready by hand (the comment is already on
the thread), or remove junco:planning to re-plan from scratch.Ask mode
Add junco:ask alongside the trigger label and the issue routes straight to the
read-only Q&A path — junco:queued directly, no plan, no approval. The session
browses the mapped clone with read-only tools and posts its answer as the comment. No branch,
no PR.
External repos (fork-PR mode)
The label loop assumes push and label access. For an upstream repo you don't control, junco dispatches in fork-PR mode instead: fork, clone the fork's upstream into a managed directory, work the issue, push the branch to your fork, open a draft PR upstream. It applies no labels and posts no comments on the upstream issue — the draft PR is the single artifact that reaches the project.
junco dispatch acme/reef-api#52
Re-dispatching the same issue collides on the existing branch by design. To push
review-feedback commits, submit a ticket with
amends_pr: <PR number>, repo: the managed clone, and
push_remote: fork — the upstream PR updates in place.
Offline behavior
When GitHub is unreachable, label flips, issue comments, and the PR push+create sequence queue as
durable ops under <dataDir>/outbox/ — one JSON file per op, replayed FIFO,
idempotent, surviving daemon crashes. Tickets still finalize locally; the outbox is durability,
not gating. A non-network failure on one op dead-letters it after 3 attempts to
outbox/dead/, which junco doctor flags. See
operations.
junco outbox junco outbox flush