npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ironforgesoftware/junco

v0.14.0

Published

A harness-agnostic coding-agent worker that turns Markdown tickets into git pull requests.

Readme

junco

Issues in. Pull requests out.

npm CI coverage node license

junco.ironforgesoftware.com — the one-page tour.

Junco is a daemon that runs on your machine. Label a GitHub issue junco and it plans the work as an issue comment; approve with a label, and it executes with a supervised coding agent in an isolated git worktree and opens the pull request — all watched from a fullscreen terminal dashboard. It drives the agent against any OpenAI-compatible inference endpoint you point it at — or a hosted provider from the embedded catalog. Your code, your git, and your credentials stay in a loop you control. The other door is a folder: Markdown tickets with a small YAML header, authored by any tool or human — junco is harness-agnostic on the dispatch side.

 🐦 junco  acme/reef-api   ●2 review · ⚑1 PR · ✓14 · daemon ● up 6h · ◐1 ⏳2
╭ 1 repos ─────────╮╭ 2 issues · 14 ─────────────────────╮╭ 3 PRs · reef-api ──────╮
│▌acme/reef-api 2● ││▌● #52 Fix reef color…   plan-ready ││▌✗ #52 fix-color-lut ✗2 │
│ acme/tide-cli    ││ ◐ #46 Bleaching alert      working ││ ◐ #48 tide-cache    ◍1 │
│──────────────────││ ○ #61 Add tide tables          3h  ││ ● #41 alert-copy    ✓4 │
│ queue            ││ ✓ #44 Coral survey       done  2d  ││                        │
│ ◐ #46 · turn 14  ││                                    ││                        │
│ 2 waiting        ││                             2/14   ││                        │
╰──────────────────╯╰────────────────────────────────────╯╰────────────────────────╯
 ↑/↓ move · ←/→ panes · enter preview · m import · o approve · c chat · / filter · ? help

The loop: label → plan → approve → PR

  1. Label an issue junco. The daemon's next sweep verifies the labeler has write access, plans the work in a read-only session, and posts the plan as an issue comment — the issue flips to junco:plan-ready.
  2. Read the plan. Edit it if you like. The comment is ordinary markdown, and whatever it says at approval time is what executes.
  3. Apply junco:approved. Junco verifies who applied it (a write+ collaborator) and that it postdates the plan comment, then queues an execution ticket — junco:queued, then junco:working while the agent runs in an isolated worktree with verification and a diff-vs-spec critic.
  4. The pull request arrives as a draft carrying a deterministic Closes owner/repo#N line, and the issue flips to junco:done — or junco:failed, with the reason as a comment.

Three properties worth knowing:

  • Fails closed. Ticket frontmatter is always built by the bridge — never from model output or issue text — and any verification error stops the dispatch.
  • Questions skip planning. Add junco:ask alongside the trigger label for read-only Q&A, answered as a comment: no branch, no PR.
  • Offline-tolerant. When GitHub is unreachable, labels, comments, and PR pushes queue in a durable outbox — FIFO replay, idempotent, dead-lettered after 3 attempts. junco outbox inspects it; finished work is never lost to a dead network.

One issue, end to end:

$ junco logs -f
09: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 passed
09:42:58 INFO  [gh-acme-reef-api-52] critic: pass
09: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/57
09: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

GitHub mode guide — setup, lifecycle labels, trust model.

Why junco

  • Plans before code — the plan is an editable comment on the issue, and nothing executes until an approval that junco verifies (who applied it, and that it came after the plan).
  • A dashboard worth living in — a fullscreen terminal UI for the whole loop: watch repos, read plans, approve, track the queue, track your open PRs, and run any junco command from a palette without leaving it.
  • Tickets in, pull requests out — a ticket is a Markdown file with a small YAML header. Junco claims it, works in an isolated git worktree, verifies the result, runs a diff-vs-spec critic, and opens a draft PR. Tickets without a repo: are Q&A: answered in place, read-only, no git involved.
  • Fork-PR modejunco import owner/repo#N plans and PRs an issue on a repo you don't own: it forks, clones the fork into a managed directory, and opens the draft PR upstream — no labels or comments on their repo.
  • Supervised, not hopeful — loop guards catch stuck agents, timeouts salvage the commits already made, transient failures retry with backoff, and every run leaves a full transcript.
  • Offline-tolerant — when GitHub is unreachable, an outbox queues the comments, labels, and PR pushes durably and drains itself on reconnect.
  • Local-first by design — your machine, your git, your gh auth, your choice of inference endpoint. There is no third service in the loop unless you choose one.
  • Its own GitHub identity, if you want onejunco auth login (or the setup wizard's Account chapter) gives the daemon a dedicated bot account, so PRs, comments, and commits are attributed to the bot instead of you, and the account that approves work is not the one that dispatched it.

It audits, you decide what to file

Audit and investigate are junco's two read-only modes: audit sweeps a whole repo and turns what it finds into a backlog of candidate issues, while investigate (below) deep-reads one already-filed issue and turns your understanding of it into a single draft comment — audit generates backlog, investigate deepens one item of it.

junco audit <path|owner/repo|owner/repo#N> audits a repo — npm audit for the dependency tree plus a read-only agent pass over the code — and parks the findings for review instead of filing them right away. junco audit review lists what's pending; junco audit review <id> shows each finding's fingerprint, severity, and title; junco audit file <id> --all (or --only <fingerprint,…>) files the ones you confirm as GitHub issues titled [<severity>] <title> (<ruleId>). Every finding carries a fingerprint, and filing dedupes on it against the repo's most recent 500 issues — any author, closed ones included — so nothing is filed twice.

It works on any watched repo, owned or not. On a repo you own, filed issues get junco:finding + severity/<level> labels (best-effort), and --auto-plan adds the trigger label so junco plans its own findings for you to approve. On a repo you don't own, issues file label-free — junco never assumes triage rights it doesn't have — and --auto-plan has no effect there.

Point it at one issue instead of the whole repo — junco audit owner/repo#N — and the audit scopes to the code that issue implicates; filed findings carry a Context: line GitHub cross-references onto the issue's timeline automatically (no comment is posted; that's junco investigate, below). Unlike the bare owner/repo form above, an issue reference auto-provisions an unwatched repo the same way junco import/junco investigate do. → Repo audit guide

It investigates, you decide what to post

junco investigate <owner/repo#N|issue-url> reads a single issue and investigates it against the repo, read-only — root cause, evidence, repro steps, a suggested fix direction — then parks the result as a comment draft instead of posting it. junco investigate review lists pending drafts; junco investigate review <id> previews exactly what would post, footer included; junco investigate edit <id> opens it in $EDITOR for a full rewrite; junco investigate post <id> is the human confirm step that actually posts the comment. Every posted comment carries a disclosure footer by default (--no-footer to omit it). It works identically on owned and unowned repos — an unwatched repo is auto-forked and provisioned the same way junco import does. → Issue investigation guide

Chat with the agent

Press c on any repo, issue or PR in the dashboard to open an ongoing, read-only chat with the coding agent about that repository — from an issue or PR it prefills /issue N or /pr N into the composer, not sent. Ask anything ("what does this module do?", "is there a cheaper way to do #42?"), and when you want work done, ask for a ticket: the agent drafts it inline and junco parks it for you to review, the same confirm gate audit/investigate above use. s submits the draft, e opens it in $EDITOR, r cycles its route (auto → inbox → issue), D discards it — nothing is ever submitted, filed, or dispatched without that confirm. Ask the agent to submit a draft it just parked and, with chat.submitTool on (the default), it calls its one action tool, junco_submit, itself — proposing the same submit as a y/n card instead of the s key, and reporting back what actually happened once you decide. Every dispatch branch is reachable from the conversation: a plain ticket, a ticket set, a plan set, an amend on an open PR, an apply-ticket patch, or a request to audit/investigate. /pr N and /issue N pull that PR or issue's context into the conversation. The session lives in the daemon, not the dashboard, so it survives a dashboard quit or a daemon restart; junco transcript --chat owner/repo prints one outside the TUI. The chat's tools are the same read-only subset a Q&A ticket gets, plus that one action tool; /chat/* never leaves loopback. → ARCHITECTURE.md § The chat path · Dashboard

Sixty seconds to a running worker

Requires Node ≥ 22.19, plus git and an authenticated gh for PR flows. The execution sandbox is on by default: macOS uses the built-in Seatbelt (nothing to install); Linux needs bubblewrap (apt install bubblewrap / dnf install bubblewrap) — or set sandbox.backend: "none" / sandbox.enabled: false.

npx @ironforgesoftware/junco   # first run → setup wizard; afterwards → dashboard (daemon ensured)

junco dashboard (or bare junco on a first run) opens a full-screen guided walkthrough — workspace, model setup (an inference endpoint with live discovery, or a hosted provider from the built-in catalog), repo containment, the GitHub bridge, and the recommended extras — then creates the queue, verifies the result with a flight check, and lands you in the dashboard. Re-run it anytime from the command palette ("setup") to tune an existing config (it only writes what you change). junco config init scaffolds defaults non-interactively — the headless equivalent for scripted setups. (Prefer a global install: npm install -g @ironforgesoftware/junco, then the command is just junco.)

junco dashboard                # the cockpit: watch repos, dispatch, approve, monitor PRs
junco start                    # or run the daemon in the foreground; Ctrl-C to stop
junco submit my-task.md        # feed it a Markdown ticket directly
junco skill install --harness claude   # link the junco-dispatch skill into your agent harness

Or drop a ticket in a folder

The inbox is the second door: drop a Markdown ticket (junco submit, or any tool writing files) and it runs the same 14-phase pipeline — claimed by atomic rename, executed in a worktree, verified, reviewed by the critic, opened as a draft PR — with requeue-and-backoff on transient failures. junco schema prints the frontmatter contract, examples/ has templates, and the bundled junco-dispatch skill teaches coding agents to write well-formed tickets. → Tickets guide

When the exact bytes are already known, skip the agent: an apply ticket carries a git format-patch series in a junco-patch fence — or junco submit --patch <series.patch> --repo <path> composes one for you — and Junco lands it with git am --3way and opens the PR with zero model turns. Verification still gates the PR; a series that no longer applies cleanly escalates to a single agent session that treats the patch as a spec. → Apply tickets

Documentation

| Guide | What's inside | | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------- | | Tickets | Ticket flavors, frontmatter reference, examples, submission, the PR-flow lifecycle | | Configuration | The config.json skeleton, key knobs, hot-reload, and the junco config CLI | | GitHub mode | Setup, the plan → approve → PR loop, lifecycle labels, offline behavior, trust model | | Repo audit | junco audit — audit any watched repo, review parked findings, file the ones you confirm | | Issue investigation | junco investigate — investigate an issue read-only, review the drafted comment, post the ones you confirm | | Dashboard | Every pane, key, and the command palette | | Bot account | Give the daemon its own GitHub identity — setup, how it works, doctor checks, migration notes | | Operations | Health endpoint, running as a service, security model, troubleshooting | | ARCHITECTURE.md | The runtime, module by module — accurate and maintained |

CLI at a glance

| | | | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | junco start / junco restart | run the daemon / restart the installed service | | junco submit <file> | queue a ticket (also reads stdin) | | junco submit --patch <file> --repo <path> | compose an apply ticket from a git format-patch series — zero model turns (--title, --why, --verify) | | junco submit --plan <file> --repo <path> | compile a junco-plan fence into a dependency-ordered ticket set, one PR per task (needs planSets.enabled) | | junco submit --as-issue <file> | file the ticket as a parked, unlabeled issue via the bot account — your trigger label launches it (also --plan) | | junco lint <file> | validate a ticket (plan-lint + repo/branch preflight) without submitting | | junco submit --dry-run <file> | report destination, discarded frontmatter, and lint without submitting | | junco dashboard | the fullscreen TUI | | junco import <owner/repo#N \| url> | plan and PR any repo's issue — direct branches when the bot can push, fork-PR mode otherwise | | junco status / junco list / junco logs -f | daemon, queue, and log visibility | | junco prs | list junco-authored pull requests across watched repos | | junco audit <path\|owner/repo\|owner/repo#N> [--auto-plan] | audit a repo, or scope to one issue (owned or external); findings await review (audit review, audit file, audit discard) | | junco investigate <owner/repo#N\|url> | investigate an issue (owned or external); draft awaits review (investigate review, investigate edit, investigate post) | | junco retry <name…\|--all> | move failed tickets back to the inbox | | junco rm <name> | delete a queued ticket from the inbox | | junco outbox [flush] | inspect or push the offline GitHub backlog | | junco unwatch <owner/repo> [--plan] | stop watching a repo and delete its junco-owned state (--plan previews as JSON) | | junco data [--json] / junco data migrate | print the data tree (paths, counts, provenance); migrate unifies legacy roots (configuration guide) | | junco worktree prune <path> | prune a stale or backup worktree (lock-guarded; refuses a live one) | | junco doctor | preflight config, git/gh auth, endpoint, model | | junco transcript <ticket-id> \| --chat <owner/repo> | print a ticket's recorded event transcript — runs, tool calls, results, the agent's answer (--thinking, --tools); --chat prints a repo's dashboard chat transcript instead | | junco replay <ticket-id\|path.jsonl> | re-run a recorded transcript through the guards under a chosen policy — a what-if report, not a live rerun | | junco auth login | log the bot account in (bot account guide) | | junco auth grant <owner/repo> | grant the bot push access to a repo — invite as you, accept as the bot (bot account guide) | | junco config / junco schema / junco service | config path/list/get/set/init, ticket schema, render a launchd/systemd service file to stdout | | junco update | install the latest release and drain-restart the supervised daemon | | junco skill install [--harness <name\|path>] | link the junco-dispatch skill into agent-harness skills dirs (claude, codex, pi, omp, opencode) | | junco run-once / junco inbox-path | process one ticket and exit (dev/cron; no lock) / print the inbox path | | junco --version | print the running version |

Contributing

Contributions are welcome — junco is young, and the codebase is still small enough to hold in your head.

git clone https://github.com/ironforgesoftware/junco && cd junco
npm install
npm test          # vitest, ~5,200 tests, ~40 s
  • Run the full gate before a PR: npm run lint && npm run format:check && npm run typecheck && npm run build && npm test && npm run test:e2e
  • Development is test-first with a commit per unit of work; the suite is green at every commit. Conventional commit messages (feat:, fix:, …).
  • ARCHITECTURE.md is accurate and maintained — read it before touching the runtime, and keep it true when you do.
  • For features, open an issue first — plans are cheap, rework isn't.

The longer version — conventions, testing expectations, commit and PR policy — lives in CONTRIBUTING.md. And junco can submit tickets against itself — drop a PR-flow ticket with repo: pointing at this repository.

License

MIT

Named after the dark-eyed junco — a small, unassuming snowbird that works through winter.