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

@nickysagan/issue-orchestrator

v0.1.2

Published

A small, supervised GitHub issue queue that keeps autonomous coding workers alive.

Downloads

469

Readme

issue-orchestrator

A small, supervised issue queue. A single Node supervisor picks up open issues labeled agent-ready (ascending) and keeps at most two autonomous subscription-authenticated ccode implementation workers alive — each in its own tmux window running:

ccode --print --permission-mode auto --model claude-opus-4-8 "/github-issue <number>"

Usage limits are enforced by Usage Sentinel, which pauses this orchestrator's entire Docker container — supervisor and workers together — rather than this repository stopping workers itself. The full model name pins issue workers to Opus 4.8 instead of the Claude Code default or the moving opus alias.

A finished PR is not merged automatically. It first passes through the managed review gate below, which uses a third, separately reserved worker slot.

Orchestrator

Zero-dependency Node ≥20.8.0 on Linux (the supervisor guard uses a Linux abstract Unix socket). No build step.

Installed/current-repository usage

The package is published publicly on npmjs, so no registry configuration or token is needed:

npm install -g @nickysagan/issue-orchestrator@latest

The scope names the package; the installed command is issue-orchestrator.

Run it from the target project repository, not from the package checkout:

cd /path/to/target-project
issue-orchestrator

The shared agent-devcontainer also exposes that command through the literal alias:

start work

The supervisor resolves the origin of that current working directory, checks GitHub App authentication, registers its own container with Sentinel, and starts autonomous workers itself:

ccode --print --permission-mode auto --model claude-opus-4-8 "/github-issue <number>"

Non-interactive print mode skips the workspace-trust prompt, and each process exits after its command finishes. A supervisor that cannot resolve its container ID or register its lease exits nonzero rather than run unenforced. Do not start Claude separately.

Only one supervisor per repository per Linux network namespace may run at a time. A second invocation in the same namespace for the same resolved owner/repo exits nonzero with an already running error before authentication, the container lease, tmux, or worker startup. Ownership is held by a kernel-owned Linux abstract Unix socket, so it is released on normal exit and automatically when the supervisor process dies. Devcontainers normally have distinct network namespaces and therefore independent guards; containers that share a network namespace also share this guard.

Neither the image build nor devcontainer startup launches the supervisor or an LLM. Work begins only when a user explicitly runs issue-orchestrator or its start work alias.

Repository-checkout usage

npm test                 # node --test over test/
node bin/supervisor.mjs  # start the supervisor loop
tmux attach -t orchestrator   # watch the workers directly

How it works

  • Claim — the lowest-numbered agent-ready issue has its label swapped agent-readyagent-running, then a tmux window issue-<n> opens running this autonomous command:

    ccode --print --permission-mode auto --model claude-opus-4-8 "/github-issue <n>"

    Non-interactive print mode skips the workspace-trust prompt; the process exits and its tmux window closes after the command finishes.

  • Complete — a worker finishes by leaving its PR in draft and putting agent-review on the issue. Reaching any phase label is what marks implementation done: the supervisor closes the tmux window and frees the slot, and agent-running stays. An already-closed window is treated as closed; a failure at any later step is logged and retried by the next poll.

  • Vanished — if a worker window disappears before the issue reaches a phase label, the workflow died. There is no repair worker, so the supervisor fails closed: it comments on the issue — including the vanished worker's log path and the tail of its output — and sets agent-blocked. The issue is never restarted automatically, because its draft PR or worktree may still exist.

  • Worker logs — every launch tees the window's combined output to <git-common-dir>/issue-orchestrator/logs/<issue|review>-<n>.<attempt>.log, keeping the latest three attempts. Surfaced tails are scrubbed of secrets. A run that reaches its end stamps a final [orchestrator <ISO>] ... finished ... line into its log, so a tail can be placed in time without the file's mtime.

  • Active-container lease — at startup the supervisor resolves its own exact 64-character Docker container ID (from /proc/self/mountinfo; the short hostname form is not accepted) and registers it with PUT /managed-containers/<id> on Sentinel. Registration is a lease, not an admission decision: Sentinel never allows or denies a start. Every later poll re-PUTs the same ID as its heartbeat, well inside the five-minute lease; a clean exit DELETEs it as best-effort cleanup, and an abrupt exit is handled by Sentinel's lease expiry. A failed heartbeat is logged and retried on the next poll. The supervisor keeps a local guard of two implementation workers plus one reviewer.

  • Usage enforcement lives in Sentinel — when Claude Code's five-hour or weekly window reaches 95%, Sentinel docker pauses every registered container, freezing this supervisor and every worker process in place, and unpauses only after a fresh valid reading puts both windows below 95%. This repository reads no usage telemetry, applies no thresholds, calls no Docker API, and never kills a worker because of usage.

  • Stop — the supervisor exits when nothing is queued, no worker or reviewer window is live, and every managed issue rests in agent-blocked or user-merge-review. Merge and post-merge cleanup monitoring are not yet implemented.

Live container pause/unpause check: docs/smoke-checks/README.md.

Managed review gate

A managed PR receives an independent automated review and then either stops with documented blockers or becomes ready for the owner. The supervisor never approves and never merges.

Labels

At startup — after the repository is resolved and the GitHub App auth check passes, and before the first poll — the supervisor creates any of these labels that the repository is missing. Labels that already exist are never renamed, recoloured, or re-described, and no GitHub mutation ever happens at image-build time (the build has neither a target repository nor runtime credentials).

| Label | Colour | Meaning | |---|---|---| | agent-ready | 0e8a16 | Ready for issue-orchestrator claim | | agent-running | 1d76db | Managed by issue-orchestrator | | agent-review | 5319e7 | Waiting for or undergoing automated review | | agent-blocked | d73a4a | Automated workflow blocked; findings posted | | user-merge-review | fbca04 | Automated review passed; waiting for owner review and merge |

agent-running is the durable ownership marker: it is applied at claim and stays until post-merge cleanup (not yet implemented). Exactly one phase label — agent-review, agent-blocked, or user-merge-review — is active alongside it. Issue labels are canonical and the PR mirrors them; every poll repairs a mismatch, issuing an edit only when the sets actually differ.

A PR with no linked agent-running issue is ignored entirely — manual /github-issue PRs and unrelated agent/* branches are never touched. More than one PR closing an issue, a branch that disagrees with its closing reference, or an agent-review issue with no PR all fail closed: an actionable comment plus agent-blocked.

Capacity

Two reserved implementation slots plus one reviewer slot that is never borrowed for implementation. The pools are separate tmux window namespaces — issue-<n> and review-<n> — each counting only its own live windows. The oldest eligible agent-review PR gets a fresh reviewer window running:

ccode --print --permission-mode auto --model claude-opus-4-8 "/review-pr <pr>"

The reviewer slot frees as soon as that window exits. Waiting on CI holds no slot, because it is pure label state with no window.

Review marker

The reviewer (Sadotu/agent-skills, review-pr) records each pass in one immutable PR comment carrying a single-line marker:

<!-- review-pr:v1 {"fingerprint":"<64-hex>","head":"<40-hex>","base":"<40-hex>","issueUpdatedAt":"<ISO>","prUpdatedAt":"<ISO>","issue":41,"pr":72,"pass":1,"verdict":"PASS"} -->

The reviewer is the producer and owns this format; this repository only consumes it. Verdicts are exactly PASS and BLOCKING.

A marker is applied only when all three hold:

  • Authorship — the comment has viewerDidAuthor: true, so the same GitHub App identity the supervisor authenticates as wrote it. Every fingerprint input is public, so without this check any commenter could forge a PASS.
  • Identity — its issue and pr are the managed pair being gated.
  • Freshness — its fingerprint equals the live fingerprint, sha256(head 0x1e base 0x1e issue-body 0x1e pr-body). Bodies decide freshness, not updatedAt: a new comment or a label edit moves the timestamps while reviewing the same content, whereas any real change to the head, the base, the issue text, or the PR text invalidates the pass. issueUpdatedAt and prUpdatedAt are recorded for audit only.

Comparing against live state rather than a snapshot captured at launch needs no persistence, so the same content is handled once even across a supervisor restart or a crash between the comment and the label transition. A marker that fails any check is discarded silently: nothing is posted, nothing transitions, and the PR simply queues a fresh pass. Parsing fails closed on an unsupported tag, malformed JSON, or a missing or ill-typed field. A trusted, applicable marker carrying an unsupported verdict is the one case that is not discarded — it blocks, so a contract break surfaces instead of looping.

Transitions

BLOCKING — the PR is kept or returned to draft and agent-review becomes agent-blocked on issue and PR. The reviewer's findings stand alone in its own comment; the supervisor adds nothing and stops. There is no automatic repair.

PASS — the PR is marked ready for review first, so repositories whose CI triggers on ready_for_review start their checks. Checks are read on the following poll, never in the same one that opened the PR:

| Checks | Outcome | |---|---| | None configured | Green → user-merge-review | | All complete and successful, neutral, or skipped | Green → user-merge-review | | Any still running | Keep agent-review; reviewer slot stays free | | Any failed | Return to draft, agent-blocked, post the failing check names and URLs | | Data unreadable | Transition nothing; retry next poll |

Every check GitHub reports is treated as required. "No checks configured" and "could not read the checks" are deliberately distinct: only the former counts as green.

GitHub authentication

gh does not auto-consume the GitHub App credential, so the supervisor mints a short-lived App installation token (via gh-app-token.sh, overridable with GH_APP_TOKEN_SCRIPT) and injects it as GH_TOKEN for every gh call, re-minting each poll. At startup it runs an authenticated gh repo view smoke check and exits with a clear message if the App is not authenticated — rather than churning on unauthenticated calls every poll.

Configuration

The local concurrency guard is fixed at two implementation slots plus one reviewer slot. Two knobs are environment-tunable:

| Var | Default | Meaning | |-----|---------|---------| | SENTINEL_URL | http://usage-sentinel:4317 | Usage Sentinel base URL for the managed-container lease, on the shared container network; set this explicitly (for example, http://host.docker.internal:4317) only when Sentinel is exposed on the host | | POLL_MS | 60000 | Poll interval |

Labels are created at startup — see the managed review gate below.

Repo contents

| Path | Purpose | |------|---------| | agents.toml / agents.lock | dotagents manifest — declares which skills are installed and pins their source commits | | .agents/skills/ | Installed skills (github-issue, setup) — managed artifacts, restored from the manifest, not committed | | .claude/skills | Symlink to .agents/skills so Claude Code picks the skills up | | CLAUDE.md | Agent instructions and gotchas for working in this repo |

Skills

  • github-issue — runs a GitHub issue end to end: select issue, open a draft PR immediately, self-resolve design decisions (logged to the PR), implement in an isolated worktree, verify against the issue, mark ready.
  • setup — connects the repo to the container-coding-agent GitHub App and verifies git/gh authenticate as the App.

Both are sourced from Sadotu/agent-skills.

Releasing

package.json holds the version, and merging the bump is the whole release. Bump it in a normal pull request; when that lands on main, .github/workflows/publish.yml sees a version the registry does not carry, runs the tests, publishes, and pushes the matching v<version> tag. A merge that does not bump the version finds its version already published and exits without releasing anything.

Publishing goes to npmjs via trusted publishing, so no npm token is stored anywhere: npm exchanges the workflow's OIDC identity for a short-lived credential. Tagging is a second job, so the job holding an npm credential cannot write to this repository and the job that can push a tag holds no npm credential. A published version cannot be republished; bump and merge again.

Pushing a v* tag by hand still works and takes the same path, with one extra guard: the tag must equal v<version> or the run fails.

Trusted publishing can only be configured on a package that already exists, so 0.1.0 was published by hand (npm login && npm publish) to bootstrap it. Every later release goes through the workflow.

Package visibility is set on the package, not inherited from this private repository, and the setting appears only once a version exists. So after the first release, set it once under Sadotu → Packages → issue-orchestrator → Package settings.

Development environment

Agents work on this repo from a shared, sandboxed devcontainer. That environment is not part of this app — it lives in its own repo: Sadotu/agent-devcontainer (image, setup scripts, security model, auth docs). A local .devcontainer/ folder pointing at that image may exist in a checkout but is gitignored.

GitHub access is via the scoped container-coding-agent GitHub App — never a personal token, never gh auth login. See CLAUDE.md for the auth wiring.