pincer-workflow 0.2.2 → 0.3.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 +16 -15
- package/bin/pincer.js +52 -12
- package/package.json +2 -2
- package/template/.agents/skills/pincer-code/SKILL.md +19 -16
- package/template/.agents/skills/pincer-evaluate/SKILL.md +28 -9
- package/template/.agents/skills/pincer-narrow/SKILL.md +27 -21
- package/template/.agents/skills/pincer-plan/SKILL.md +28 -20
- package/template/.agents/skills/pincer-release/SKILL.md +14 -9
- package/template/.agents/skills/pincer-status/SKILL.md +1 -1
- package/template/.claude/commands/pincer-code.md +18 -15
- package/template/.claude/commands/pincer-evaluate.md +28 -9
- package/template/.claude/commands/pincer-narrow.md +25 -19
- package/template/.claude/commands/pincer-plan.md +26 -18
- package/template/.claude/commands/pincer-release.md +13 -8
- package/template/.claude/commands/pincer-status.md +1 -1
- package/template/.claude/hooks/block-dangerous.sh +7 -18
- package/template/.claude/hooks/hook-policy.cjs +258 -0
- package/template/.claude/hooks/ticket-guard.sh +6 -63
- package/template/.claude/references/prd-template.md +3 -3
- package/template/.claude/references/ticket-template.md +22 -4
- package/template/.codex/README.md +8 -4
- package/template/.github/prompts/pincer-code.prompt.md +18 -15
- package/template/.github/prompts/pincer-evaluate.prompt.md +28 -9
- package/template/.github/prompts/pincer-narrow.prompt.md +25 -19
- package/template/.github/prompts/pincer-plan.prompt.md +26 -18
- package/template/.github/prompts/pincer-release.prompt.md +13 -8
- package/template/.github/prompts/pincer-status.prompt.md +1 -1
- package/template/AGENTS.md +2 -3
- package/template/docs/dry-run-checklist.md +19 -15
- package/template/docs/release-checklist.md +34 -0
- package/template/scripts/pincer-status.sh +64 -23
- package/template/scripts/pincer-ticket-lib.sh +270 -0
- package/template/scripts/pincer-ticket.sh +57 -46
- package/template/scripts/sync-prompts.sh +6 -1
package/README.md
CHANGED
|
@@ -47,13 +47,13 @@ install as skills under `.agents/skills/`, which Codex discovers from the repo
|
|
|
47
47
|
loaded. Inside the Codex skills every cross-reference already reads
|
|
48
48
|
`$pincer-narrow`, `$pincer-status` and so on.
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
`~/.codex/config.toml`
|
|
50
|
+
Pincer does not currently install a Codex hook adapter, so its Codex guardrail
|
|
51
|
+
posture uses `~/.codex/config.toml` — `approval_policy = "on-request"` and
|
|
52
52
|
`sandbox_mode = "workspace-write"`; never run with approvals disabled. The
|
|
53
53
|
ticket scripts (`scripts/pincer-ticket.sh`, `scripts/pincer-status.sh`) are
|
|
54
54
|
plain bash and work unchanged; the rule in `AGENTS.md` against hand-editing
|
|
55
55
|
ticket state carries the weight the hook carries on Claude Code, and
|
|
56
|
-
`$pincer-status` flags
|
|
56
|
+
`$pincer-status` flags missing, failed, or stale ticket readiness.
|
|
57
57
|
Full notes in `.codex/README.md`.
|
|
58
58
|
|
|
59
59
|
### GitHub Copilot (VS Code)
|
|
@@ -65,7 +65,7 @@ in chat. `.github/copilot-instructions.md` is wired to `AGENTS.md`.
|
|
|
65
65
|
|
|
66
66
|
Claude users can install PINCER as a plugin instead — commands arrive
|
|
67
67
|
namespaced (`/pincer:plan` … `/pincer:release`) and update automatically
|
|
68
|
-
through the marketplace
|
|
68
|
+
through the marketplace. The plugin's structured hook parser requires Node.js 18+:
|
|
69
69
|
|
|
70
70
|
```
|
|
71
71
|
/plugin marketplace add orchestratedbyalex/pincer-workflow
|
|
@@ -86,7 +86,7 @@ want the repo-side rules too can copy `AGENTS.md` from the
|
|
|
86
86
|
npx pincer-workflow@latest update
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
Files you never touched are refreshed in place. (Installs older than v0.2.0 gain the ticket state machine, the status report and the ticket-guard hook on update; `.claude/settings.json` conflicts if you edited it — merge the new hook entry from the `.new` file. v0.2.2 replaces the Codex adapter: the commands are now skills in `.agents/skills/` invoked as `$pincer-*`, since Codex no longer loads `~/.codex/prompts/` — you can delete the copies there.) Files you edited are left
|
|
89
|
+
Files you never touched are refreshed in place. (Installs older than v0.2.0 gain the ticket state machine, the status report and the ticket-guard hook on update; `.claude/settings.json` conflicts if you edited it — merge the new hook entry from the `.new` file. v0.2.2 replaces the Codex adapter: the commands are now skills in `.agents/skills/` invoked as `$pincer-*`, since Codex no longer loads `~/.codex/prompts/` — you can delete the copies there. v0.2.3 ships the playbooks, rubrics and templates under `.claude/` on every platform, which Codex- and Copilot-only installs were missing. v0.3.0 makes trust revocable: every verification attempt is recorded, `done` re-runs the check, tickets carry `prd:`, the release audit is read-only, and `.pincer.json` moves to schema 2 — an install from 0.2.x is treated as an untrusted baseline, so on the first update every changed file arrives as a `.new` proposal once; hooks now need Node 18+.) Files you edited are left
|
|
90
90
|
alone — the new version lands next to them as `<file>.new` for a manual merge.
|
|
91
91
|
`npx pincer-workflow doctor` checks the health of an install (hook executable,
|
|
92
92
|
`.gitignore` covering `.env*`, no unmerged `*.new` files, version current).
|
|
@@ -96,21 +96,22 @@ alone — the new version lands next to them as `<file>.new` for a manual merge.
|
|
|
96
96
|
| Piece | Purpose |
|
|
97
97
|
| --- | --- |
|
|
98
98
|
| `AGENTS.md` | Project rules, single cross-platform source (workflow order, security defaults, secrets, untrusted-content and dependency rules) |
|
|
99
|
-
| `.claude/commands/` | The five playbooks plus `/pincer-status` (canonical — adapters are generated from them) |
|
|
99
|
+
| `.claude/commands/` | The five playbooks plus `/pincer-status` (canonical — adapters are generated from them; ships on every platform together with `agents/` and `references/`) |
|
|
100
100
|
| `.claude/agents/` | `codebase-explorer` and `code-quality-reviewer` subagents, with inline fallbacks for platforms without subagents |
|
|
101
101
|
| `scripts/pincer-ticket.sh` | The ticket state machine: `start` (enforces dependency order) → `verify` (runs the ticket's check, stamps a receipt only on green) → `done` (refuses without a matching receipt or with unticked criteria) |
|
|
102
|
-
| `scripts/pincer-status.sh` | Read-only state report: PRD,
|
|
103
|
-
| `.claude/hooks/` + `settings.json` |
|
|
102
|
+
| `scripts/pincer-status.sh` | Read-only state report: current PRD, associated tickets, clock-based elapsed time, optional user budget, warnings, and next command |
|
|
103
|
+
| `.claude/hooks/` + `settings.json` | Claude guardrails for documented destructive command forms and ticket state writes; Node.js 18+ parses hook payloads structurally |
|
|
104
104
|
| `.agents/skills/` · `.codex/` · `.github/` | Generated Codex skills and Copilot prompt files + platform wiring (`.codex/README.md` covers the Codex posture) |
|
|
105
105
|
| `scripts/sync-prompts.sh` | Regenerates the adapters after you edit a playbook |
|
|
106
106
|
| `scripts/build-plugin.sh` | Regenerates the Claude Code plugin (`plugin/`) from the template |
|
|
107
|
-
| `docs/
|
|
107
|
+
| `docs/release-checklist.md` | General, read-only candidate audit used by `/pincer-release` |
|
|
108
|
+
| `docs/dry-run-checklist.md` | Separate manual platform trial for the Pincer kit |
|
|
108
109
|
|
|
109
110
|
## Design principles
|
|
110
111
|
|
|
111
|
-
- **Approval gates scale with decision cost** — a human owns
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
- **Approval gates scale with decision cost** — a human owns architecture, scope,
|
|
113
|
+
and merge decisions; unchanged authorization persists across resume and routine
|
|
114
|
+
verification, while explicit budgets shape the depth of work.
|
|
114
115
|
- **Nothing is done while its verification fails** — every ticket carries a
|
|
115
116
|
runnable check, and "done" is a state only a passing run of that check can
|
|
116
117
|
unlock: the receipt is stamped by the script, never typed by the agent.
|
|
@@ -121,9 +122,9 @@ alone — the new version lands next to them as `<file>.new` for a manual merge.
|
|
|
121
122
|
- **Security is threaded through every stage** — designed in at Plan, specified
|
|
122
123
|
as reject-path criteria at Narrow, enforced by a pre-commit sweep at Code,
|
|
123
124
|
audited mechanically at Evaluate and Release.
|
|
124
|
-
- **
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
- **Layered guardrails** — Claude hooks cover documented high-risk command and
|
|
126
|
+
ticket-state forms, while sandbox and approval controls remain the security
|
|
127
|
+
boundary. Other platforms use their native controls plus `/pincer-release`.
|
|
127
128
|
|
|
128
129
|
## License
|
|
129
130
|
|
package/bin/pincer.js
CHANGED
|
@@ -19,10 +19,15 @@ import { createRequire } from 'node:module';
|
|
|
19
19
|
const TEMPLATE = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'template');
|
|
20
20
|
const VERSION = createRequire(import.meta.url)('../package.json').version;
|
|
21
21
|
const MANIFEST = '.pincer.json';
|
|
22
|
+
const MANIFEST_SCHEMA = 2;
|
|
22
23
|
|
|
24
|
+
// The playbooks, subagent rubrics and PRD/ticket templates under .claude/ are
|
|
25
|
+
// the canonical kit and are read by every platform's adapter (the Codex skills
|
|
26
|
+
// and Copilot prompts point at them), so they ship everywhere; only Claude
|
|
27
|
+
// Code's own wiring (CLAUDE.md, settings.json, hooks) is platform-specific.
|
|
23
28
|
const PLATFORM_ROOTS = {
|
|
24
|
-
common: ['AGENTS.md', 'docs/dry-run-checklist.md', 'scripts/sync-prompts.sh', 'scripts/pincer-ticket.sh', 'scripts/pincer-status.sh'],
|
|
25
|
-
claude: ['CLAUDE.md', '.claude'],
|
|
29
|
+
common: ['AGENTS.md', 'docs/release-checklist.md', 'docs/dry-run-checklist.md', 'scripts/sync-prompts.sh', 'scripts/pincer-ticket.sh', 'scripts/pincer-ticket-lib.sh', 'scripts/pincer-status.sh', '.claude/commands', '.claude/agents', '.claude/references'],
|
|
30
|
+
claude: ['CLAUDE.md', '.claude/settings.json', '.claude/hooks'],
|
|
26
31
|
codex: ['.codex', '.agents'],
|
|
27
32
|
copilot: ['.github'],
|
|
28
33
|
};
|
|
@@ -49,17 +54,40 @@ function readManifest(dir) {
|
|
|
49
54
|
const p = path.join(dir, MANIFEST);
|
|
50
55
|
if (!fs.existsSync(p)) return null;
|
|
51
56
|
try {
|
|
52
|
-
|
|
57
|
+
const data = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
58
|
+
if (!data || !Array.isArray(data.platforms) || !data.platforms.length ||
|
|
59
|
+
!data.platforms.every(p => ['claude', 'codex', 'copilot'].includes(p)) ||
|
|
60
|
+
!data.files || typeof data.files !== 'object' || Array.isArray(data.files) ||
|
|
61
|
+
Object.keys(data.files).some(p => path.isAbsolute(p) || p.split(/[\\/]/).includes('..')) ||
|
|
62
|
+
(data.schema !== undefined && data.schema !== MANIFEST_SCHEMA)) {
|
|
63
|
+
fail(`${MANIFEST} has an unsupported or invalid schema — restore a valid manifest before updating.`);
|
|
64
|
+
}
|
|
65
|
+
return data;
|
|
53
66
|
} catch {
|
|
54
67
|
fail(`${MANIFEST} exists but is not valid JSON — fix or remove it first.`);
|
|
55
68
|
}
|
|
56
69
|
}
|
|
57
70
|
|
|
58
71
|
function writeManifest(dir, platforms, hashes) {
|
|
59
|
-
const data = { version: VERSION, platforms, files: hashes };
|
|
72
|
+
const data = { schema: MANIFEST_SCHEMA, version: VERSION, platforms, files: hashes };
|
|
60
73
|
fs.writeFileSync(path.join(dir, MANIFEST), JSON.stringify(data, null, 2) + '\n');
|
|
61
74
|
}
|
|
62
75
|
|
|
76
|
+
// Preserve in-progress merges too. Reuse an identical proposal, never replace
|
|
77
|
+
// a different existing sidecar (including one left by an earlier release).
|
|
78
|
+
function writeProposal(dest, content) {
|
|
79
|
+
const base = dest + '.new';
|
|
80
|
+
let proposal = base;
|
|
81
|
+
let suffix = 0;
|
|
82
|
+
while (fs.existsSync(proposal)) {
|
|
83
|
+
if (fs.readFileSync(proposal).equals(content)) return proposal;
|
|
84
|
+
proposal = `${base}.${sha(content).slice(0, 12)}${suffix ? `.${suffix}` : ''}`;
|
|
85
|
+
suffix++;
|
|
86
|
+
}
|
|
87
|
+
fs.writeFileSync(proposal, content, { flag: 'wx' });
|
|
88
|
+
return proposal;
|
|
89
|
+
}
|
|
90
|
+
|
|
63
91
|
// Copies template files into dir. `baseline` (manifest hashes) tells an update
|
|
64
92
|
// which existing files are unmodified and therefore safe to refresh.
|
|
65
93
|
function install(dir, platforms, baseline) {
|
|
@@ -86,9 +114,11 @@ function install(dir, platforms, baseline) {
|
|
|
86
114
|
fs.writeFileSync(dest, src);
|
|
87
115
|
results.written.push(rel);
|
|
88
116
|
} else {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
117
|
+
const proposal = writeProposal(dest, src);
|
|
118
|
+
// Only a version actually installed by us grants overwrite permission.
|
|
119
|
+
// null means we have never established a trusted upstream baseline.
|
|
120
|
+
hashes[rel] = baseline?.[rel] ?? null;
|
|
121
|
+
results.conflicted.push({ rel, proposal: path.relative(dir, proposal) });
|
|
92
122
|
}
|
|
93
123
|
}
|
|
94
124
|
|
|
@@ -115,11 +145,11 @@ function ensureGitignore(dir) {
|
|
|
115
145
|
function report({ written, skipped, conflicted }) {
|
|
116
146
|
if (written.length) console.log(` wrote ${written.length} file(s)`);
|
|
117
147
|
if (skipped.length) console.log(` skipped ${skipped.length} file(s) already up to date`);
|
|
118
|
-
for (const rel of conflicted) {
|
|
119
|
-
console.log(` CONFLICT ${rel} —
|
|
148
|
+
for (const { rel, proposal } of conflicted) {
|
|
149
|
+
console.log(` CONFLICT ${rel} — local content preserved; the new version is at ${proposal}`);
|
|
120
150
|
}
|
|
121
151
|
if (conflicted.length) {
|
|
122
|
-
console.log('\n
|
|
152
|
+
console.log('\n Review and merge each reported proposal, then remove the resolved sidecars.');
|
|
123
153
|
}
|
|
124
154
|
}
|
|
125
155
|
|
|
@@ -180,7 +210,11 @@ async function cmdUpdate() {
|
|
|
180
210
|
const manifest = readManifest(dir);
|
|
181
211
|
if (!manifest) fail(`no ${MANIFEST} here — run \`pincer init\` first.`);
|
|
182
212
|
console.log(`\nUpdating PINCER ${manifest.version} -> ${VERSION} for: ${manifest.platforms.join(', ')}\n`);
|
|
183
|
-
|
|
213
|
+
// v1 manifests could adopt a local edit as their baseline. There is no safe
|
|
214
|
+
// way to distinguish those from upstream files after the fact.
|
|
215
|
+
const baseline = manifest.schema === MANIFEST_SCHEMA ? manifest.files : null;
|
|
216
|
+
if (!baseline) console.log(' Legacy baselines are untrusted; differing files will be preserved for review.');
|
|
217
|
+
report(install(dir, manifest.platforms, baseline));
|
|
184
218
|
}
|
|
185
219
|
|
|
186
220
|
function cmdDoctor() {
|
|
@@ -217,7 +251,13 @@ function cmdDoctor() {
|
|
|
217
251
|
console.log(` note locally edited (kept as-is on update): ${edited.join(', ')}`);
|
|
218
252
|
}
|
|
219
253
|
|
|
220
|
-
const leftovers = walk(TEMPLATE)
|
|
254
|
+
const leftovers = [...new Set([...walk(TEMPLATE), ...Object.keys(manifest.files)])].flatMap(rel => {
|
|
255
|
+
const parent = path.dirname(path.join(dir, rel));
|
|
256
|
+
const base = path.basename(rel) + '.new';
|
|
257
|
+
return fs.existsSync(parent) ? fs.readdirSync(parent)
|
|
258
|
+
.filter(name => name === base || name.startsWith(base + '.'))
|
|
259
|
+
.map(name => path.join(parent, name)) : [];
|
|
260
|
+
});
|
|
221
261
|
check(leftovers.length === 0, 'no unmerged *.new files', leftovers.map((p) => path.relative(dir, p)).join(', '));
|
|
222
262
|
|
|
223
263
|
console.log(problems ? `\n${problems} problem(s) found.` : '\nAll good.');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pincer-workflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "PINCER — a PRD-driven agentic delivery workflow for Claude Code, Codex CLI, and GitHub Copilot. Plan · Investigate · Narrow · Code · Evaluate · Release.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"pincer": "bin/pincer.js"
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"node": ">=18"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
-
"test": "node test/smoke.test.js && node test/ticket.test.js"
|
|
17
|
+
"test": "node test/smoke.test.js && node test/installer.test.js && node test/ticket.test.js && node test/validation.test.js && node test/verification.test.js && node test/recovery.test.js && node test/hooks.test.js && node test/workflow.test.js && node test/distribution.test.js"
|
|
18
18
|
},
|
|
19
19
|
"keywords": [
|
|
20
20
|
"claude-code",
|
|
@@ -7,30 +7,32 @@ description: "Implement tickets sequentially with verification and one commit pe
|
|
|
7
7
|
|
|
8
8
|
# $pincer-code — Ticket Implementation
|
|
9
9
|
|
|
10
|
-
You are implementing the tickets in `tickets/` sequentially.
|
|
11
|
-
|
|
10
|
+
You are implementing the tickets in `tickets/` sequentially. The approved PRD, ticket
|
|
11
|
+
breakdown, and existing session authorization define the work; run continuously and report
|
|
12
|
+
progress between tickets unless a material scope or design decision appears.
|
|
12
13
|
|
|
13
|
-
**Initial request:** the text that follows the `$pincer-code` mention
|
|
14
|
+
**Initial request:** the text that follows the `$pincer-code` mention, if any (when omitted, use the playbook's documented default)
|
|
14
15
|
|
|
15
16
|
Ticket state lives in the ticket file's frontmatter and is written **only** by
|
|
16
17
|
`scripts/pincer-ticket.sh` (`start` → `verify` → `done`). `verify` runs the ticket's
|
|
17
18
|
Verification block and stamps a receipt only on a green exit; `done` refuses without a
|
|
18
19
|
receipt that matches the current check, or with unticked acceptance criteria. Never edit
|
|
19
|
-
`status`, `started`, `verified`, or `finished` by hand — on Claude Code a hook blocks it.
|
|
20
|
+
`status`, `started`, `last_check`, `verified`, or `finished` by hand — on Claude Code a hook blocks it.
|
|
20
21
|
|
|
21
22
|
## Before the loop
|
|
22
23
|
|
|
23
24
|
Run `scripts/pincer-status.sh`. It lists every ticket's state, what is blocked, elapsed
|
|
24
25
|
build time from the clock, and the next action. If a ticket is `in_progress`, you are
|
|
25
26
|
resuming: read it, check `git status` / `git diff` for uncommitted work, and continue
|
|
26
|
-
from wherever the receipt says you are.
|
|
27
|
+
from wherever the receipt says you are. Do not ask the user to reconfirm unchanged,
|
|
28
|
+
previously authorized work.
|
|
27
29
|
|
|
28
30
|
## Loop (per ticket, in dependency order)
|
|
29
31
|
|
|
30
32
|
1. **Start:** `scripts/pincer-ticket.sh start T-{NN}` — refuses while a `depends_on` ticket
|
|
31
33
|
isn't done, and stamps the start time. Read the ticket and the files it references.
|
|
32
34
|
Announce: "Starting T-{NN}: {title}."
|
|
33
|
-
2. **Implement.** Follow the conventions in `
|
|
35
|
+
2. **Implement.** Follow the conventions in `AGENTS.md` and the PRD's architecture and
|
|
34
36
|
visual direction. Installing a dependency not named in the PRD's architecture is a
|
|
35
37
|
stop-and-ask: verify it's the real package on the registry (linked repo, downloads —
|
|
36
38
|
hallucinated names get typosquatted), say why it earns its place, and wait for a yes.
|
|
@@ -43,26 +45,27 @@ from wherever the receipt says you are. Confirm the starting point with the user
|
|
|
43
45
|
4. **Self-review the diff** before committing: silent failures (empty catches,
|
|
44
46
|
un-awaited promises), leftover debug code, drift from the ticket's acceptance criteria.
|
|
45
47
|
Then a security sweep of the same diff:
|
|
46
|
-
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
`.env.example` as a blocker.
|
|
48
|
+
- Check for secret-like assignments without printing values. If a scanner reports a
|
|
49
|
+
possible secret, report only its file and line until the value is safely redacted;
|
|
50
|
+
environment references and names in `.env.example` are allowed.
|
|
50
51
|
- External input touched by this diff is validated server-side, and untrusted
|
|
51
52
|
content (user input, LLM output) is escaped where rendered — per the
|
|
52
|
-
Security defaults in `
|
|
53
|
+
Security defaults in `AGENTS.md`.
|
|
53
54
|
- No error path leaks internals (stack traces, key names with values) to the client.
|
|
54
55
|
If the review changed code, run `verify` again — the receipt must match the code you commit.
|
|
55
56
|
5. **Close the ticket:** tick every verified acceptance-criteria checkbox (`- [ ]` → `- [x]`;
|
|
56
57
|
editing the checkboxes is allowed), then `scripts/pincer-ticket.sh done T-{NN}`. A
|
|
57
58
|
criterion that was cut is a scope change to record in the PRD, not a box to skip.
|
|
58
|
-
|
|
59
|
+
Inspect `git status --short`, preserve pre-existing staged work, and stage only the
|
|
60
|
+
explicit paths changed for this ticket plus its ticket file. Review `git diff --cached`
|
|
61
|
+
before committing as `T-{NN}: {title}`.
|
|
59
62
|
6. Give a one-line progress update using the elapsed figure from
|
|
60
|
-
`scripts/pincer-status.sh` ("T-02 done, 3 remaining, 38m elapsed
|
|
63
|
+
`scripts/pincer-status.sh` ("T-02 done, 3 remaining, 38m elapsed") and continue.
|
|
61
64
|
|
|
62
|
-
##
|
|
65
|
+
## Budget rules
|
|
63
66
|
|
|
64
|
-
-
|
|
65
|
-
|
|
67
|
+
- If the user set `PINCER_BUILD_BUDGET_MIN` or stated another budget, use the elapsed
|
|
68
|
+
figure from `scripts/pincer-status.sh` rather than estimating. If the remaining tickets won't fit,
|
|
66
69
|
stop and propose a scope cut: which remaining tickets to drop or shrink. Cutting scope
|
|
67
70
|
deliberately beats an unfinished mess — record the cut in the PRD's Out of Scope.
|
|
68
71
|
- If a ticket reveals the plan was wrong, stop and say so rather than silently diverging.
|
|
@@ -12,10 +12,15 @@ run the pipeline, then present results.
|
|
|
12
12
|
|
|
13
13
|
## Steps
|
|
14
14
|
|
|
15
|
-
1. Run `scripts/pincer-status.sh`.
|
|
15
|
+
1. Run `scripts/pincer-status.sh`. Review only tickets associated with the selected
|
|
16
|
+
PRD. Every such ticket should be `done` with a current receipt; if one
|
|
16
17
|
is still open or in progress, stop and ask whether it was cut (then it goes in the
|
|
17
18
|
PRD's Out of Scope) or should be finished first via `$pincer-code`. Then get the full
|
|
18
|
-
diff of the
|
|
19
|
+
diff of the change: identify the actual base commit before this change from
|
|
20
|
+
its ticket commits and recorded context. If it cannot be established, resolve
|
|
21
|
+
that uncertainty before claiming a complete review. Record full commit IDs for
|
|
22
|
+
`base` and `candidate` (`git rev-parse HEAD`), then review `git diff <base>..<candidate>`.
|
|
23
|
+
Require a clean candidate before review, excluding only the notes being written.
|
|
19
24
|
2. Dispatch a `code-quality-reviewer` agent with: the diff, the PRD's Success Criteria and
|
|
20
25
|
Scope sections, and the list of tickets. If the diff is large, split by area and
|
|
21
26
|
dispatch two in parallel. (No subagents on this platform? Review the diff yourself
|
|
@@ -25,10 +30,11 @@ run the pipeline, then present results.
|
|
|
25
30
|
4. If the project has a UI, look at it — don't only read the code. Start it, open it in
|
|
26
31
|
the browser (screenshot via Chrome DevTools MCP if available), and check it against
|
|
27
32
|
the PRD's Visual Direction and Success Criteria. Note anything visibly broken or off.
|
|
28
|
-
5. Run a mechanical security audit
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
a secret committed then deleted is
|
|
33
|
+
5. Run a mechanical security audit:
|
|
34
|
+
- Inspect the relevant history with a secret scanner that redacts values, when one is
|
|
35
|
+
available. Otherwise review likely locations without copying candidate values into
|
|
36
|
+
output. Report file, line, and remediation only; a secret committed then deleted is
|
|
37
|
+
still leaked.
|
|
32
38
|
- `.gitignore` covers `.env*` (except `.env.example`), and `git ls-files | grep -i env`
|
|
33
39
|
shows only `.env.example`.
|
|
34
40
|
- `npm audit --omit=dev` (or the ecosystem's equivalent) — report high/critical only.
|
|
@@ -39,9 +45,22 @@ run the pipeline, then present results.
|
|
|
39
45
|
7. Present findings as a short list with `file:line` references, ordered by severity.
|
|
40
46
|
Security findings always rank above style-adjacent ones. For each, say whether you
|
|
41
47
|
recommend fixing now (within the timebox) or noting as known-issue.
|
|
42
|
-
8. Fix
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
8. Fix findings clearly within the authorized PRD through a new ticket associated with
|
|
49
|
+
that PRD. Use `pincer-ticket.sh` to start, verify, and close it, then make a scoped
|
|
50
|
+
`T-{NN}: {title}` commit. Ask only when a fix changes scope, architecture, or another
|
|
51
|
+
material decision; never make an ad-hoc `review: fixes` commit.
|
|
52
|
+
9. Close out: write a brief `NOTES.md` at the repo root with frontmatter:
|
|
53
|
+
```yaml
|
|
54
|
+
---
|
|
55
|
+
prd: .prd/prd-vN.md
|
|
56
|
+
base: <full reviewed base commit ID>
|
|
57
|
+
candidate: <full reviewed candidate commit ID>
|
|
58
|
+
---
|
|
59
|
+
```
|
|
60
|
+
Record the candidate before the separate NOTES commit. Status accepts a later
|
|
61
|
+
commit only when its diff from the candidate changes solely `NOTES.md`; changes
|
|
62
|
+
to source, tickets, or PRD require reevaluation. Legacy notes without these
|
|
63
|
+
references do not establish readiness. Then describe what was built, what was cut
|
|
45
64
|
and why, known issues, and what you'd do next with more time. Then a **Handover**
|
|
46
65
|
section, written for the stranger who inherits this repo in six months: how to get
|
|
47
66
|
oriented (which file to read first), what each dependency is for and why it earned
|
|
@@ -7,22 +7,26 @@ description: "Turn the approved PRD into local, AI-ready ticket files"
|
|
|
7
7
|
|
|
8
8
|
# $pincer-narrow — PRD to Local Tickets
|
|
9
9
|
|
|
10
|
-
You are decomposing the PRD into
|
|
11
|
-
markdown files (no external tracker needed).
|
|
12
|
-
|
|
10
|
+
You are decomposing the PRD into coherent, independently verifiable tickets stored as
|
|
11
|
+
local markdown files (no external tracker needed). Ticket count and size follow the
|
|
12
|
+
change's dependencies and risk, plus any budget the user supplied.
|
|
13
13
|
|
|
14
|
-
**Initial request:** the text that follows the `$pincer-narrow` mention
|
|
14
|
+
**Initial request:** the text that follows the `$pincer-narrow` mention, if any (when omitted, use the playbook's documented default)
|
|
15
15
|
|
|
16
16
|
## Steps
|
|
17
17
|
|
|
18
|
-
1. Run `scripts/pincer-status.sh`. If tickets already exist
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
1. Run `scripts/pincer-status.sh`. If tickets already exist for another PRD, leave them
|
|
19
|
+
as history. New tickets continue the numbering and existing ones are never renumbered.
|
|
20
|
+
If tickets already exist for this PRD, extend them only when the current request already
|
|
21
|
+
authorizes that work; otherwise present the concrete addition before asking. Then read the
|
|
22
|
+
PRD (`the text that follows the `$pincer-narrow` mention, if any (when omitted, use the playbook's documented default)` or the latest `.prd/prd-v*.md`). If its status isn't `draft`, ask
|
|
21
23
|
which PRD to use.
|
|
22
24
|
2. Decompose into tickets. Rules:
|
|
23
|
-
- Each ticket is one coherent unit
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
- Each ticket is one coherent unit. Use S, M, or L as relative scope indicators and
|
|
26
|
+
split work when that improves dependency order, verification, or ownership.
|
|
27
|
+
- For greenfield work, use a walking skeleton when it reduces integration risk. For
|
|
28
|
+
brownfield work, begin with the smallest protected vertical change; add a
|
|
29
|
+
characterization ticket before changing load-bearing code that lacks coverage.
|
|
26
30
|
- Order by dependency; note blockers explicitly ("depends on T-01").
|
|
27
31
|
- Every ticket gets a runnable command in its Verification block — a fenced `bash`
|
|
28
32
|
block that exits 0 only when the ticket is done. `scripts/pincer-ticket.sh verify`
|
|
@@ -34,20 +38,22 @@ build window.
|
|
|
34
38
|
LLM output) gets an acceptance criterion for the reject path — what invalid
|
|
35
39
|
input produces (e.g. "empty goal → 400 with a clear message"), not only the
|
|
36
40
|
happy path.
|
|
37
|
-
-
|
|
38
|
-
`.env.example`) and an `.env.example` naming any required secrets
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
is preceded by a characterization ticket — a test that pins the current
|
|
42
|
-
behavior before any ticket is allowed to change it.
|
|
41
|
+
- A greenfield setup ticket includes `.gitignore` covering `.env*` (except
|
|
42
|
+
`.env.example`) and an `.env.example` naming any required secrets before any
|
|
43
|
+
secret can exist in the repo. In brownfield repositories, preserve and verify
|
|
44
|
+
the existing ignore and environment conventions.
|
|
43
45
|
3. Write each ticket to `tickets/T-{NN}-{slug}.md` using
|
|
44
|
-
`.claude/references/ticket-template.md`, with `status: open
|
|
45
|
-
|
|
46
|
+
`.claude/references/ticket-template.md`, with `status: open` and an explicit
|
|
47
|
+
`prd: .prd/prd-vN.md` naming the selected PRD. Never infer this association from
|
|
48
|
+
numbering or old notes. The other state fields
|
|
49
|
+
(`started`, `last_check`, `verified`, `finished`) are added later by `scripts/pincer-ticket.sh` —
|
|
46
50
|
never write them yourself.
|
|
47
51
|
4. Present the ticket list (number, title, size, dependencies) as a table.
|
|
48
52
|
|
|
49
|
-
|
|
53
|
+
Present the concrete breakdown and build order. Reuse existing authorization for the same
|
|
54
|
+
scope and order; ask only when the breakdown introduces a material decision or scope change.
|
|
50
55
|
|
|
51
|
-
5.
|
|
52
|
-
|
|
56
|
+
5. Once authorized, update the selected PRD frontmatter to `status: ticketed`. Inspect
|
|
57
|
+
existing staged changes, stage that PRD and the explicit new ticket paths, review
|
|
58
|
+
`git diff --cached`, and commit only those paths. Finish with:
|
|
53
59
|
"Tickets ready in `tickets/`. Run `$pincer-code` to start implementing."
|
|
@@ -7,19 +7,21 @@ description: "Create a PRD through brief discovery, codebase scan, and an archit
|
|
|
7
7
|
|
|
8
8
|
# $pincer-plan — PRD Creation
|
|
9
9
|
|
|
10
|
-
You are turning a task brief into a
|
|
11
|
-
|
|
10
|
+
You are turning a task brief into a reviewable PRD. Scale discovery and detail to
|
|
11
|
+
the change's uncertainty, risk, and any time budget the user supplied. The PRD feeds
|
|
12
12
|
`$pincer-narrow` next.
|
|
13
13
|
|
|
14
|
-
**Initial request:** the text that follows the `$pincer-plan` mention in the user's message (ask
|
|
14
|
+
**Initial request:** the text that follows the `$pincer-plan` mention in the user's message (ask only if the required input is missing)
|
|
15
15
|
|
|
16
|
-
First run `scripts/pincer-status.sh`. If a PRD already exists,
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
First run `scripts/pincer-status.sh`. If a PRD already exists, preserve it and select
|
|
17
|
+
the next unused numeric version for this change. Use the brief and repository state to
|
|
18
|
+
distinguish a revision from a new change; ask only if that distinction changes scope or
|
|
19
|
+
architecture. If tickets for the current PRD are in progress, resume `$pincer-code`
|
|
20
|
+
unless the user explicitly authorized a separate change.
|
|
19
21
|
|
|
20
|
-
## Phase 1: Discovery
|
|
22
|
+
## Phase 1: Discovery
|
|
21
23
|
|
|
22
|
-
1. If `the text that follows the `$pincer-plan` mention in the user's message (ask
|
|
24
|
+
1. If `the text that follows the `$pincer-plan` mention in the user's message (ask only if the required input is missing)` contains the brief, extract what you can before asking anything.
|
|
23
25
|
Never ask a question the brief already answers.
|
|
24
26
|
2. Ask only the questions whose answers would change the architecture or scope.
|
|
25
27
|
Batch them (max 3–4 at once). Typical ones:
|
|
@@ -29,9 +31,10 @@ or a fresh start; if tickets are in progress, stop and point at `$pincer-code` i
|
|
|
29
31
|
3. If the project has a frontend, ask one design question: "What should this feel like,
|
|
30
32
|
and what should it NOT look like?" Capture the answer for the Visual Direction section.
|
|
31
33
|
|
|
32
|
-
Summarize your understanding in 3–5 sentences
|
|
34
|
+
Summarize your understanding in 3–5 sentences. Existing authorization in the request or
|
|
35
|
+
session carries forward; ask only about an unresolved choice that materially changes the result.
|
|
33
36
|
|
|
34
|
-
## Phase 2: Codebase scan (conditional
|
|
37
|
+
## Phase 2: Codebase scan (conditional)
|
|
35
38
|
|
|
36
39
|
If the repo already contains source code, launch 1–2 `codebase-explorer` agents in parallel
|
|
37
40
|
(one for architecture/structure, one for patterns relevant to the feature). Read the 2–3 most
|
|
@@ -46,7 +49,7 @@ touches are load-bearing, what test coverage protects them (run the suite, don't
|
|
|
46
49
|
and the blast radius + rollback story for the change. Record these in the PRD's
|
|
47
50
|
Architecture section. Greenfield speed assumptions do not transfer to brownfield work.
|
|
48
51
|
|
|
49
|
-
## Phase 3: Architecture
|
|
52
|
+
## Phase 3: Architecture
|
|
50
53
|
|
|
51
54
|
Propose the architecture: components, data flow, integration points, and key decisions.
|
|
52
55
|
- Recommend one approach; mention an alternative only when the trade-off is real.
|
|
@@ -59,23 +62,28 @@ Propose the architecture: components, data flow, integration points, and key dec
|
|
|
59
62
|
- Verify the contract of any external API the plan builds on (one live request or the
|
|
60
63
|
current official docs) before designing around it — endpoint shapes remembered from
|
|
61
64
|
training data are guesses.
|
|
62
|
-
-
|
|
65
|
+
- Respect any explicit delivery budget. Record deliberate cuts in Out of Scope.
|
|
63
66
|
|
|
64
|
-
|
|
67
|
+
Prepare the full draft before seeking any approval still required. The user should review a
|
|
68
|
+
concrete scope and architecture; do not repeat an approval already given for the same decision.
|
|
65
69
|
|
|
66
|
-
## Phase 4: Write the PRD
|
|
70
|
+
## Phase 4: Write the PRD
|
|
67
71
|
|
|
68
72
|
1. Load `.claude/references/prd-template.md` and write all core sections.
|
|
69
|
-
2. Include optional sections
|
|
70
|
-
3. Save to `.prd/prd-
|
|
73
|
+
2. Include optional sections when risk or the product context warrants them.
|
|
74
|
+
3. Save to the next unused `.prd/prd-v{N}.md` (create `.prd/` if needed), with `N`
|
|
75
|
+
matching the filename and frontmatter:
|
|
71
76
|
```yaml
|
|
72
77
|
---
|
|
73
|
-
version:
|
|
78
|
+
version: {N}
|
|
74
79
|
status: draft
|
|
75
80
|
date: {today}
|
|
76
81
|
---
|
|
77
82
|
```
|
|
78
|
-
4. If `.git/` doesn't exist, run `git init
|
|
79
|
-
|
|
83
|
+
4. If `.git/` doesn't exist, run `git init`. Commit the PRD and only the intended setup
|
|
84
|
+
paths after inspecting existing staged work; planning should be visible in history
|
|
85
|
+
without absorbing unrelated brownfield changes.
|
|
80
86
|
|
|
81
|
-
|
|
87
|
+
Present the saved draft and obtain approval only when the same scope/architecture was not
|
|
88
|
+
already authorized. Finish with: "PRD saved to `.prd/prd-v{N}.md`. Run `$pincer-narrow`
|
|
89
|
+
to break it into work items."
|
|
@@ -7,24 +7,29 @@ description: "Audit the repo against the workflow checklist — pass/fail per it
|
|
|
7
7
|
|
|
8
8
|
# $pincer-release — Workflow Audit
|
|
9
9
|
|
|
10
|
-
You are auditing the current repo state against `docs/
|
|
10
|
+
You are auditing the current repo state against `docs/release-checklist.md`. Read-only:
|
|
11
11
|
report pass/fail, never fix anything — fixes belong to the stage commands.
|
|
12
12
|
|
|
13
|
-
**Requested stage:** the text that follows the `$pincer-release` mention
|
|
13
|
+
**Requested stage:** the text that follows the `$pincer-release` mention, if any (when omitted, use the playbook's documented default)
|
|
14
14
|
|
|
15
15
|
## Steps
|
|
16
16
|
|
|
17
|
-
1. Read `docs/
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
1. Read `docs/release-checklist.md` — it is the source of truth for product-candidate
|
|
18
|
+
readiness. `docs/dry-run-checklist.md` is a separate manual platform trial and must
|
|
19
|
+
not impose toy-project or Pincer-kit assumptions on this audit.
|
|
20
|
+
2. Run `scripts/pincer-status.sh` to determine the selected PRD and which stages have run
|
|
21
|
+
(it reads `.prd/`, associated `tickets/`, `NOTES.md`; add `git log`). If `the text that follows the `$pincer-release` mention, if any (when omitted, use the playbook's documented default)`
|
|
22
|
+
names a stage, check only up
|
|
20
23
|
to that stage.
|
|
21
24
|
3. Check every applicable item mechanically where possible:
|
|
22
25
|
- File existence and frontmatter: read the files.
|
|
23
26
|
- Commit format and story: `git log --oneline`.
|
|
24
|
-
- Receipts: every done ticket carries `
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
- Receipts: every done ticket carries current `last_check` and `verified` evidence;
|
|
28
|
+
any status warning fails the audit. Do not call `pincer-ticket.sh` from Release:
|
|
29
|
+
it writes receipts and would invalidate the evaluated candidate.
|
|
30
|
+
- Run the repository's candidate-wide release gate directly (`npm test`, or the
|
|
31
|
+
equivalent declared by the project) and report its actual output. Any failure
|
|
32
|
+
blocks PASS. Confirm `git status --short` remains clean afterward.
|
|
28
33
|
4. For judgment items (tickets genuinely S/M, history reads as a story), give your
|
|
29
34
|
verdict AND one sentence of evidence — never a bare pass.
|
|
30
35
|
5. Present a table: checklist item | pass/fail/skipped | evidence. Order by stage.
|
|
@@ -14,7 +14,7 @@ start of a session. Read-only: change nothing.
|
|
|
14
14
|
|
|
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, every ticket with its state and clock-based
|
|
17
|
-
elapsed time, what is blocked, build time against
|
|
17
|
+
elapsed time, what is blocked, build time against any explicit user budget, any warnings (a ticket
|
|
18
18
|
marked done without a verification receipt), and the next command to run.
|
|
19
19
|
2. Report in three lines: where the workflow is, what is in progress or blocked, and the
|
|
20
20
|
next command. Quote the `Next` line as-is.
|