docs: the nudge-hook pattern, with a worked example, and the approver carve-out cross-reference - #34
Merged
Conversation
… carve-out cross-reference Closes #7. Closes #33. #7 — the kit documented only how a hook *refuses*. Adds the advisory variant: a PreToolUse hook that returns no permissionDecision, emits additionalContext, and lets the call through. The rule it settles is gate-vs-nudge — gate when the violation is mechanically provable, nudge when the judgement belongs to the agent or a wrong block would cost more than a missed reminder. Two corrections to the issue as filed. The MAH nudges it harvests fire on PreToolUse, not PostToolUse, and the difference is load-bearing: a reminder that arrives after the edit is too late to change it. And the contract itself is not in the reference — the docs describe additionalContext but never the omit-the-decision case — so it was probed rather than inferred, and the README says so. Ships sensitive-edit-nudge.{ps1,sh} as the worked example: fires on auth/identity/ security/migrations/infra paths, reminds the agent the change is risk:high. Installed but deliberately unregistered — the mechanism is the kit's, the policy is the team's. Message is ASCII-only and the JSON is [ordered] because the two twins must emit identical bytes, and PowerShell mangled an em dash and shuffled hashtable keys. #33 — anti-patterns.md stated the sole-approver rule as unconditional, the one place it appeared without pointing at the single-maintainer carve-out. Both statements were true in their own scope, which is exactly why a reader could not tell which governed. Verified: hook contract probed live; both twins across nine payloads (sensitive paths, Windows separators, near-miss directories, malformed JSON, empty stdin) emit identical bytes and fail open; the shipped script fired end-to-end on a gated path and stayed silent on an ordinary one; check_standard.py clean; 37 tests pass. Self-approved under the solo-maintainer carve-out in docs/team.md: internal repo, no second maintainer, mechanical ladder green, and named here rather than taken silently. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aesqvsMqJpzEdpDXDTjvF
4 tasks
MCKRUZ
added a commit
to MCKRUZ/claude-code-sdlc
that referenced
this pull request
Jul 31, 2026
Regenerates the bundled payload from delivery-standard/kit after MCKRUZ/intent-driven-development#34, which added the nudge-hook pattern to the kit's hooks README and shipped sensitive-edit-nudge.{ps1,sh} as its worked example. Without this the plugin installs a README describing a hook the adopter does not have. `sync_kit.py` ran clean (123 files, --check reports in sync), but two things needed a hand afterward and neither is caught by the sync itself: - shutil.copytree does not carry the git executable bit on Windows, so the new .sh landed 100644 while its three siblings are 100755. Installed non-executable it dies with 'Permission denied' — the exact failure install_harness.py warns about. Set with update-index --chmod=+x. Every future .sh added to the kit will need the same, which is worth fixing in sync_kit.py rather than remembering. - The golden installed-tree snapshot caught the two new files, as designed. Regenerated via GOLDEN_REGEN=1; the diff is exactly the two expected paths and nothing else. 531 passed, 6 skipped. Self-approved under the solo-maintainer carve-out: internal repo, no second maintainer, suite green, and named here rather than taken silently. Claude-Session: https://claude.ai/code/session_014aesqvsMqJpzEdpDXDTjvF Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
MCKRUZ
added a commit
that referenced
this pull request
Jul 31, 2026
#35 was filed after the list in #34 was written, so the list went stale the same day it was refreshed. Which is the argument #35 itself makes. Claude-Session: https://claude.ai/code/session_014aesqvsMqJpzEdpDXDTjvF Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #7. Closes #33.
#7 — the pattern the kit used but never documented
Every hook in
kit/hooks/refuses. This adds the other half: a hook that fires on the same event, returns no decision, and drops a sentence into the agent's context at the moment of action.The rule it settles is gate vs. nudge. Gate when the rule is absolute and the violation is mechanically provable — build red, receipt missing. Nudge when the judgement belongs to the agent, or when a wrong block would cost more than a missed reminder. Without that middle option, those rules go in
CLAUDE.mdand get forgotten, which is the argument the README already makes for the gates.Two corrections to the issue as filed:
PostToolUse. They arePreToolUse, and the difference is load-bearing — a reminder that arrives after the edit is too late to change it.additionalContextand coverpermissionDecision, but never the case where you omit the decision entirely — which is the whole trick. Given that section is headed "verified — do not 'improve' these", it was probed rather than inferred, and the README records both the result and the date.The worked example
sensitive-edit-nudge.{ps1,sh}fires when the agent edits an auth, identity, security, migrations, orinfra/path and reminds it the change isrisk:high. Installed but not registered — a nudge encodes one team's policy, so the kit ships the mechanism and leaves the rule to the adopter. Registration snippet is in the README.Two defects found and fixed in it during verification: PowerShell mangled an em dash in the message to a hyphen, and its hashtable emitted JSON keys in arbitrary order (it flipped between runs). The message is ASCII-only now and the JSON is
[ordered], both with comments explaining why — the twins have to emit identical bytes or neither can be pinned by a test.#33 — the sole-approver cross-reference
docs/anti-patterns.mdstated the rule as "a hard rule at every team size", the one place it appeared without pointing at the single-maintainer carve-out indocs/team.md. Both statements were true in their own scope — anti-pattern 2 describes delivery pods, where there genuinely is always a second person — and that is exactly why a reader who had seen both could not tell which governed. Now it points. The glossary already did.Test plan
src/authors/), missingfile_path, malformed JSON, empty stdin — byte-identical output, fail-open throughout, exit 0 every timesrc/Api/Auth/TokenService.cs, silent onsrc/Api/Orders/OrderService.cspython scripts/check_standard.py— no driftpytest scripts/tests— 37 passed.shtwin committed mode 755, LF endings, matching the other threeFollow-ups (not in this PR)
scripts/sync_kit.pyre-run soclaude-code-sdlc/harness/picks up the new hook — separate repo, separate PR, being opened alongside this one.kit/README.md, two trees inGOLD-STANDARD.md, its HTML twin) andcheck_standard.pywould not have caught a miss — the same class of drift it was built to catch.Approval
Self-approved under the solo-maintainer carve-out in
docs/team.md: internal repo, no second maintainer, mechanical ladder green, named here rather than taken silently.🤖 Generated with Claude Code
https://claude.ai/code/session_014aesqvsMqJpzEdpDXDTjvF