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

pipeline-worker

v0.1.29

Published

Automated git-worktree workflow: captures intent from a diff via Claude Code or GitHub Copilot CLI, runs build/lint/test, opens a GitLab MR or GitHub PR, and auto-fixes failing pipelines — with a companion forge MCP server (TOON-encoded responses).

Readme

pipeline-worker

CI npm License: MIT

Automate the last mile of your local changes: pipeline-worker takes the uncommitted diff in your repo and drives it — unattended — all the way to a merged, locally-synced result.

  1. Captures your staged + unstaged changes (your working tree is only read, not modified, up through this point).
  2. Replays them in a disposable git worktree.
  3. Asks a coding agent (Claude Code, Pi, or GitHub Copilot CLI) to infer the intent: change type, branch slug, commit message, summary.
  4. Runs your build / lint / test commands, fail-fast.
  5. Commits, pushes, and opens a GitLab MR or GitHub PR — the branch name is composed from the configurable branchPattern.
  6. Polls the CI pipeline; on failure it hands the pipeline URL to the agent, which pulls the failed jobs and logs itself via whatever GitLab/GitHub MCP tooling is available (pipeline-worker's own forge MCP server, or an external one the agent already has configured), commits the fix, pushes, and re-polls — capped at maxFixAttempts before escalating to a human with an MR comment.
  7. Once the MR/PR is ready to merge (or, with PIPELINE_WORKER_CLEANUP_EARLY, as soon as the MR/PR is opened), resets your repo's current branch back to HEAD (see PIPELINE_WORKER_CLEANUP below) — your changes now live safely on the feature branch instead of sitting uncommitted locally too.
  8. By default (PIPELINE_WORKER_AUTO_MERGE_ON_GREEN), waits for the forge to confirm the auto-merge actually landed, then (after a few seconds' grace for the ref to settle) fast-forwards your local target branch from origin — so your local main already contains the merged result when the run ends. Best-effort: if the merge is held up (e.g. by required approvals), you switched branches mid-run, or your local target branch diverged, it leaves everything untouched and tells you to git pull instead. Set PIPELINE_WORKER_AUTO_MERGE_ON_GREEN=false to go back to opening the MR/PR and merging it yourself.

While attached to a real terminal, the run renders as a live step tree — header line, then one row per step (capture, worktree, checks, ci-watch, merge, ...) with a status glyph, duration, and best-effort token count, updated in place. CI logs and piped output fall back to the previous append-only narration (or force it yourself with PIPELINE_WORKER_PLAIN_OUTPUT=true).

Polling is plain REST and costs zero agent tokens; the agent is invoked only when a pipeline actually fails, and fetches whatever pipeline/job detail it needs through pipeline-worker's token-efficient TOON-encoded MCP server (or an external forge MCP server, if the agent has one available).

Requirements

  • Node.js >= 20.12 and git
  • One coding agent CLI on your PATH: Claude Code (claude), Pi (pi), or GitHub Copilot CLI (copilot)
  • A GitLab or GitHub token with API access to the repo

Agents

| CLI | PIPELINE_WORKER_AGENT | Setup | Per-invocation model selection | | --- | ----------------------- | ----- | ------------------------------ | | Claude Code | claude | npm install -g @anthropic-ai/claude-code | ✅ (--model) | | Pi | pi | npm install -g @earendil-works/pi-coding-agent | ✅ (--model) — any provider/model | | GitHub Copilot CLI | copilot | Install via GitHub's docs | ❌ (uses its own configured model) |

Pi supports models from any provider — Anthropic, OpenAI, Google Gemini, DeepSeek, Groq, OpenRouter, etc. Configure your provider/api-key via pi's own setup (/login), env vars, or --provider in the adapter.

Install

npm install -g pipeline-worker

This installs two equivalent commands, pipeline-worker and the shorter pw — use whichever you prefer (e.g. pw run --ticket PROJ-123).

Quick start

Set these once in your shell profile (~/.zshrc / ~/.bashrc) and every repo on the machine picks them up — no per-repo setup needed:

export PIPELINE_WORKER_AGENT=claude     # or pi, or copilot
export PIPELINE_WORKER_FORGE=gitlab
export PIPELINE_WORKER_GITLAB_HOST=https://gitlab.example.com
export PIPELINE_WORKER_GITLAB_TOKEN=glpat-xxxxx
export PIPELINE_WORKER_GITLAB_REPO_BASE=$HOME/REPO   # local dir that mirrors the GitLab namespace root — enables auto-detected projectId in any repo underneath it

Then, in any repo:

cd your-repo
# hack, hack, hack — leave the changes uncommitted, then:
pipeline-worker

Configuration

pipeline-worker is configured entirely through real environment variables — set them in your shell profile once, and every repo picks them up.

| Env var | Default | Meaning | | --------------------------------------- | ---------------------------- | ----------------------------------------------------------------------------- | | PIPELINE_WORKER_AGENT | claude | claude, pi, or copilot | | PIPELINE_WORKER_FORGE | gitlab | gitlab or github | | PIPELINE_WORKER_GITLAB_HOST | — | e.g. https://gitlab.example.com | | PIPELINE_WORKER_GITLAB_PROJECT_ID | — | numeric project id | | PIPELINE_WORKER_GITLAB_REPO_BASE | — | local dir mirroring the GitLab namespace root, for auto-detecting projectId | | PIPELINE_WORKER_GITLAB_TOKEN | — | GitLab API token | | PIPELINE_WORKER_GITHUB_REPO | auto-detected from origin | owner/name slug — only needed when origin isn't a GitHub remote | | PIPELINE_WORKER_GITHUB_TOKEN | falls back to GITHUB_TOKEN | GitHub token | | PIPELINE_WORKER_POLL_INTERVAL_SECONDS | 15 | pipeline poll cadence; use 60 for slow pipelines | | PIPELINE_WORKER_BRANCH_PATTERN | pipeline-worker/{name} | feature branch naming template — see below | | PIPELINE_WORKER_CLEANUP | true | reset repoRoot to HEAD once cleanup fires (see PIPELINE_WORKER_CLEANUP_EARLY for when) (false to keep your local uncommitted changes as-is) | | PIPELINE_WORKER_CLEANUP_EARLY | false | true resets repoRoot as soon as the MR/PR is opened (diff committed + pushed), instead of waiting for CI to go green — frees the repo (and the run lock) for a new pipeline-worker run while this run's CI-watch/fix loop keeps going in the background | | PIPELINE_WORKER_INTENT_MODEL | haiku | model used for the intent-capture step (branch/commit/summary); claude and pi support per-invocation model selection — copilot ignores it | | PIPELINE_WORKER_BUILD | auto-detected from toolchain | build command override; set to an empty string to skip the stage | | PIPELINE_WORKER_LINT | auto-detected from toolchain | lint command override; set to an empty string to skip the stage | | PIPELINE_WORKER_TEST | auto-detected from toolchain | test command override; set to an empty string to skip the stage | | PIPELINE_WORKER_MAX_FIX_ATTEMPTS | 5 | how many CI-fix attempts before escalating to a human — tracked independently from merge-conflict-resolution attempts, so a long-lived PR needing several rebases can't exhaust the budget meant for real bug-fixing | | PIPELINE_WORKER_RUN_LINT_AND_TEST | true | run the local lint and test stages (false to run only build — for repos where an earlier workflow, e.g. upstream CI, already verified lint/test) | | PIPELINE_WORKER_UPDATE_CHANGELOG | false | once checks pass, add a bullet (from the captured intent's summary) under CHANGELOG.md's [Unreleased] section — feature/bugfix/chore map to the Added/Fixed/Changed categories — creating the file, Keep a Changelog-style, if the repo has none — and include it in the same commit | | PIPELINE_WORKER_AUTO_MERGE_ON_GREEN | true | once the MR/PR opens, ask the forge to merge it automatically as soon as CI (and any required approvals) allow — best-effort; if the forge rejects it (auto-merge not enabled for the repo, pending approvals, ...) the run continues normally and you merge manually. Once the forge confirms the merge landed, the run also fast-forwards your local target branch from origin (waiting a few seconds for the ref to settle first), so your local main is already up to date when the run ends. Set to false to go back to opening the MR/PR and merging it yourself | | PIPELINE_WORKER_MERGE_METHOD | squash | merge, squash, or rebase — passed to auto-merge. GitLab has no per-request rebase option; rebase there falls back to the project's own default merge method | | PIPELINE_WORKER_SQUASH_ON_MERGE | false | once CI is green, collapse every commit this run made on the branch into one (titled from the captured intent) and force-push — keeps history clean regardless of the repo's merge-strategy setting. Off by default: rewrites published history (force-push), a materially different risk from everything else this tool does. Only reliable with auto-merge off — the forge may already have merged (and deleted) the branch before this step runs | | PIPELINE_WORKER_PLAIN_OUTPUT | false | force the append-only, non-redrawing narration even on a real terminal (the same output CI/piped runs always get) — useful when pasting output into a bug report or feeding it to another tool |

Branch naming

PIPELINE_WORKER_BRANCH_PATTERN controls the feature branch name, built from three placeholders:

| Placeholder | Filled by | | ----------- | ------------------------------------------------------------------- | | {type} | feature, bugfix, or chore — inferred from the diff by the agent | | {ticket} | the --ticket <id> flag passed to pipeline-worker run | | {name} | a short kebab-case slug describing the change — inferred by the agent |

For example, a team using GitLab issue-linked branches would set:

export PIPELINE_WORKER_BRANCH_PATTERN='{type}/{ticket}/{name}'
pipeline-worker run --ticket PROJ-123
# -> bugfix/PROJ-123/fix-login-redirect

A pattern that includes {ticket} requires --ticket to be passed; the run fails fast at the naming step otherwise.

Check command auto-detection

build / lint / test are picked from the repo's toolchain (first marker found wins; mixed-language repos should set PIPELINE_WORKER_BUILD / PIPELINE_WORKER_LINT / PIPELINE_WORKER_TEST explicitly):

| Toolchain | Marker | build | lint | test | | ----------------- | ------------------------------------------------------ | ---------------- | ----------------------------------- | ------------------------------------------------ | | Node / TypeScript | package.json | npm run build | npm run lint | npm test — each only if the script is declared | | .NET | *.sln / *.csproj / *.fsproj / *.vbproj at root | dotnet build | dotnet format --verify-no-changes | dotnet test | | Go | go.mod | go build ./... | go vet ./... | go test ./... | | Python | pyproject.toml / setup.py / requirements.txt | — | — | pytest |

A stage with no command () is skipped. If no toolchain is detected and no commands are configured, all local checks are skipped with a warning.

Commands

| Command | What it does | | -------------------------------------------- | ------------------------------------------------------------------------- | | pipeline-worker (or pipeline-worker run) [--ticket <id>] | Capture the current diff and drive it to a green MR/PR | | pipeline-worker serve | Start the forge MCP server over stdio (used by the agent during fix runs) | | pipeline-worker resume --branch <name> [--target <branch>] | Resume watching/fixing a run after a crash, or adopt a branch pipeline-worker has no record of | | pipeline-worker status --branch <name> | Print the persisted state of a run | | pipeline-worker sessions [--branch <name>] | List every persisted run in this repo, or show one run's full step-by-step timeline | | pipeline-worker update | Install the latest release from npm (npm install -g pipeline-worker@latest) |

Before doing any work, pipeline-worker run checks npm for a newer published version and installs it automatically if the locally installed one is out of date (the update takes effect on the next run). This check is best-effort: if npm is unreachable or the install fails, the run proceeds anyway on whatever version is already installed.

Adopting a branch pipeline-worker never ran on

pipeline-worker resume --branch <name> also works for a branch pipeline-worker has no persisted state for at all — e.g. one you committed and pushed by hand. It checks out the branch and checks the forge for an open PR/MR for it:

  • No PR/MR yet: runs it like a fresh pipeline-worker run from this point on — build/lint/test checks (aborting the same way a normal run does on failure), intent capture, then opens the MR/PR — targeting --target <branch> if given, or origin's auto-detected default branch otherwise.
  • PR/MR already open: re-captures intent from the branch's actual diff, overwrites the PR/MR's description with it (using the PR/MR's own target branch — no guessing needed), and resumes the normal watch/fix loop: poll CI, and on failure pull the failed jobs' logs, hand them to the agent to fix, commit, push, and repoll.

Every time a run hands a turn to the agent (resolving a conflict, capturing intent, fixing a failed pipeline), the output includes that turn's duration and an agent session: <id> line — claude --resume <id>, pi --session <id>, or copilot --resume <id> opens the same session later to see exactly what it did and why. Copilot CLI has no way to report the session id it picked for itself, so pipeline-worker assigns one via --name instead and reports that.

How the fix loop stays bounded

Every retry path has a cap: local checks abort the run before an MR is ever opened; if no CI pipeline shows up for the MR/PR within 60s, the run ends there instead of polling; otherwise pipeline polling gives up after a 2-hour safety window; fix attempts stop at maxFixAttempts; a fix attempt that changes no files, or a pipeline that ends canceled/skipped, escalates immediately instead of spending agent tokens. Escalation always leaves a comment on the MR/PR so a human knows to take over.

License

MIT