pi-gauntlet

Opinionated, gated workflow skills, subagent personas, and runtime extensions for the pi coding agent.

Packages

Package details

extensionskill

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

Buy Me A Coffee

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:

  1. (Optional) Before there's even a spec, /skill:shape-ticket can 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-bug triages a raw bug report into an evidenced verdict - and can hand off to shape-ticket, brainstorming, or a bounded hotfix - before any spec exists.

  2. Opt in with /skill:brainstorming and 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/N or /issues/N URL), 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 word merge-forward opts 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. brainstorming sets 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>, or smaller or none); otherwise it opens with one sentence naming what it checked, and every approach it proposes ends with a Pattern: 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-delivery verifies venue: 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:** deferred under **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 later brainstorming #N reconstructs 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 later brainstorming #N on 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 prints spec-only PR without the gate marker - running lint and council and 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.

  3. By default, writing-plans decomposes 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 select loop-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.

  4. subagent-driven-development executes the plan in waves, with task implementers followed by one integrated wave-reviewer after 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 fresh loop-implementer per seed or row iteration, without implement-phase reviewers. Each row starts with the shared allowance (default 4); approval replies such as 4; allowance 6 override it for one run. Under either loop approval option, the last allowed attempt escalates once per row on escalationLoop.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, while rows +N raises 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.

  5. 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 a happy-path: failed - unattributable line - 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, 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 result goes straight to the branch options with no extra conformance sign-off.

  6. 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 in merge: form push non-force). A spec whose header carries **PR:** (approved at a spec-PR re-gate) and no ## Rework record replaces the two create rows with Push to PR #N and mark it ready for review and Push 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 runs gh 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:** deferred stops finishing (and gauntlet-resume) with spec approved for handoff only - run brainstorming #N before any phase change, verification, or push. The PR-rework push appends a ## Rework block 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. Its Before: handle includes the full portable pre-rework SHA and the local refs/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.

  7. (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-delivery owns 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 (mergeStateStatus not BLOCKED) 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 a mergeable / fixable verdict) 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 the AC coverage block to the ticket or the PR; own-merge, approved, and closed-PR menus offer a recommended cleanup row that tears down the gate's worktree and branch and runs the overrides file's ## cleanup steps - 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 fresh loop-implementer over 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 the linearis CLI; owns all linearis mechanics and the ## Issue tracker overrides schema; tracker-facing skills route to it). Five more require explicit entry (disable-model-invocation: true): brainstorming starts the gated workflow on explicit consent - use /skill:brainstorming for 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-bug is 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 to skills/chase-bug/hotfix.md after the menu - run it with /skill:chase-bug. gauntlet-performance reads the committed run telemetry (current repo by default, --dir <path> adds others) through the parse-only gauntlet-performance CLI 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 via shape-ticket, drill into one run); it writes nothing unless you pick render - run it with /skill:gauntlet-performance [--dir <path>]... [--since <version>]. gauntlet-handoff ends a session whose flow a fresh session will continue: it invokes pi-cohort's handoff skill (--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 contract skills/gauntlet-resume/reference/brief-contract.md - run it with /skill:gauntlet-handoff [--out <path> | --key <name>]. gauntlet-resume is the only way back into an interrupted flow from a fresh session: it takes a gauntlet-handoff brief (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 through using-git-worktrees and pins the spec), restores phase/plan tracker state through the legal arming sequence (start brainstorm, skip with resume: reasons, plan_check before 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-tracker and phase-tracker are tools skills call to track progress (with a TUI widget); verify-before-ship is 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 scoped Verification: 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 calls plan_tracker refresh to 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 rejects implement or verify completion while tracker tasks remain pending or in progress; see its configuration reference. phase-tracker also registers plan_check, which verifies a plan against its spec and against the grammar in skills/writing-plans/reference/plan-contract.md, including that each task's Tests: 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. telemetry records 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 until finishing-a-development-branch seals it once with gauntlet-telemetry-seal (a telemetry: commit under git; the working-copy snapshot in a plain jj workspace) - and blocks a brainstorm write into 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.

  1. Implement phase with tasks complete/in_progress/pending in a .worktrees/<branch> flow, session in the primary checkout: /skill:gauntlet-handoff writes <tmpdir>/pi-handoff/<branch>.md with the six core headings then ## Process state last; a fresh session running /skill:gauntlet-resume <path> restores implement with the three statuses and ends Gate history not restored; re-validating <task> before any stage advance.
  2. Plan phase, No plan active.: the brief keeps that line and Active task: none; resume restores phase-only with no plan_tracker init.
  3. Hotfix context with non-pending trackers: the brief ends at ## Skills loaded; resume takes the chase-bug route.
  4. Fresh session, zero arguments: the listing shows the briefs from 1-3 and a pick restores; /skill:gauntlet-resume /nonexistent.md stops naming that path without listing anything.
  5. Branch hotfix/x: the default file is pi-handoff/hotfix-x.md and appears in the zero-argument listing.
  6. Primary session, idle trackers, spec tracked on main: /skill:gauntlet-resume doc/specs/<x>.md creates the worktree and asks the approval question; approval leaves phase_tracker at plan in_progress with brainstorm ⊘ (resume: ...).
  7. Fresh idle session, same seed: the registered worktree is reused (no creation) and the question repeats. Run once on a consumer whose ## using-git-worktrees override lays worktrees out as sibling dirs, once on .worktrees/.
  8. After writing-plans commits the plan beside the seeded spec: /skill:gauntlet-handoff then 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.
  9. Spec approved with 2, then /skill:gauntlet-handoff and a fresh /skill:gauntlet-resume <brief>: the closing line is followed by Standing grant active: <sentence> and the next amend batch applies without a menu. A spec approved with 1 prints No 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_tracker tool 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 subagent in tools: start with inherited extensions (pi-cohort #26), which multi-PR gatekeep-pr needs. Skills that dispatch agents (requesting-code-review, subagent-driven-development, dispatching-parallel-agents, writing-plans, forge-skill, shape-ticket, roasting-the-spec) call subagent({}), 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 use async: false; do not enable pi-cohort's incompatible forceTopLevelAsync setting. 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-development stops 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.

  1. 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 }
    }
    EOF
    
  2. Start Claude Code interactively in that directory: claude

  3. When prompted, trust the folder (this exact folder - trust is what activates the marketplace; there is no separate marketplace prompt).

  4. Run /plugin and confirm: marketplace pi-gauntlet is listed, plugin gauntlet is enabled. If it shows as known but not installed, run /plugin install gauntlet@pi-gauntlet and re-check.

  5. Confirm exactly six skills are registered under the plugin (via the /plugin details view): shape-ticket, gatekeep-pr, check-delivery, chase-bug, linear, forge-skill.

  6. Invoke /gauntlet:shape-ticket with 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 its reference/split-axes.md before 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.

  7. Invoke /gauntlet:gatekeep-pr in the scratch repo. Expected with no GitHub origin: the skill stops before provisioning with discovery failed: origin is not a GitHub repository. With a GitHub origin and no matching PR, expect no open PRs authored by <login> or awaiting <login>'s review in <owner/repo> naming origin (@me when the viewer login is unreadable). Neither outcome reports missing pi tools or mutates the repo.

  8. Invoke /gauntlet:check-delivery with 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.

  9. Negative check: type /gauntlet:brainstorming. Expected: no such skill - the allowlist excluded it.

  10. Optional validator pass: claude plugin validate . from a checkout of pi-gauntlet (strict mode if available). Expected: no schema errors.

  11. 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.json suppresses the default agents/ scan of the repo's pi personas. The marketplace uses strict: true so its skill allowlist can coexist with that manifest. Keep the skill allowlist in the marketplace: a manifest skills field adds to the default scan rather than restricting it. Direct --plugin-dir loading 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:

  1. Repo root REVIEW.md - always wins over everything below it.
  2. Shipped skills/gatekeep-pr/review-baseline.md - the generic default rubric.
  3. 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 gate section - 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, ## cleanup section - the ordered post-gate steps the cleanup menu 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.