junco
contents

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.

  1. Dispatch → plan. An eligible issue — trigger label junco present, 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 to junco: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 to junco:planning.
  2. 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.
  3. Approve → execute. A write+ collaborator applies junco:approved after 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, then junco:working.
  4. Finalize. One closing comment — PR link plus summary, or the failure reason — and the issue flips to junco:done or junco:failed. The draft PR body carries Closes 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.

note — if the junco:planningjunco: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
warn — an upstream issue body is untrusted input; no labeler vouched for it. Review the draft PR's diff before marking it ready — that draft gate replaces the plan-review hop an owned repo gets.

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