@color4pen/specrunner
v0.4.8
Published
AI CI/CD runner — submit request.md, get a PR back
Readme
SpecRunner
request.md in, pull request out — a self-hosted AI CI/CD runner powered by Anthropic Claude.
Full documentation: docs/.
Quick Start
specrunner init must be run inside a git repository — it writes .gitignore entries and creates
the specrunner/ scaffold that the pipeline depends on. Run git init first if you are starting
from an empty directory.
mkdir my-project && cd my-project
git init
npm install -D @color4pen/specrunner
npx specrunner init
npx specrunner login
# Create a request, edit it, run the pipeline
npx specrunner request new my-feature
# → specrunner/drafts/my-feature/request.md
npx specrunner run my-feature
# Review the PR, then archive
npx specrunner job archive --with-merge my-featureJoining an existing project
If you are cloning a repository that already uses SpecRunner (the specrunner/ scaffold and .specrunner/config.json are committed), run:
git clone <repo-url> && cd <repo>
npm install
npx specrunner init # creates local .gitignore entries and machine-local directories
npx specrunner login # stores your GitHub tokenspecrunner init is safe to re-run; it does not overwrite existing config. The specrunner/ scaffold and project config are already in the repository — you do not need to recreate them.
When a job escalates (ambiguous request, unresolvable findings, unfixable build), its state is preserved — resume it directly:
specrunner job resume my-featureRunning SpecRunner on a schedule against approved GitHub issues is an operational option — see Automation with GitHub Issues below and the operations runbook.
How the Pipeline Works
- request-review — validates the request; escalates if unclear or rejected
- design — creates branch, generates spec files
- spec-review / spec-fixer — reviews the spec; loops until approved
- test-case-gen — generates test case definitions
- test-materialize — converts test scenarios to test code (standard pipeline only)
- implementer — writes the implementation
- bite-evidence — verifies tests are base-red / candidate-green (standard pipeline only)
- verification / build-fixer — runs build/typecheck/test/lint; loops until passed
- code-review / code-fixer — reviews the code; loops until approved
- conformance — checks architecture conformance; returns to implementer if needed
- adr-gen — generates an ADR when
request.adristrue - pr-create — opens the GitHub PR
Each judge step returns approved or needs-fix. Verdicts are derived by the CLI from agent findings — agents never judge their own work. When iteration budgets are exhausted, the job escalates for human input.
Installation
# As a dev dependency (recommended)
npm install -D @color4pen/specrunner
# Or globally
npm install -g @color4pen/specrunnerProvider SDKs (@anthropic-ai/claude-agent-sdk for local runtime, @openai/codex-sdk for Codex) ship as optional dependencies and install by default. Their prebuilt platform binaries dominate install size — roughly 200 MB each (~400 MB combined) (measured on macOS arm64: claude-agent-sdk ≈216 MB, codex-sdk ≈188 MB; sizes vary by OS/arch and SDK version). Most users need only one runtime. To cut install size by ~200 MB, install with --omit=optional and add only the SDK you use:
npm install -D --omit=optional @color4pen/specrunner
npm install -D @anthropic-ai/claude-agent-sdk # Claude (local runtime, default)
# or
npm install -D @openai/codex-sdk # CodexConfiguration
Two layers, deep-merged (project overrides global):
| Layer | Path | Created by |
|---|---|---|
| User global | ~/.config/specrunner/config.json | specrunner init |
| Project local | <repo>/.specrunner/config.json | Hand-created (partial overlay) |
// .specrunner/config.json — project local example
{
"version": 1,
"steps": {
"defaults": { "model": "claude-sonnet-4-6" },
"design": {
"byRequestType": {
"spec-change": { "model": "claude-opus-4-6[1m]" },
"new-feature": { "model": "claude-opus-4-6[1m]" }
}
}
}
}For the full configuration reference (environment variables, verification commands, test placement, inbox settings, archive settings, log retention, GitHub Enterprise host), see docs/configuration.md.
Extending the Review Chain
- Rules (
specrunner/rules/<step>/*.md) — extra discipline injected into a step's prompt. No extra session. - Custom reviewers (
specrunner/reviewers/<name>.md) — independent review lens with its own convergence loop, budget, and model override. Declared as data (purpose / criteria / judgment sections in markdown), validated at job start, and run as a parallel fan-out aftercode-review— member reviewers execute concurrently, with only their commit/push serialized (FIFO mutex). Scoped withpathsglobs andrequestTypes. - Regression gate — runs automatically when custom reviewers are present. Re-checks every fixed finding against the final code.
Scaffold a definition: specrunner reviewers new <name>.
The extensible surface is the review chain. The pipeline shape is code, not configuration.
Automation with GitHub Issues
For unattended operation, SpecRunner can poll GitHub issues instead of running from drafts.
specrunner inbox run polls for issues with the approval label (default: specrunner-approved) and:
- Starts new jobs from issues whose body is a valid
request.md - Resumes jobs when a
/resumecomment is posted after escalation - Rejects issues that fail validation (posts a comment with the error)
Basic flow: create a GitHub issue whose body follows the request.md format → apply the approval label → the next inbox run picks it up.
Schedule it with cron, launchd, or GitHub Actions to run the pipeline without touching the CLI. See docs/operations.md for the full unattended-loop runbook (authentication layers, crontab setup, scheduling examples, failure resilience).
Authentication
Token resolution order: GH_TOKEN env > GITHUB_TOKEN env > gh auth token > credentials.json.
| Context | Setup |
|---|---|
| Interactive | specrunner login (device flow) |
| GitHub Actions | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} (injected automatically) |
| Self-hosted / cron | Fine-grained PAT via GH_TOKEN env var (expires after at most 1 year; must be rotated) |
Automation contexts (cron, CI, always-on schedulers) cannot run device flow and typically cannot reach the interactive keychain. Use the GH_TOKEN env var for these contexts. See docs/operations.md for the full authentication setup.
Run specrunner doctor to see which source is currently resolved.
Runtime Modes
Local (default) — runs agents locally via the Claude Agent SDK. No API key needed beyond the GitHub token.
Managed — runs agents in Anthropic's cloud. Requires SPECRUNNER_API_KEY.
export SPECRUNNER_API_KEY=sk-ant-...
specrunner runtime setup
specrunner run my-featureCommand Reference
Request commands
specrunner request new <slug> Create request.md from template
specrunner request generate "<text>" Generate request.md via LLM
specrunner request ls List active requests
specrunner request validate <file|slug> Validate request.md syntax
specrunner request template Print scaffold template to stdoutJob commands
specrunner run <slug|file> Start pipeline (alias: job start)
specrunner job ls List all jobs
specrunner job show <jobId|slug> Show job state
specrunner job resume <slug> Resume a halted job
specrunner job cancel <jobId> Cancel job and cleanup
specrunner job archive <slug> Archive and teardown
specrunner job stats [--json] Run-level statistics (cost, convergence, duration)Environment commands
specrunner init Initialize config scaffold
specrunner login GitHub Device Flow OAuth
specrunner doctor Diagnose environment / config / auth
specrunner runtime setup Set up managed runtime
specrunner runtime status Show managed runtime status
specrunner runtime reset Reset managed runtime configInbox & extension commands
specrunner inbox run Poll approved issues, start / resume jobs
specrunner rules new <step> <slug> Scaffold a rules file
specrunner reviewers new <name> Scaffold a custom reviewer definitionSee docs/request-authoring.md for how to write effective requests.
Cost
Actual cost depends on request complexity, fixer iterations, and model selected. Cache reads dominate token volume. Measured figures from this project's own runs are in docs/cost.md.
Design Principles
- Verdicts are derived, not self-reported. Review agents return findings; the CLI derives verdicts, verifies file:line references, and owns all transitions. Agents never judge their own work.
- State lives in your repository, not in a process. Job history is branch-borne. Kill the process, reboot — the next run picks up where things stood.
- Runs anywhere Node runs. One
npm installand a crontab line. No daemon, no Docker, no SaaS.
The reasoning behind these choices is in docs/design-philosophy.md.
Built by itself
Every feature was implemented, reviewed, and merged by this pipeline running on its own repository.
Stability
SpecRunner is 0.x. State and config file formats may receive breaking changes between releases. Migrations are provided in minor releases with upgrade notes in the changelog.
Assumptions
- Trust model:
request.mdis trusted input. Designed for solo use where the author also reviews and merges the PR. - Workspace setup: Worktree dependency install is language-agnostic. When no lockfile or
package.jsonis found, install is skipped automatically. For non-JS projects (Python, Go, Rust, etc.) or explicit control, setworkspace.setupin config (e.g.["uv sync"],["go mod download"]). See docs/configuration.md. - Verification: Default verification detects Node.js/Bun
package.jsonscripts. For other languages, setverification.commandsin config. See docs/configuration.md. - Commit history trust:
git log/git diffoutput is included in agent prompts. Running on repositories with untrusted commit history is not recommended.
Troubleshooting
Lint failure in verification pipeline
- Run
bun run lint --fixto resolve mechanical issues - Review remaining warnings manually
- Prefix unused variables with
_to suppressno-unused-vars
Silent exit (process exits without error)
- Enable diagnostic logging:
SPECRUNNER_DEBUG=pipeline specrunner run <request> - Check which boundary log point was last emitted
- Job state is preserved — run
specrunner job resume <slug>to continue
