cursordoctrine 0.4.6 → 0.5.2
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/INSTALL.md +16 -13
- package/README.md +8 -10
- package/bin/cli.mjs +1 -40
- package/linux/hooks/anti-slop-audit.sh +5 -4
- package/linux/hooks/final-review.md +41 -14
- package/linux/hooks/final-review.sh +17 -15
- package/linux/hooks/semantic-density-audit.sh +4 -5
- package/linux/hooks/subagent-stop-review.sh +12 -10
- package/linux/hooks.json +2 -14
- package/package.json +2 -2
- package/skills/anti-slop/SKILL.md +6 -7
- package/windows/doctrine.md +22 -26
- package/windows/hooks/anti-slop-audit.ps1 +4 -4
- package/windows/hooks/final-review.md +41 -14
- package/windows/hooks/final-review.ps1 +19 -18
- package/windows/hooks/self-review.md +7 -14
- package/windows/hooks/semantic-density-audit.ps1 +4 -5
- package/windows/hooks/subagent-stop-review.ps1 +12 -10
- package/windows/hooks.json +2 -14
- package/linux/hooks/anchor-set-nudge.sh +0 -77
- package/linux/hooks/minimal-edit-audit.sh +0 -120
- package/windows/hooks/anchor-set-nudge.ps1 +0 -76
- package/windows/hooks/minimal-edit-audit.ps1 +0 -124
package/INSTALL.md
CHANGED
|
@@ -76,13 +76,14 @@ echo '{"conversation_id":"t1","status":"completed"}' | bash ~/.agents/hooks/fina
|
|
|
76
76
|
echo '{"conversation_id":"t2","file_path":"/tmp/x.py"}' | bash ~/.agents/hooks/self-review-trigger.sh
|
|
77
77
|
echo '{"conversation_id":"t2","status":"completed"}' | bash ~/.agents/hooks/subagent-stop-review.sh # expect {"followup_message": "SUBAGENT FINAL REVIEW ..."} once, then {}
|
|
78
78
|
echo '{"conversation_id":"t2"}' | bash ~/.agents/hooks/post-tool-use.sh # drain t2's leftover feedback file
|
|
79
|
-
# anchor
|
|
80
|
-
|
|
81
|
-
echo '{"conversation_id":"t3"}'
|
|
82
|
-
|
|
83
|
-
echo '{"conversation_id":"t3"}' | bash ~/.agents/hooks/post-tool-use.sh
|
|
84
|
-
echo '{}' | bash ~/.cursor/inject-doctrine.sh
|
|
85
|
-
python3 ~/.cursor/skills/anti-slop/scripts/scan_slop.py --help
|
|
79
|
+
# intent-anchor: writes .scope.json from the current prompt and re-injects it.
|
|
80
|
+
# Needs a repo root in cwd (it will NOT write to $HOME - that's the guard).
|
|
81
|
+
echo '{"conversation_id":"t3","cwd":"/tmp","file_path":"/tmp/x.py"}' | bash ~/.agents/hooks/intent-anchor.sh
|
|
82
|
+
cat /tmp/.scope.json # expect a JSON scaffold with intent placeholder
|
|
83
|
+
echo '{"conversation_id":"t3"}' | bash ~/.agents/hooks/post-tool-use.sh # expect additional_context with the scaffold
|
|
84
|
+
echo '{}' | bash ~/.cursor/inject-doctrine.sh # expect {"additional_context": ...}
|
|
85
|
+
python3 ~/.cursor/skills/anti-slop/scripts/scan_slop.py --help # expect usage text (final review's scanner)
|
|
86
|
+
rm -f /tmp/.scope.json # cleanup the test scaffold
|
|
86
87
|
```
|
|
87
88
|
|
|
88
89
|
If the scanner check fails, the final review still works — it falls back to the
|
|
@@ -96,11 +97,13 @@ Windows (same payloads, swap `bash ~/...sh` for `pwsh.exe -NoProfile -File $HOME
|
|
|
96
97
|
echo '{"command":"git push --force"}' | pwsh.exe -NoProfile -File $HOME\.agents\hooks\permission-gate.ps1
|
|
97
98
|
echo '{"conversation_id":"t2","file_path":"C:\tmp\x.py"}' | pwsh.exe -NoProfile -File $HOME\.agents\hooks\self-review-trigger.ps1
|
|
98
99
|
echo '{"conversation_id":"t2","status":"completed"}' | pwsh.exe -NoProfile -File $HOME\.agents\hooks\subagent-stop-review.ps1 # SUBAGENT FINAL REVIEW once, then {}
|
|
99
|
-
# anchor
|
|
100
|
-
|
|
101
|
-
echo '{"conversation_id":"t3"}'
|
|
102
|
-
|
|
100
|
+
# intent-anchor: writes .scope.json from the current prompt and re-injects it.
|
|
101
|
+
# Needs a repo root in cwd (it will NOT write to $HOME - that's the guard).
|
|
102
|
+
echo '{"conversation_id":"t3","cwd":"C:\tmp","file_path":"C:\tmp\x.py"}' | pwsh.exe -NoProfile -File $HOME\.agents\hooks\intent-anchor.ps1
|
|
103
|
+
Get-Content C:\tmp\.scope.json # expect a JSON scaffold with intent placeholder
|
|
104
|
+
echo '{"conversation_id":"t3"}' | pwsh.exe -NoProfile -File $HOME\.agents\hooks\post-tool-use.ps1 # additional_context with the scaffold
|
|
103
105
|
python $HOME\.cursor\skills\anti-slop\scripts\scan_slop.py --help
|
|
106
|
+
Remove-Item C:\tmp\.scope.json -Force # cleanup the test scaffold
|
|
104
107
|
```
|
|
105
108
|
|
|
106
109
|
Also validate the config: `~/.cursor/hooks.json` must parse as JSON.
|
|
@@ -109,7 +112,7 @@ Also validate the config: `~/.cursor/hooks.json` must parse as JSON.
|
|
|
109
112
|
|
|
110
113
|
1. Restart Cursor (hooks.json is read at startup).
|
|
111
114
|
2. Open any project and start a new agent chat. The doctrine should be in context — ask the agent "what does your doctrine say about diffs?" and it should answer from §2; ask "what is the Anchor Set?" and it should answer from `pre-compile.md` (Objective / Constraints / Scope / Deterministic success).
|
|
112
|
-
3. Have the agent make a small edit to a tracked file. On the next turn it should receive a `SELF-REVIEW TRIGGER` message, and
|
|
115
|
+
3. Have the agent make a small edit to a tracked file. On the next turn it should receive a `SELF-REVIEW TRIGGER` message, and `intent-anchor` should have written `.scope.json` to the repo root (intent from your prompt, `<TODO>` placeholders for files/acceptance). The scaffold regenerates when your prompt changes and is re-injected every turn.
|
|
113
116
|
4. Ask the agent to run `git push --force` (in a throwaway repo). The permission gate must block it.
|
|
114
117
|
5. Finish a small implementation and stop. A single `FINAL REVIEW` follow-up should fire — exactly once.
|
|
115
118
|
6. Delegate a small edit to a subagent (e.g. ask the agent to "use a generalPurpose subagent to add a comment to <file>"). The subagent should receive one `SUBAGENT FINAL REVIEW` follow-up before returning, and the parent should see `SUBAGENT WORK DETECTED` at its next tool boundary. (`subagentStop` is only read at startup — if nothing fires, restart Cursor again.)
|
|
@@ -120,4 +123,4 @@ Also validate the config: `~/.cursor/hooks.json` must parse as JSON.
|
|
|
120
123
|
|
|
121
124
|
Tell the user what was installed, which checks passed, and anything that failed with the exact error. Do not silently work around a failing check.
|
|
122
125
|
|
|
123
|
-
Kill switches if something misbehaves: `HOOKS_ENFORCE=0` (everything advisory off), `PERM_GATE_ENFORCE=0`, `
|
|
126
|
+
Kill switches if something misbehaves: `HOOKS_ENFORCE=0` (everything advisory off), `PERM_GATE_ENFORCE=0`, `INTENT_ANCHOR_ENFORCE=0` (thin-intent `.scope.json` scaffold/re-injection off), `SEMANTIC_DENSITY_ENFORCE=0`, `SCOPE_GATE_ENFORCE=0`, `ANTI_SLOP_ENFORCE=0`, `FINAL_REVIEW_ENFORCE=0`, `SUBAGENT_REVIEW_ENFORCE=0`.
|
package/README.md
CHANGED
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
|
|
22
22
|
Cursor hooks that make the agent review its own edits without bolting a static-analysis pipeline onto every keystroke. No regex army, no scoring engine. Four jobs:
|
|
23
23
|
|
|
24
|
-
1. **Compile intent before coding** (proactive) — at session start the agent gets the doctrine plus the **Anchor Set** discipline (`pre-compile.md`): before writing code it must emit *Objective / Constraints / Scope / Deterministic success
|
|
24
|
+
1. **Compile intent before coding** (proactive) — at session start the agent gets the doctrine plus the **Anchor Set** discipline (`pre-compile.md`): before writing code it must emit *Objective / Constraints / Scope / Deterministic success*. `intent-anchor` materializes that as `.scope.json` on the first tool of each turn (auto-created, regenerated when the prompt changes) and re-injects it into context every turn, so the contract stays in focus against Salience Dilution.
|
|
25
25
|
2. **Inject the doctrine** at session start — every chat starts with the same short governing text (`doctrine.md`, `USER-RULES.md`, `declared-editing.md` the YAGNI ultra ladder, and `pre-compile.md` the thin intent-compilation phase).
|
|
26
|
-
3. **Hand the model its own edits back** (reactive) — after each agent edit, a self-review prompt goes into a pending file (plus semantic-density, scope-gate, anti-slop
|
|
26
|
+
3. **Hand the model its own edits back** (reactive) — after each agent edit, a self-review prompt goes into a pending file (plus semantic-density, scope-gate, and anti-slop advisories when they trip). Next turn the model reads its diff, fixes real bugs, stays quiet otherwise.
|
|
27
27
|
4. **Gate blast radius** — one permission gate denies a short explicit list of dangerous commands (`rm -rf /`, `curl | sh`, force-push, `npm publish`, ...). Everything else passes.
|
|
28
28
|
|
|
29
|
-
When an implementation finishes, the stop hook runs one final review over everything that changed, then stops.
|
|
29
|
+
When an implementation finishes, the stop hook runs one final review over everything that changed, then stops. Seven axes. The first is **intent trace**: the hook pulls your last user message from the transcript and prepends it to the review so the model has to tie every diff hunk to a concrete request. Anything it can't trace is a hallucinated requirement and gets reverted. The last is **mechanics & stack integrity** (N+1, idempotency, transactions, boundary validation, zombie listeners, god components, determinism) — patterns the regex scanner can't catch because they need semantic judgement. That's the only check that catches "clean code, wrong feature" — linters and later axes miss it.
|
|
30
30
|
|
|
31
31
|
Subagents get the same treatment. If a delegated run edited files, it reviews its own work before the result goes back to the parent. Those edits fold into the parent's final review. Every bound is enforced twice: in the script and in `hooks.json`.
|
|
32
32
|
|
|
@@ -90,13 +90,13 @@ Two machine-checkable consequences:
|
|
|
90
90
|
- **`scope-gate-audit`** (afterFileEdit, opt-in via `.scope.json` existing) audits every edit against `files[]` and quotes `intent` + `acceptance` back on a violation. Editing outside the declared set is the textbook scope-creep signal.
|
|
91
91
|
- **final-review axis 0** (intent trace) traces every diff hunk back to `intent`. Anything untraceable is a hallucinated requirement.
|
|
92
92
|
|
|
93
|
-
On the **first
|
|
93
|
+
On the **first tool of each agent turn**, `intent-anchor` materializes the Anchor Set: it writes `.scope.json` to the repo root (regenerating it when the prompt changed) and re-injects it into context. One scaffold per prompt, re-injection per turn. The latch is armed on first fire and cleared **unconditionally** by the stop hook on every turn boundary, so the next turn re-fires and can never get stranded silenced mid-session.
|
|
94
94
|
|
|
95
95
|
The Anchor Set is skipped for trivial one-liners (typo, literal) — the `declared-editing.md` ladder's rung 1 governs when it's overkill.
|
|
96
96
|
|
|
97
97
|
### Keeping the contract alive: `intent-anchor` (anti-Salience-Dilution)
|
|
98
98
|
|
|
99
|
-
Writing `.scope.json` once is not enough. As a conversation fills with code, logs and errors, the token of the original request shrinks to a rounding error against the recent history — *Salience Dilution* — and the agent stops checking the contract it wrote at prompt 1. It forgets symmetry, colors, the acceptance bar.
|
|
99
|
+
Writing `.scope.json` once is not enough. As a conversation fills with code, logs and errors, the token of the original request shrinks to a rounding error against the recent history — *Salience Dilution* — and the agent stops checking the contract it wrote at prompt 1. It forgets symmetry, colors, the acceptance bar. Re-injecting the contract every turn is what defeats this: the requirements are re-stated in front of the model before each edit, not just written once and hoped-for.
|
|
100
100
|
|
|
101
101
|
`intent-anchor` (`postToolUse`, registered first so it runs before `post-tool-use` drains the bus) does two things on the **first tool boundary of every turn** (per-turn latch, cleared unconditionally at each stop):
|
|
102
102
|
|
|
@@ -114,7 +114,7 @@ Crucially, `intent-anchor` carries the **semantic** contract (`intent`/`acceptan
|
|
|
114
114
|
| Session | `sessionStart` | `inject-doctrine` reads doctrine + user rules + declared-editing + **pre-compile** and emits them as `additional_context`. |
|
|
115
115
|
| Every turn | `postToolUse` | **`intent-anchor`** (registered first) re-injects `.scope.json` into `additional_context` at the first tool boundary of each turn — the anti-Salience-Dilution move that keeps `intent` + `acceptance` in the model's attentional focus before edits pile up. If the prompt changed since last turn, it demands the contract be updated. Then `post-tool-use` folds subagent markers and drains the feedback file. |
|
|
116
116
|
| Shell | `beforeShellExecution` | `permission-gate` checks the command against a deny list. Allow by default, deny by list, fail open. |
|
|
117
|
-
| Edit | `afterFileEdit` + `stop` | **Proactive:** `anchor
|
|
117
|
+
| Edit | `afterFileEdit` + `stop` | **Proactive:** `intent-anchor` (`postToolUse`) scaffolds `.scope.json` per prompt and re-injects it each turn. **Reactive:** `self-review-trigger` stashes the review prompt per edit; `semantic-density-audit`, `scope-gate-audit` (opt-in, audits `.scope.json`), and `anti-slop-audit` append advisories when they trip; `final-review` fires one end-of-implementation seven-axis pass. |
|
|
118
118
|
| Subagent | `subagentStop` | `subagent-stop-review` fires one in-subagent final review when a delegated run edited files, before the result returns to the parent. Marker-gated and flag-braked like `final-review`. |
|
|
119
119
|
|
|
120
120
|
## Layout
|
|
@@ -149,9 +149,7 @@ All hooks fail open and always exit 0. Nothing here can block your session.
|
|
|
149
149
|
|---|---|---|
|
|
150
150
|
| `HOOKS_ENFORCE=0` | on | turns off all advisory hooks at once |
|
|
151
151
|
| `PERM_GATE_ENFORCE=0` | on | disables the permission gate |
|
|
152
|
-
| `
|
|
153
|
-
| `INTENT_ANCHOR_ENFORCE=0` | on | disables the thin-intent re-injection (per-turn `.scope.json` echo into `additional_context`) |
|
|
154
|
-
| `MINIMAL_EDITING_ENFORCE=0` | on | disables the over-edit advisory (deprecated in 0.3.0) |
|
|
152
|
+
| `INTENT_ANCHOR_ENFORCE=0` | on | disables the thin-intent `.scope.json` scaffold + re-injection |
|
|
155
153
|
| `SCOPE_GATE_ENFORCE=0` | on | disables the declared-scope advisory (opt-in: only fires when `.scope.json` exists) |
|
|
156
154
|
| `SEMANTIC_DENSITY_ENFORCE=0` | on | disables the semantic-opacity advisory |
|
|
157
155
|
| `ANTI_SLOP_ENFORCE=0` | on | disables the slop advisory |
|
|
@@ -164,7 +162,7 @@ All hooks fail open and always exit 0. Nothing here can block your session.
|
|
|
164
162
|
|
|
165
163
|
- **State lives under `$HOME`**, in `~/.cursor/.hooks-pending/`, keyed by conversation id. No repo litter. Concurrent sessions can't drain each other's prompts. Stale state older than 7 days gets swept on every stop.
|
|
166
164
|
- **`afterFileEdit` output isn't consumed by Cursor**, so edit hooks write to a pending file and `post-tool-use` re-emits it at the next tool boundary. That's the whole message bus.
|
|
167
|
-
- **One review per implementation.** The stop hook arms a per-conversation flag before emitting its follow-up, so a crash can't re-fire it and a long chat still gets a review after each implementation. The `anchor
|
|
165
|
+
- **One review per implementation.** The stop hook arms a per-conversation flag before emitting its follow-up, so a crash can't re-fire it and a long chat still gets a review after each implementation. The `intent-anchor` per-turn latch is separate and simpler: it's cleared **unconditionally** on every stop, so the scaffold/re-inject re-fires on the first tool of each new turn and can never get stranded silenced mid-session.
|
|
168
166
|
- **The `.scope.json` contract is opt-in.** No `.scope.json` in the repo root → `scope-gate-audit` stays silent and the system falls back to the `declared-editing` ladder plus the final-review footprint check. Writing the file is how the agent opts into a machine-checked scope.
|
|
169
167
|
- **Subagents are first-class.** `afterFileEdit` fires inside subagents keyed by the subagent's conversation id. The harness normalizes agent edits (incl. `StrReplace`) to tool type `Write`, and `postToolUse` never fires for the `Task` tool — verified by payload capture. Matchers cover `Write|StrReplace|EditNotebook` defensively. `subagentStop` reviews the subagent in its own context. The parent folds orphaned subagent markers (from the `subagents/` transcript directory) into its own at every tool boundary and at stop.
|
|
170
168
|
|
package/bin/cli.mjs
CHANGED
|
@@ -284,43 +284,6 @@ function verify() {
|
|
|
284
284
|
return true;
|
|
285
285
|
});
|
|
286
286
|
|
|
287
|
-
check('anchor-set nudge fires once per turn, stop re-arms it', () => {
|
|
288
|
-
// anchor-set-nudge appends to feedback-<cid>.txt (the shared bus) rather
|
|
289
|
-
// than emitting JSON directly; drain it the same way post-tool-use does.
|
|
290
|
-
const drainedOf = (cidv) => runHook(hook('post-tool-use'), { conversation_id: cidv });
|
|
291
|
-
|
|
292
|
-
// --- Turn 1 -------------------------------------------------------------
|
|
293
|
-
// First edit -> nudge stashes into the feedback bus and arms the latch.
|
|
294
|
-
runHook(hook('anchor-set-nudge'), { conversation_id: 'npxv3', file_path: join(HOME, 'x.py') });
|
|
295
|
-
if (!drainedOf('npxv3').includes('PRE-COMPILE NUDGE')) {
|
|
296
|
-
return { ok: false, detail: 'nudge did not reach the feedback bus on first edit' };
|
|
297
|
-
}
|
|
298
|
-
// Second edit same turn -> latch armed, nudge must stay silent.
|
|
299
|
-
runHook(hook('anchor-set-nudge'), { conversation_id: 'npxv3', file_path: join(HOME, 'y.py') });
|
|
300
|
-
if (drainedOf('npxv3').includes('PRE-COMPILE NUDGE')) {
|
|
301
|
-
return { ok: false, detail: 'nudge re-fired on second edit (latch not gating)' };
|
|
302
|
-
}
|
|
303
|
-
// End of turn: final-review clears the latch unconditionally. Drive a
|
|
304
|
-
// review-less stop (no session-edits marker) so it hits the clear path and
|
|
305
|
-
// exits {}, same as a turn that produced no reviewable edits.
|
|
306
|
-
const stopOut = runHook(hook('final-review'), { conversation_id: 'npxv3', status: 'completed' });
|
|
307
|
-
if (stopOut !== '{}' && stopOut.replace(/\s/g, '') !== '{}') {
|
|
308
|
-
// A review fired (fine - the earlier edit left a session-edits marker via
|
|
309
|
-
// self-review-trigger if one ran). What matters is the latch got cleared;
|
|
310
|
-
// we verify that with the next-turn re-fire below.
|
|
311
|
-
}
|
|
312
|
-
// --- Turn 2 -------------------------------------------------------------
|
|
313
|
-
// First edit of the NEXT turn -> latch was cleared at the stop boundary, so
|
|
314
|
-
// the nudge MUST re-fire. This is the regression that 0.4.0 shipped broken:
|
|
315
|
-
// the latch only cleared on the fragile second-stop path, so it stranded
|
|
316
|
-
// and the nudge went permanently silent mid-session.
|
|
317
|
-
runHook(hook('anchor-set-nudge'), { conversation_id: 'npxv3', file_path: join(HOME, 'z.py') });
|
|
318
|
-
if (!drainedOf('npxv3').includes('PRE-COMPILE NUDGE')) {
|
|
319
|
-
return { ok: false, detail: 'nudge did NOT re-fire on the next turn (latch stranded at the stop boundary)' };
|
|
320
|
-
}
|
|
321
|
-
return true;
|
|
322
|
-
});
|
|
323
|
-
|
|
324
287
|
check('intent-anchor scaffolds .scope.json per-prompt, never to $HOME', () => {
|
|
325
288
|
// The user-requested behavior: every NEW prompt -> a fresh .scope.json
|
|
326
289
|
// in the repo root, intent locked from the query. Same prompt -> re-inject
|
|
@@ -513,9 +476,7 @@ Examples
|
|
|
513
476
|
Kill switches (environment variables, all hooks fail open)
|
|
514
477
|
HOOKS_ENFORCE=0 everything advisory off
|
|
515
478
|
PERM_GATE_ENFORCE=0 permission gate off
|
|
516
|
-
|
|
517
|
-
INTENT_ANCHOR_ENFORCE=0 thin-intent re-injection off (per-turn .scope.json echo)
|
|
518
|
-
MINIMAL_EDITING_ENFORCE=0 over-edit advisory off (deprecated in 0.3.0)
|
|
479
|
+
INTENT_ANCHOR_ENFORCE=0 thin-intent scaffold/re-injection off
|
|
519
480
|
SEMANTIC_DENSITY_ENFORCE=0 semantic-opacity advisory off
|
|
520
481
|
SCOPE_GATE_ENFORCE=0 declared-scope advisory off
|
|
521
482
|
ANTI_SLOP_ENFORCE=0 slop advisory off
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# anti-slop-audit.sh - afterFileEdit "AI slop" advisory (Cursor, Linux).
|
|
3
3
|
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# analysis can cheaply and precisely flag, plus a self-review checklist for
|
|
7
|
-
# the parts it cannot.
|
|
4
|
+
# Guards the parts of the slop taxonomy static analysis can cheaply and
|
|
5
|
+
# precisely flag, plus a self-review checklist for the parts it cannot.
|
|
8
6
|
#
|
|
9
7
|
# Statically flagged (high-precision, deliberately low false-positive):
|
|
10
8
|
# * new dependency added to a manifest
|
|
@@ -174,6 +172,9 @@ msg="Anti-slop audit - $rel
|
|
|
174
172
|
${flag_block}${checklist}
|
|
175
173
|
|
|
176
174
|
(Advisory; the bug pass is the self-review trigger. Disable: ANTI_SLOP_ENFORCE=0)"
|
|
175
|
+
# Expand ~ so the model gets literal absolute paths (followups should be
|
|
176
|
+
# copy-pasteable; bash expands ~ but the agent may not be in a bash context).
|
|
177
|
+
msg="$(expand_agent_paths "$msg")"
|
|
177
178
|
|
|
178
179
|
# --- append to the shared pending file --------------------------------------
|
|
179
180
|
cid="$(safe_conversation_id "$input")"
|
|
@@ -56,26 +56,18 @@ Step A — mechanical scan (if available):
|
|
|
56
56
|
Step B — canonical checklist (always):
|
|
57
57
|
Read `~/.agents/hooks/anti-slop.md` and apply ALL 13 items to every hunk you
|
|
58
58
|
changed this session. That file is the single source of truth for slop
|
|
59
|
-
detection —
|
|
60
|
-
|
|
61
|
-
surface. Fix every hit; consolidate clones to one source of truth.
|
|
59
|
+
detection — it is NOT repeated here. Fix every hit; consolidate clones to one
|
|
60
|
+
source of truth.
|
|
62
61
|
|
|
63
62
|
Step C — session footprint (also in the header above):
|
|
64
63
|
If "Session footprint" shows >5 files or the request was simple, justify each
|
|
65
64
|
file or trim. Unjustified files are slop.
|
|
66
65
|
|
|
67
|
-
Step D — declared scope (closing gate for Compuerta 1):
|
|
68
|
-
If `.scope.json` exists in the repo root, run the session's full diff against
|
|
69
|
-
the declared contract. In your shell:
|
|
70
|
-
for f in $(git diff --name-only HEAD); do
|
|
71
|
-
python ~/.cursor/skills/anti-slop/scripts/scope_match.py --path "$f" --patterns-file .scope.json
|
|
72
|
-
done
|
|
73
|
-
Any file reporting `"in_scope": false` is a scope violation you must justify
|
|
74
|
-
(add to .scope.json with a one-line reason) or revert. If `.scope.json` does
|
|
75
|
-
not exist, this step is skipped — the declared-editing ladder and the
|
|
76
|
-
per-edit scope-gate-audit hook are the opt-in discipline.
|
|
77
|
-
|
|
78
66
|
Fix with edits now; re-run the scan (if Step A ran) and the tests; then stop.
|
|
67
|
+
(The per-edit `scope-gate-audit` hook already checks `.scope.json` files[] on
|
|
68
|
+
every edit — Step D of older versions ran that loop again here. Removed: it
|
|
69
|
+
duplicated the live hook and burned tokens. If `.scope.json` exists, trust the
|
|
70
|
+
per-edit gate; the intent trace in axis 0 is the whole-session backstop.)
|
|
79
71
|
|
|
80
72
|
## 5. Wiring completeness
|
|
81
73
|
For every user-visible behavior you added or changed (button, form submit, API
|
|
@@ -97,3 +89,38 @@ faked, either wire it now or remove the dead half so the diff does not ship
|
|
|
97
89
|
scaffolding that looks complete but does nothing. Stubs you intend to wire later
|
|
98
90
|
must be marked with a `TODO(wire):` comment naming what is missing; unmarked
|
|
99
91
|
dead ends are failures.
|
|
92
|
+
|
|
93
|
+
## 6. Mechanics & Stack Integrity
|
|
94
|
+
Stateless, cheap mechanical checks. These are patterns the regex scanner CANNOT
|
|
95
|
+
catch (they need semantic/transversal judgement), so do them by reading the
|
|
96
|
+
diff. If a pattern below is present, FIX it — do not explain, delete and write
|
|
97
|
+
the correct pattern.
|
|
98
|
+
|
|
99
|
+
Backend / DB:
|
|
100
|
+
- N+1 query: a query/fetch inside a loop over a list -> batch it or join.
|
|
101
|
+
- Non-idempotent mutation: a POST/PUT that double-applies on retry -> make it
|
|
102
|
+
idempotent (idempotency-key) or wrap in a transaction.
|
|
103
|
+
- Transactional integrity: multi-write ops (DB/API/files) without rollback or
|
|
104
|
+
a compensating action on partial failure -> wrap in a transaction or Saga.
|
|
105
|
+
- Missing boundary validation: external input (API/params/DB/URL) trusted
|
|
106
|
+
without a schema (Zod/Pydantic/Joi) -> validate at the boundary; never
|
|
107
|
+
hand-validate deeper in the logic.
|
|
108
|
+
|
|
109
|
+
Frontend (React / Next / Astro / Tailwind):
|
|
110
|
+
- Zombie listener: a useEffect that adds a listener/subscription/timer
|
|
111
|
+
without a cleanup `return` -> add it.
|
|
112
|
+
- God component: a single file doing fetch + state + business logic + JSX
|
|
113
|
+
(>150 lines) -> split hooks / logic / render.
|
|
114
|
+
- Tailwind soup & magic tokens: a className with >~6 utilities repeated across
|
|
115
|
+
elements, or hardcoded hex / z-[9999] -> extract to a component or cva,
|
|
116
|
+
use design tokens.
|
|
117
|
+
- Index-as-key in non-static lists -> use a unique id.
|
|
118
|
+
|
|
119
|
+
Determinism / purity:
|
|
120
|
+
- Date.now(), Math.random(), process.env read inline in business logic ->
|
|
121
|
+
inject them (param or a context module) so the function is pure & testable.
|
|
122
|
+
- In-place mutation of shared state (arr.push, obj.prop =) when a caller holds
|
|
123
|
+
a reference -> return new structures ([...arr, x], .map/.filter).
|
|
124
|
+
|
|
125
|
+
You do NOT need to run a tool for these — read the diff and apply the named fix.
|
|
126
|
+
If none apply, say so in one line.
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# final-review.sh - stop hook (Cursor, Linux).
|
|
3
3
|
#
|
|
4
|
-
# ONE comprehensive end-of-implementation review across
|
|
5
|
-
# intent, correctness, reliability, coverage, anti-slop,
|
|
4
|
+
# ONE comprehensive end-of-implementation review across seven axes:
|
|
5
|
+
# intent, correctness, reliability, coverage, anti-slop, wiring completeness,
|
|
6
|
+
# and mechanics & stack integrity. When the agent finishes
|
|
6
7
|
# an implementation that touched files, Cursor auto-submits this hook's
|
|
7
8
|
# `followup_message` as the next user turn, so the model re-audits everything
|
|
8
9
|
# it changed this session and FIXES what fails.
|
|
@@ -36,21 +37,18 @@ cid="$(safe_conversation_id "$input")"
|
|
|
36
37
|
pending_dir="$(hooks_pending_dir)"
|
|
37
38
|
marker="$pending_dir/session-edits-$cid.txt"
|
|
38
39
|
flag="$pending_dir/reviewed-$cid.flag"
|
|
39
|
-
anchor_flag="$pending_dir/anchor-declared-$cid.flag"
|
|
40
40
|
intent_latch="$pending_dir/intent-injected-$cid.flag"
|
|
41
41
|
|
|
42
42
|
# Sweep state from sessions that died before their stop hook ran.
|
|
43
43
|
find "$pending_dir" -maxdepth 1 -type f -mtime +7 -delete 2>/dev/null
|
|
44
44
|
|
|
45
|
-
# Unconditionally clear the per-turn
|
|
46
|
-
# stop is a turn boundary; clearing here (not only inside the
|
|
47
|
-
# block below) guarantees
|
|
48
|
-
# turn and can never get stranded silenced mid-session
|
|
49
|
-
# - anchor-declared-<cid>.flag (anchor-set-nudge, first-edit reminder)
|
|
50
|
-
# - intent-injected-<cid>.flag (intent-anchor, first-tool re-injection)
|
|
45
|
+
# Unconditionally clear the intent-anchor per-turn latch so the next turn
|
|
46
|
+
# re-fires. Every stop is a turn boundary; clearing here (not only inside the
|
|
47
|
+
# reviewed-flag block below) guarantees it re-fires on the first tool of the
|
|
48
|
+
# NEXT turn and can never get stranded silenced mid-session.
|
|
51
49
|
# last-query-<cid>.hash is NOT cleared here - it persists turn-to-turn so
|
|
52
50
|
# intent-anchor can detect prompt changes; the 7-day sweep above reaps it.
|
|
53
|
-
rm -f "$
|
|
51
|
+
rm -f "$intent_latch" 2>/dev/null
|
|
54
52
|
|
|
55
53
|
# One-shot brake: the previous stop for this conversation emitted the review.
|
|
56
54
|
if [ -f "$flag" ]; then
|
|
@@ -83,16 +81,17 @@ body=""
|
|
|
83
81
|
if [ -z "$body" ]; then
|
|
84
82
|
body='FINAL REVIEW - audit everything you changed this session and FIX what fails
|
|
85
83
|
(do NOT revert the behaviour the user asked for):
|
|
84
|
+
0. Intent trace - tie every diff hunk back to the ORIGINAL REQUEST above.
|
|
85
|
+
Anything untraceable is a hallucinated requirement: revert it. Runs FIRST.
|
|
86
86
|
1. Correctness - logic, edge cases (null/empty/zero/boundary), language traps, security.
|
|
87
87
|
2. Reliability - error paths handled (no empty catch), timeouts/retries, resources
|
|
88
88
|
released on every path, no races, input validated at the boundary.
|
|
89
89
|
3. Coverage - behaviour-bearing changes have real tests; RUN the suite if present;
|
|
90
90
|
no tautological tests.
|
|
91
|
-
4. Anti-slop -
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
slop (retries, await-in-loop, log spam), unjustified files.
|
|
91
|
+
4. Anti-slop - if the anti-slop scanner exists, run `python <scanner> --all` first;
|
|
92
|
+
then read ~/.agents/hooks/anti-slop.md (the single source of truth) and apply all
|
|
93
|
+
13 items to the session diff. Consolidate clones; drop premature abstraction,
|
|
94
|
+
unneeded deps, operational slop, unjustified files. Do NOT re-list the items here.
|
|
96
95
|
5. Wiring completeness - for every user-visible behavior you added/changed
|
|
97
96
|
(button, submit, API call, route, state transition), trace its execution
|
|
98
97
|
path to a REAL EFFECT (persist, mutate, call, render). A dead end is slop:
|
|
@@ -101,6 +100,9 @@ if [ -z "$body" ]; then
|
|
|
101
100
|
now or remove the dead half; mark later-stubs with TODO(wire):.
|
|
102
101
|
Fix now, re-run the scan + tests, then stop. If an axis is clean, say so in one line.'
|
|
103
102
|
fi
|
|
103
|
+
# Expand ~ in the body AND the fallback, so the model gets literal absolute
|
|
104
|
+
# paths it can paste at the shell (bash expands ~, but followups should emit
|
|
105
|
+
# literals agents can copy-paste without re-interpreting).
|
|
104
106
|
body="$(expand_agent_paths "$body")"
|
|
105
107
|
|
|
106
108
|
# Regla R1 (re-entry): if this review pass is a re-audit after a failed gate or
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# semantic-density-audit.sh - afterFileEdit "semantic opacity" advisory (Cursor, Linux).
|
|
3
3
|
#
|
|
4
|
-
# Guards the naming layer the other audit hooks do not see.
|
|
5
|
-
# watches
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# say nothing.
|
|
4
|
+
# Guards the naming layer the other audit hooks do not see. anti-slop-audit
|
|
5
|
+
# watches generated-code PATTERNS; this hook watches whether the identifiers
|
|
6
|
+
# the agent JUST introduced actually communicate intent. DataManager,
|
|
7
|
+
# process(), utils.ts, CoreEngine - names that exist but say nothing.
|
|
9
8
|
#
|
|
10
9
|
# Mechanism: extract ADDED lines from `git diff HEAD -- <rel>` (with the
|
|
11
10
|
# untracked-file fallback anti-slop-audit uses), pipe them to density_scan.py
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# Counterpart of final-review.sh for delegated work. afterFileEdit DOES fire
|
|
5
5
|
# inside subagents (verified: a subagent run left its edits in
|
|
6
6
|
# session-edits-<subagent-cid>.txt), but subagents get no `stop` event, so
|
|
7
|
-
# that marker is never drained and the
|
|
7
|
+
# that marker is never drained and the seven-axis review never fires for
|
|
8
8
|
# delegated implementations. This hook closes the loop: when a subagent
|
|
9
9
|
# finishes and ITS conversation has a session-edits marker, return ONE
|
|
10
10
|
# followup_message so the subagent audits its own implementation before the
|
|
@@ -44,13 +44,13 @@ cid="$(safe_conversation_id "$input")"
|
|
|
44
44
|
pending_dir="$(hooks_pending_dir)"
|
|
45
45
|
marker="$pending_dir/session-edits-$cid.txt"
|
|
46
46
|
flag="$pending_dir/reviewed-$cid.flag"
|
|
47
|
-
anchor_flag="$pending_dir/anchor-declared-$cid.flag"
|
|
48
47
|
intent_latch="$pending_dir/intent-injected-$cid.flag"
|
|
49
48
|
|
|
50
|
-
# Unconditionally clear the per-turn
|
|
51
|
-
# Clearing here (not only inside the reviewed-flag block below)
|
|
52
|
-
#
|
|
53
|
-
|
|
49
|
+
# Unconditionally clear the intent-anchor per-turn latch so the next subagent
|
|
50
|
+
# run re-fires. Clearing here (not only inside the reviewed-flag block below)
|
|
51
|
+
# can never strand it silenced. last-query-<cid>.hash is kept (cross-turn
|
|
52
|
+
# prompt-change detect).
|
|
53
|
+
rm -f "$intent_latch" 2>/dev/null
|
|
54
54
|
|
|
55
55
|
# One-shot brake: the previous subagentStop for this id emitted the review.
|
|
56
56
|
if [ -f "$flag" ]; then
|
|
@@ -76,13 +76,15 @@ body=""
|
|
|
76
76
|
[ -f "$prompt_file" ] && body="$(cat "$prompt_file")"
|
|
77
77
|
if [ -z "$body" ]; then
|
|
78
78
|
body='Audit everything you changed in this run and FIX what fails (do NOT revert the
|
|
79
|
-
behaviour the task asked for):
|
|
79
|
+
behaviour the task asked for). Seven axes, in order:
|
|
80
|
+
0. Intent trace - tie every diff hunk back to your original task. Untraceable = hallucinated.
|
|
80
81
|
1. Correctness - logic, edge cases (null/empty/zero/boundary), language traps, security.
|
|
81
82
|
2. Reliability - error paths handled, no swallowed errors, resources released.
|
|
82
83
|
3. Coverage - behaviour-bearing changes have real tests; RUN the suite if present.
|
|
83
|
-
4. Anti-slop - if
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
4. Anti-slop - if the scanner exists, run it --all first; otherwise read
|
|
85
|
+
~/.agents/hooks/anti-slop.md (the single source of truth) and apply all 13 items.
|
|
86
|
+
5. Wiring completeness - trace every added behavior to a REAL EFFECT (persist/mutate/call/render).
|
|
87
|
+
A dead end (handleSubmit that doesn'"'"'t persist, an endpoint no caller invokes) is slop.
|
|
86
88
|
If an axis is clean, say so in one line. Then stop.'
|
|
87
89
|
fi
|
|
88
90
|
body="$(expand_agent_paths "$body")"
|
package/linux/hooks.json
CHANGED
|
@@ -15,12 +15,6 @@
|
|
|
15
15
|
"matcher": "^(Write|StrReplace|EditNotebook)$",
|
|
16
16
|
"_comment": "5s: record the edit in ~/.cursor/.hooks-pending/session-edits-<conversation_id>.txt and stash the self-review prompt in feedback-<conversation_id>.txt. The harness normalizes agent file edits (incl. StrReplace) to tool type 'Write' in this event - verified via payload capture - so ^Write$ matches them all; the alternation is defensive against future harness versions reporting raw tool names. Anchored so TabWrite (every user tab-completion) stays excluded. The model is the auditor. NOTE: fires inside subagent contexts too, keyed by the SUBAGENT's conversation_id - see subagentStop + the marker fold in post-tool-use.sh/final-review.sh."
|
|
17
17
|
},
|
|
18
|
-
{
|
|
19
|
-
"command": "bash ~/.agents/hooks/minimal-edit-audit.sh",
|
|
20
|
-
"timeout": 15,
|
|
21
|
-
"matcher": "^(Write|StrReplace|EditNotebook)$",
|
|
22
|
-
"_comment": "15s (DEPRECATED in 0.3.0, superseded by semantic-density-audit + declared-editing; retained for compat, removal slated for 0.4.0): minimal-editing advisory on the edited file (git --numstat line-count). Size-based gate; the intent-declared gate supersedes it. Appends findings to the conversation's pending file; never blocks. Disable: HOOKS_ENFORCE=0 or MINIMAL_EDITING_ENFORCE=0."
|
|
23
|
-
},
|
|
24
18
|
{
|
|
25
19
|
"command": "bash ~/.agents/hooks/semantic-density-audit.sh",
|
|
26
20
|
"timeout": 15,
|
|
@@ -37,13 +31,7 @@
|
|
|
37
31
|
"command": "bash ~/.agents/hooks/anti-slop-audit.sh",
|
|
38
32
|
"timeout": 15,
|
|
39
33
|
"matcher": "^(Write|StrReplace|EditNotebook)$",
|
|
40
|
-
"_comment": "15s: AI-slop advisory
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
"command": "bash ~/.agents/hooks/anchor-set-nudge.sh",
|
|
44
|
-
"timeout": 5,
|
|
45
|
-
"matcher": "^(Write|StrReplace|EditNotebook)$",
|
|
46
|
-
"_comment": "5s: PROACTIVE pre-compile nudge. On the FIRST edit of each agent turn (per conversation), remind the agent to compile its Anchor Set (pre-compile.md) into .scope.json BEFORE piling on more code. The reactive audits (self-review / anti-slop / final-review axis 0) only fire after code exists; this catches intent dilution at token ~50 instead of ~5000. One-shot per turn: gated by anchor-declared-<cid>.flag, armed here on first edit and cleared UNCONDITIONALLY by final-review.sh / subagent-stop-review.sh on every stop - so it re-fires on the first edit of the next turn and can never get stranded silenced. Advisory only; never blocks. Disable: HOOKS_ENFORCE=0 or ANCHOR_NUDGE_ENFORCE=0."
|
|
34
|
+
"_comment": "15s: AI-slop advisory. git diff flags new deps / premature abstractions (Factory/Repository/Mediator/CQRS/DDD) / redundant comments, and injects the anti-slop.md self-review checklist on substantial edits (>= ANTI_SLOP_CHECKLIST_LINES, default 40). Appends to the conversation's pending file; never blocks. Disable: HOOKS_ENFORCE=0 or ANTI_SLOP_ENFORCE=0."
|
|
47
35
|
}
|
|
48
36
|
],
|
|
49
37
|
"postToolUse": [
|
|
@@ -78,7 +66,7 @@
|
|
|
78
66
|
"stop": [
|
|
79
67
|
{
|
|
80
68
|
"command": "bash ~/.agents/hooks/final-review.sh",
|
|
81
|
-
"timeout":
|
|
69
|
+
"timeout": 10,
|
|
82
70
|
"loop_limit": 5,
|
|
83
71
|
"_comment": "5s: ONE comprehensive end-of-implementation review across correctness + reliability + coverage + anti-slop. If the agent edited files this loop (session-edits-<conversation_id> marker), returns {followup_message} so Cursor auto-submits ONE review pass. Bounded by the script's per-conversation reviewed-flag (one review per implementation); loop_limit is the harness-side runaway cap. Disable: HOOKS_ENFORCE=0 or FINAL_REVIEW_ENFORCE=0."
|
|
84
72
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cursordoctrine",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Thin self-review hooks for Cursor — the model is the auditor.
|
|
3
|
+
"version": "0.5.2",
|
|
4
|
+
"description": "Thin self-review hooks for Cursor — the model is the auditor. Pruned + deduplicated: intent-anchor (auto-scaffolded .scope.json per prompt + per-turn re-injection against Salience Dilution), intent-trace final review, unified anti-slop checklist as single source of truth.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"cursordoctrine": "bin/cli.mjs"
|
|
7
7
|
},
|
|
@@ -20,7 +20,7 @@ description: >-
|
|
|
20
20
|
duplicate utilities.
|
|
21
21
|
metadata:
|
|
22
22
|
layer: active-cleanup
|
|
23
|
-
pairs-with: declared-editing
|
|
23
|
+
pairs-with: declared-editing, semantic-density-audit
|
|
24
24
|
---
|
|
25
25
|
|
|
26
26
|
# Anti-Slop
|
|
@@ -228,7 +228,7 @@ The `stop` hook (`~/.agents/hooks/final-review.ps1` on Windows,
|
|
|
228
228
|
`~/.agents/hooks/final-review.sh` on Linux) fires after the agent finishes an
|
|
229
229
|
implementation that edited files. It extracts the last `<user_query>` from the
|
|
230
230
|
session transcript (Tier 0 intent trace), reports session footprint (Tier 5),
|
|
231
|
-
and auto-submits a `followup_message` so the model audits
|
|
231
|
+
and auto-submits a `followup_message` so the model audits seven axes: intent,
|
|
232
232
|
correctness, reliability, coverage, anti-slop, wiring completeness. Axis 4 delegates to this skill's
|
|
233
233
|
scanner (`scan_slop.py --all`) and the canonical checklist at
|
|
234
234
|
`~/.agents/hooks/anti-slop.md` (13 items, including semantic contracts,
|
|
@@ -275,8 +275,7 @@ low-density identifiers per edit — shares `low_density.py` with this scanner's
|
|
|
275
275
|
`semantic_density` bucket), the **scope-gate-audit hook**
|
|
276
276
|
(`scope-gate-audit.ps1` / `.sh`, Compuerta 1 — opt-in declared-scope gate
|
|
277
277
|
that flags edits outside `.scope.json`; shares `scope_match.py` with the
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
**declared-editing** (YAGNI ultra ladder injected at session start
|
|
281
|
-
|
|
282
|
-
active "delete it now" layer those only nudge toward.
|
|
278
|
+
**stop hook** (`final-review.ps1` / `.sh`,
|
|
279
|
+
seven-axis session review incl. intent trace, wiring completeness, and mechanics & stack integrity), and
|
|
280
|
+
**declared-editing** (YAGNI ultra ladder injected at session start).
|
|
281
|
+
This skill is the active "delete it now" layer those only nudge toward.
|
package/windows/doctrine.md
CHANGED
|
@@ -13,27 +13,25 @@ new rule, you do not add it here — you do the work.
|
|
|
13
13
|
|
|
14
14
|
## 1. You are the auditor
|
|
15
15
|
|
|
16
|
-
The harness
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
(installed under `~/.agents/hooks/` — if you cannot find it, run
|
|
25
|
-
`find ~/.agents ~/.cursor ~/.config -name self-review.md 2>/dev/null`
|
|
26
|
-
on first session).
|
|
16
|
+
The harness ships a set of **advisory hooks** — small scripts that flag
|
|
17
|
+
patterns after you edit (semantic density, declared-scope drift, AI slop) and
|
|
18
|
+
hand them back to you as `additional_context`. They never block, never revert,
|
|
19
|
+
never decide anything. They surface signals; **you** decide. A permission-gate
|
|
20
|
+
denies a short list of dangerous shell commands (`rm -rf` on absolute paths,
|
|
21
|
+
`curl|sh`, force-push, `npm publish`, ...). That is the only hard block. After
|
|
22
|
+
every `Edit`, a self-review prompt is handed back to you so you re-read your
|
|
23
|
+
own diff and fix bugs.
|
|
27
24
|
|
|
28
25
|
This means:
|
|
29
26
|
|
|
30
|
-
- You do not need a
|
|
31
|
-
|
|
32
|
-
changed, see if it is wrong,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
- You do not need a deterministic gate to catch bugs. The hooks seed signals
|
|
28
|
+
(regex hits, scope violations, low-density names); you do the actual audit
|
|
29
|
+
— **read the file you just changed, see if it is wrong, fix it if so.**
|
|
30
|
+
A self-review you do yourself, in your own context, is **free** — you have
|
|
31
|
+
the file, the diff, the user's intent, and the ability to fix.
|
|
32
|
+
- The hooks are advisory, not authoritative. If a hook flags something and you
|
|
33
|
+
disagree, say so in one line and proceed. You outrank the hooks. They exist
|
|
34
|
+
to remind you, not to overrule you.
|
|
37
35
|
- "Bugs" means things that would fail a careful code review at
|
|
38
36
|
Anthropic / Stripe / Vercel. Style, naming, formatting, missing
|
|
39
37
|
type hints, "you could write this more idiomatically" — these are
|
|
@@ -140,20 +138,18 @@ When you call Bash:
|
|
|
140
138
|
|
|
141
139
|
## 7. What you do not do
|
|
142
140
|
|
|
143
|
-
- You do not
|
|
144
|
-
|
|
141
|
+
- You do not treat the advisory hooks as a gate to satisfy. They surface
|
|
142
|
+
signals; the hooks do not block, and you are the auditor. Optimize for
|
|
143
|
+
"the change is correct, small, and the user can review it in 30 seconds,"
|
|
144
|
+
not for "no hook fired."
|
|
145
145
|
- You do not write to `.stuck-files/`, `.audit-baselines/`, or any
|
|
146
146
|
other hook state directory. Those are not your concern.
|
|
147
|
-
- You do not maintain a "strict quality gate" config. There isn't
|
|
148
|
-
one. The rules above *are* the gate.
|
|
149
147
|
- You do not set kill-switch env vars (`HOOKS_ENFORCE=0`,
|
|
150
|
-
`
|
|
148
|
+
`INTENT_ANCHOR_ENFORCE=0`, etc.) to silence the hooks. They exist; work
|
|
149
|
+
with them, or tell the user if one is wrong.
|
|
151
150
|
- You do not re-read the doctrine on every turn. You read it once,
|
|
152
151
|
at session start, and internalize it. The self-review trigger
|
|
153
152
|
will re-prompt you for the specific edit you're auditing.
|
|
154
|
-
- You do not optimize for "the gate passed." You optimize for
|
|
155
|
-
"the change is correct, small, and the user can review it in
|
|
156
|
-
30 seconds."
|
|
157
153
|
|
|
158
154
|
---
|
|
159
155
|
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# anti-slop-audit.ps1 - afterFileEdit "AI slop" advisory (Cursor).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
# over-editing (diff size / token-Levenshtein / added complexity). This hook
|
|
5
|
-
# guards the rest of the taxonomy: the parts static analysis can cheaply and
|
|
3
|
+
# Guards the parts of the slop taxonomy static analysis can cheaply and
|
|
6
4
|
# precisely flag, plus a self-review checklist for the parts it cannot.
|
|
7
5
|
#
|
|
8
6
|
# Statically flagged (high-precision, deliberately low false-positive):
|
|
@@ -209,9 +207,11 @@ Fix guilty items now. Never revert what the user asked for.
|
|
|
209
207
|
$flagBlock = if ($flags.Count -gt 0) { "Static signals on this edit:`n" + ($flags -join "`n") + "`n`n" } else { '' }
|
|
210
208
|
|
|
211
209
|
# Concatenate (do NOT interpolate $checklist - its content must stay literal).
|
|
210
|
+
# Expand ~ on the final message so the model gets literal absolute paths
|
|
211
|
+
# (Windows pwsh does NOT expand ~; the agent may paste paths into a shell).
|
|
212
212
|
$header = "Anti-slop audit - $rel`n`n"
|
|
213
213
|
$footer = "`n`n(Advisory; the bug pass is the self-review trigger. Disable: ANTI_SLOP_ENFORCE=0)"
|
|
214
|
-
$msg = $header + $flagBlock + $checklist + $footer
|
|
214
|
+
$msg = Expand-AgentPaths ($header + $flagBlock + $checklist + $footer)
|
|
215
215
|
|
|
216
216
|
# --- append to the shared pending file ------------------------------------
|
|
217
217
|
$cid = Get-SafeConversationId $obj
|