junco · coding-agent worker · v0.11.0 · MIT
Issues in.
Pull requests out.
Label a GitHub issue junco and a plan appears as a comment. Approve it, and
junco drives a coding agent in a sandboxed worktree until a draft PR arrives — watched from a
dashboard built for the whole loop.
npm install -g @ironforgesoftware/junco
MIT · runs entirely on your machine · local endpoint or hosted provider
- designation
- harness-agnostic coding-agent worker · local daemon
- input
- GitHub issues you label · Markdown tickets (YAML frontmatter)
- output
- draft pull requests · plan comments · in-place answers
- cockpit
- fullscreen terminal dashboard ·
junco dashboard - endpoint
- any OpenAI-compatible endpoint · or a hosted provider from the built-in catalog
- sandbox
- OS-level isolation of agent tools · on by default · fails closed
- identity
- your
ghauth · optional dedicated bot account for daemon traffic - data root
- one
dataDir· queue, clones, worktrees, transcripts, parked reviews - spend
- per-session cost ledger · optional daily budget cap
- runtime
- Node ≥ 22.19 · git · gh
- records
- per-ticket JSONL transcripts · structured worker.log
The dashboard
junco dashboard — repos, issues, plans, the queue, and every junco-authored PR one keystroke apart.
-
Watched repos and the queue card; the repo's
junco-labeled issues; junco's PRs, attention-first.1/2/3jump panes;enteropens detail. -
Every action is a label mutation through your own
ghauth; the daemon's sweep does the rest. -
A command palette (
:) runs the actual junco CLI — no reimplementation, no drift.
The loop
$ junco logs -f09:14:07 INFO github bridge: dispatched issue {"nwo":"acme/reef-api","issue":52,"id":"gh-acme-reef-api-52-plan","kind":"plan"}09:14:52 INFO [gh-acme-reef-api-52-plan] finalized {"dst":"done/gh-acme-reef-api-52-plan.md","status":"completed"}── plan on #52 · junco:plan-ready · a human reads it, applies junco:approved ──09:31:02 INFO github bridge: approved plan dispatched for execution {"nwo":"acme/reef-api","issue":52,"id":"gh-acme-reef-api-52"}09:31:05 INFO claimed {"src":"inbox/gh-acme-reef-api-52.md","dst":"processing/gh-acme-reef-api-52.md"}09:42:31 INFO [gh-acme-reef-api-52] spec verification: 2/2 checks passed09:42:58 INFO [gh-acme-reef-api-52] critic: pass09:43:41 INFO [gh-acme-reef-api-52] pushed junco/gh-acme-reef-api-52 (3 new commits)09:43:56 INFO [gh-acme-reef-api-52] opened PR https://github.com/acme/reef-api/pull/5709:43:57 INFO [gh-acme-reef-api-52] finalized (pr-flow) {"dst":"done/gh-acme-reef-api-52.md","status":"completed"}09:43:58 INFO idle
- Approval is verified — write access, applied after the plan comment; junco fails closed otherwise.
- The plan is an editable issue comment; what it says at approval time is what executes.
-
junco:askskips planning — read-only Q&A answered as a comment; no branch, no PR.
It files its own issues
junco assess audits a repo — npm audit plus a read-only agent
pass — and parks every finding for review. Nothing reaches a tracker until you confirm;
filed issues arrive fingerprinted, severity-labeled, deduped.
junco analyze drafts one issue's investigation as a comment, posted only
on your say-so.
● [high] Unsanitized template in exportCsv (sql-injection) junco:finding · severity/high · junco
Under the hood: every issue becomes a ticket
The bridge writes execution tickets into the same inbox/ as
junco submit — one queue, one pipeline, wherever work comes from.
---
id: fix-tide-rounding
priority: normal
timeout_minutes: 30
repo: ~/code/reef-api
base_branch: main
pr_title: "fix: round tide heights to one decimal"
draft: true
---
# Round tide heights to one decimal
`TideTable.render()` prints raw floats. Round display values
to one decimal; leave the underlying data untouched.
## Steps
- [ ] Add `formatHeight()` in src/tideTable.ts; use it in `render()`.
- [ ] Commit: `git add -A && git commit -m "fix: round tide heights"`
## Verification
```bash
npm test
```
## Done when
- [ ] 1 commit on the branch; `npm test` green.
No repo: field? Then it's a Q&A ticket — answered in place, read-only.
junco schema prints the full contract.
Capabilities
- Atomic claiming
- A ticket moves
inbox/ → processing/in one rename; ownership is never ambiguous. - Plans before code
- In GitHub mode the plan is an issue comment; nothing runs until a verified
junco:approvedlabel. - Supervised sessions
- Four loop guards on the event stream: nudge → escalate → kill. Every run leaves a JSONL transcript.
- Timeout salvage
- Commits made before the cutoff are pushed and opened as a draft PR instead of thrown away.
- Requeue with backoff
- Transient endpoint failures set
retry_countandnot_before, then return the ticket to the inbox. - Offline outbox
- Comments, labels, and PR pushes queue durably while GitHub is unreachable, then drain on reconnect.
- Sandboxed by default
- Agent tools run OS-confined: writes jailed to the worktree, network denied unless a ticket opts in, credentials scrubbed. Fails closed.
- Provider gate
- A bad key, empty quota, or rate limit pauses claiming loudly — and never burns a ticket's retry budget.
- Spend you can see
- Every session's cost lands in a per-day ledger;
daily_budget_usdstops the queue at the cap until midnight. - Local-first
- Your machine, your git, your
ghauth. No third service in the loop unless you choose a hosted provider. - PR monitor
- junco-authored PRs sorted attention-first — failing checks and requested changes surface at the top.
junco prsprints the same list. - Verify, then critique
- Verification blocks run in the worktree; a critic reads the diff against the spec — a MISSING verdict buys exactly one corrective pass.
- Bot identity
- Daemon GitHub traffic can run as a dedicated bot account you grant per-repo access with
junco auth grant; interactive commands stay under your ownghauth. - One data root
- Queue, clones, worktrees, transcripts, and parked reviews resolve under a single
dataDir.junco dataprints the tree;junco data migrateunifies a legacy layout. - Stay current
- A newer release surfaces in the dashboard,
junco status, andjunco doctor;junco updateinstalls it and drain-restarts the supervised daemon.
Sixty seconds to a running worker
Node ≥ 22.19 · git · an authenticated gh for PR flows.
npx @ironforgesoftware/junco # first run → guided setup walkthrough
junco # ensures the daemon is up, then the cockpit: watch, dispatch, approve, monitor
junco submit my-task.md # or feed it a Markdown ticket directly
{
"github": {
"enabled": true,
"repos": [{ "nwo": "acme/reef-api", "path": "~/code/reef-api" }]
}
}
Contribute
junco is young; the codebase still fits in your head. ~3,200 tests run in under a minute; ARCHITECTURE.md is accurate and maintained. For features, open an issue first — plans are cheap, rework isn't. junco dogfoods: it submits tickets against its own repository.
git clone https://github.com/ironforgesoftware/junco && cd junco
npm install && npm test # vitest, ~3,200 tests, under a minute
Label an issue. Get a pull request.
npm install -g @ironforgesoftware/junco