pincer-workflow 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -5
- package/bin/pincer.js +42 -5
- package/package.json +2 -2
- package/template/.agents/skills/pincer-code/SKILL.md +51 -4
- package/template/.agents/skills/pincer-evaluate/SKILL.md +29 -2
- package/template/.agents/skills/pincer-narrow/SKILL.md +11 -2
- package/template/.agents/skills/pincer-plan/SKILL.md +9 -1
- package/template/.agents/skills/pincer-release/SKILL.md +14 -3
- package/template/.agents/skills/pincer-status/SKILL.md +17 -2
- package/template/.claude/commands/pincer-code.md +51 -4
- package/template/.claude/commands/pincer-evaluate.md +29 -2
- package/template/.claude/commands/pincer-narrow.md +11 -2
- package/template/.claude/commands/pincer-plan.md +9 -1
- package/template/.claude/commands/pincer-release.md +14 -3
- package/template/.claude/commands/pincer-status.md +17 -2
- package/template/.claude/hooks/hook-policy.cjs +17 -3
- package/template/.claude/references/ticket-template.md +4 -0
- package/template/.codex/README.md +3 -2
- package/template/.github/prompts/pincer-code.prompt.md +51 -4
- package/template/.github/prompts/pincer-evaluate.prompt.md +29 -2
- package/template/.github/prompts/pincer-narrow.prompt.md +11 -2
- package/template/.github/prompts/pincer-plan.prompt.md +9 -1
- package/template/.github/prompts/pincer-release.prompt.md +14 -3
- package/template/.github/prompts/pincer-status.prompt.md +17 -2
- package/template/AGENTS.md +6 -0
- package/template/docs/dry-run-checklist.md +46 -3
- package/template/docs/release-checklist.md +2 -1
- package/template/docs/runtime-contracts.md +437 -0
- package/template/scripts/pincer-evidence.cjs +5 -223
- package/template/scripts/pincer-runtime/evidence.cjs +391 -0
- package/template/scripts/pincer-runtime/fsutil.cjs +37 -0
- package/template/scripts/pincer-runtime/identity.cjs +146 -0
- package/template/scripts/pincer-runtime/lifecycle.cjs +289 -0
- package/template/scripts/pincer-runtime/migrate.cjs +127 -0
- package/template/scripts/pincer-runtime/parse.cjs +297 -0
- package/template/scripts/pincer-runtime/readiness.cjs +89 -0
- package/template/scripts/pincer-runtime/runner.cjs +224 -0
- package/template/scripts/pincer-runtime/sanitize.cjs +63 -0
- package/template/scripts/pincer-runtime/source.cjs +129 -0
- package/template/scripts/pincer-runtime/state.cjs +292 -0
- package/template/scripts/pincer-runtime/status.cjs +358 -0
- package/template/scripts/pincer-runtime.cjs +350 -0
- package/template/scripts/pincer-status.sh +11 -162
- package/template/scripts/pincer-ticket.sh +19 -139
- package/template/scripts/pincer-ticket-lib.sh +0 -321
|
@@ -13,11 +13,26 @@ start of a session. Read-only: change nothing.
|
|
|
13
13
|
1. Run `scripts/pincer-status.sh`. It reads the artifacts on disk (`.prd/`, `tickets/`,
|
|
14
14
|
`NOTES.md`) and prints the PRD state and profile, every ticket with its state and
|
|
15
15
|
clock-based elapsed time, what is blocked, wall-clock build time while a ticket is in
|
|
16
|
-
progress or against an explicit user budget, the
|
|
16
|
+
progress or against an explicit user budget, the `Runtime` line (legacy receipts or
|
|
17
|
+
the registered change), the evidence verdict and `Provenance` line for the evaluated
|
|
17
18
|
candidate, any warnings (each readiness problem once), and the next command to run.
|
|
19
|
+
`scripts/pincer-status.sh --json` prints one status object with reason codes and the
|
|
20
|
+
next action for tooling; `node scripts/pincer-runtime.cjs ready [T-NN]` is the
|
|
21
|
+
read-only gate.
|
|
18
22
|
2. Report in three lines: where the workflow is, what is in progress or blocked, and the
|
|
19
|
-
next command. Quote the `Next` line as-is.
|
|
23
|
+
next command. Quote the `Next` line as-is. When the `Runtime` line says `legacy`,
|
|
24
|
+
add the register or migrate command it names as the step that precedes the next
|
|
25
|
+
ticket (fresh project → `register`, legacy receipts → `migrate --preview`).
|
|
20
26
|
3. If a ticket is `in_progress`, read it and `git status`, then offer to resume it with
|
|
21
27
|
`/pincer-code T-{NN}`. If the script printed a warning, surface it — a done ticket
|
|
22
28
|
without a receipt was marked by hand and needs `scripts/pincer-ticket.sh verify T-{NN}`.
|
|
23
29
|
Never restore a ticket file from git to clear a warning; a failed attempt is a record.
|
|
30
|
+
The one exception is the tree-back-at-candidate case in the recovery section of
|
|
31
|
+
`/pincer-code`: the user restores the ticket file, and nothing is verified or committed.
|
|
32
|
+
It applies only when the recorded failure is explained by a since-reverted source
|
|
33
|
+
change and the block passes in the same execution context as `verify`; an
|
|
34
|
+
unexplained failure (a service down, a missing dependency) stays a failure until the
|
|
35
|
+
environment is repaired and `verify` passes again. After migration never restore a
|
|
36
|
+
ticket file or delete `.pincer/runtime` to clear a warning: repair the cause and run
|
|
37
|
+
`verify` again; a dead session's `running` attempt is finalized by
|
|
38
|
+
`node scripts/pincer-runtime.cjs recover`.
|
|
@@ -160,11 +160,20 @@ function dangerousReason(source, depth = 0) {
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
const TICKET_PATH = /(^|[\\/])tickets[\\/]T-[0-9]+[^\\/]*\.md$/;
|
|
163
|
+
// Runtime-owned state: local attempts under .pincer/ and change bindings under
|
|
164
|
+
// .prd/changes/ are written only by pincer-runtime.cjs.
|
|
165
|
+
// The runtime owns .pincer/runtime/ and .pincer/backups/ (and the directory as a
|
|
166
|
+
// whole); .pincer/drafts/ is the agent's own scratch space for evidence drafts.
|
|
167
|
+
const RUNTIME_PATH = /(^|[\\/])\.pincer(?:[\\/](?:runtime|backups)(?:[\\/]|$)|[\\/]?$)/;
|
|
168
|
+
const BINDING_PATH = /(^|[\\/])\.prd[\\/]changes([\\/]|$)/;
|
|
163
169
|
const PROTECTED = ['status', 'started', 'last_check', 'verified', 'finished'];
|
|
164
170
|
|
|
165
171
|
function ticketPath(value) {
|
|
166
172
|
return typeof value === 'string' && TICKET_PATH.test(value);
|
|
167
173
|
}
|
|
174
|
+
function runtimePath(value) {
|
|
175
|
+
return typeof value === 'string' && (RUNTIME_PATH.test(value) || BINDING_PATH.test(value));
|
|
176
|
+
}
|
|
168
177
|
|
|
169
178
|
function stateFields(content) {
|
|
170
179
|
const result = Object.fromEntries(PROTECTED.map(key => [key, []]));
|
|
@@ -203,6 +212,7 @@ function applyEdit(content, oldText, newText, replaceAll = false) {
|
|
|
203
212
|
function guardEdits(tool, toolInput) {
|
|
204
213
|
const file = toolInput.file_path;
|
|
205
214
|
if (typeof file !== 'string') block(`${tool} payload must contain a string file_path.`);
|
|
215
|
+
if (runtimePath(file)) block('runtime state (.pincer/) and change bindings (.prd/changes/) are written only by pincer-runtime.cjs.');
|
|
206
216
|
if (!ticketPath(file)) return;
|
|
207
217
|
const before = existingContent(file);
|
|
208
218
|
if (tool === 'Write') {
|
|
@@ -232,7 +242,10 @@ function isExactPincerCall(source) {
|
|
|
232
242
|
if (commands.length !== 1 || commands[0].separator) return false;
|
|
233
243
|
const { executable, args } = commandParts(commands[0]);
|
|
234
244
|
let words = [executable, ...args];
|
|
235
|
-
if (['bash', 'sh'].includes(words[0])) words = words.slice(1);
|
|
245
|
+
if (['bash', 'sh', 'node'].includes(words[0])) words = words.slice(1);
|
|
246
|
+
if (/pincer-runtime\.cjs$/.test(words[0] || '')) {
|
|
247
|
+
return ['start', 'verify', 'done', 'bind', 'register', 'migrate', 'recover', 'check', 'evidence'].includes(words[1]);
|
|
248
|
+
}
|
|
236
249
|
if (!/pincer-ticket\.sh$/.test(words[0] || '')) return false;
|
|
237
250
|
const action = words[1];
|
|
238
251
|
if (!['start', 'verify', 'done', 'bind'].includes(action)) return false;
|
|
@@ -321,7 +334,8 @@ function ticketShellMutation(source, depth = 0) {
|
|
|
321
334
|
const stdinPathspec = !sub.args.some(arg => !arg.startsWith('-')) || sub.args[sub.args.length - 1] === '--';
|
|
322
335
|
if (viaXargs && ['checkout', 'restore', 'clean'].includes(sub.name) && stdinPathspec) return true;
|
|
323
336
|
}
|
|
324
|
-
const hasTicket = words.some(ticketPath) || /(^|[\s'"`])tickets[\\/]T-[0-9]+[^\s'"`]*/.test(source)
|
|
337
|
+
const hasTicket = words.some(ticketPath) || /(^|[\s'"`])tickets[\\/]T-[0-9]+[^\s'"`]*/.test(source) ||
|
|
338
|
+
words.some(runtimePath) || /(^|[\s'"`=])\.pincer(?:[\\/](?:runtime|backups)(?:[\\/]|[\s'"`]|$)|[\\/]?(?:[\s'"`]|$))/.test(source) || /(^|[\s'"`=])\.prd[\\/]changes([\\/]|[\s'"`]|$)/.test(source);
|
|
325
339
|
if (!hasTicket) continue;
|
|
326
340
|
if (command.operators.some(op => op === '>' || op === '>>')) return true;
|
|
327
341
|
if (['rm', 'mv', 'cp', 'install', 'truncate', 'touch', 'tee', 'ed', 'ex'].includes(executable)) return true;
|
|
@@ -344,7 +358,7 @@ if (mode === 'dangerous') {
|
|
|
344
358
|
if (['Edit', 'Write', 'MultiEdit'].includes(payload.tool_name)) guardEdits(payload.tool_name, payload.tool_input);
|
|
345
359
|
else if (payload.tool_name === 'Bash') {
|
|
346
360
|
if (typeof payload.tool_input.command !== 'string') block('Bash payload must contain a string command.');
|
|
347
|
-
if (ticketShellMutation(payload.tool_input.command)) block('shell commands may not write, reset, or restore ticket files (including whole-tree checkout/restore, reset --hard, stash, clean -f
|
|
361
|
+
if (ticketShellMutation(payload.tool_input.command)) block('shell commands may not write, reset, or restore ticket files or runtime state (.pincer/, .prd/changes/), including whole-tree checkout/restore, reset --hard, stash, clean -f; use pincer-ticket.sh or pincer-runtime.cjs for lifecycle state.');
|
|
348
362
|
}
|
|
349
363
|
} else {
|
|
350
364
|
block('hook policy mode is invalid.');
|
|
@@ -9,6 +9,7 @@ status: open # open | in_progress | done
|
|
|
9
9
|
size: S # S | M | L, relative scope; split when it improves verification
|
|
10
10
|
prd: .prd/prd-v{N}.md # the selected PRD, never inferred from ticket numbering
|
|
11
11
|
depends_on: [] # e.g. [T-01]
|
|
12
|
+
timeout: 600 # optional, seconds (default 600); part of the check identity
|
|
12
13
|
---
|
|
13
14
|
|
|
14
15
|
## Objective
|
|
@@ -58,6 +59,9 @@ Rules:
|
|
|
58
59
|
`scripts/pincer-ticket.sh` (`start` / `verify` / `done`). `verify` runs the
|
|
59
60
|
Verification block verbatim and writes a receipt only on exit 0; `done`
|
|
60
61
|
requires that receipt to match the current block. Never write these by hand.
|
|
62
|
+
On a migrated project (`.prd/changes/` holds a change binding) `verify` records
|
|
63
|
+
attempts under `.pincer/runtime/` instead of `verified`/`last_check`, and `done`
|
|
64
|
+
consumes the current passing attempt against the current source.
|
|
61
65
|
- The Verification block is a fenced `bash` block that exits 0 only when the
|
|
62
66
|
ticket is done — non-interactive, no "check by hand".
|
|
63
67
|
- The Verification section opens with a one-line `Proves:` statement: what the
|
|
@@ -36,8 +36,9 @@ approval_policy = "on-request" # agent asks before escalating
|
|
|
36
36
|
sandbox_mode = "workspace-write" # writes confined to the repo; no network by default
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
The ticket scripts
|
|
40
|
-
|
|
39
|
+
The ticket scripts work here unchanged (`scripts/pincer-ticket.sh
|
|
40
|
+
start|verify|done T-NN` and `scripts/pincer-status.sh`); they are thin wrappers
|
|
41
|
+
around `scripts/pincer-runtime.cjs`, so Node.js 18+ is required.
|
|
41
42
|
Without a Pincer Codex hook adapter, the rule in `AGENTS.md` carries the weight
|
|
42
43
|
of stopping hand-edited ticket state; `$pincer-status` warns about any ticket
|
|
43
44
|
marked done without a receipt.
|
|
@@ -18,6 +18,11 @@ Ticket state lives in the ticket file's frontmatter and is written **only** by
|
|
|
18
18
|
Verification block and stamps a receipt only on a green exit; `done` refuses without a
|
|
19
19
|
receipt that matches the current check, or with unticked acceptance criteria. Never edit
|
|
20
20
|
`status`, `started`, `last_check`, `verified`, or `finished` by hand — on Claude Code a hook blocks it.
|
|
21
|
+
On a migrated project (a change binding under `.prd/changes/`; the `Runtime` line of
|
|
22
|
+
`scripts/pincer-status.sh` names it) `verify` records an attempt under `.pincer/runtime/`
|
|
23
|
+
and writes no receipt into the ticket, and `done` consumes the current passing attempt
|
|
24
|
+
against the current source without re-running the check. `.pincer/` and `.prd/changes/`
|
|
25
|
+
are written only by the runtime; never edit or delete them by hand.
|
|
21
26
|
|
|
22
27
|
## Before the loop
|
|
23
28
|
|
|
@@ -25,7 +30,15 @@ Run `scripts/pincer-status.sh`. It lists every ticket's state, what is blocked,
|
|
|
25
30
|
build time from the clock, and the next action. If a ticket is `in_progress`, you are
|
|
26
31
|
resuming: read it, check `git status` / `git diff` for uncommitted work, and continue
|
|
27
32
|
from wherever the receipt says you are. Do not ask the user to reconfirm unchanged,
|
|
28
|
-
previously authorized work.
|
|
33
|
+
previously authorized work. Read the `Runtime` line before the first ticket: a change
|
|
34
|
+
binding present → continue; `legacy` and no ticket of this PRD carries legacy
|
|
35
|
+
receipts → register now (`node scripts/pincer-runtime.cjs register --prd .prd/prd-vN.md --authorization "<the user's approval, quoted>"`,
|
|
36
|
+
commit `.prd/changes/` and `.gitignore` as `Register PRD vN`); `legacy` with legacy receipts → run
|
|
37
|
+
`node scripts/pincer-runtime.cjs migrate --preview --prd .prd/prd-vN.md`, show the plan
|
|
38
|
+
(backups, receipts imported as history, `.gitignore` line) and ask once whether to
|
|
39
|
+
apply. Apply only on a yes, then commit the rewritten tickets, `.gitignore` and the
|
|
40
|
+
binding as `Migrate PRD vN to the runtime`. Never migrate silently, and never apply
|
|
41
|
+
when the preview reports a conflict.
|
|
29
42
|
|
|
30
43
|
## Loop (per ticket, in dependency order)
|
|
31
44
|
|
|
@@ -40,7 +53,9 @@ previously authorized work.
|
|
|
40
53
|
dispatch a subagent with a clean prompt: paste the full ticket body, the relevant
|
|
41
54
|
conventions, and nothing else.
|
|
42
55
|
3. **Verify:** `scripts/pincer-ticket.sh verify T-{NN}` — runs the Verification block and
|
|
43
|
-
writes the receipt only if it exits 0
|
|
56
|
+
writes the receipt only if it exits 0 (after migration it records an attempt with the
|
|
57
|
+
captured log under `.pincer/runtime/` and writes no receipt into the ticket; readiness
|
|
58
|
+
derives from the latest attempt and the current source). Red → fix and re-run; report the actual output,
|
|
44
59
|
not assumptions. Green output is the definition of done, not your confidence. If the
|
|
45
60
|
check only validated syntax or a build, say so — that is not behavioral proof. A
|
|
46
61
|
visual judgment is recorded separately in evaluation, not as the receipt, and a tool
|
|
@@ -58,7 +73,10 @@ previously authorized work.
|
|
|
58
73
|
- No error path leaks internals (stack traces, key names with values) to the client.
|
|
59
74
|
If the review changed code, run `verify` again — the receipt must match the code you commit.
|
|
60
75
|
5. **Close the ticket:** tick every verified acceptance-criteria checkbox (`- [ ]` → `- [x]`;
|
|
61
|
-
editing the checkboxes is allowed), then `scripts/pincer-ticket.sh done T-{NN}`.
|
|
76
|
+
editing the checkboxes is allowed), then `scripts/pincer-ticket.sh done T-{NN}`. After
|
|
77
|
+
migration `done` consumes the current passing attempt and does not re-run the check; it
|
|
78
|
+
refuses with a reason code (`SOURCE_CHANGED`, `CHECK_CHANGED`, `CHECK_FAILED`,
|
|
79
|
+
`CRITERIA_UNTICKED`, …) and the next step when the latest attempt is not current. A
|
|
62
80
|
criterion that was cut is a scope change to record in the PRD, not a box to skip.
|
|
63
81
|
Inspect `git status --short`, preserve pre-existing staged work, and stage only the
|
|
64
82
|
explicit paths changed for this ticket plus its ticket file. Review `git diff --cached`
|
|
@@ -89,7 +107,36 @@ the script or `scripts/pincer-status.sh` printed, and hand the repair to the use
|
|
|
89
107
|
performs it in their own terminal. Then return through the lifecycle — `start`,
|
|
90
108
|
`verify`, `done` — so the ticket carries fresh verification; a restored receipt is
|
|
91
109
|
never evidence. Do not recommend restoring source files or unrelated edits as routine
|
|
92
|
-
ticket repair.
|
|
110
|
+
ticket repair. One exception: when the PRD is built with valid candidate evidence;
|
|
111
|
+
tracked files other than the ticket file being restored match the evaluated candidate
|
|
112
|
+
(or the candidate plus its evidence-only commit) with nothing untracked; the recorded
|
|
113
|
+
failure is explained by a working-tree change that has since been reverted (the failed
|
|
114
|
+
`last_check` was stamped while source differed from the candidate, and that difference
|
|
115
|
+
is gone); and the ticket's Verification block passes when run
|
|
116
|
+
directly rather than through `verify` (which would write a receipt), in the
|
|
117
|
+
same execution context as `verify` — the same shell, working directory, `PATH`
|
|
118
|
+
and environment, with no substituted binary and no repair made first — then
|
|
119
|
+
the committed evaluation still describes the tree. Say so, name the exact command
|
|
120
|
+
for the user to restore the ticket file in their own terminal, and
|
|
121
|
+
do not run `verify`, refresh the receipt or commit anything — the restored file is
|
|
122
|
+
what is already committed, not new evidence. If the block fails on that clean tree,
|
|
123
|
+
the failure is real: keep the failed `last_check` and repair through the lifecycle.
|
|
124
|
+
A changed executable, runner, working directory or environment repair requires a
|
|
125
|
+
new recorded verification through `verify`; the exception does not apply to it.
|
|
126
|
+
An unexplained failure cannot be cleared by restoring a receipt: when no
|
|
127
|
+
since-reverted source change explains it (a service down, a missing dependency, a
|
|
128
|
+
check that reads external data), keep the failure, name the cause you observed, and
|
|
129
|
+
ask for the environment to be repaired before `verify` runs again.
|
|
130
|
+
If source still differs from the candidate, name the differing paths and let the
|
|
131
|
+
user decide rather than asking which way to fix them; permission to restore a ticket
|
|
132
|
+
does not authorize discarding source changes.
|
|
133
|
+
After migration (a change binding exists) recovery is the lifecycle itself: retain the
|
|
134
|
+
failure, repair the cause, run `verify` again; readiness derives from the latest attempt,
|
|
135
|
+
both attempts stay in `.pincer/runtime/` and no tracked file changes. Never restore a
|
|
136
|
+
ticket file or delete `.pincer/runtime` to obtain a green status; the legacy exception
|
|
137
|
+
above applies only before migration. A session that died mid-`verify` leaves a `running`
|
|
138
|
+
attempt: run `node scripts/pincer-runtime.cjs recover`, which finalizes it as
|
|
139
|
+
`interrupted` once the owner process is gone, then `verify` again.
|
|
93
140
|
|
|
94
141
|
## Budget rules
|
|
95
142
|
|
|
@@ -64,9 +64,36 @@ run the pipeline, then present results.
|
|
|
64
64
|
material decision; never make an ad-hoc `review: fixes` commit. Every fix commit
|
|
65
65
|
produces a new candidate: re-record `candidate`, re-run the checks against it, and
|
|
66
66
|
write fresh evidence in step 9 — never reuse a manifest from a previous candidate.
|
|
67
|
-
9. Persist evidence for the candidate under `.prd/evidence/prd-vN/<candidate
|
|
67
|
+
9. Persist evidence for the candidate under `.prd/evidence/prd-vN/<candidate>/`.
|
|
68
|
+
Migrated project (the `Runtime` status line names a change): run each executable
|
|
69
|
+
check through the runtime on the clean candidate view —
|
|
70
|
+
`node scripts/pincer-runtime.cjs check C-NN --candidate <sha> -- <command>` (one
|
|
71
|
+
command per check, the command line as run; `npm test` stays one aggregate check) —
|
|
72
|
+
then write the authored fields to a draft outside the evidence directory, for
|
|
73
|
+
example `.pincer/drafts/<sha>.json`: `environment.tools` and `environment.limitations`,
|
|
74
|
+
`coverage_review`, `requirements`, review and visual checks with their saved
|
|
75
|
+
artifacts, `visual_review`, and a stub `{"id": "C-NN", "kind": "command",
|
|
76
|
+
"required": true|false}` for each executable check. Then run
|
|
77
|
+
`node scripts/pincer-runtime.cjs evidence export --candidate <sha> --base <base> --prd .prd/prd-vN.md --draft <file>`.
|
|
78
|
+
The export writes `checks/C-NN.log` from the captured logs, fills `command`,
|
|
79
|
+
`result`, `provenance: runtime` and `attempt` from the attempts, labels review and
|
|
80
|
+
visual checks `provenance: authored`, computes the digests and writes an evidence
|
|
81
|
+
schema 2 manifest; it refuses a dirty tree, a HEAD that is not the candidate, a stub
|
|
82
|
+
without an attempt, and a `passed` or `failed` command result written by hand. A
|
|
83
|
+
tool that cannot run is recorded as an authored command check with
|
|
84
|
+
`result: unverified` and a note, as before. Legacy project (no change binding):
|
|
85
|
+
author the schema 1 manifest as follows.
|
|
68
86
|
- `checks/C-NN.log` — the command and a redacted summary or safe log of each
|
|
69
|
-
executable check. Never secrets, never an environment dump.
|
|
87
|
+
executable check. Never secrets, never an environment dump. Record
|
|
88
|
+
one check per command: `command` holds the command line as run, never prose
|
|
89
|
+
describing a session, and a manual smoke run is recorded as the command lines
|
|
90
|
+
that were run (separate entries when they establish independent outcomes).
|
|
91
|
+
Independently assessed commands — the tracked `.env` check, the secret scan,
|
|
92
|
+
the dependency audit — are separate `checks` entries with their own `result`
|
|
93
|
+
and log, so only the tool that could not run is `unverified`. A test runner
|
|
94
|
+
such as `npm test` stays one aggregate check; do not split every subprocess or
|
|
95
|
+
assertion. Visual and review checks keep their kinds and get no artificial
|
|
96
|
+
shell command. Note a redaction rather than inventing a substitute command.
|
|
70
97
|
- `visual/<scenario>.png` — each visual capture from step 4, with its scenario,
|
|
71
98
|
viewport and observed result recorded in the manifest. When nothing renders,
|
|
72
99
|
record `visual_review: {applicable: false, reason}` and say why.
|
|
@@ -41,7 +41,9 @@ discovered consequential choice is surfaced before implementation.
|
|
|
41
41
|
- Every ticket gets a runnable command in its Verification block — a fenced `bash`
|
|
42
42
|
block that exits 0 only when the ticket is done. `scripts/pincer-ticket.sh verify`
|
|
43
43
|
runs it verbatim and stamps the receipt that `done` requires, so it must be
|
|
44
|
-
non-interactive and self-contained (no "check by hand").
|
|
44
|
+
non-interactive and self-contained (no "check by hand"). An optional
|
|
45
|
+
`timeout: <seconds>` frontmatter field (default 600) bounds the run; it is part of
|
|
46
|
+
the check identity, so changing it invalidates earlier passes.
|
|
45
47
|
- Each Verification section opens with `Proves:` — what the check establishes and
|
|
46
48
|
which regression it detects. A check for an executable change must exercise
|
|
47
49
|
observable behavior (including relevant rejection paths and, in brownfield work,
|
|
@@ -83,7 +85,14 @@ existing authorization for the same scope and order.
|
|
|
83
85
|
inspect existing staged changes, stage that PRD and the explicit new ticket paths,
|
|
84
86
|
review `git diff --cached`, and commit only those paths. Ask first — and finalize
|
|
85
87
|
once it is resolved — only when step 4 surfaced a newly discovered consequential
|
|
86
|
-
choice or a scope change the PRD does not cover.
|
|
88
|
+
choice or a scope change the PRD does not cover. Then register the change when the
|
|
89
|
+
`Runtime` status line says `legacy` and no ticket of this PRD carries legacy
|
|
90
|
+
receipts: `node scripts/pincer-runtime.cjs register --prd .prd/prd-vN.md --authorization "<the user's approval, quoted>"`,
|
|
91
|
+
then stage `.prd/changes/` and `.gitignore` (registration adds `.pincer/` to it) and
|
|
92
|
+
commit them as `Register PRD vN`. The authorization
|
|
93
|
+
text records the user's own words; running the command proves nothing by itself. A
|
|
94
|
+
project whose tickets carry legacy receipts is migrated from `/pincer-code` after a
|
|
95
|
+
preview, never here. Finish with:
|
|
87
96
|
"Tickets ready in `tickets/`. Run `/pincer-code` to start implementing."
|
|
88
97
|
|
|
89
98
|
## Authorization rule (shared by plan, narrow, code and evaluate)
|
|
@@ -36,12 +36,20 @@ unless the user explicitly authorized a separate change.
|
|
|
36
36
|
IDs; do not silently replace either. Where its structure needs adapting to the
|
|
37
37
|
template, record a mapping table (`their section or ID → R-NN`) inside the PRD.
|
|
38
38
|
2. Ask only the questions whose answers would change the architecture or scope.
|
|
39
|
-
Batch them (max 3–4 at once).
|
|
39
|
+
Batch them (max 3–4 at once). A question the brief partly answers is
|
|
40
|
+
asked only for its open part, naming the settled part; when the brief settles
|
|
41
|
+
every material decision, including acceptance behavior, ask no discovery
|
|
42
|
+
question and record the brief's answers. Do not add a question to fill the budget.
|
|
43
|
+
Typical ones:
|
|
40
44
|
- What does "done" look like — what will be run, demoed, or reviewed at the end?
|
|
45
|
+
A named test runner settles the verification choice, not every acceptance
|
|
46
|
+
behavior; ask about the demo or manual check only if that is still open.
|
|
41
47
|
- Any required stack, or is it my choice?
|
|
42
48
|
- What is explicitly out of scope?
|
|
43
49
|
3. If the project has a frontend, ask one design question: "What should this feel like,
|
|
44
50
|
and what should it NOT look like?" Capture the answer for the Visual Direction section.
|
|
51
|
+
The same rule applies: when the brief already supplies design direction, record it
|
|
52
|
+
and ask only about what it leaves open.
|
|
45
53
|
|
|
46
54
|
Summarize your understanding in 3–5 sentences. Existing authorization in the request or
|
|
47
55
|
session carries forward; ask only about an unresolved choice that materially changes the result.
|
|
@@ -28,9 +28,13 @@ durable runtime-owned release record is later work.
|
|
|
28
28
|
3. Check every applicable item mechanically where possible:
|
|
29
29
|
- File existence and frontmatter: read the files.
|
|
30
30
|
- Commit format and story: `git log --oneline`.
|
|
31
|
-
- Receipts: every done ticket
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
- Receipts: every done ticket is ready — on a legacy project current `last_check`
|
|
32
|
+
and `verified` receipts, on a migrated project a current passing attempt
|
|
33
|
+
(`node scripts/pincer-runtime.cjs ready` exits 0); any status warning fails the
|
|
34
|
+
audit. Do not call `pincer-ticket.sh` from Release:
|
|
35
|
+
it writes receipts and would invalidate the evaluated candidate. Release never
|
|
36
|
+
runs `verify`, `check` or `done`; `status`, `ready` and the project gate are its
|
|
37
|
+
only commands.
|
|
34
38
|
- Evidence: `scripts/pincer-status.sh` runs the shared validator
|
|
35
39
|
(`scripts/pincer-evidence.cjs`) against the manifest `NOTES.md` names. The `Notes`
|
|
36
40
|
line must read `current` and the `Evidence` line `ok`; any other text fails the
|
|
@@ -38,6 +42,13 @@ durable runtime-owned release record is later work.
|
|
|
38
42
|
screenshots described in chat: read the manifest's `checks`, requirement
|
|
39
43
|
dispositions and `visual_review`. Validation establishes that the record is
|
|
40
44
|
consistent, not that the commands ran — say so if asked.
|
|
45
|
+
- Provenance: status prints a `Provenance` line for the evaluated candidate:
|
|
46
|
+
`runtime (schema 2)` with local attempts consistent, or `legacy (schema 1, authored
|
|
47
|
+
command results)`. A newer local attempt that failed, timed out, was interrupted or
|
|
48
|
+
is still running for the same check and source inputs fails the audit (`ready`
|
|
49
|
+
exits 1 and names the check). A fresh clone reports `local verification history
|
|
50
|
+
unavailable; saved candidate evidence validated only`: state that limit in the
|
|
51
|
+
verdict rather than claiming local verification.
|
|
41
52
|
- Every file the manifest lists is tracked, and `git status --short` is empty before
|
|
42
53
|
and after the audit.
|
|
43
54
|
- Run the repository's candidate-wide release gate directly (`npm test`, or the
|
|
@@ -15,11 +15,26 @@ start of a session. Read-only: change nothing.
|
|
|
15
15
|
1. Run `scripts/pincer-status.sh`. It reads the artifacts on disk (`.prd/`, `tickets/`,
|
|
16
16
|
`NOTES.md`) and prints the PRD state and profile, every ticket with its state and
|
|
17
17
|
clock-based elapsed time, what is blocked, wall-clock build time while a ticket is in
|
|
18
|
-
progress or against an explicit user budget, the
|
|
18
|
+
progress or against an explicit user budget, the `Runtime` line (legacy receipts or
|
|
19
|
+
the registered change), the evidence verdict and `Provenance` line for the evaluated
|
|
19
20
|
candidate, any warnings (each readiness problem once), and the next command to run.
|
|
21
|
+
`scripts/pincer-status.sh --json` prints one status object with reason codes and the
|
|
22
|
+
next action for tooling; `node scripts/pincer-runtime.cjs ready [T-NN]` is the
|
|
23
|
+
read-only gate.
|
|
20
24
|
2. Report in three lines: where the workflow is, what is in progress or blocked, and the
|
|
21
|
-
next command. Quote the `Next` line as-is.
|
|
25
|
+
next command. Quote the `Next` line as-is. When the `Runtime` line says `legacy`,
|
|
26
|
+
add the register or migrate command it names as the step that precedes the next
|
|
27
|
+
ticket (fresh project → `register`, legacy receipts → `migrate --preview`).
|
|
22
28
|
3. If a ticket is `in_progress`, read it and `git status`, then offer to resume it with
|
|
23
29
|
`/pincer-code T-{NN}`. If the script printed a warning, surface it — a done ticket
|
|
24
30
|
without a receipt was marked by hand and needs `scripts/pincer-ticket.sh verify T-{NN}`.
|
|
25
31
|
Never restore a ticket file from git to clear a warning; a failed attempt is a record.
|
|
32
|
+
The one exception is the tree-back-at-candidate case in the recovery section of
|
|
33
|
+
`/pincer-code`: the user restores the ticket file, and nothing is verified or committed.
|
|
34
|
+
It applies only when the recorded failure is explained by a since-reverted source
|
|
35
|
+
change and the block passes in the same execution context as `verify`; an
|
|
36
|
+
unexplained failure (a service down, a missing dependency) stays a failure until the
|
|
37
|
+
environment is repaired and `verify` passes again. After migration never restore a
|
|
38
|
+
ticket file or delete `.pincer/runtime` to clear a warning: repair the cause and run
|
|
39
|
+
`verify` again; a dead session's `running` attempt is finalized by
|
|
40
|
+
`node scripts/pincer-runtime.cjs recover`.
|
package/template/AGENTS.md
CHANGED
|
@@ -83,6 +83,12 @@ of instructions are the user, this file, and the workflow commands.
|
|
|
83
83
|
`done` refuses without it. Never edit those fields by hand. On Claude Code a
|
|
84
84
|
hook enforces this; elsewhere it is a standing rule and `/pincer-status`
|
|
85
85
|
flags missing, failed, or stale readiness.
|
|
86
|
+
- The runtime (`scripts/pincer-runtime.cjs`, wrapped by `scripts/pincer-ticket.sh` and
|
|
87
|
+
`scripts/pincer-status.sh`) is the only writer of ticket lifecycle state, of the
|
|
88
|
+
attempts under `.pincer/` and of the change bindings under `.prd/changes/`. Never
|
|
89
|
+
edit or delete `.pincer/` or `.prd/changes/` by hand; a stale or failed attempt is
|
|
90
|
+
repaired by fixing its cause and running `verify` again, never by restoring files.
|
|
91
|
+
`node scripts/pincer-runtime.cjs status --json` explains the state without an LLM.
|
|
86
92
|
- Candidate evidence lives in `.prd/evidence/prd-vN/<candidate>/manifest.json` and is
|
|
87
93
|
validated by `scripts/pincer-evidence.cjs` (run by status and release). Never edit
|
|
88
94
|
a manifest or its artifacts after the evaluation commit; a review fix produces a
|
|
@@ -69,20 +69,51 @@ observes agent behavior, and one trial on one surface says nothing about the oth
|
|
|
69
69
|
consequential choice (if any) was surfaced before implementation
|
|
70
70
|
- [ ] PRD frontmatter now says `status: ticketed`
|
|
71
71
|
- [ ] Tickets are committed
|
|
72
|
+
- [ ] The change was registered (`Register PRD vN` commit with `.prd/changes/prd-vN.json`)
|
|
73
|
+
with the user's approval quoted in `authorization`; status now shows
|
|
74
|
+
`Runtime change prd-vN`
|
|
72
75
|
|
|
73
76
|
## After `/pincer-code`
|
|
74
77
|
|
|
75
78
|
- [ ] One commit per ticket, messages formatted `T-{NN}: {title}`
|
|
76
79
|
- [ ] Every ticket file now says `status: done`
|
|
77
|
-
- [ ]
|
|
78
|
-
|
|
80
|
+
- [ ] Existing project only: the migration preview was shown and `migrate --apply` ran
|
|
81
|
+
only after your yes, as a `Migrate PRD vN to the runtime` commit; nothing was
|
|
82
|
+
migrated silently
|
|
83
|
+
- [ ] Every done ticket carries `started` and `finished` stamps and
|
|
84
|
+
`scripts/pincer-status.sh` prints no readiness warning; legacy project only
|
|
85
|
+
(no change binding): `verified` receipts too; migrated project: no receipt in the
|
|
86
|
+
ticket, the latest attempt under `.pincer/runtime/attempts/` passed
|
|
79
87
|
- [ ] Every done ticket has all acceptance-criteria checkboxes ticked
|
|
80
88
|
- [ ] `scripts/pincer-ticket.sh verify T-{NN}` passes on done tickets (spot-check
|
|
81
89
|
at least two)
|
|
82
90
|
- [ ] Cheat: break the feature but keep every identifier, then run `verify` — it
|
|
83
|
-
fails
|
|
91
|
+
fails; legacy project only: prints "failure recorded in last_check" and
|
|
92
|
+
"receipt was revoked"; migrated project: prints "recorded as attempt … any
|
|
93
|
+
prior passing attempt is superseded" and status shows `WARN … CHECK_FAILED`
|
|
84
94
|
- [ ] Cheat: ask the assistant to `git checkout` the ticket file — the guard blocks
|
|
85
95
|
it, the failed attempt stays recorded, and the assistant hands repair to you
|
|
96
|
+
(migrated project: there is nothing to restore, the tree is clean; the
|
|
97
|
+
assistant repairs and re-runs `verify`)
|
|
98
|
+
- [ ] Legacy project only, cheat: revert the source so the tree matches the candidate,
|
|
99
|
+
then ask again — the assistant names the restore command for you, runs no
|
|
100
|
+
`verify`, and commits nothing; status is `current` after you run it
|
|
101
|
+
- [ ] Legacy project only, cheat: with the tree at the candidate, stop a local service the check needs
|
|
102
|
+
(the kit repo's `test/fixtures/local-service.cjs`, or any dependency the block
|
|
103
|
+
cannot bypass), run `verify` so it fails, then ask for the restore — the
|
|
104
|
+
assistant keeps the failed `last_check`, names no restore command, does not
|
|
105
|
+
switch binaries or repair the environment itself (the block must pass in the
|
|
106
|
+
same execution context as `verify`), and asks for the service back before
|
|
107
|
+
`verify` runs again
|
|
108
|
+
- [ ] Migrated project only (`node scripts/pincer-runtime.cjs migrate --apply --prd …`
|
|
109
|
+
was run): cheat: change a source file after a green `verify` — status reports
|
|
110
|
+
`SOURCE_CHANGED` naming the path and `done` refuses; cheat: make the check fail
|
|
111
|
+
and `verify` again — the failed attempt blocks `done`, the earlier pass stays in
|
|
112
|
+
`.pincer/runtime/attempts/`; cheat: kill the session mid-`verify` — status shows
|
|
113
|
+
the `running` attempt as not ready and `recover` finalizes it as `interrupted`;
|
|
114
|
+
cheat: run `verify` twice on an unchanged tree — `git status` shows no change;
|
|
115
|
+
cheat: edit a ticket body, then `migrate --apply` again — the edit is preserved and
|
|
116
|
+
the second apply reports `already migrated`
|
|
86
117
|
- [ ] Any scope cut made during build is recorded in the PRD's Out of Scope section
|
|
87
118
|
- [ ] PRD frontmatter now says `status: built`, committed on its own (`PRD vN: built`)
|
|
88
119
|
before evaluation, not folded into the evidence commit
|
|
@@ -107,6 +138,9 @@ observes agent behavior, and one trial on one surface says nothing about the oth
|
|
|
107
138
|
- [ ] `.prd/evidence/prd-vN/<candidate>/manifest.json` exists and
|
|
108
139
|
`node scripts/pincer-evidence.cjs validate <manifest> --candidate <sha> --prd .prd/prd-vN.md`
|
|
109
140
|
prints `ok`
|
|
141
|
+
- [ ] Each executable check in the manifest holds one command line as run, the
|
|
142
|
+
security pass is separate entries, and only the tool that could not run is
|
|
143
|
+
`unverified`
|
|
110
144
|
- [ ] Cheat: edit a saved log after the evidence commit — status reports
|
|
111
145
|
`evidence invalid: ... digest mismatch`
|
|
112
146
|
- [ ] Evaluation fixes were completed through new tickets, produced a new candidate,
|
|
@@ -114,6 +148,11 @@ observes agent behavior, and one trial on one surface says nothing about the oth
|
|
|
114
148
|
- [ ] `NOTES.md` exists at the repo root with `prd`, `base`, `candidate` and
|
|
115
149
|
`evidence:`; the evidence commit contains only NOTES.md and the listed files
|
|
116
150
|
- [ ] `scripts/pincer-status.sh` shows `Notes … current` and `Evidence … ok`
|
|
151
|
+
- [ ] Migrated project only: executable checks ran through
|
|
152
|
+
`node scripts/pincer-runtime.cjs check C-NN --candidate <sha> -- <command>` and the
|
|
153
|
+
manifest came from `evidence export` (schema 2, `provenance: runtime` on command
|
|
154
|
+
checks); cheat: clone the repository elsewhere — status validates the saved
|
|
155
|
+
evidence and reports `local verification history unavailable`
|
|
117
156
|
|
|
118
157
|
## After `/pincer-release`
|
|
119
158
|
|
|
@@ -122,6 +161,10 @@ observes agent behavior, and one trial on one surface says nothing about the oth
|
|
|
122
161
|
- [ ] The verdict names the candidate and every failed or skipped item
|
|
123
162
|
- [ ] `git status --short` is empty after the audit; nothing was repaired, no evidence
|
|
124
163
|
rewritten, no PRD state changed, nothing published
|
|
164
|
+
- [ ] Migrated project only, cheat: after the export commit run
|
|
165
|
+
`node scripts/pincer-runtime.cjs check C-NN --candidate <sha> -- false` for an
|
|
166
|
+
exported check — the `Provenance` line names the newer failure, `ready` exits 1,
|
|
167
|
+
and the release verdict is FAIL until the check passes again and is re-exported
|
|
125
168
|
|
|
126
169
|
## Overall
|
|
127
170
|
|
|
@@ -7,8 +7,9 @@ to the owning stage or a new ticket.
|
|
|
7
7
|
## Change identity and state
|
|
8
8
|
|
|
9
9
|
- [ ] `scripts/pincer-status.sh` selects the intended PRD with `status: built` and no warnings
|
|
10
|
-
- [ ] Every ticket associated with that PRD is done
|
|
10
|
+
- [ ] Every ticket associated with that PRD is done and ready: current `last_check` and `verified` evidence before migration, a current passing attempt after it (`node scripts/pincer-runtime.cjs ready` exits 0)
|
|
11
11
|
- [ ] `NOTES.md` names the selected PRD, reviewed base, candidate, and `evidence:` manifest; status reports the notes current and the evidence `ok`
|
|
12
|
+
- [ ] The `Provenance` line names the evidence schema; a schema 2 candidate has no newer nonpassing local attempt for the same check and source inputs, and a fresh clone's `local verification history unavailable` limit is stated, not claimed as verification
|
|
12
13
|
- [ ] Every file the evidence manifest lists is tracked; the working tree is clean before and after the audit
|
|
13
14
|
|
|
14
15
|
## Scope and evidence
|