pi-gauntlet
Opinionated, gated workflow skills, subagent personas, and runtime extensions for the pi coding agent.
Package details
Install pi-gauntlet from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-gauntlet- Package
pi-gauntlet- Version
8.1.3- Published
- Nov 1, 2026
- Downloads
- 13.8K/mo · 4,968/wk
- Author
- jjuraszek
- License
- MIT
- Types
- extension, skill
- Size
- 2.3 MB
- Dependencies
- 1 dependency · 1 peer
Pi manifest JSON
{
"image": "https://raw.githubusercontent.com/jjuraszek/pi-gauntlet/main/pi-gauntlet.png",
"skills": [
"./skills"
],
"extensions": [
"./extensions/phase-tracker.ts",
"./extensions/plan-tracker.ts",
"./extensions/verify-before-ship.ts",
"./extensions/telemetry.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-gauntlet
The gated workflow for the pi coding agent: brainstorm, plan, implement, verify, ship - each stage a gate the next can't open until it closes.
The problem
Point an agent at a task and let it loop until done - that's the easy 5%. LLMs are more a compressed library with a sampler on top than an independent mind: they produce fluent analysis faster than humans can audit it, and humans can't efficiently unravel that flood of output from the authenticity of a sound idea. So the agent quietly drifts from what you asked, and by the time you look, the diff is too big to honestly review.
It is a model problem - one-shotting an idea makes a great demo, not a product. But no better model fixes it on its own: Cursor, Claude Code, and Codex all drift the same way on long tasks, because nothing in a bare loop confronts output against original intent, and a model cannot audit itself - the same blind spot that wrote the bug will happily approve it. A weak generator needs a strong harness - because fluency is not correctness.
Why pi-gauntlet exists
pi-gauntlet is the scaffolding that makes the loop hold: brainstorm → plan → implement → verify → ship. Gates between phases are automated checks, not signatures to collect - a multi-model spec critique, an adversarial code review, and a closing conformance check that confronts the finished diff and docs against your original verbatim prompt, not the plan that got derived from it. The agent can't wave itself through a gate, and you're not rubber-stamping each step by hand.
Human judgment is spent on the two decisions that need it - what to build, up front, and how to land it, at the end. The middle runs without pausing for you. The spec and docs get committed to the repo, so the next change starts from ground truth, not a blank slate.
Part of the pi agent toolkit
Four independent extensions for the pi coding agent, each owning one concern of running agents seriously:
- pi-quiver - capabilities (ground-truth ingestion: fetch, doc conversion, session tools)
- pi-cohort - coordination (delegate to focused child agents)
- pi-condense - context economy (prune context, keep it recoverable)
- pi-gauntlet - process (this repo: the gated brainstorm→ship workflow)
pi-gauntlet's only hard dependency is pi-cohort - every gate that dispatches a reviewer or an implementer does it through pi-cohort's subagent(). pi-condense is not required, but a long gated run generates a lot of tool output; pruning it as you go is what keeps that run affordable.
What a run looks like
Concretely, one change through the gauntlet:
(Optional) Before there's even a spec,
/skill:shape-ticketcan create one tracker issue or repair a comma/whitespace list of issue refs - shaping each into a Context/Problem/Idea/Acceptance Criteria ticket, grounded by a repository audit, an AC integrity check, and a cheap council roast. Repair finishes preparation for all tickets before presenting exact-diff confirmations sequentially in ref order; each approval writes that ticket before the next gate, and may include one optional gated comment for a Reporter note or overlap evidence. The audit checks factual claims, Idea fit, AC mechanisms against cited repo guidance, and already-stated observable legs in configured sibling checkouts. It reports in-motion work and attempts a best-effort scenario through authorized current-system reads, without promising reproduction or a fix; missing access or nothing to observe is reported, not a new approval gate. Implementer detail moves into the gated Reporter note; brainstorming reads that note with the ticket so the spec retains the detail. A failed roast is retried once, then surfaced inline at the gate if it fails again. It's a tool, not a phase: no worktree, no plan/phase tracker, runs from any repo state. The agent may start it on its own when the ask is "file a ticket" or another skill routes there; the write still waits for your yes on the presented diff. Similarly,/skill:chase-bugtriages a raw bug report into an evidenced verdict - and can hand off to shape-ticket, brainstorming, or a bounded hotfix - before any spec exists.Opt in with
/skill:brainstormingand describe the change. The command is the reliable discovery-and-entry path; explicit prose requesting brainstorming/the gauntlet also supplies consent when the skill is already loaded or an available instruction or route identifies it. An ordinary implementation request or an agent recommendation is not consent. A leading run of GitHub references (#N,owner/repo#N, or a/pull/Nor/issues/NURL), separated by whitespace or commas, resolves each reference as a PR first: related open, same-repository, non-fork PRs on one base form one rework subject, including drafts. Admission runs in listed order and relatedness is checked before provisioning; the first retained PR is home, whose existing branch rebases onto the fetched PR base by default, then member commits replay onto it in listed order. The first intent wordmerge-forwardopts out and keeps the merge path. An unresolved conflict after its scoped helper aborts that step and continues to the spec with the repair as Task 1. A single non-PR reference follows the ticket path. The first non-reference token starts intent text; mid-sentence references and other ticket/free-text subjects keep their existing paths. The combined code, PR-carried specs, claims, and review threads are the brainstorm input, with each PR's provenance retained; only home's bound ticket supplies acceptance criteria, while member tickets supply context. A single PR retains the same rework path without member replays or a close offer. The combined state is judged against constraints from the fetched current base HEAD, not the fork point or the PRs' proposed policy edits; see the PR-subject contract and PR-head worktree owner.brainstormingsets up an isolated worktree (on the existing branch for PR rework), explores the codebase, and turns the subject into a written spec - when its recon finds a cited case that the ask is the wrong change (misdiagnosed, wrong-sized, already solved, a band-aid, or cutting across a sound pattern - including a repo convention that is itself debt) and can name the alternative, question one is a framing question (as framed,pivot: <alternative>, orsmaller or none); otherwise it opens with one sentence naming what it checked, and every approach it proposes ends with aPattern:line naming what it follows or cuts across; when the run starts from a ticket, the spec carries the ticket's acceptance criteria verbatim, each with a disposition (in-scope,deviates:,deferred:,venue:,elsewhere:for a row another repo's part delivers), scope cuts come only from your answer to a cut question and are listed at the gate, the conformance gate checks the in-scope ones, and/skill:check-deliveryverifiesvenue:rows before the prod deploy. A multi-model critique runs on it automatically. If the spec replaces a known prior spec, brainstorming marks the predecessor with a> **Superseded by:**banner under its title (default format, syntax overridable via.pi/gauntlet-overrides.md; candidates come from brainstorming's scout recon, never a mechanical sweep). You read and approve the spec - human gate 1. Options 1/2/4/5 approve and pick an engine; option 6 approves the content only: it writes**Engine:** deferredunder**Amend-grant:** none, pushes the branch, opens a draft PR carrying just the spec, prints the URL, and ends the flow - no plan, no loop, no handoff brief. For a coordinated spec, it first pushes every companion branch to origin, then opens one home draft PR; it creates no companion PRs. A laterbrainstorming #Nreconstructs the recorded companions from their origin branches before re-presenting the implementation gate; the publication and re-gate owner defines all-member preflight, recovery, and cleanup. The branch stays; a gauntlet-owned worktree is removed, a host-owned checkout is reported and left. Option 6 is withheld on a PR subject (Withheld: draft PR - #N already exists) and when the branch's diff against the default branch is not spec-only. A laterbrainstorming #Non that PR classifies it from the diff alone: one added spec carrying the marker plus banner-only predecessor edits re-presents the gate with 1/2/4/5 (3 only when the spec commit carries a council audit) and skips gather, questionary, council, and scout; a spec-only diff without the marker printsspec-only PR without the gate marker - running lint and counciland takes the normal brainstorm path with the carried spec as the draft; any other diff takes the rework path. Approval at that re-gate writes**Engine:**,**Amend-grant:**, and**PR:** <owner/repo#N>as a new commit on the PR branch and chains into planning or the loop as usual. Before approval, PR rework's sole write/run exception outside the spec directories permits only the base sync (rebase or merge), each member replay or merge, their conflict helpers' edits to the conflicted files, and their scoped conflict tests; other subjects have no implementation code yet.By default,
writing-plansdecomposes the approved spec into atomic, independently-verifiable tasks, grouped into parallel waves where they don't touch the same files. Experimental approval options 4/5 instead selectloop-implementation: the plan phase is skipped and a stamped acceptance-criteria ledger replaces the task plan. Option 4 retains amendment review; option 5 grants auto-apply amends, with redraws still stopping. See Loop engine operations.subagent-driven-developmentexecutes the plan in waves, with task implementers followed by one integratedwave-reviewerafter the scoped test gate passes. The reviewer checks anchored spec clauses and code quality together; repairs stay on the current tree and pass the same gate before re-review. TDD-locked: red, green, refactor. Independent implementation, review, and council batches remain parallel, but their dispatches are foreground: the orchestrator waits for terminal results before accepting work or advancing a phase. The loop alternative to step 3 runs one freshloop-implementerper seed or row iteration, without implement-phase reviewers. Each row starts with the shared allowance (default 4); approval replies such as4; allowance 6override it for one run. Under either loop approval option, the last allowed attempt escalates once per row onescalationLoop.implModel(the main-loop model when unset); one exit-verification repair per flow uses the same model. Exhaustion and stagnation stop for a human decision:retry <n> | <hint>adds one attempt to that row, whilerows +Nraises every row's allowance. Attempts never reset and there is no total iteration cap. Ledger refresh completes implement when every row is closed; verify step 1 runs the gate set: deduplicated (owning checkout, command) pairs from done rows' recorded checks, with ownership from the ledger. Gate output goes to logs; the driver keeps exit codes and paths, not test output. CI on push owns the full run.verify: the parent first runs the plan's full verification command set for waves, or the ledger gate set for loop; only a passing result permits whole-diff code review, then the conformance gate. A review fix invalidates that result, so the parent reruns the same set before the next review or conformance gate. Loop conformance repairs and finish also use the gate set, never the ledger's full
verification:command. When the overrides file declares a happy path for the touched paths (see Project-specific overrides), the parent runs it once here, between code review and the conformance gate, and the reviewer reads its transcript as runtime evidence - a hang or a failed request shows up in the audit with the transcript quoted - as a gap when an origin clause ties to it, otherwise as ahappy-path: failed - unattributableline - never as a silent green. The conformance subagent reads the finished code and docs against your original words from step 1, not the plan, and reports per-requirement: delivered, partial, missing, drifted, or unauthorized. Unauthorized rows - shipped surface no human input asked for, whether it crept in or was laundered through the spec - follow their recommendation like every other row: a contained removal auto-runs, anything another requirement leans on is deferred with a plain-language "I'd cut it / I'd keep it" recommendation. Inside a brainstorming-entered flow this gate is machine-blocked from being skipped. Compatible executable recommendations auto-run through an isolated fix-and-re-audit loop with no prompt; anything still open surfaces as a numbered decision brief - one item per decision, the problem in plain words first, lettered options each with a one-line consequence, andRecommended: <letter> - <reason>orNo recommendation - pick one. Reply with one line per item (1. B), or bare1to take every recommendation (no-recommendation items are re-asked by number); a currentCONFORMS/ no-concerns result goes straight to the branch options with no extra conformance sign-off.finishing-a-development-branch: PR, draft PR, squash, keep, or discard; PR rework's row 1 offers a lease push of the rebased home branch to the existing PR (Base:records inmerge:form push non-force). A spec whose header carries**PR:**(approved at a spec-PR re-gate) and no## Rework recordreplaces the two create rows withPush to PR #N and mark it ready for reviewandPush to PR #N, keep it a draft(Push to PR #N (already ready for review)when the PR is already ready): both push without force after strip-and-seal, the first then runsgh pr ready, neither rewrites the PR body, and both are withheld when origin's branch head is no longer an ancestor of local HEAD. For coordinated specs, these header-linked rows 1/2 deliver companions in recorded order before one home seal carrying every companion PR URL, then push home and apply its readiness choice. Row 1 makes companion drafts ready too; row 2 creates drafts but never converts an already-ready PR back to draft. Companion URLs appear in the shipped summary, companions first and home last, not in the unchanged home PR body; keep that summary for cross-repo review because successful home delivery removes receipts. A spec still carrying**Engine:** deferredstops finishing (andgauntlet-resume) withspec approved for handoff only - run brainstorming #Nbefore any phase change, verification, or push. The PR-rework push appends a## Reworkblock naming absorbed PRs while retaining the original description bytes; the header-linked**PR:**push leaves the body untouched. Only after a successful rework push and home-description edit does one gated confirmation show the exact close comments and eligible member targets, linking home; declining or any other finish option leaves members open. Closing never deletes member branches, and finish posts no review-thread replies. ItsBefore:handle includes the full portable pre-rework SHA and the localrefs/gauntlet/pre-rework/pr-<N>ref in the rework checkout. The finishing owner defines the landing and body-update contract. Once a PR exists, run/skill:gatekeep-pr <pr>to verify it before merging - it judges the diff against the spec at the PR's head (the acceptance-criteria dispositions and Design you approved; the PR description when no spec applies) - rows the spec defers or deviates are settled, every other row needs its mechanism (code, tests, docs) - and against the rubric; whatever can be seen only after merge is left to step 6. Human gate 2 - the only other decision you make.(Optional) Once the merge lands,
/skill:check-delivery <ref>can prove delivery - default-branch landing, delivery target, per-AC evidence - before the tracker status advances. Explicit ask only, no auto-chain: deploys commonly lag merges by minutes to hours, so an auto-run would routinely check too early.
Only the machine-owned plan -> implement and verify -> ship handoffs receive a branch-local one-shot nudge after an unexpected settled stop; it is fire-and-forget, does not bypass either human gate, and older Pi hosts without agent_settled retain existing behavior.
flowchart LR
T["shape-ticket<br/>(optional)"]
R([explicit opt-in]) --> B[brainstorm<br/>+ spec]
T -.-> R
B --> G1{{human gate 1:<br/>approve spec}}
G1 --> P[plan]
G1 -.option 6.-> H[draft spec PR]
H -.brainstorming re-entry.-> G1
P --> I[implement<br/>waves + reviews]
I --> V[verify]
V --> M{{machine gate:<br/>conformance vs<br/>original words}}
M --> S[ship]
S --> G2{{human gate 2:<br/>merge / PR / discard}}
G2 --> D([done])
D -.optional.-> CD["/skill:check-delivery"]
In create mode, shape-ticket runs one bounded overlap check after clarification, across active and finished work: at most 120 seconds, 6 search requests, and 5 detailed candidates. It recommends useful enrichment of the same concern, a justified new ticket, or no write; a finished ticket with compatible additions favors an evidence comment or no write, not a duplicate. Compatible requirements may extend a documented unstarted ticket's body; started, finished, or unknown workflows keep their bodies protected. The existing confirmation menu shows mutually exclusive enrichment, create-anyway, and no-write choices with exact payloads and coverage limits. Selecting an unchanged displayed write option approves only that changeset; advice alone never writes or changes status.
Use /skill:shape-ticket --skip-overlap <ask> to bypass discovery explicitly. Repair mode never discovers candidates. Bypass still retains source reads, known conflicts, integrity checks, roast, approval, and source revalidation. Incomplete search coverage is disclosed, not treated as proof of no overlap; independent sessions can still race, so this is not a uniqueness guarantee.
Between gate 1 and gate 2, both engines take named authorized recommendations under the spec's amend grant and run one bounded escalated execution round before eligible stops; budgets, cap, stagnation, boundary failures and redraws still stop, and budget-only grants supply no amend permission. Planning takes concrete baseline narrow or amend recommendations under that permission; fix-first enters ticket shaping's own gate. An implementer-evidenced text correction to a drafted AC is an amendment, not a redraw; ticket rows, row add/remove and problem or component boundary changes still require redraw approval. See execution continuation. Once gate 1 picks an engine, task breakdown, implementation and reviews proceed within those limits; option 6 parks the approved spec in a draft PR and planning starts only when someone runs brainstorming #N on it and approves at the re-gate. Changing an approved spec later goes through brainstorming's Amending an approved spec: a fresh-context reviewer clears evidence-backed factual corrections on its own, escalations reach you as one readable batch, and only a redraw is a full stop - not a third numbered gate. That's the mechanism. What follows is the machinery behind it.
Multi-repo runs
A run has one home repository and one leg per selected repository. The home's ## shape-ticket - sibling: declarations define eligible companions, not automatic membership: the ask must select a declared companion by repo identifier, the declared clone URL's NAME, or the URL itself, or the ticket must select it through a matching repo-group heading. Unselected siblings are not resolved. Members are ordered home first, then selected siblings in declaration order. Every member gets its own worktree with the same full branch and derived worktree name.
The approved home spec records ## Legs, including each leg's scope, rules and resolved contract:. Each companion commits a leg file with the same filename in its own spec directory, carrying the home pointer, Problem, binding decisions and its own leg block. Plan and ledger stay home-owned; task Leg: selects the checkout for implementation and review. Committed artifacts use portable repo identifiers, not machine-local paths. See the membership and artifact contract.
Home overrides and settings govern flow policy. Each leg's own overrides and settings govern checkout operations, directories and verification; absent configuration uses defaults. Recorded contract: lines are authoritative for every spec with ## Legs, including one-member runs: amend the home block and affected companion file before using a changed contract. Finish does not replace them by rereading overrides. Legacy specs without ## Legs are home-only and retain the finish-time reread.
Option 6's draft-PR handle is one home draft PR plus companion branches on origin, with no brief, companion PRs or receipts. brainstorming #N preflights every recorded companion before provisioning them from origin and re-gating under the publication and re-gate contract. This extends the spec-only draft-PR design without superseding it; PR lists still take the rework path. The separate gauntlet-handoff / gauntlet-resume route carries every member in the brief's legs: block. Resume starts only from the home primary, validates companion repository, branch and home pointer, and announces per-leg HEAD and dirty drift. On that route a missing companion worktree requires a live-validated completion receipt; draft-PR re-entry instead uses the published origin branch. The brief contract owns the brief grammar and admission rules.
One finish choice spans all legs. PR, draft PR and squash deliver companions in declaration order, then seal and deliver home; keep preserves all legs, and discard lists all legs before one confirmation. Verification and conformance run per leg; home's passing tests do not credit companions. Delivery failure stops without rollback and reports shipped and unshipped legs. A retry from the brief validates home-owned receipts and skips only proven deliveries; stale PR heads are updated, and failed post-squash verification reruns without another squash. See the delivery and recovery contract.
Architecture
A gatekeep-pr run after your newest submitted, non-dismissed review uses that review's commit as its baseline when it is an ancestor of the assessed head. The reviewer checks your posted items and only the intervening code delta; the report shows Prior review: <k> of <n> items addressed. Contract checks still judge the whole head. See the review task.
gatekeep-pr selects one course per run: assess posts open blockers as one review (request-changes on someone else's PR, comment on your own), posts nothing with zero blockers, and performs no repair or sync; deliver repairs blockers, syncs, pushes, watches CI, and re-reviews until readiness, an obstacle, or a cap exit. deliver with nits stores deliver-nits and includes current and later nits. A ready first report skips the course pick and renders the final menu directly. Delivery rebases your own non-bot branch with --force-with-lease unless its history contains merge commits; someone else's, bot-authored, and merge-containing heads merge base instead. Final merge and approve remain separate picks; approval is offered only on someone else's non-draft PR with zero blockers. See the course loop and menu templates. In pi, /skill:gatekeep-pr 12 15 18 [--rebase [base]] gates a set of PR numbers or same-repository URLs, with one fresh pr-gatekeeper child and one worktree per PR. The parent shows a summary and unchanged per-PR menus in input order, queues every pick until the last menu, then executes the queued work in parallel. The set must fit pi-cohort's parallel.maxTasks (default 8); it is never chunked. With --rebase, the parent asks once per set for eligible other-author or unreadable-author heads, excluding no-op heads and heads with merge commits. Multi-PR mode rejects positional issue references and is pi-only. An explicit no-argument invocation on either harness discovers your open PRs in origin, authored by you or directly awaiting your review (not team requests), excludes drafts and the APPROVED and CHANGES_REQUESTED states, and sorts by additions plus deletions, then PR number, ascending. One match gates directly on the single-PR path; multiple matches enter pi's batch path, while Claude Code stops with the sorted discovered, smallest first: list. Every report shows the refreshed viewer Role: under Delivers, not in the batch summary row. See the parent-child contract.
The course, target/scope baseline, repair and sync usage, and poll deadline live in one OS temporary continuation record, whose path appears in the tracker or checklist and show evidence. Gatekeep initializes independent repair-round and sync budgets to 2 x closureReview.maxFixRounds (default 5, no-tool fallback 2 x 5). Only source-changing repair waves spend rounds; conflict-only syncs spend the separate sync budget, and description-only work, watches, and re-reviews spend neither. Obstacle deliver extends each cap by 2 x the resolved value without resetting usage; a timeout continuation instead opens one more watch window without extending caps. Only the gate's own push automatically renews the CI window (timeout minutes, default 15). The verify-phase runtime guard still uses 1 x the resolved value and can block a gatekeep dispatch earlier.
Non-final stop removes an eligible tracked-clean, non-primary worktree, created or reused, with no unpushed commits and a matching configured home; otherwise it keeps the tree and reports why. It never deletes the branch, pulls base, or runs cleanup overrides. See the stop lifecycle. Missing or invalid state stops course work without resetting budgets. Terminal exit deletes the record; OS cleanup can remove it earlier, and a new session never discovers or resumes authority automatically. This is a skill protocol, not hard runtime enforcement.
pi-gauntlet ships three kinds of pieces, layered on top of pi-cohort's dispatch:
- 21 skills - the workflow logic. Sixteen activate automatically when pi sees the matching kind of task, and the workflow skills chain through their gates:
shape-ticket(creates one tracker issue or repairs a comma/whitespace list of refs against a Context/Problem/Idea/Acceptance-Criteria template, with a grounded repo audit, an AC integrity check, a cheap council roast, and sequential per-ticket exact-diff write confirmations; model-invocable so other skills and commands can route "file a ticket" to it, the gate still needs your yes),gatekeep-pr(model-invocable on an explicit ask that names the PR and the verb; the gates still need your selection - is consent-gated pre-merge verification of a PR against the scope contract at its head - the approved spec's acceptance-criteria dispositions and Design when the PR carries one, else the PR's stated intent; the ticket is cross-checked, never judged here (check-deliveryowns it) - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; a pending commit status that GitHub does not report as blocking the gating actor (mergeStateStatusnotBLOCKED) is not waited for - external-CI commit statuses included - while a running Actions check, an unknown merge state, and every other merge precondition still withhold; the project's verification command runs only as fallback), a rubric-based review, a compact bottom-up report (what the PR delivers, including rows deferred or deviating per spec, PR comments, nits, blockers, then amergeable/fixableverdict) and course and terminal menus whose rows derive from the actor's permissions on the PR; nothing mutates (repairs, pushes, reviews, merges, tracker comments) until you pick a course or terminal row, except the opt-in--rebase [base]sync that rebases, reviews, and lease-pushes the head before verification, or holds the rebased head locally when a conflict stop's scoped tests fail, so a selected delivery course resolves it before the lease push; after your own merge two opt-in rows post theAC coverageblock to the ticket or the PR; own-merge, approved, and closed-PR menus offer a recommendedcleanuprow that tears down the gate's worktree and branch and runs the overrides file's## cleanupsteps - run it with/skill:gatekeep-pr [<pr>] [--rebase [base]](no argument: your open PRs)),check-delivery(model-invocable on an explicit ask that names the ticket and the verb; the gates still need your selection - is a post-merge detective control: proves an issue actually shipped (default-branch landing, delivery target, per-AC evidence) before its tracker status advances; it never writes a terminal status - run it with/skill:check-delivery <ref>),writing-plans,roasting-the-spec,test-driven-development,subagent-driven-development,loop-implementation(the plan-free implement driver that iterates a freshloop-implementerover the spec's acceptance-criteria ledger when approval picks the loop engine),dispatching-parallel-agents,verification-before-completion,requesting-code-review,receiving-code-review,using-git-worktrees,finishing-a-development-branch,forge-skill,linear(reads/searches/comments on/manages Linear tickets via thelinearisCLI; owns all linearis mechanics and the## Issue trackeroverrides schema; tracker-facing skills route to it). Five more require explicit entry (disable-model-invocation: true):brainstormingstarts the gated workflow on explicit consent - use/skill:brainstormingfor reliable discovery, or opt in through reachable explicit prose or a human-selected handoff; after spec approval, downstream planning and implementation still chain automatically.chase-bugis human-only bug triage: read-only root-cause discovery to an evidenced verdict menu (real bug -> ticket/brainstorm/hotfix/respond; five negative verdicts), then a gated response to the reporter for addressable origins (GitHub issue / tracker ticket) and a rendered verdict summary otherwise - it never fixes during triage; the hotfix row hands off toskills/chase-bug/hotfix.mdafter the menu - run it with/skill:chase-bug.gauntlet-performancereads the committed run telemetry (current repo by default,--dir <path>adds others) through the parse-onlygauntlet-performanceCLI and answers with one example-led recommendation, 3-5 cornerstone numbers, a council assessment when available, and a menu of at most three actions (render a report file, open the recommendation as a ticket viashape-ticket, drill into one run); it writes nothing unless you pick render - run it with/skill:gauntlet-performance [--dir <path>]... [--since <version>].gauntlet-handoffends a session whose flow a fresh session will continue: it invokes pi-cohort'shandoffskill (--out <path>or--key <name>, default key = the run worktree's branch with/flattened to-, default file<tmpdir>/pi-handoff/<key>.md), then appends the gauntlet process-state section (phase/plan tracker status) per the shared contractskills/gauntlet-resume/reference/brief-contract.md- run it with/skill:gauntlet-handoff [--out <path> | --key <name>].gauntlet-resumeis the only way back into an interrupted flow from a fresh session: it takes agauntlet-handoffbrief (a file path, pasted text, or - with no arguments - a pick from the briefs under<tmpdir>/pi-handoff/), a bare worktree that already holds a spec, or a spec tracked on main under a configured spec dir (a spec seed: it creates or reuses the worktree throughusing-git-worktreesand pins the spec), restores phase/plan tracker state through the legal arming sequence (start brainstorm,skipwithresume:reasons,plan_checkbefore implement-or-later), and never infers approval from artifacts - run it with/skill:gauntlet-resume [<brief-file> | <spec>.md | <worktree-name-or-path>]. - 10 subagent personas - the specialized child agents the skills dispatch via pi-cohort:
implementer,loop-implementer,wave-reviewer,conformance-reviewer,spec-summarizer,plan-writer,spec-council-member,spec-council-synthesizer,spec-council-applier,pr-gatekeeper. See doc/personas.md for what each one does and why its permissions are scoped the way they are. - 4 runtime extensions - the enforcement layer.
plan-trackerandphase-trackerare tools skills call to track progress (with a TUI widget);verify-before-shipis a hook that warns if you push or open a PR without a passing test run since your last edit (expected when a loop gate set does not match its patterns; the scopedVerification:line answers it, not a full local run); a phase-tracker flow guard reminds on implement-phase commits missing spec/code review. Both engines use the tracker: waves manages plan tasks, while loop callsplan_tracker refreshto project ledger rows and preserve conformance tasks. Loop implement completes when every row is closed, then verify step 1 runs the ledger's gate set in the owning checkouts. In a brainstorming-entered flow, phase-tracker rejectsimplementorverifycompletion while tracker tasks remain pending or in progress; see its configuration reference. phase-tracker also registersplan_check, which verifies a plan against its spec and against the grammar in skills/writing-plans/reference/plan-contract.md, including that each task'sTests:commands are selective and never the full suite, and that every test command carries a passing base-commit result; a pass stamps the plan and spec content hashes for implementation and returns a bounded task manifest; see the manifest contract and size limit.telemetryrecords one YAML record per gauntlet run (phase timing, models, personas, gate/fix rounds, diff at ship) that ships in the squash beside the spec - it is written only inside a brainstorming-entered flow, kept out of history untilfinishing-a-development-branchseals it once withgauntlet-telemetry-seal(atelemetry:commit under git; the working-copy snapshot in a plain jj workspace) - and blocks a brainstormwriteinto an already-shipped spec; see its configuration reference. See doc/configuration.md for the settings each one reads.
pi-gauntlet is opinionated: it recommends this pipeline for non-trivial changes, but starts brainstorming only after explicit user consent. Enforcement is opt-in by entry, not ambient: once brainstorming starts a flow, the phase-tracker extension mechanically blocks a phase from closing before its gate runs, and warns once if the main loop writes code during implement (subagents own implement-phase edits). A change made without entering the flow (a typo, a formatting run, a dependency bump - see "When to use / when NOT to use") is not gated; the discipline of routing real work through the pipeline is a convention the tooling supports, not a trap it springs on every edit.
Worktree contract. pi runs in the primary checkout; the work happens in .worktrees/<branch>. Skills never cd there - the worktree path is a value from the using-git-worktrees report (or the handoff brief on gauntlet-resume), carried as dispatch cwd: "<path>", as git -C <path>, or as (cd "<path>" && <cmd>) for other cwd-bound commands; the runtime extensions derive the checkout from the artifact path they act on. Requires git >= 2.31; a plain (non-colocated) jj workspace has no .git, so the resolver falls back to jj root there, reading primary-vs-workspace from .jj/repo (a directory in the primary checkout, a pointer file in added workspaces).
Handoff and resume
/skill:gauntlet-handoff and /skill:gauntlet-resume are a pair: cohort's handoff skill writes the six flow-agnostic headings, gauntlet-handoff appends ## Process state, and gauntlet-resume reads the whole brief back. Both gauntlet skills read one grammar file, skills/gauntlet-resume/reference/brief-contract.md; the repo validator (scripts/ci.mjs) fails if a grammar line appears anywhere else under skills/. Requires pi-cohort >= 7.1.0 (the handoff skill, pi-cohort #18); on an older pi-cohort, gauntlet-handoff stops before writing. A resume also reads the spec's **Amend-grant:** header line and prints Standing grant active: <sentence> or No standing grant. on the line after its closing line; the brief itself carries no grant. On a plan_check failure, resume repairs plan citation drift itself (moved anchors, changed literals, file rows that completed tasks deleted) and stops only when a task must change.
Smoke walkthrough (release-gated)
Run by a human against pi-cohort >= 7.1.0, before a pi-gauntlet release claims the pair works; record the outcome in the release commit body.
- Implement phase with tasks
complete/in_progress/pendingin a.worktrees/<branch>flow, session in the primary checkout:/skill:gauntlet-handoffwrites<tmpdir>/pi-handoff/<branch>.mdwith the six core headings then## Process statelast; a fresh session running/skill:gauntlet-resume <path>restores implement with the three statuses and endsGate history not restored; re-validating <task> before any stage advance. - Plan phase,
No plan active.: the brief keeps that line andActive task: none; resume restores phase-only with noplan_tracker init. - Hotfix context with non-pending trackers: the brief ends at
## Skills loaded; resume takes thechase-bugroute. - Fresh session, zero arguments: the listing shows the briefs from 1-3 and a pick restores;
/skill:gauntlet-resume /nonexistent.mdstops naming that path without listing anything. - Branch
hotfix/x: the default file ispi-handoff/hotfix-x.mdand appears in the zero-argument listing. - Primary session, idle trackers, spec tracked on main:
/skill:gauntlet-resume doc/specs/<x>.mdcreates the worktree and asks the approval question; approval leavesphase_trackerat plan in_progress with brainstorm⊘ (resume: ...). - Fresh idle session, same seed: the registered worktree is reused (no creation) and the question repeats. Run once on a consumer whose
## using-git-worktreesoverride lays worktrees out as sibling dirs, once on.worktrees/. - After writing-plans commits the plan beside the seeded spec:
/skill:gauntlet-handoffthen a fresh/skill:gauntlet-resume <brief>restores plan phase; a fresh/skill:gauntlet-resume <worktree>reaches "Spec with plan" with task evidence from the plan commit. - Spec approved with
2, then/skill:gauntlet-handoffand a fresh/skill:gauntlet-resume <brief>: the closing line is followed byStanding grant active: <sentence>and the next amend batch applies without a menu. A spec approved with1printsNo standing grant.; a spec with two**Amend-grant:**lines stops before any tracker call, naming both lines.
Key concepts
| Term | Meaning |
|---|---|
| Gate | A machine-enforced checkpoint between phases (e.g. within a brainstorming-entered flow, complete verify is blocked until conformance review has run). Not a suggestion. |
| Spec council | Multi-model critique of the spec before you see it (roasting-the-spec); members and chair return saved-file references, and a fresh applier inherits the main loop's model and thinking unless overridden, edits only the spec, and returns the audit. The main loop checks structure without ingesting member/chair findings, re-reads the spec, and hands it to the unchanged user gate to ratify or revert. Members flag unrelated extras or sufficient in-scope simplifications (over-spec); every member closes with a lean: line - "nothing to cut" is a first-class answer - and the chair tallies them (lean: <k> of <n> members found nothing to cut). Falls back to a single-model critique if no council is configured. |
| Conformance gate | The closing check: does the delivered code + docs match your original prompt, not the derived plan? Compatible executable recommendations auto-fix first; anything still open renders as a numbered decision brief - one item per decision, the problem in plain words first, lettered options each with a one-line consequence, and Recommended: <letter> - <reason> or No recommendation - pick one. Reply with one line per item (1. B), or bare 1 to take every recommendation (no-recommendation items are re-asked by number); a current CONFORMS / no-concerns handoff goes straight to branch options with no extra sign-off. |
| Wave | A batch of N >= 1 plan tasks with disjoint files, run through the one wave loop; N > 1 dispatches concurrently |
| Overrides file | .pi/gauntlet-overrides.md - where you put project-specific detail the generic skills don't know (CI command, worktree wrapper, routing rules). |
When to use / when NOT to use
Use it for any change with more than one moving part: a feature, a refactor across files, anything where "what did we actually agree to build" matters by the time it's done. Start with /skill:brainstorming; a request to implement the change alone does not opt you in.
Don't use it for a one-line fix, a typo, or a throwaway spike you're going to discard. The gates have real overhead - a spec, a plan, a conformance check - and that overhead isn't worth paying for a change trivial enough to just make. Between that carve-out and the full pipeline sits one middle tier: chase-bug's hotfix row - a small, evidenced, urgent fix landed as an unpushed squash, entered only through the triage verdict menu.
Requirements
- pi-coding-agent ≥ 0.85.1 - tested minimum for sequential
phase_trackertool execution, which persists a tracker update before a later tool call in the same model message. - pi-cohort >= 7.6.6 - required peer package, including binary-safe worktree patches; it also lets a persona with
subagentintools:start with inherited extensions (pi-cohort #26), which multi-PRgatekeep-prneeds. Skills that dispatch agents (requesting-code-review,subagent-driven-development,dispatching-parallel-agents,writing-plans,forge-skill,shape-ticket,roasting-the-spec) callsubagent({}), which pi-cohort provides. pi-gauntlet does not vendor the dispatch tool; without pi-cohort those skills have nothing to call. Gauntlet execution dispatches explicitly useasync: false; do not enable pi-cohort's incompatibleforceTopLevelAsyncsetting. See pi-cohort's dispatch configuration for that setting's owner and semantics. A wave of N >= 1 tasks dispatches its implementers and first spec reviews as one chain call.subagent-driven-developmentstops before dispatch on unsupported installs; there is no older-runtime fallback.
Both packages must be listed in your .pi/settings.json#packages array (pi adds them automatically when you pi install). pi-gauntlet and pi-cohort are versioned independently but release together whenever dispatch semantics change - pin compatible versions of both. At each pi-gauntlet release, set the pi-cohort peer minimum and README floor together to the newest released pi-cohort version; /skill:release checks the registry before proceeding.
Install
Project scope (recommended - committable via the repo's .pi/settings.json; -l writes to project settings):
pi install -l npm:pi-cohort
pi install -l npm:pi-gauntlet
User scope (all repos under your pi profile; the default target is user settings):
pi install npm:pi-cohort
pi install npm:pi-gauntlet
Pin an exact release with npm:pi-gauntlet@X.Y.Z. See doc/install-internals.md for what the postinstall step actually does (symlink vs copy, PI_GAUNTLET_AGENT_DIR, upgrading from the pre-rename package).
Spec search index
gauntlet-spec-index provides lexical search over two corpora in one per-worktree cache. From a repository worktree, run node <pi-gauntlet-package>/bin/gauntlet-spec-index.mjs --query "<text>" [--corpus specs|docs] [--limit N] [--exclude <repo-relative path>]...; it requires Node >=24.15.0 and refreshes its FTS5 index on every query. --corpus specs (the default) searches <spec dir>/*.md for each resolved flowGuards.specDirs entry (default doc/specs and docs/specs) at the repository root and one service level down and prints tab-separated score, path, service, title, status, shipped_at, state, files, and snippet columns. --corpus docs searches project documentation and prints score, path, title, and snippet; the snippet is the matched ##/### heading line when one holds a query term, else a body fragment. Docs candidates are the tracked and untracked, non-gitignored *.md files (git ls-files -co --exclude-standard, so nested repositories and submodules are not indexed) matching an include list - default **/doc/**/*.md, **/docs/**/*.md, README.md, AGENTS.md, where a slash-free entry also matches one service level down - minus the resolved spec and plan dirs (matched as literal path components), **/node_modules/**, .pi/gauntlet/**, .worktrees/**, symlinks, and files whose first line is the context-draft marker; ** never matches a dot directory, so .pi/*.md or .github/*.md is indexed only through an explicit include. A project replaces the include list with - docs: <glob> bullets under a ## Spec index heading in its gauntlet overrides file (see Project-specific overrides); the exclusions are not configurable through the overrides file; the spec and plan dir exclusions follow flowGuards.specDirs. Both corpora pass the same confidence rule before --limit applies: a query term is evidence when it occurs in fewer than half the rows of the queried table (stem variants of one word count once); query tokens split on word boundaries, so gauntlet-spec-index searches as three words; a row is returned only when it matches at least two distinct evidence terms in the corpus's strong fields - title or goal for specs, title or headings for docs - and rows scoring below half the best live row's score are dropped (every docs row is live). A query with no real match therefore prints the header only and exits 0 - and when the queried corpus has fewer than 10 documents, also writes one stderr line naming the corpus and its size (gauntlet-spec-index: docs corpus has 5 documents - too small for the confidence rule; no rows returned), so a small corpus and a genuine miss stay distinguishable; a corpus of two or fewer files never returns rows. --exclude (repeatable) removes a path before the rule runs, so the spec under review never sets the bar. state is superseded when a > **Superseded by:** ... - fully banner sits in the block directly under the title and live otherwise; named-section banners and consumer-defined banner syntaxes both read as live. Live rows sort before superseded rows, then by score. The files column is a ;-separated list of repo-relative paths the spec's shipped change modified and that still exist in the repository, the literal missing when the spec's telemetry record has no derived.modified_files list, or blank when there is no readable record or no recorded path remains. The cache lives at .pi/gauntlet/index.sqlite, and its first creation adds /.pi/gauntlet/index.sqlite* to Git's info/exclude so the database and SQLite sidecars stay out of git status. /skill:brainstorming queries the specs corpus twice - the scout at gather time from the request, and the main loop at spec-writing from the finished spec's title, goal, and headings, surfacing new live candidates at the review gate - and the scout queries the docs corpus once to render Docs touched: lines that round 2 weighs as documentation-impact candidates.
Performance digest
gauntlet-performance digests telemetry records without judging them: node <pi-gauntlet-package>/bin/gauntlet-performance.mjs [--dir <repo root or telemetry dir>]... [--since <version>] [--json] prints a corpus: line, one row per run (run_id, repo, spec, version, status - shipped* when the record has no ship phase - wall, per-phase minutes, tokens, cost, models, dispatches, disp/task, coord, fix_round_grants, reopens, conformance loops, reviewer findings, council dispatches, and big - the count of parent calls whose cache write exceeded 50k tokens with their share of the run's parent cache-write tokens (- for records without parent_calls)), a by version block of p50/max over shipped, non-truncated runs, a council block grouped by member roster, and skipped: lines for files it could not use. Each council table shows member total, unique, applied, uniq_appl, deferred, rejected blocker/major/minor counts and uniq_appl_nonminor/run; chair: shows runs, average clusters and members reported, and retried runs. Roster flags (JSON flags[].rule: low_unique_applied - fewer than 0.2 unique-and-applied blocker/major findings per run; high_rejection - over 50% rejected while another member is below 25%) require five runs and print as flag: <member> - <detail>. Smaller groups print not enough runs to assess (N of 5); absent council data prints no council data in selected records. JSON includes council: [{ roster, runs, members, chairs, flags }]. Default corpus is the current repo's telemetry dir; each --dir adds a repo root (its own telemetry.dir setting is honoured) or a bare telemetry dir. --since compares versions numerically. Exit 0 always except usage errors. /skill:gauntlet-performance is the reasoning layer on top.
disp/task counts recorded implement-phase dispatch-result events divided by plan.tasks - plan.skipped; missing plan data, zero denominator or dropped events print n/a. coord is yes only for a non-empty sealed legs: list. Telemetry also records verification_runs: parent bash matcher hits from implement start through seal, not child checks or an assertion that verification passed. See the telemetry reference for the counter window and name-based reopen rules.
For local development against a checkout instead of npm:
git clone git@github.com:jjuraszek/pi-gauntlet.git ~/repos/pi-gauntlet
cd ~/repos/pi-gauntlet && npm install # installs the yaml dependency and links the agents
cd ~/path/to/your/repo
pi install -l ~/repos/pi-gauntlet
Evals
Run node eval/run.mjs <target> to check a wording change on fixed inputs: two frozen replay models produce before/after outputs, and one frozen judge checks must-hold facts against a committed intent.md. The eval process explains the single driver, target and sample layout, newest-only primary replies with a bounded judgment-refresh audit, and anonymization rule. Model calls run manually, never in CI; CI runs deterministic library tests, structural lint, and hygiene checks. eval/ is checkout-only and excluded from the npm tarball.
Use from Claude Code
Six skills are exposed to Claude Code via the plugin marketplace at
.claude-plugin/marketplace.json: shape-ticket, gatekeep-pr,
check-delivery, chase-bug, linear, and forge-skill. They are
harness-portable by design - every pi-specific mechanic they touch
(plan_tracker, gauntlet_setting, subagent()) carries an inline fallback,
so they run on Claude Code's native facilities; gatekeep-pr is the exception -
it dispatches its helpers through the harness's subagent tool (Claude Code's
Agent tool) with the duty text inlined in the prompt and has no inline path.
On both harnesses, gatekeep-pr uses the same temporary continuation record
and action-scoped consent protocol; Claude Code uses native file operations
and a checklist when pi's tracker is absent. Native tool permissions still apply.
forge-skill is the authoring skill for skills, personas, prompt templates,
slash commands, and files the repo routes to it under
gauntlet's conventions (imperative voice, minimal diff, low conditionality,
extraction over 500 lines); Claude Code namespaces plugin skills, so it lists
as /gauntlet:forge-skill and coexists with the skill-authoring skill of
obra/superpowers - invoke the one
whose conventions the repo follows. This is the supported set. Not exposed,
in two classes: (a) genuinely pi-bound surface - the full gated pipeline
(brainstorming -> writing-plans -> subagent-driven-development -> verify ->
finish), the spec council, the conformance gate, flow guards,
verify-before-ship, and all piGauntlet.* settings, which depend on pi
extensions; (b) runtime-neutral skills (e.g. receiving-code-review,
using-git-worktrees) that are simply out of scope for this channel, not
incompatible - re-adding one is a one-line allowlist append. For
Claude-Code-native equivalents of the methodology skills, see
obra/superpowers.
Setup
Add to your repo's .claude/settings.json:
{
"extraKnownMarketplaces": {
"pi-gauntlet": {
"source": { "source": "github", "repo": "jjuraszek/pi-gauntlet" }
}
},
"enabledPlugins": { "gauntlet@pi-gauntlet": true }
}
Add "ref": "vX.Y.Z" to the source object to pin a tag; the default tracks the
default branch. Claude Code merges settings entries whole (no field-level
merge), so teams layering managed settings must carry the full objects.
Registration, installation, and enablement are distinct steps in Claude Code:
extraKnownMarketplaces registers the marketplace, enabledPlugins records
enablement intent. If a fresh machine shows the plugin as known but not
installed, run /plugin install gauntlet@pi-gauntlet once. Alternative path
without touching settings.json: /plugin marketplace add jjuraszek/pi-gauntlet,
then install.
Invocation: /gauntlet:shape-ticket (or bare /shape-ticket when unambiguous).
Updates: the plugin's marketplace version equals the npm version; the release
script writes it on every release, so Claude Code sees each release as a new
plugin version. .claude-plugin/plugin.json intentionally omits version, so
it cannot override the marketplace's release version. Third-party marketplaces
do not auto-update by default - run
claude plugin update gauntlet@pi-gauntlet or turn on auto-update for the
marketplace in /plugin. claude update updates Claude Code itself, not plugins.
Project instructions: Claude Code reads CLAUDE.md, pi reads AGENTS.md - a
symlink keeps one source of truth: ln -s AGENTS.md CLAUDE.md. The gauntlet
overrides ladder (.pi/gauntlet-overrides.md -> gauntlet-overrides.md ->
doc/gauntlet-overrides.md) works unchanged on Claude Code - it is a plain
file read.
Trust gotcha: the marketplace auto-activates only after you trust that
exact repo folder in interactive Claude Code. Trusting a parent folder,
claude -p, or SDK runs in untrusted folders silently skip
extraKnownMarketplaces with no error.
Smoke test
npm test runs the pinned Claude Code development dependency against disposable
Git marketplaces and isolated homes. It checks actual session inventories for
fresh installs and cached upgrades: zero gauntlet agents, exactly the six skills,
and native helper availability. Negative controls reproduce the agent leak,
manifest conflict, and full-skill scan. No credentials or model responses are
used; artifacts remain under the printed temp directory. Run it separately with
node scripts/claude-plugin-smoke.test.mjs; CLAUDE_BIN selects another binary
for compatibility testing. This test gates local releases and CI publication.
Use the interactive smoke below to check model-driven skill behavior and helper
execution before a Claude packaging release. For a candidate that is not yet
published, add its local marketplace checkout in an isolated CLAUDE_CONFIG_DIR
instead of the GitHub source. Stop before tracker writes.
Create a scratch repo and add the marketplace config:
mkdir -p /tmp/cc-smoke/.claude && cd /tmp/cc-smoke && git init cat > .claude/settings.json <<'EOF' { "extraKnownMarketplaces": { "pi-gauntlet": { "source": { "source": "github", "repo": "jjuraszek/pi-gauntlet" } } }, "enabledPlugins": { "gauntlet@pi-gauntlet": true } } EOFStart Claude Code interactively in that directory:
claudeWhen prompted, trust the folder (this exact folder - trust is what activates the marketplace; there is no separate marketplace prompt).
Run
/pluginand confirm: marketplacepi-gauntletis listed, plugingauntletis enabled. If it shows as known but not installed, run/plugin install gauntlet@pi-gauntletand re-check.Confirm exactly six skills are registered under the plugin (via the
/plugindetails view): shape-ticket, gatekeep-pr, check-delivery, chase-bug, linear, forge-skill.Invoke
/gauntlet:shape-ticketwith a deliberately two-concern ask (e.g. "shape a ticket: CSV import for operators, plus a partner-facing status API") so the skill deterministically consults itsreference/split-axes.mdbefore proposing a split. Expected: skill activates, reads the reference file, reaches its tracker capability ladder without erroring on missing pi tools. Stop at the first human gate; write nothing to any tracker.Invoke
/gauntlet:gatekeep-prin the scratch repo. Expected with no GitHub origin: the skill stops before provisioning withdiscovery failed: origin is not a GitHub repository. With a GitHub origin and no matching PR, expectno open PRs authored by <login> or awaiting <login>'s review in <owner/repo>naming origin (@mewhen the viewer login is unreadable). Neither outcome reports missing pi tools or mutates the repo.Invoke
/gauntlet:check-deliverywith no deliverable reference. Expected: the skill activates and asks for / reports a missing deliverable set - a reported skip, not a pass, and no pi-tool error.Negative check: type
/gauntlet:brainstorming. Expected: no such skill - the allowlist excluded it.Optional validator pass:
claude plugin validate .from a checkout of pi-gauntlet (strict mode if available). Expected: no schema errors.Agent check: type
@gauntlet:in the mention typeahead (or open the plugin's details). Expected: the plugin registers no agents -"agents": []in.claude-plugin/plugin.jsonsuppresses the defaultagents/scan of the repo's pi personas. The marketplace usesstrict: trueso its skill allowlist can coexist with that manifest. Keep the skill allowlist in the marketplace: a manifestskillsfield adds to the default scan rather than restricting it. Direct--plugin-dirloading of the repository bypasses the marketplace's skill allowlist and is not the supported installation path.
Project-specific overrides
The gauntlet overrides file is the one place a repo tunes gauntlet's Markdown surface: skills read it as instructions, and gauntlet-spec-index reads ## Spec index. Discovery checks .pi/gauntlet-overrides.md, <repo root>/gauntlet-overrides.md, then <repo root>/doc/gauntlet-overrides.md; first found wins, never merged (<repo root> is git rev-parse --show-toplevel, or the current directory outside a repo). ## conventions applies to every skill without a relevance judgment; ## <skill-name> applies to that skill's steps and wins over conflicting conventions. Missing or empty conventions adds no rules; a lower-priority file cannot supplement the selected file. A repo declares procedure files for forge-skill in its AGENTS.md (Claude Code: CLAUDE.md), not here, because the overrides file is read only after a skill loads - for example Edits to projects/*/README.md follow /skill:forge-skill.
What you can tweak
| Heading / key | Read by | Default (absent) | Extends or overrides | Effect |
|---|---|---|---|---|
## conventions |
every skill | no added rules | extends | repo-wide rules applied without a relevance judgment |
## <skill-name> (e.g. ## writing-plans) |
that skill | no added rules | overrides the named step | replaces or extends the step it names |
## using-git-worktrees - home: <path pattern> |
using-git-worktrees, finishing-a-development-branch, gatekeep-pr | <primary>/.worktrees/<name> |
overrides | where worktrees live; <name> is the branch (/ -> -) or pr-<N>; the ownership test at cleanup |
## using-git-worktrees - create: <command> |
using-git-worktrees, gatekeep-pr | git worktree add at home: |
overrides | creation command run from the primary; <name>, <branch> substituted, other <token>s resolved from context or asked once |
## using-git-worktrees - destroy: <command> |
finishing-a-development-branch, gatekeep-pr | git worktree remove + prune when the path matches home: |
overrides | removal command run from the primary; a failure keeps the branch |
## cleanup items - <label>: <command or /skill:...> |
gatekeep-pr | git teardown and base sync only | extends | ordered post-gate steps with <issue>, <pr>, <merge-sha>; inherits ## PR gate timeout minutes:; missing placeholders or unlanded-change steps are skipped with a reason; /skill: items keep their own gates |
## PR gate keys (verification command, timeout minutes, requires credentials, local verification, ci checks, issue fetch, merge policy) |
gatekeep-pr | per-key defaults in the block below | overrides | the gate's verification, evidence, and merge configuration |
## comms style |
gatekeep-pr | shipped wording rules | extends | tone and format of reports, menus, and external payloads |
## verification-before-completion |
verification-before-completion; gatekeep-pr (verification command only); chase-bug (hotfix verification) | repo test entrypoint discovery | overrides | the canonical verification target |
## Spec index - docs: <glob> |
gauntlet-spec-index bin |
**/doc/**/*.md, **/docs/**/*.md, README.md, AGENTS.md |
overrides | the docs corpus include list; quotes/backticks stripped, fixed exclusions still apply, no other keys read |
## Issue tracker keys |
shape-ticket, linear, chase-bug, check-delivery, brainstorming (repo: and tracker selection) |
capability ladder / git remote |
overrides | which tracker, repo, and commands ticket work uses |
## shape-ticket - sibling: <clone url> |
shape-ticket (audit), brainstorming (membership), gauntlet-resume, finishing-a-development-branch | single-repo audit and run | extends | sibling checkouts for an already-stated second observable leg are expected beside PRIMARY (the primary checkout, not the current worktree) under the repository name; missing siblings report the path to clone to and never block, the committed URL names the sibling in report lines and supplies the clone hint while identity comparison ignores the clone scheme, and the flow never clones, fetches, or creates a sibling; paths are not accepted (see the detailed grammar); only companions explicitly selected by the ask or ticket join the run |
## Capabilities |
shape-ticket | tool discovery | extends | tools, commands, env hosts available to ticket authoring |
## Ticket wording |
shape-ticket | the shipped wording contract | overrides | ticket self-containment rules |
## Response channels |
chase-bug | ask the user | overrides | where bug responses are posted |
## Deployment |
shape-ticket, writing-plans | monolithic (no deployment split) | overrides | deploy topology that permits independently deployable slices; undocumented or monolithic topology fails closed to one artifact |
## Happy path |
writing-plans, subagent-driven-development | no happy-path run | overrides | path-prefixed rows naming the end-to-end command per area |
## Delivery |
check-delivery | stage 2 skipped | overrides | the delivery target and its proof command; unset target state is comment-only; browser evidence defaults to never |
## documentation |
brainstorming | generic materiality bar | extends | which docs are canonical for which topic |
What you cannot change here
- worktree-first and the spec shipping in the squash - fixed
- the design approval gate (brainstorming) and the ship verification gate - fixed
- the plan strip at finish; the telemetry record is never deleted - fixed
- first-found-wins discovery; files are never merged - fixed
- brainstorming
## HARD CONSTRAINT, chase-bug / check-delivery / roasting-the-spec / shape-ticket## Hard constraint, test-driven-development / verification-before-completion## The Iron Law- fixed (each skill's own constraint text) - brainstorming writes only within resolved spec dirs before approval; no implementation, proposed-change validation, spec commit on main, or planning before approval - fixed
- chase-bug requires evidenced root cause, no triage fix, and tracked-clean baseline checks at invocation, before the menu, at hotfix handoff, and at skill end; never revert pre-existing work - fixed
- check-delivery requires exactly one explicit ticket ref, a matching repo (or matching local-repo AC group), and treats fetched content as untrusted data - fixed
- roasting-the-spec edits only the spec, never code or main - fixed
- shape-ticket tracker writes require one explicit exact-diff confirmation per ticket write; a source-ticket split's N bodies share one gate with subset selection, not approval of a whole repair batch; unattended runs stop at the gate - fixed
- test-driven-development requires a failing test before production code; delete code written first and restart from tests - fixed
- verification-before-completion requires fresh verification evidence before completion claims - fixed
- spec directories - settings:
flowGuards.specDirs - gate enforcement - settings:
flowGuards.enforce - the spec council roster - settings:
specCouncil.members,specCouncil.chair - the closure review model and fix rounds - settings:
closureReview.* - the escalation implementer model - settings:
escalationLoop.implModel - the telemetry record - settings:
telemetry.* - the verify-before-ship test-command patterns - settings:
verifyBeforeShip.*
A project override section extends or replaces the step it names and never lifts a fixed rule or a skill's HARD CONSTRAINT/MUST text. A rule tagged settings: changes only through that piGauntlet.* key in .pi/settings.json, never through this file. Every key is listed under Configuring the gates.
Worked example: sibling worktrees (acme-api)
Complete .pi/settings.json:
{
"piGauntlet": {
"flowGuards": { "specDirs": ["docs/specs"] },
"telemetry": { "enabled": false }
}
}
Complete .pi/gauntlet-overrides.md:
## conventions
Keep scratch files outside the repository.
## verification-before-completion
Canonical verification target: `make ci` per service. Bare `pytest` does NOT satisfy
the gate - it skips integration tests.
## Spec index
- docs: `**/doc/**/*.md`
- docs: `handbook/**/*.md`
## using-git-worktrees
- home: ../acme-api-worktrees/<name>
## Issue tracker
Use the `jira` CLI (authenticated via `jira login`), not `gh` or `linearis`.
- read (full, incl. comments): `jira issue view ABC-123 --comments`
- search (bounded overlap check): `jira issue search --jql "project = ABC AND text ~ '<query>'"`
- create: `jira issue create --project ABC --type Task --summary "<title>" --description "<body>"`
- update: `jira issue edit ABC-123 --summary "<title>" --description "<body>"`
- post comment (approved Reporter note/evidence): `jira issue comment ABC-123 --body "<text>"`
## PR gate
- verification command: npm test
## cleanup
- close ticket: jira issue move <issue> Done --comment "Delivered in <pr>, merged <merge-sha>."
- release: /skill:release
linear setup: preferred, not required - linearis installed and authenticated
(or a Linear MCP server as a fallback when linearis is missing). Without either, the
skill reports the gap and continues; it never blocks the run. Optional - the five
## Issue tracker override keys (tracker, workspace urlKey, default team,
self, id cache); the full schema is documented once, in
skills/linear/SKILL.md - not restated here. Off switch:
set tracker: github or tracker: none in ## Issue tracker to disable Linear
entirely - no linearis probing, no prompts.
Coexistence: the five ## Issue tracker keys compose with the free-form
command-mapping convention above, they don't replace it. tracker: adds exclusive
tracker selection; free-form verb mappings keep working both without a tracker:
key (ladder rung 1, as today) and as the mechanics source when tracker: names an
unknown value.
Close verb defaults and overrides
shape-ticket resolves close: as a free-form command mapping under
## Issue tracker, not a sixth Linear configuration key. Its defaults are:
| Audit reason | GitHub reason | Linear status |
|---|---|---|
| Delivered | completed |
Done |
| Superseded, premise contradicted, not reproduced | not planned |
Canceled |
| Duplicate with a tracker-native target | duplicate |
Duplicate |
GitHub uses one close-with-evidence command:
gh issue close <n> --reason "<reason>" [--duplicate-of <ref>] --comment "<evidence>".
Linear posts evidence first with linearis issues discuss <id> --body "<evidence>",
then closes with linearis issues update <id> --status <Done|Canceled|Duplicate> [--duplicate-of <ref>]. A native duplicate target is a GitHub issue number or URL,
or a Linear identifier such as ABC-123, for the selected tracker. Only that
mapping includes --duplicate-of; a nonnative target uses not planned /
Canceled and keeps the reference in the evidence.
Add - close: <command> under ## Issue tracker to replace the entire close
sequence, including evidence posting. Override renamed Linear workflows there.
Section prose also applies: if a mapped state is reserved for humans, the menu
shows Close as <reason> - run by hand: <operations>; selecting it writes nothing.
Selecting an executable close row authorizes only its displayed operations and
evidence, not a body edit or Reporter note. This explicit close gate still applies
when ordinary status changes are described as "announced, not gated". This mapping
is separate from the ## cleanup close ticket convention in the example above.
See the tracker resolution ladder
for resolution details.
Worked example: wrapper-managed worktrees (acme-mono)
Complete .pi/settings.json:
{
"piGauntlet": {
"flowGuards": { "specDirs": ["doc/specs"] }
}
}
Complete .pi/gauntlet-overrides.md:
## using-git-worktrees
- home: ../acme-mono-<name>
- create: script/worktree create <name> <subproject> --branch <branch>
- destroy: script/worktree destroy <name>
The wrapper symlinks build/ into the tree; never replace it with a directory.
## Deployment
One deploy workflow ships the whole system at once - nothing ships independently.
## Happy path
| Row | Paths | Command | Timeout |
|---|---|---|---|
| dashboard | `dashboard/` | `script/e2e-dashboard` | 3m |
| excavation | `excavation/` | `cd excavation && make e2e` | 2m |
| cross-cutting | `dashboard/`, `excavation/`, `docker-compose.yml`, `Makefile` | `script/e2e-stack` | 5m |
## Delivery
- target state: Ready
- deploy watch: gh run watch --workflow deploy.yml (run for <sha>)
- delivery target: curl -fsS https://staging.example.com/version | grep <sha>
- timeout: 15m
- ref convention: (ref ABC-123)
- synthesized AC gaps: block
- descope edits: strikethrough
The Happy path table selects a row by repo-relative path prefix. cross-cutting takes precedence when multiple project rows match or only its own paths match. No matching row means no run. Commands run through bash -c and must be self-contained, worktree-safe, tear down on TERM/INT, and leave no residue. Timeout accepts s, m, or h (default 10m, malformed values fall back); GNU timeout or gtimeout is required, with TERM then KILL after 30 seconds. Exit 0 passes; 75 or 126 reports not run; other nonzero exits, timeout, or residue fail.
Delivery is single-ticket. timeout defaults to 10 minutes when stage 2 runs, ref convention to tracker-native forms, AC location to the ticket body, synthesized AC gaps to soft, and descope edits to unset. Malformed synthesized-gap values fall back to soft; malformed descope values remain unset, with one warning. descope edits: strikethrough needs an edit-body verb and gate approval; without the verb, the entire batched write degrades to manual output.
REVIEW.md convention
/skill:gatekeep-pr (the pre-merge gate) reads an optional root-level REVIEW.md -
discovered at the repo root only, read from the PR's base (never the PR's own head,
so a PR can't weaken the rubric that gates it). It's a plain data file, not agent
instructions: a rubric other tooling can read too. The skill is fully functional with
no REVIEW.md present - it falls back to the shipped baseline rubric
(skills/gatekeep-pr/review-baseline.md).
Overlay precedence, first match wins on any conflict:
- Repo root
REVIEW.md- always wins over everything below it. - Shipped
skills/gatekeep-pr/review-baseline.md- the generic default rubric. - Reviewer-persona defaults.
A REVIEW.md entry that names a baseline concern (e.g. a severity mapping) replaces
it; everything it doesn't name stays baseline. Severities it introduces but doesn't
map to blocking/non-blocking are treated as blocking (fail-safe), noted in the
gate's output.
REVIEW.md is a diff over the baseline, not a full rewrite. Starter template:
# REVIEW.md
Severity mapping: Critical and Moderate findings block merge;
Minor is a nit. Migration-safety findings also block merge.
Project checks (in addition to the baseline):
- Schema migrations are additive and reversible - no destructive column drops
without a documented backfill/rollback plan.
- New background jobs declare an explicit retry/backoff policy - unbounded
retries block merge.
Everything else follows the shipped baseline rubric.
Thin-wrapper contract
A consumer repo that wants its own trigger phrases for the pre-merge gate (e.g. "gate
this PR", "ready to merge?") adds a wrapper skill that carries zero data - only a
name, its trigger phrases, and an instruction to follow /skill:gatekeep-pr. All
customization lives in three places, never in the wrapper itself:
REVIEW.md- the review rubric (see above).- The gauntlet overrides file,
## PR gatesection - everything operational:
## PR gate
- verification command: <command> # required unless documented elsewhere
- timeout minutes: 15 # optional; default 15; bounds each gh pr checks --watch window
- requires credentials: false # optional; true => skill reports "not run" as missing evidence
- local verification: always # optional; default (absent) = CI-first; "always" forces the local run even when exact-head CI is green
- ci checks: <comma-separated check names> # optional; narrows which checks count as evidence; absent = all checks on the assessed head
- issue fetch: <command with <ref> placeholder> # optional, replaces gh issue view
- merge policy: squash | merge-commit | rebase # optional; default squash; chooses gh pr merge flag for final merge only, never sync strategy or approval
- The gauntlet overrides file,
## cleanupsection - the ordered post-gate steps thecleanupmenu row runs (contract under Project-specific overrides above).
An existing ## verification-before-completion overrides section is an accepted
equivalent source for the verification command only; all other PR-gate keys
still live under ## PR gate. A ## comms style section in the same overrides
file extends gatekeep-pr's wording rules - the rendered report and menu, and every
external payload (review bodies, replies, tracker comments, commit subjects) alike. Worktree placement for the gate is the ## using-git-worktrees contract above.
Anything a wrapper skill contains beyond trigger phrases is misplaced - move it to
REVIEW.md or the overrides file instead.
Configuring the gates
Settled skill-owned turns carry a machine-readable first line identifying a gate, question, or terminal outcome. Programs answering these turns use the gate inventory and reply contract; the rendered row bodies define valid replies.
Choose experimental loop options 4/5, configure the per-row allowance and worker model, and operate the planless ledger through Loop engine operations. The menu shows the resolved allowance; ; allowance N overrides it for one run. Resume preserves an existing allowance or migrates a legacy cap after pending recovery. Waves remains the default.
| Want to ... | Read |
|---|---|
| Author an implement engine | Implement engine contract |
The conformance gate's model, the spec council's roster, and the phase-tracker's flow guards are all configured per pi preset (or per repo, via .pi/settings.json). Keys below are relative to piGauntlet.
| Key | Owner (extension) | Default | Effect |
|---|---|---|---|
specCouncil.members |
phase-tracker (gauntlet_setting), roasting-the-spec |
[] (worker critique) |
council models for the spec critique - detail |
specCouncil.chair |
same | unset (inherits the main loop) | chair model - detail |
closureReview.enforce |
phase-tracker | true |
conformance gate on/off - detail |
closureReview.model |
phase-tracker | unset (inherits) | conformance reviewer model - detail |
closureReview.maxFixRounds |
phase-tracker | 5 |
fix rounds before escalation - detail |
escalationLoop.implModel |
phase-tracker | unset (main loop) | execution escalation under either loop option; review escalation remains separate - detail |
loopEngine.maxIterationsPerRow |
phase-tracker | 4 (floor 1) |
fresh-ledger per-row allowance; run override on approval 4/5 - detail |
phaseModels.plan / .implement / .verify / .ship |
phase-tracker | unset (no switch) | provider/id[:level] applied persistently at that phase's start - detail |
flowGuards.enforce |
phase-tracker | true |
phase gates on/off - detail |
flowGuards.specDirs |
phase-tracker, plan-tracker; telemetry and spec-index consumers | ["doc/specs", "docs/specs"] |
where specs and sibling plans live - detail |
verifyBeforeShip.testCommands |
verify-before-ship | the DEFAULT_TEST_COMMANDS patterns in extensions/lib/gauntlet-settings.ts (make, npm, pnpm, yarn, pytest, rspec, cargo, go) |
patterns that count as a test run - detail |
verifyBeforeShip.warningReference |
verify-before-ship | unset | pointer shown with the warning - detail |
telemetry.enabled |
telemetry | true |
record each flow - detail |
telemetry.dir |
telemetry | .pi/gauntlet/telemetry |
record location - detail |
telemetry.buckets |
telemetry | test / docs / config globs (DEFAULT_TELEMETRY_BUCKETS) |
file classification - detail |
For Markdown instructions rather than runtime settings, use Project-specific overrides. Repo-local settings replace each configured second-level object wholesale; see the deep reference.
Relationship to the other repos
pi-gauntlet is the process layer: it enforces the workflow, but every reviewer and implementer it dispatches runs through pi-cohort's subagent() - that's a hard dependency, not an integration you can skip. pi-condense is optional but keeps a long gated run's context (and cost) from growing unbounded across all those dispatches. pi-quiver is complementary - if a brainstorm or implementation step needs to pull in a real doc or web page, that's what ingests it safely.
Roadmap
Nothing committed beyond what's shipped. Changes land via CHANGELOG.md.
Lineage
pi-gauntlet's skill methodology was inspired by obra/superpowers (MIT, Copyright (c) 2025 Jesse Vincent), by way of coctostan/pi-superpowers-plus. The pi runtime integration, enforced phase gates, multi-model spec council, conformance-review gate, and parallel execution waves are pi-gauntlet's own. Thanks to the upstream authors; their copyright is preserved in LICENSE.
Contributing
See CONTRIBUTING.md - issues follow a Context / Problem / Idea / Acceptance Criteria template; PRs run the pi-gauntlet workflow (one-liners exempt from ceremony, never from keeping docs truthful).
Support
Buy me a coffee if this saves you time.
License
MIT. See LICENSE. Portions derive from obra/superpowers (MIT) and coctostan/pi-superpowers-plus; their copyright notice is preserved in LICENSE.
