pincer-workflow 1.0.0 → 1.0.1

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 CHANGED
@@ -9,14 +9,15 @@ Copilot from one kit, and it has no dependencies.
9
9
 
10
10
  ## Install
11
11
 
12
- PINCER 1.0 is available as a package attached to the [GitHub release](https://github.com/orchestratedbyalex/pincer-workflow/releases/tag/v1.0.0).
13
- npm's `latest` is still 0.7.0 pending publication. Download `pincer-workflow-1.0.0.tgz`
14
- into your project and install that exact release:
12
+ PINCER 1.0 is live on [npm](https://www.npmjs.com/package/pincer-workflow).
13
+ Install it in your project:
15
14
 
16
15
  ```bash
17
- npx ./pincer-workflow-1.0.0.tgz init --platform all
16
+ npx pincer-workflow@latest init --platform all
18
17
  ```
19
18
 
19
+ The same package is also attached to the [GitHub release](https://github.com/orchestratedbyalex/pincer-workflow/releases/tag/v1.0.1).
20
+
20
21
  Node.js 22+, git and bash are required. PINCER uses your coding tool's own
21
22
  authentication; it does not require a provider API key.
22
23
 
@@ -27,8 +28,9 @@ Then start your agent in the repository and run the blueprint:
27
28
  $pincer-blueprint # Codex CLI
28
29
  ```
29
30
 
30
- Until the blueprint has run there is no agreement, and every other stage refuses with
31
- `no agreement yet: run /pincer-blueprint`. `scripts/pincer-status.sh` works in any
31
+ Until the blueprint has run there is no agreement, and every other stage refuses.
32
+ Codex-only installs point to `$pincer-blueprint`; Claude Code, Copilot and mixed
33
+ installs use `/pincer-blueprint`. A draft spec stays at the plan approval step. `scripts/pincer-status.sh` works in any
32
34
  shell from the first minute and always ends with the next command.
33
35
 
34
36
  ## The journey
@@ -53,7 +55,7 @@ The stages the agreement keeps, and what the interview can bend:
53
55
  | narrow | `/pincer-narrow` | spec to tickets with runnable checks | tickets as local files or as forge issues; one ticket per change |
54
56
  | code | `/pincer-code` | build tickets in order, one commit each, verify, done | branch per ticket or commit to main; PR or no PR; implementer agent or the main session |
55
57
  | evaluate | `/pincer-evaluate` | review the diff with the roster, run the checks, save evidence | review in the PR instead of a local report; evidence on or off; the roster |
56
- | release | `/pincer-release` | read-only audit, then acceptance recorded | audit a merged PR and a deploy instead of a clean tree; who accepts |
58
+ | release | `/pincer-release` | read-only audit, then acceptance recorded and committed | audit a merged PR and a deploy instead of a clean tree; who accepts |
57
59
  | status | `/pincer-status` | where the work stands, the next command | nothing; always on |
58
60
 
59
61
  Each stage is a short skill with the same six sections (Reads, Steps, Checks, Writes,
@@ -68,7 +70,9 @@ yours to edit; the Codex skills and Copilot prompts are generated from them.
68
70
  check, or with an unticked criterion.
69
71
  - `scripts/pincer-ticket.sh accept T-NN --by "<name>" --words "<their words>"` records
70
72
  the acceptance of a done ticket: a person named in the agreement, quoted. The agent
71
- runs it only after the person said so.
73
+ runs it only after the person said so. Release commits those three acceptance
74
+ fields separately, checks the final tree is clean, and keeps the evaluated
75
+ candidate distinct from the acceptance commit.
72
76
  - The eight lifecycle fields of a ticket are written only by that script. On Claude
73
77
  Code a hook enforces it; on Codex and Copilot it is a standing rule, and status flags
74
78
  a missing, failed or stale receipt and every done ticket without acceptance.
@@ -98,7 +102,7 @@ codes, the gate, the manifest, generation, recovery.
98
102
  | `.claude/agents/` | the review agents the roster names, with the model of their tier |
99
103
  | `.codex/agents/` | the same agents as Codex agent files, generated when Codex is installed |
100
104
  | `.claude/pincer/library/models.json` | the tier table: the model each platform runs a tier on |
101
- | `docs/engine.md`, `docs/release-checklist.md` | the engine contract and the fifteen-item release audit |
105
+ | `docs/engine.md`, `docs/release-checklist.md` | the engine contract and the release audit |
102
106
  | `specs/`, `tickets/`, `evidence/` | the default homes, all overridable in `harness.json` |
103
107
 
104
108
  Secrets never enter the kit: `init` adds `.env`, `.env.*` and `!.env.example` to
@@ -136,8 +140,8 @@ each installed platform will run.
136
140
  ## Update
137
141
 
138
142
  ```bash
139
- npx ./pincer-workflow-1.0.0.tgz update # edited files get a .new sidecar
140
- npx ./pincer-workflow-1.0.0.tgz doctor # checks the install and agreement
143
+ npx pincer-workflow@latest update # edited files get a .new sidecar
144
+ npx pincer-workflow@latest doctor # checks the install and agreement
141
145
  ```
142
146
 
143
147
  With an agreement in place, `update` also refreshes the library and regenerates the
@@ -147,9 +151,9 @@ it as `<file>.new`.
147
151
  ## Trying it locally before release
148
152
 
149
153
  ```bash
150
- npm pack # in this repository: pincer-workflow-1.0.0.tgz
151
- cp pincer-workflow-1.0.0.tgz ../some-project/ && cd ../some-project
152
- npx ./pincer-workflow-1.0.0.tgz init --platform all # the ./ matters: npx treats a bare path as a command
154
+ npm pack # in this repository: pincer-workflow-1.0.1.tgz
155
+ cp pincer-workflow-1.0.1.tgz ../some-project/ && cd ../some-project
156
+ npx ./pincer-workflow-1.0.1.tgz init --platform all # the ./ matters: npx treats a bare path as a command
153
157
  scripts/pincer-status.sh # prints "no agreement yet" and "Next: /pincer-blueprint"
154
158
  ```
155
159
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pincer-workflow",
3
- "version": "1.0.0",
4
- "description": "PINCER \u2014 a harness builder for AI coding agents. It looks at your project, interviews you, writes the project agreement, and runs the pipeline that agreement describes. Claude Code, Codex CLI and GitHub Copilot.",
3
+ "version": "1.0.1",
4
+ "description": "PINCER — a harness builder for AI coding agents. It looks at your project, interviews you, writes the project agreement, and runs the pipeline that agreement describes. Claude Code, Codex CLI and GitHub Copilot.",
5
5
  "bin": {
6
6
  "pincer": "bin/pincer.js"
7
7
  },
@@ -28,7 +28,7 @@ says; add no tool, step or role they did not choose.
28
28
  `.claude/skills/pincer-blueprint/formats/harness.md` (every field of `harness.json`)
29
29
  and `.claude/skills/pincer-blueprint/formats/roster-rules.md` (how the roster follows the answers).
30
30
  - The prompts under `.claude/skills/pincer-blueprint/prompts/`, one per question, named in the steps.
31
- - `the text that follows the `$pincer-blueprint` mention, if any (when omitted, use the skill's documented default)`: notes the person gave up front. Treat them as pre-filled answers to confirm, not as answers.
31
+ - the text that follows the `$pincer-blueprint` mention, if any (when omitted, use the skill's documented default): notes the person gave up front. Treat them as pre-filled answers to confirm, not as answers.
32
32
 
33
33
  ## Steps
34
34
  1. [session] Run `scripts/pincer-status.sh --stage blueprint` (always `on`; the plain report also says whether `harness.json` exists), then `node scripts/pincer-blueprint.cjs recon --json --network` and read the whole result: `kind`, `reasons`, `facts`, `prefill`, `unavailable`.
@@ -18,7 +18,7 @@ Run it first in any new session.
18
18
  - The ticket file of any `in_progress` ticket, and `git status`, to offer a resumption.
19
19
 
20
20
  ## Steps
21
- 1. [session] Run `scripts/pincer-status.sh` with `the text that follows the `$pincer-status` mention, if any (when omitted, use the skill's documented default)` when given (for example `--json`). This stage is always on, so `--stage status` only prints `on`; the plain report is what you need. Read every line, the warnings included.
21
+ 1. [session] Run `scripts/pincer-status.sh` with the text that follows the `$pincer-status` mention, if any (when omitted, use the skill's documented default) when given (for example `--json`). This stage is always on, so `--stage status` only prints `on`; the plain report is what you need. Read every line, the warnings included.
22
22
  2. [session] Report in three lines: where the work is (project, stages, tickets done and open), what is blocked (warnings, invalid tickets, missing acceptances, a stage that is off and that the next step needs), and the `Next:` line quoted as the script printed it.
23
23
  3. [session] If a ticket is `in_progress`: read its file, run `git status`, say what is uncommitted, and offer to resume with the command the report names (usually `scripts/pincer-ticket.sh verify T-NN`).
24
24
  4. [session] If a warning names a ticket file (a missing, failed or stale receipt, lifecycle fields edited by hand): say what fixes it (run `verify` again; let the person repair the field) and never restore, reset or rewrite a ticket file to clear it.
@@ -1,42 +1,45 @@
1
1
  ---
2
2
  name: pincer-release
3
- description: "Read-only audit of the candidate against the release checklist, then the person's acceptance recorded on every ticket"
3
+ description: "Audit the evaluated candidate, record the person's acceptance, and commit only that acceptance before the final clean-tree check"
4
4
  argument-hint: "[none]"
5
5
  ---
6
6
  # Release
7
7
 
8
- Audits the candidate against `docs/release-checklist.md` and records the person's
9
- acceptance. Read-only: it reports pass or fail per item and fixes nothing; a failure
10
- goes back to its stage through a new ticket. The one thing it writes is the
11
- acceptance, through the script, after the person said so. A step that changes the
12
- tree invalidates the audit: if `git status --short` is not empty afterwards the
13
- verdict is FAIL and names the change.
8
+ Runs a read-only audit first, then records and commits the person's acceptance.
9
+ The audit fixes nothing: a failed implementation or evidence check returns to its
10
+ stage through a new ticket. Acceptance is a separate, narrowly scoped write after
11
+ the person says yes. Keep the evaluated candidate, the audited checkout and the
12
+ acceptance commit distinct; an acceptance commit is not a new tested implementation.
14
13
 
15
14
  ## Reads
16
15
  - `docs/release-checklist.md`: the items, grouped Tickets, Evidence, Review, Acceptance.
17
- - `harness.json`: `stages.release.audit` (`tree` or `pr`), `systems.deploy`, `repo.checks`, `repo.pr`, `homes.evidence`, `people` (who may accept).
16
+ - `harness.json`: `stages.release.audit` (`tree` or `pr`), `systems.deploy`, `repo.checks`, `repo.pr`, `repo.branches`, `homes.evidence`, `people` (who may accept).
18
17
  - `scripts/pincer-status.sh`: every ticket's state, receipts, acceptances and warnings.
19
18
  - The evidence manifest under the evidence home when `stages.evaluate.evidence` is on; the review report.
20
19
  - With `pr`: `gh pr view <number> --json state,mergedAt,statusCheckRollup` and `gh pr checks <number>`.
21
20
  - Each ticket's `## Done when` and `## How the person checks`.
22
21
 
23
22
  ## Steps
24
- 1. [session] Run `scripts/pincer-status.sh --stage release`; on a non-zero exit print its message and stop. Then read `harness.json` for the fields above and `docs/release-checklist.md`.
25
- 2. [session] Run the plain `scripts/pincer-status.sh`. Every ticket of the change must be `done` with `verified` on its line and no `Warnings:` block; otherwise the audit already fails and names the ticket.
26
- 3. [session] Audit by `stages.release.audit`. `tree`: `git status --short` is empty; run every command in `repo.checks` (or `npm test` when the list is empty) directly and quote the output; the tree is still empty afterwards. `pr`: the pull request is merged, its checks are green, and when `systems.deploy` names a deploy you observed it ran (a run listed by `gh run list`, or the URL the person gives you). Never run `verify`, `done` or any ticket write here.
27
- 4. [session] Evidence and review: when `stages.evaluate.evidence` is on, `node scripts/pincer-evidence.cjs validate <manifest> --candidate <sha>` prints `ok`, and every artifact it lists is tracked; the review report exists and every finding has a disposition; every fix after evaluate has its own `T-NN:` commit.
28
- 5. [session] Walk the checklist: for each item, pass or fail and one sentence of evidence from status output or git, never a bare pass. Present the table grouped as the checklist is.
29
- 6. [session] Acceptance. Show the person the result and, for each ticket, its `## Done when` lines and how they can check. Ask whether they accept. Only after they say so, for each ticket: `scripts/pincer-ticket.sh accept T-NN --by "<name>" --words "<their words>"`, the name from `people` with `accepts: true`, the words theirs, not a paraphrase. A ticket they do not accept stays as it is and the audit fails on it.
30
- 7. [session] Verdict, one line naming the candidate: `PASS — candidate <sha>: workflow artifacts complete and accepted` or `FAIL — candidate <sha>: <n> items failed; fix via <command>`. A failure that is a workflow bug rather than a run mistake names the project copy under `.claude/skills/` whose steps should be tightened. Then `scripts/pincer-status.sh`.
23
+ 1. [session] Run `scripts/pincer-status.sh --stage release`; on a non-zero exit print its message and stop. Read `harness.json` and `docs/release-checklist.md`. Record the full `audit_head` from `git rev-parse HEAD`. With evidence on, record the evaluated `candidate` from its manifest; without evidence, the candidate is `audit_head`. Compare the candidate to `audit_head`: only the retained evaluation artifacts and previously recorded acceptance fields may differ. Any implementation, check, spec or agreement change needs a new evaluation; never relabel an old manifest as the current candidate.
24
+ 2. [session] Run `scripts/pincer-status.sh`. Every ticket of the change must be `done` with `verified` on its line. Before acceptance, a `T-NN done without acceptance` warning is expected for an unaccepted ticket and does not block the technical audit; every other warning fails it. Record those tickets as pending acceptance, never as accepted.
25
+ 3. [session] Read-only audit. `git status --short` must be empty before and after it, including the index. With `tree`, run every command in `repo.checks` (or `npm test` when empty) directly and quote the output. With `pr`, the implementation pull request must be merged with green checks and the deploy named in `systems.deploy` must have been observed. Do not run `verify`, `done`, `accept` or any other file write during this phase. A check that changes the tree fails the audit; do not clear the change to make it pass.
26
+ 4. [session] Evidence and review: with evidence on, run `node scripts/pincer-evidence.cjs validate <manifest> --candidate <candidate>`; it must print `ok`, and every listed artifact must be tracked. The review report must exist and every finding have a disposition; every implementation fix after evaluate needs its own `T-NN:` commit and a new evaluation. Confirm `HEAD` is still `audit_head`.
27
+ 5. [session] Present the checklist with evidence per item. Technical items are pass or fail; acceptance items remain pending until the person responds. A technical failure stops here and names the stage to fix it. Otherwise show the result, each ticket's `## Done when` lines, and how to check it, then ask whether the person accepts. This is not a final PASS yet.
28
+ 6. [session] Only after the person says so, run `scripts/pincer-ticket.sh accept T-NN --by "<name>" --words "<their words>"` for each ticket they accept. The name must be an acceptor in `people`; quote their actual words, never a paraphrase or a synthetic approval. Do not rewrite an already accepted ticket unless the person explicitly replaces that acceptance. A declined or unanswered ticket stays unaccepted and the final verdict remains pending or failed.
29
+ 7. [session] Commit the acceptance separately. Inspect `git diff --name-only`, `git diff --unified=0 -- <accepted ticket paths>`, and the index. The entire diff from `audit_head` may change only `accepted`, `accepted_by`, and `accepted_words` in those tickets' frontmatter; no ticket body, verification receipt, other field, source file or evidence artifact may change. Unexpected changes stop release; do not hide, restore or include them. Stage only the explicit ticket paths, inspect `git diff --cached`, then commit as `accept: <candidate short sha>`. Record the full `acceptance_commit`. If no new acceptance was written, make no empty commit and retain the existing acceptance commit identity. Follow the agreement's branch and PR policy; pushing or merging needs the user's existing authorization or a new explicit instruction. When that policy requires an acceptance PR, keep release pending until it is merged and its required checks pass.
30
+ 8. [session] Final check. `git status --short` must be empty. Inspect the committed diff from `audit_head` through the acceptance commit again: only the three acceptance fields in the accepted tickets may differ. Run status: every ticket of the change must be done, verified and accepted by a named person, with no warnings. When evidence is on, revalidate the unchanged evidence against the original `candidate`, not the acceptance commit. A changed artifact, unexpected commit or implementation change fails this check and requires a new evaluation.
31
+ 9. [session] Verdict: `PASS — candidate <candidate>, acceptance commit <acceptance_commit>: workflow artifacts complete and accepted` only when all applicable items pass, including any required acceptance PR. Otherwise report `PENDING — candidate <candidate>: <remaining acceptance or publication step>` or `FAIL — candidate <candidate>: <failed items>; fix via <command>`. Name every failed item first. A workflow bug names the project copy under `.claude/skills/` whose steps should change. Finish with `scripts/pincer-status.sh`.
31
32
 
32
33
  ## Checks
33
- - `git status --short` is empty after the audit; nothing was repaired, rewritten or published.
34
- - Every acceptance recorded names a person from `people` with `accepts: true` and quotes their words.
35
- - The verdict names the candidate and every failed item appears before it.
34
+ - The technical audit changed no files; the acceptance phase changed only the three allowed frontmatter fields and committed them separately.
35
+ - `git status --short` is empty at the end; no implementation change was hidden inside acceptance.
36
+ - Every acceptance names a person from `people` with `accepts: true` and quotes their words.
37
+ - Evidence still validates against its original candidate; the verdict separately names the acceptance commit and any pending remote step.
36
38
 
37
39
  ## Writes
38
- - The acceptance fields of each ticket, only through `scripts/pincer-ticket.sh accept`, only after the person said so.
39
- - Nothing else.
40
+ - The three acceptance fields, only through `scripts/pincer-ticket.sh accept`, only after the person said so.
41
+ - One acceptance-only commit when new acceptance was recorded; any required branch or PR follows the agreement and the user's authorization.
42
+ - No implementation, verification receipt, agreement or evidence edits; no implicit push, merge or publication.
40
43
 
41
44
  ## Without subagents
42
45
  No agents are involved; the audit is the session's own reading of status, git and the evidence.
@@ -129,15 +129,28 @@ on every platform.
129
129
 
130
130
  ## Acceptance
131
131
 
132
- The floor has two halves: a ticket is `done` only on a receipt, and accepted only when
133
- a named person said so. `accept` writes `accepted`, `accepted_by` and `accepted_words`
134
- together, and the validator refuses a ticket carrying one or two of the three. The name
135
- must be in `people` with `accepts: true`; the words are the person's, quoted as they
136
- said them, never a paraphrase. Acceptance gates nothing in the lifecycle (the next
137
- ticket may start), but status warns about every done ticket without it and names the
138
- next step: `/pincer-release` when that stage is on, else the `accept` command itself.
139
- Release passes only when every done ticket of the change carries it. The agent runs
140
- `accept` only after the person said so.
132
+ A ticket is `done` only on a receipt and accepted only when a named person said so.
133
+ `accept` writes `accepted`, `accepted_by` and `accepted_words` together; the validator
134
+ refuses a partial trio. The name must be in `people` with `accepts: true`; quote the
135
+ person's words verbatim. Acceptance does not block the next ticket, but status warns
136
+ about each done ticket without it and points to release (or `accept` if release is off).
137
+ Release passes only when every done ticket is accepted. Run `accept` only after the person says so; it never commits or publishes.
138
+
139
+ Release first audits read-only, allowing only `done without acceptance` warnings; all other warnings fail.
140
+ Record the manifest's evaluated `candidate` and current `audit_head` separately; only retained evidence
141
+ and existing acceptance fields may differ, never implementation, checks, spec or agreement.
142
+ Without evidence, `audit_head` is the candidate. The technical audit starts and ends with a clean tree.
143
+
144
+ After the person accepts, inspect working-tree, staged and committed diffs against `audit_head`:
145
+ only `accepted`, `accepted_by` and `accepted_words` in those tickets' frontmatter may change.
146
+ Commit separately as `accept: <candidate short sha>`, recording its full `acceptance_commit`;
147
+ skip an empty commit when nothing was newly accepted. Require a clean tree, status without warnings
148
+ and unchanged evidence validated against the original candidate. The verdict names both identities;
149
+ acceptance is not a newly tested candidate. Unexpected changes stop release for re-evaluation.
150
+
151
+ Branch and PR rules still apply: a required acceptance PR must be merged with passing checks before PASS.
152
+ Never push, merge or publish without the user's authorization. Unanswered acceptance or an incomplete
153
+ required remote step is pending, not passed.
141
154
 
142
155
  ## Evidence manifest schema 1
143
156
 
@@ -1,32 +1,37 @@
1
1
  # Release checklist
2
2
 
3
- What `/pincer-release` audits before the person accepts. Read-only: every item is
4
- checked from `scripts/pincer-status.sh` output or from git, and a failure goes back to
5
- its stage through a new ticket. Pass or fail per item, one sentence of evidence each.
3
+ `/pincer-release` first audits without writing files, then records the person's
4
+ acceptance and commits only those acceptance fields. Technical checks must pass
5
+ before asking for acceptance. Mark acceptance items pending until the person has
6
+ responded; pending acceptance alone is not a technical audit failure. Final PASS
7
+ requires every applicable item below. Give one sentence of evidence per item.
6
8
 
7
9
  ## Tickets
8
10
 
9
- - [ ] `scripts/pincer-status.sh` prints the agreement line and no `Warnings:` block
11
+ - [ ] status prints the agreement; before acceptance, its only permitted warnings are `T-NN done without acceptance`; after acceptance there are no warnings
10
12
  - [ ] every ticket of the change is `done` with `verified` on its status line
11
13
  - [ ] no ticket line reads `invalid`
12
14
  - [ ] `git log --oneline` shows one `T-NN: <title>` commit per ticket, in dependency order
13
15
 
14
16
  ## Evidence
15
17
 
16
- - [ ] `git status --short` is empty before the audit and after it
17
- - [ ] every command in `repo.checks` passes when run directly, output quoted
18
- - [ ] with evidence on: `node scripts/pincer-evidence.cjs validate <manifest> --candidate <sha>` prints `ok <sha>` and every artifact it lists is tracked
19
- - [ ] with `stages.release.audit` = `pr`: the pull request is merged, its checks are green, and the deploy named in `systems.deploy` was observed
18
+ - [ ] record the full evaluated `candidate` and pre-acceptance `audit_head`; their diff contains only retained evaluation artifacts and previously recorded acceptance fields, with no implementation, check, spec or agreement changes
19
+ - [ ] `git status --short` is empty before and after the read-only audit; no check wrote files or moved `HEAD`
20
+ - [ ] with tree audit, every command in `repo.checks` passes when run directly, output quoted
21
+ - [ ] with evidence on, `node scripts/pincer-evidence.cjs validate <manifest> --candidate <candidate>` prints `ok <candidate>` and every listed artifact is tracked; repeat after acceptance against the same original candidate
22
+ - [ ] with PR audit, the implementation PR is merged with green checks and the named deploy was observed; any acceptance PR required by the agreement is also merged with its required checks passing before final PASS
20
23
 
21
24
  ## Review
22
25
 
23
- - [ ] the review report exists (a file under the evidence home, or the PR comment) and every finding has a file, a line and a disposition
24
- - [ ] every fix after evaluate went through its own ticket and `T-NN:` commit, never an ad-hoc commit
25
- - [ ] no secret environment file is tracked: `git ls-files | grep -i '^\.env'` shows only `.env.example`
26
+ - [ ] the review report exists and every finding has a file, a line and a disposition
27
+ - [ ] every implementation fix after evaluate went through its own ticket and `T-NN:` commit, followed by a new evaluation
28
+ - [ ] no secret environment file is tracked: `git ls-files | grep -i '^\.env'` shows only `.env.example`, or no entries when no environment example is needed
26
29
 
27
30
  ## Acceptance
28
31
 
29
32
  - [ ] the person saw the result and every ticket's `Done when` lines before being asked
30
33
  - [ ] every done ticket shows `accepted by <name>` in status, the name from `people` with `accepts: true`
31
- - [ ] `accepted_words` holds the person's own words, not a paraphrase
32
- - [ ] the audit wrote nothing but the acceptances: no `verify`, no `done`, no ticket edits, and `git status --short` is still empty
34
+ - [ ] `accepted_words` holds the person's own words, not a paraphrase or synthetic approval
35
+ - [ ] only `accept` wrote acceptance; the complete staged and committed diff from `audit_head` changes only `accepted`, `accepted_by`, and `accepted_words` in the intended tickets' frontmatter, never their body, receipt or any other file
36
+ - [ ] new acceptance is retained in a separate `accept: <candidate short sha>` commit; the verdict identifies both the evaluated candidate and acceptance commit, and `git status --short` is empty
37
+ - [ ] no push, merge or publication occurred without the user's authorization; any required remote acceptance step is complete or explicitly pending rather than passed
@@ -158,7 +158,9 @@ function renderCodex(stage, fields, body, codex) {
158
158
  const sentence = optional
159
159
  ? `the text that follows the \`$pincer-${stage}\` mention, if any (when omitted, use the skill's documented default)`
160
160
  : `the text that follows the \`$pincer-${stage}\` mention in the user's message (ask only if the required input is missing)`;
161
- const text = codexMentions(body.split('$ARGUMENTS').join(sentence));
161
+ // Replace the whole inline-code placeholder before bare occurrences so the
162
+ // sentence's own skill code span is not nested inside another pair of ticks.
163
+ const text = codexMentions(body.replace(/`\$ARGUMENTS`|\$ARGUMENTS/g, () => sentence));
162
164
  return `---\nname: pincer-${stage}\ndescription: ${quoted(describe(stage, fields))}\n---\n${generatedComment(skillFile(stage))}\n\n${codexHint(codex)}${bodyText(text)}`;
163
165
  }
164
166
  function renderCopilot(stage, fields, body, copilot) {
@@ -12,6 +12,13 @@ const generate = require('./generate.cjs');
12
12
  const SCRIPT = 'scripts/pincer-ticket.sh';
13
13
  const { STAGES, ALWAYS_ON, HARNESS_FILE } = harnessModule;
14
14
 
15
+ // Only a Codex-only install unambiguously chooses dollar-style skill mentions.
16
+ // Mixed installs keep the shared slash spelling; shell paths are never rewritten.
17
+ function commandMentions(root, text) {
18
+ const platforms = generate.manifestPlatforms(root);
19
+ return platforms.length === 1 && platforms[0] === 'codex' ? generate.codexMentions(text) : text;
20
+ }
21
+
15
22
  // Is a ticket's receipt current? Lifted from 0.7: the wording is what a done
16
23
  // ticket that needs attention has always shown.
17
24
  function readiness(text, fields) {
@@ -97,7 +104,7 @@ function gather(root) {
97
104
  if (t.status === 'done' && !t.ready) report.warnings.push(`${t.id} done: ${t.readiness}`);
98
105
  if (t.status === 'done' && !t.accepted) report.warnings.push(`${t.id} done without acceptance`);
99
106
  }
100
- report.next = nextCommand(report);
107
+ report.next = commandMentions(root, nextCommand(report));
101
108
  return report;
102
109
  }
103
110
 
@@ -107,13 +114,18 @@ function nextCommand(report) {
107
114
  const tickets = report.tickets;
108
115
  const broken = tickets.find((t) => t.problem);
109
116
  if (broken) return `fix ${broken.file}`;
117
+ const draft = report.stages.plan === 'on' && report.specs.find((s) => !['approved', 'built'].includes(s.status));
110
118
  if (report.stages.plan === 'on' && report.specs.length === 0 && tickets.length === 0) return '/pincer-plan <brief>';
111
- if (tickets.length === 0) return '/pincer-narrow';
119
+ if (tickets.length === 0) {
120
+ if (draft) return `/pincer-plan ${draft.file} (awaiting approval)`;
121
+ return report.stages.narrow === 'on' ? '/pincer-narrow' : '/pincer-code';
122
+ }
112
123
  const inProgress = tickets.find((t) => t.status === 'in_progress');
113
124
  if (inProgress) return `${SCRIPT} verify ${inProgress.id}`;
114
125
  if (tickets.some((t) => t.status === 'open')) return '/pincer-code';
115
126
  const stale = tickets.find((t) => t.status === 'done' && !t.ready);
116
127
  if (stale) return `${SCRIPT} verify ${stale.id}`;
128
+ if (draft) return `/pincer-plan ${draft.file} (awaiting approval)`;
117
129
  if (report.stages.evaluate === 'on' && report.harness.stages.evaluate.evidence && report.evidence.length === 0) return '/pincer-evaluate';
118
130
  const unaccepted = tickets.find((t) => t.status === 'done' && !t.accepted);
119
131
  if (unaccepted) {
@@ -153,9 +165,9 @@ function stageGate(root, name) {
153
165
  if (!STAGES.includes(name)) return { exit: 2, message: `${name} is not a stage (${STAGES.join(', ')})` };
154
166
  if (ALWAYS_ON.includes(name)) return { exit: 0, message: 'on' };
155
167
  const loaded = harnessModule.load(root);
156
- if (!loaded.ok) return { exit: 3, message: loaded.missing ? loaded.message : `${HARNESS_FILE}: ${loaded.message}` };
168
+ if (!loaded.ok) return { exit: 3, message: loaded.missing ? commandMentions(root, loaded.message) : `${HARNESS_FILE}: ${loaded.message}` };
157
169
  if (!harnessModule.stageOn(loaded.harness, name)) return { exit: 3, message: `stage ${name} is off in ${HARNESS_FILE}` };
158
170
  return { exit: 0, message: 'on' };
159
171
  }
160
172
 
161
- module.exports = { readiness, gather, nextCommand, render, stageGate };
173
+ module.exports = { readiness, gather, nextCommand, render, stageGate, commandMentions };
@@ -9,6 +9,7 @@ const path = require('node:path');
9
9
  const { spawn } = require('node:child_process');
10
10
  const parse = require('./parse.cjs');
11
11
  const harnessModule = require('./harness.cjs');
12
+ const { commandMentions } = require('./status.cjs');
12
13
  const { nowIso, atomicWrite } = require('./util.cjs');
13
14
 
14
15
  const EXIT = { OK: 0, REFUSED: 1, USAGE: 2, HARNESS: 3, INTERRUPTED: 130 };
@@ -24,7 +25,7 @@ const refuse = (message, options) => { throw new Refusal(message, options); };
24
25
  // Every verb needs an agreement with the code stage on; tickets live in its home.
25
26
  function agreement(root) {
26
27
  const loaded = harnessModule.load(root);
27
- if (!loaded.ok) refuse(`${harnessModule.HARNESS_FILE}: ${loaded.message}`, { exit: EXIT.HARNESS, prefix: '' });
28
+ if (!loaded.ok) refuse(`${harnessModule.HARNESS_FILE}: ${loaded.missing ? commandMentions(root, loaded.message) : loaded.message}`, { exit: EXIT.HARNESS, prefix: '' });
28
29
  if (!harnessModule.stageOn(loaded.harness, 'code')) refuse(`stage code is off in ${harnessModule.HARNESS_FILE}`, { exit: EXIT.HARNESS, prefix: '' });
29
30
  return { harness: loaded.harness, tickets: harnessModule.homes(loaded.harness).tickets };
30
31
  }