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

@sanchaymittal/cnk

v0.1.1

Published

Cross-provider subagent relay CLI, daemon, and TUI

Readme

cnk — cross-provider subagent relay

Daemon + thin CLI that lets any parent coding agent spawn another coding-agent adapter as an ephemeral subagent using that provider's own subscription auth, with provider-specific model selection, push-notify on terminal events, and optional cursor-streamed events back to the parent.

For the launch-level overview, start with the root README.md. This file is the daemon/product reference. Adapter defaults and effort routing live in packages/adapters/src/adapters/catalog.ts; the generated table is in docs/model-catalog.md.

Architecture

  • Daemon — long-running supervisor. Owns the subagent process tree, adapter event streams (~/.cnk/subagents/<id>.jsonl), CloudEvents terminal logs (~/.cnk/events/<subject>.jsonl), 4-JSONL append-only control-plane stores, and notification dispatch.
  • CLIcnk <subcommand> opens a UDS connection to the daemon and speaks JSON-RPC. Auto-spawns the daemon on first call.
  • TUIcnk, cnk tui, and compatibility alias cnkcli open the integrated OpenTUI interface. It uses the same daemon RPC surface as the CLI.

Sockets and state live under ~/.cnk/ (cnkd.sock, cnkd.json, cnkd.lock.d/, subs.jsonl, pids.jsonl, sub-seqs.jsonl, subject-seqs.jsonl, subagents/, events/). Adapter event streams used by cnk tail, cnk usage, and the TUI LiveTail live under subagents/.

Storage layout

~/.cnk/
├── cnkd.json                  # daemon PID + port registry
├── cnkd.sock                  # UDS socket
├── cnkd.lock.d/               # atomic-mkdir singleton lock
│   └── pid                    # owning daemon PID
├── subs.jsonl                 # subscription registry mutations
├── subs.snap.json             # subs projection snapshot
├── pids.jsonl                 # active-pid registry mutations
├── pids.snap.json
├── sub-seqs.jsonl             # per-subscription sequence counters
├── sub-seqs.snap.json
├── subject-seqs.jsonl         # per-subject sequence counters
├── subject-seqs.snap.json
├── subagents/
│   └── <id>.jsonl             # adapter event stream
└── events/
    └── <subject>.jsonl        # per-subagent CloudEvents log (CEEnvelope per line)

All files are created with mode 0o600; ~/.cnk/ itself is 0o700. Signing keys are base64-encoded inside subs.jsonl records — no sidecar key files.

Concurrency and singleton lock

The daemon acquires a singleton lock via fs.mkdir(cnkd.lock.d/, {recursive:false}) before writing to any control-plane file. If the lockdir already exists, the daemon reads the pid file inside it, checks whether that process is alive (kill(0, pid)), and either yields or heals the stale lock and retries once. This is cross-runtime safe (Node ≥ 20 and Bun ≥ 1.3 both honour POSIX mkdir atomicity).

Upgrade / migration note

The old SQLite control plane is gone. Fresh boots now initialise the JSONL stores under ~/.cnk/, and the daemon heals any stale lock or registry files from prior runs.

Runtime requirements

  • Bun ≥ 1.3 — the daemon runs under Bun. @opentui/core native FFI and Bun-native fdatasync / atomic mkdir are used throughout. No better-sqlite3 or proper-lockfile dependencies.
  • Node ≥ 20 — used for the published cnk CLI wrapper. The wrapper checks that Bun is available, then launches the Bun CLI entrypoint. The daemon process itself is spawned under Bun.

When a client auto-starts the daemon, cnk preserves the caller's PATH and adds common user CLI locations (~/.bun/bin, ~/.local/bin, /opt/homebrew/bin, /usr/local/bin, and the current runtime's bin dir). Set CNK_EXTRA_PATH to a path-delimited list when provider CLIs live elsewhere; cnk consumes it during daemon boot and appends those entries to the daemon PATH before launching adapter subprocesses.

Install

npm install -g @sanchaymittal/cnk
cnk --help

Source checkout:

npm install
npm run build
npm link --workspace @sanchaymittal/cnk

Quickstart — CLI (recommended)

For an interactive terminal session, run cnk to open the TUI. For scripts and agent harnesses, use the subcommands below. cnk run is sync — block until terminal, print the CE envelope on stdout, exit with a status code derived from the terminal kind. Modeled on gh pr view: one command, no temp-file plumbing exposed to the caller.

# Single-command sync — blocks until done, prints CE envelope JSON, exit 0
cnk run --agent codex --model gpt-5.5 'Review this diff for correctness regressions. Findings first.'

# Just the summary string (data.summary)
cnk run --agent codex --model gpt-5.5 --format summary 'Review this README for launch clarity. Return top fixes.'

# Summary + trailing newline
cnk run --agent codex --model gpt-5.5 --format text 'Review this README for launch clarity. Return top fixes.'

Exit codes: 0 done, 1 error, 124 timeout, 130 cancelled (SIGINT), 2 invalid input.

cnk run blocks via OS-level push (fs.watch → kqueue/inotify) — no polling, ~zero CPU and zero tokens during the subagent run. --timeout <ms> is opt-in (no default — wait forever). Cancel via SIGINT or wrap in shell timeout(1) if a hard bound is needed.

For AI orchestrator / harness callers: prefer --format summary — the exit code carries the terminal kind, and stdout becomes a short string (typically ~5-50 tokens) instead of the full ~500-token CE envelope. The default --format json is for human/scripting use where you want the full envelope.

For async / fan-out use cnk dispatch (returns {subagentId} immediately, caller registers a notify target):

# Push-on-terminal via exec (true push, CE envelope on stdin)
OUT=$(mktemp -t cnk-out.jsonl)
cnk dispatch \
  --intent 'long-running task' \
  --agent claude-code \
  --notify-exec /bin/sh \
  --notify-exec-args "[\"-c\",\"cat >> $OUT\"]"
# → {"subagentId":"<uuid>"}

--notify-exec <cmd> runs cmd directly (no shell). Pass --notify-exec-args '<json-array>' for arguments — daemon spawns cmd with those argv, CE envelope on stdin, env vars CNK_SUBAGENT_ID, CNK_EVENT_TYPE, CNK_SEQUENCE.

--notify-file <path> is the other shape: the daemon appends the CE envelope to <path> (NDJSON) on terminal — consumer poll-detects (until [ -s ]; cat). Prefer exec for true push (process wakes on the event); use file for ad-hoc shell where you don't need argv control.

To stream events instead of (or in addition to) notify:

cnk tail <subagentId>          # blocks, prints JSONL until terminal
cnk cancel <subagentId>        # writes terminal error event
cnk usage --runId <subagentId> # token / cost rollup
cnk transcript <subagentId>    # readable full-stream transcript
cnk status                     # last 20 live runs

cnk run --format transcript ... is the sync form when you want the same full-stream transcript immediately after terminal. Use --format summary for cheap orchestration handoffs; use transcript when judging result quality, debugging adapter behavior, or comparing providers.

Persistent subscriptions (vs the per-dispatch --notify-* flags above):

cnk sub create --kind file --path /abs/inbox.jsonl --filter '<event-type>'
cnk sub create --kind exec --cmd /usr/bin/true --args '["-c","cat >> /tmp/out.json"]' --filter '<event-type>'
cnk sub list
cnk sub delete --subId <subId>
cnk sub ping --subId <subId>

Daemon lifecycle is normally automatic, but exposed:

cnk daemon start [--detach]
cnk daemon status
cnk daemon stop

--input-json '<full payload>' on cnk dispatch is an escape hatch that bypasses individual flags — useful from scripts that already serialize.

--skills-json carries a compact skill manifest for adapter-native access and terminal metadata. The daemon does not prefeed skill content or manifest text into the child prompt; each adapter must deliberately support provider-native skill access.

Same-provider routing is available through --parent-agent <name> and --route-preference auto|relay|native. auto is the default; relay forces the generic path for parity checks; native is currently codex-only and requires the parent agent to match.

Autonomous cnk-via-cnk smoke

If you want to verify that cnk can launch real subagents from cnk itself, run the live smoke matrix:

cd packages/daemon
npm run smoke:autonomous

What it does:

  • creates a temporary git worktree for adapters that require one
  • launches real cnk run calls at multiple effort tiers
  • uses effort-based routing instead of pinning a model directly
  • verifies the subagent actually wrote the requested file
  • records which adapter won each complexity tier and which adapters failed
  • records terminal burn data (wallMs, token totals, estimated cost when the adapter emits it) so cnk-vs-direct comparisons use time, cost, and result success instead of vibes

Default routing policy in the script:

  • lowantigravity, fallback codex
  • mediumantigravity, fallback codex
  • highantigravity, fallback codex
  • xhighantigravity, fallback codex
  • maxantigravity, fallback codex

The script prints JSON so an orchestrator can consume it directly. A non-zero exit means at least one requested complexity tier had no working adapter route.

cnk-bench alpha

cnk-bench is the measured-routing successor to the autonomous smoke. It runs task directories through real cnk run, verifies each task with verify.sh, records rows, and emits a per-class routing table. The alpha corpus intentionally contains only a hermetic seed task; treat its output as harness validation, not production routing policy.

Build first, because the script imports compiled bench modules from dist:

npm run build --workspace @sanchaymittal/cnk

Safe no-provider smoke using the synthetic mock adapter:

cd packages/daemon
CNK_BIN="$PWD/dist/bin.js" npm run bench -- \
  --tasks bench/tasks \
  --classes edit-localized \
  --adapters mock \
  --efforts low \
  --n 1 \
  --out-dir /tmp/cnk-bench

This writes /tmp/cnk-bench/rows.jsonl and /tmp/cnk-bench/routing-table.json, and also prints the routing table to stdout. Without --out-dir, the routing table defaults to ${CNK_HOME:-~/.cnk}/bench/routing-table.json. For a live authenticated run, replace mock with adapters such as codex,claude-code and keep CNK_BIN pointed at the built local binary.

cnk vs direct provider CLI

cnk adds value when you need lifecycle supervision, push terminal delivery, cross-provider routing, uniform transcripts, and comparable telemetry across adapters. A direct provider CLI can be better for a one-off interactive session where that provider already has the exact UX you want and no parent harness needs to track the run.

For Antigravity specifically, the adapter intentionally wraps Google's official agy --print single-prompt surface. That means direct CLI and cnk use the same provider-side agent behavior; cnk's advantage is the normalized daemon contract, transcript storage under ~/.cnk/subagents/, and push completion delivery. The current agy print surface is text-only, so cnk cannot observe tool-call or provider token metadata from Antigravity runs.

Quickstart — from a parent agent

cnk is invoked as a plain CLI. A parent coding agent (Claude Code, Codex, etc.) shells out to cnk the same way a human does — there is no MCP server to wire. Use cnk run for blocking calls and cnk dispatch for async fan-out with push notify:

# blocking: exit code carries the terminal kind
cnk run --agent antigravity --effort medium --format summary 'Review this diff. Findings first.'

# async: returns {subagentId}; daemon pushes the terminal envelope to --notify-*
cnk dispatch --agent codex --effort high \
  --intent 'Investigate X. Do not edit files.' \
  --notify-file /abs/inbox/done.jsonl

The cnk-subagents skill (.agents/skills/cnk-subagents/SKILL.md) is the canonical guidance for when and how a host agent should delegate through cnk.

Adapters

cnk supports aider, amp, antigravity, auggie, claude-code, codex, cursor, gemini, goose, opencode, openhands, qwen, and a mock adapter for tests. Add a new agent by dropping a file into packages/adapters/src/adapters/ and registering it in packages/adapters/src/adapters/index.ts.

The model catalog is the single source of truth for adapter default models, effort routing, and manual-only model pins. Update packages/adapters/src/adapters/catalog.ts first, then regenerate docs/model-catalog.md. The catalog tests fail if the checked-in docs table drifts.

Auth: each adapter reads its provider's home dir.

  • aider → user-configured Aider model/API settings; cnk passes --no-auto-commits --no-dirty-commits
  • amp → Amp login or AMP_API_KEY; cnk uses execute mode
  • auggie → Augment/Auggie login or AUGMENT_SESSION_AUTH; cnk uses quiet print mode
  • claude-code → OAuth subscription via ~/.claude/
  • codex → ChatGPT-tier subscription via ~/.codex/config.toml OR OPENAI_API_KEY env
  • cursor → Cursor Agent login or CURSOR_API_KEY; cnk uses print mode with --output-format stream-json
  • antigravity → official agy CLI login/session; cnk uses print mode
  • gemini → legacy Gemini CLI OAuth via ~/.gemini/oauth_creds.json OR GEMINI_API_KEY
  • goose → Goose provider/model settings; cnk uses goose run --no-session
  • qwen → Qwen Code qwen auth / API-key configuration; cnk uses headless stream-json with partial messages enabled
  • openhands → OpenHands settings or LLM_* environment; cnk uses headless mode
  • opencode → provider home dir

cnk itself never holds an API key.

Local adapter readiness snapshot

Last probed: 2026-05-31 with a default-route cnk run --agent <adapter> --cwd <temp-git-repo> --timeout 120000 --format json smoke prompt after daemon PATH enrichment. This is an environment snapshot, not a provider guarantee. Working means the adapter reached terminal done; env blocked means the local daemon could not start the provider CLI; auth blocked means the adapter started far enough to report provider authentication failure.

| Adapter | Default route/model | 2026-05-31 status | Probe result | |---|---|---:|---| | aider | configured | env blocked | aider executable not found in $PATH | | amp | configured | env blocked | amp executable not found in $PATH | | antigravity | auto | not reprobed | switched to official agy --print after this snapshot | | auggie | configured | env blocked | auggie executable not found in $PATH | | claude-code | claude-sonnet-4-6 | auth blocked | authentication_failed | | codex | gpt-5.5 | Working | returned CNK_ADAPTER_SMOKE_OK | | cursor | auto | env blocked | cursor-agent executable not found in $PATH | | gemini | gemini-2.5-flash | Working | returned CNK_ADAPTER_SMOKE_OK | | goose | configured | env blocked | goose executable not found in $PATH | | mock | synthetic test adapter | Working | returned mock done | | opencode | opencode/nemotron-3-super-free | Working | returned CNK_ADAPTER_SMOKE_OK | | openhands | configured | env blocked | openhands executable not found in $PATH | | qwen | qwen3-coder-plus | env blocked | qwen executable not found in $PATH |

What's intentionally NOT here

No state machine, no DAG, no per-task git worktree, no decision cache, no scoring, no PR creation, no observability adapters, no retry loop. Caller pins agent + model. Caller decides retry policy. Caller commits + opens PRs themselves.

Adapter notes

Antigravity adapter — official CLI surface

The Antigravity adapter wraps the official agy binary:

agy --dangerously-skip-permissions --print-timeout 30m0s --add-dir <cwd> --print '<intent>'

When cnk's model catalog resolves auto, cnk omits --model and lets Antigravity choose the configured/default model. Manual model pins are passed through with --model; the built-in catalog intentionally exposes only auto because agy models is account/auth dependent. Operators can publish site-specific model IDs through $CNK_CATALOG.

The current public agy --print surface returns plain text, not structured JSONL. cnk therefore emits stdout lines as message events and synthetic session usage; it cannot currently surface Antigravity tool calls, tool results, or provider token counts.

Gemini adapter — legacy limitation

The gemini adapter wraps the gemini CLI binary (--output-format stream-json), which is Google's documented programmatic interface. The consumer Gemini CLI path stops serving requests on June 18, 2026; prefer antigravity for Google-backed consumer runs. Enterprise/API-key Gemini users can still pin --agent gemini.

The CLI applies a default system prompt and autoloads ~/.gemini/gemini.md on every run, costing ~20K input tokens before the user prompt. The adapter cannot suppress this overhead without leaving the documented public surface.

User workaround: write an empty ~/.gemini/gemini.md to drop ~4-5K of the overhead. The CLI default sysprompt remains.

Structural fix: pending publication of @google/gemini-cli-sdk (currently source-only at github.com/google-gemini/gemini-cli packages/sdk/), which exposes a custom instructions: field that would replace the default sysprompt and allow the adapter to suppress the overhead entirely.