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

@baizor/pipeline-runner

v0.3.0

Published

Standalone long-running runner daemon for cloud-dispatched pipeline runs: registers with a runner token over the control plane's /agent/v1 WSS channel (long-poll fallback seam), heartbeats, accepts job leases, ships events, and relays needs-input. Also in

Readme

pipeline-runner

Standalone, long-running runner daemon for ai-pipeline.dev: install it on a machine to execute cloud-dispatched pipeline runs. It dials OUT to the control plane's /agent/v1 WSS channel (no inbound ports), registers with a scoped runner token, heartbeats, accepts job leases, checks out an isolated workspace, drives the run through the pipeline CLI, ships events back, and relays needs_input prompts. It can also install itself as a native OS service (systemd on Linux, launchd on macOS, a Windows Service).

Prerequisite: the pipeline CLI must be on PATH

The runner does not execute pipelines itself — it shells out to the pipeline CLI (from the ai-pipeline Claude Code plugin) to match and drive runs (pipeline match, pipeline drive). Install the plugin on any machine you intend to register as a runner so pipeline resolves on PATH before running register/start.

Usage

# one-time: store identity + validate the token against the control plane
bun src/cli.ts register --url <base-url> --token <runner-token> \
    [--label repo:acme/api]... [--capacity 2] [--store-only]

# run the runner loop (connect, register, heartbeat, reconnect, accept jobs)
bun src/cli.ts start

# inspect the stored identity (token redacted)
bun src/cli.ts status

# install/uninstall/status as a native OS service
bun src/cli.ts service <install|uninstall|status> [--dry-run]

register flags:

| Flag | Required | Meaning | |---|---|---| | --url <base-url> | yes | Control-plane base URL, e.g. https://api.ai-pipeline.dev. | | --token <runner-token> | yes | Scoped runner token issued by the control plane. | | --label <k:v> | no, repeatable | Matchable label, e.g. --label repo:acme/api. os:<detected> is always added. | | --capacity <n> | no | Max parallel runs this runner accepts (positive integer). | | --cli-version <v> | no | Detected pipeline CLI version, for server-side compatibility checks. | | --plugin-version <v> | no | Detected ai-pipeline plugin version, or omit if not installed. | | --store-only | no | Store the identity but skip the one-time connect-and-validate step. |

service install supports --dry-run to print the generated systemd unit / launchd plist / sc.exe create + sc.exe failure commands without touching the system.

Reboot/logout recovery of the installed service

Crash-resume (below) only helps if the daemon actually comes back after it dies — service install now also configures the OS side of that, per platform:

  • Linux (systemd, user unit): install additionally runs loginctl enable-linger so the user's systemd instance — and this unit — keeps running after logout and starts again at boot, without an active login session. This is best-effort: if lingering can't be enabled (e.g. no polkit/D-Bus permission in a locked-down or containerized session), install still succeeds — a warning names the exact command to run yourself: loginctl enable-linger "$USER". System-unit alternative: for boot-level start that does not depend on lingering at all, run the daemon as a root SYSTEM unit instead: copy the [Unit]/[Service] block from service install --dry-run into /etc/systemd/system/pipeline-runner.service (drop the user-only WantedBy=default.target line in favor of multi-user.target if you want it before any login), then sudo systemctl enable --now pipeline-runner.service. This is a manual step — service install never requests elevation and does not manage system units itself.
  • Windows (SCM): install additionally runs sc.exe failure <name> reset= 86400 actions= restart/5000, so the Service Control Manager restarts the process 5s after a crash (the failure counter resets after 24h of uninterrupted uptime). sc.exe create ... start= auto alone — what this backend did before — starts the service at boot but configures NO recovery action, so the SCM never restarted a crashed process. Verify the configured recovery action with sc.exe qfailure pipeline-runner.
  • macOS (launchd, LaunchAgent): RunAtLoad + KeepAlive restart the daemon on crash and at LOGIN, but explicitly not at boot before anyone logs in — there is no root LaunchDaemon (/Library/LaunchDaemons) support yet; that option is deferred. service install prints this caveat. A headless Mac with auto-login is unaffected; one that waits at the login window after a reboot will not run the runner until someone logs in.

Transcript retention (crash-resume requirement)

Crash-resume below re-enters a pinned Claude Code step session mid-thought by reading its transcript. Claude Code prunes transcripts older than cleanupPeriodDays (default 30) at the startup of ANY claude process on the host — independent of this runner. On any machine that runs pipeline-runner as a service, set cleanupPeriodDays >= 14 in Claude Code's settings: the control plane parks an unanswered awaiting_input run for up to 14 days before ending it abandoned-needs-input, so the transcript must outlive that whole window or a resumable crash silently becomes an UNRECOVERABLE one (record dropped, run_status halted) the next time the runner reconciles.

Crash resume + workspace retention

A daemon death never loses a run: every accepted job persists a durable record under the runner DATA dir (%LOCALAPPDATA%\pipeline-runner\jobs\ on Windows, $XDG_STATE_HOME/pipeline-runner/jobs/ elsewhere — no secrets, the job JWT is never written to disk). On start the runner reconciles those records BEFORE connecting: a record younger than its lease TTL resumes in-place (pipeline drive --resume in the recorded checkout — pause windows restored, parked questions re-surfaced); an older one is QUARANTINED and only resumed when the control plane re-offers the run (resume_hint lease → adoption in the recorded checkout) or discarded on cancel; a record whose resume substrate is gone (checkout / next.json / claude session transcript deleted) is dropped with a run_status halted. SIGTERM/SIGINT drain gracefully: stop accepting leases, persist records, terminate drive children (their per-step state is durable), flush the event spool, exit 0. (Windows: an SCM stop is a hard terminate — that is fine; hard death is the design's baseline assumption.)

Terminal workspaces (completed / cleanly halted / cancelled runs) are deleted by default. Environment knobs:

| Variable | Meaning | |---|---| | PIPELINE_RUNNER_WORKSPACE_RETENTION=<dur> | Keep terminal workspaces for a window (30s, 15m, 12h, 7d, or plain seconds); a boot-time + hourly GC reaps expired ones. | | PIPELINE_RUNNER_KEEP_WORKSPACES=1 | Never delete workspaces or job records (infinite retention, GC off). |

Quarantined crash leftovers that no re-offer ever claims are reaped after 14 days (or the configured retention window, whichever is longer).

Identity is stored at %APPDATA%\pipeline-runner\config.json (Windows) or $XDG_CONFIG_HOME/pipeline-runner/config.json (elsewhere; ~/.config fallback) with restrictive file permissions where the OS supports them. The runner token is a secret: it is persisted (it is the runner's credential) but never logged.

Layout

src/core/wire.ts        # vendored wire-protocol subset (see header) — envelope,
                         # register/register_ack/register_reject, heartbeat/heartbeat_ack
src/core/config.ts       # identity/config store (injectable fs + path)
src/core/register.ts     # register frame build + ack/reject interpretation
src/core/backoff.ts      # exponential backoff + bounded jitter, capped
src/core/dispatcher.ts   # inbound frame router (log-and-ignore for future types)
src/core/heartbeat.ts    # heartbeat loop (injectable clock; ack pairing; directives)
src/core/transport.ts    # transport seam: WSS primary + provisional long-poll fallback
src/core/connection.ts   # the connection state machine tying it all together
src/dispatch/            # task-dispatch pipeline resolution (`pipeline match`)
src/jobs/                # lease -> accept -> workspace -> `pipeline drive`
src/shipper/             # event shipper: tails run artifacts, batches, uploads
src/relay/               # needs-input relay over the WSS channel
src/service/             # OS service install/uninstall/status (systemd/launchd/Windows)
src/cli.ts               # thin CLI: register / start / status / service

Wire protocol

The wire protocol comes from the published @baizor/pipeline-protocol npm package (repo IvanMurzak/pipeline-protocol) — zod schemas + inferred TS types, additive-only within a protocol major. src/core/wire.ts, src/jobs/wire.ts, src/relay/wire-relay.ts, and src/shipper/wire-ingest.ts are thin re-export seams over it: they keep the runner's internal import paths stable and hold the few runner-local helpers (frame builders, deliberately tolerant inbound guards) the package does not provide.

Develop

bun install
bun test            # unit tests (no network, no real home dir)
bun run typecheck   # bunx tsc --noEmit

Formerly apps/pipeline-agent in IvanMurzak/Claude-Pipeline; extracted to this standalone repo and renamed to pipeline-runner.