specpilot-harness
v0.1.0
Published
Lightweight spec workflow harness for Codex, Claude Code, OpenCode, and pi.
Readme
SpecPilot
SpecPilot is a lightweight workflow harness for Codex, Claude Code, OpenCode, and pi. It installs project-local workflow rules plus thin hook/plugin adapters.
Install
npx specpilot-harness init
npx specpilot-harness doctorInstall only selected hosts:
npx specpilot-harness init --codex --claudeRemove managed files:
npx specpilot-harness remove
npx specpilot-harness remove --purgeSet per-user preferences (written to ~/.specpilot/config.json, never touched by install/remove):
npx specpilot-harness config # show current values
npx specpilot-harness config fixRounds 3 # cap verify fix rounds (default 2)Update generated files:
npx specpilot-harness update
npx specpilot-harness update --forceMode
SpecPilot is active by default.
| Env | Behavior |
| --- | --- |
| unset or SPECPILOT=light | Inject a small engineering-floor reminder and upgrade triggers. |
| SPECPILOT=spec | Inject the active change and point to grill/spec/implement/verify rules. |
| SPECPILOT=off | Inject nothing. |
Codex project hooks also need this user-level config:
[features]
hooks = trueSpecPilot only reads that file during doctor; it never writes to your home directory.
Workflow
Rules live in .specpilot/workflow/.
Agents read them on demand:
grill.md: ask one question at a time, with a recommended answer.spec.md: create a change-scoped spec with tasks and acceptance criteria.implement.md: apply the scope ladder without crossing the engineering floor.verify.md: verify from acceptance criteria, diff, source, notes, and the methods inchecks.md— never from the implementer's summary.checks.md: team-owned list of how this project produces verification evidence; agents fill it on first use from project-native signals.
Verification adapts to the project through checks.md: a web UI verifies through a
browser user-flow, a backend through API requests, a CLI through command output, infra
through a plan/dry-run, device targets through a simulator or a named manual check.
Spec Check: lines and verify evidence both draw from it; methods that need tools not
available in every CLI must name a command-line or manual fallback, and when nothing
runnable exists verify hands the user a named manual check instead of pretending coverage.
Each change lives under .specpilot/changes/YYYY-MM-DD-slug/.
Finished changes move to .specpilot/archive/.
Local state stays in .specpilot/local/ and is ignored by git.
Customizing
Project rules — .specpilot/workflow/ (team-owned, commit them)
Rule files are meant to be hand-edited; they are yours, not the installer's.
checks.md: agents seed its Methods section on first use by reading package scripts,
CI workflows, and the README. The seed is a draft, not a decision — automatic
inference can pick the wrong command or miss the real test entry point. Review it,
correct it, commit it. Example for a web app:
## Setup
- start: `npm run dev` (frontend :5173, API :3000)
- test account: `[email protected]` / `test1234` (dev-only seed user)
- key paths: `/login`, `/dashboard`
## Methods
- tests: `npm test`
- build/typecheck: `npm run build`
- web UI behavior: browser user-flow — start per Setup, log in with the test account; fallback: `npm run test:e2e`
- API behavior: `curl -f http://localhost:3000/api/health`Setup holds what a fresh agent session needs to drive the app (boot command, dev-only test accounts, key paths) — real secrets never go in this committed file. At verify time the agent starts the project per Setup and exercises the new feature's acceptance criteria through the matching Method (e.g. a browser-tool user-flow for a UI change).
verify.md and the other rule files: tighten or extend them for the project — add a
project-specific contract check to verify.md (e.g. "a migration without a rollback
script is a blocking finding"), extend the engineering floor in implement.md, add
domain questions to grill.md.
How edits behave: update never overwrites an edited rule file (it reports
Skipped customized rule files); doctor prints a customized note so the divergence
stays visible, never an error; only update --force restores the shipped templates —
re-apply team edits after. Generated files (injector, adapters) are the opposite:
any edit fails doctor and is skipped by update; restore them with update --force.
User config — ~/.specpilot/config.json (per-user, not shared)
Personal preferences live in your home directory: the installer never creates, touches, or removes this file, and teammates do not see it. Manage it with the CLI or edit the JSON directly:
npx specpilot-harness config # show file path and current values
npx specpilot-harness config fixRounds 3 # set a key| Key | Meaning | Default |
| --- | --- | --- |
| fixRounds | Max verify fix rounds before open findings are handed back to you (integer ≥ 1) | 2 |
The file is plain JSON, e.g. {"fixRounds": 3}. Invalid or missing values are ignored
and injection falls back to the defaults — a broken config never breaks a session.
Verified matrix
| Host | Registration | Runtime adapter test |
| --- | --- | --- |
| Claude Code | .claude/settings.json hooks | Live-verified: headless session shows <specpilot-state> on SessionStart and UserPromptSubmit; SPECPILOT=off injects nothing. |
| Codex | .codex/hooks.json hooks | Live-verified: hook: UserPromptSubmit Completed, <specpilot-state> present. Requires user-level [features].hooks = true AND one-time per-project hook trust (open codex in the repo once and approve; doctor reports both). |
| OpenCode | opencode.json plugin entry | Smoke-tested by importing the plugin and calling the system transform. |
| pi | .pi/settings.json extension entry | Smoke-tested with a stub before_agent_start event. |
bash test/probe.sh runs optional live Claude/Codex injection probes; it needs real CLIs and consumes tokens.
OpenCode auto-discovery and pi native AGENTS.md loading are unverified surfaces, so SpecPilot registers explicit project-local entries instead.
Files
Generated adapters start with GENERATED by SpecPilot — do not edit.
Ownership is recorded in .specpilot/manifest.json using LF-normalized SHA256 hashes.
Update skips drifted generated files unless --force is used.
