Skip to content

Add Bash substitution rules#26

Merged
jssblck merged 2 commits into
mainfrom
jssblck/issue-19
May 29, 2026
Merged

Add Bash substitution rules#26
jssblck merged 2 commits into
mainfrom
jssblck/issue-19

Conversation

@jssblck
Copy link
Copy Markdown
Contributor

@jssblck jssblck commented May 29, 2026

Why this change

Issue #19 asks Nudge to avoid blocking and retrying when a rule can be handled by a deterministic mechanical Bash command rewrite, such as replacing npm install foo with yarn add foo.

Before this change, all PreToolUse matches were blocking rule violations, even when the desired fix was a simple substitution. This added unnecessary round trips for agents and made project-specific command wrapper rules more cumbersome than they needed to be.

This PR adds first-class action: substitute support for PreToolUse Bash rules. Substitute rules use regex replace: templates, preserve the provider's full original tool_input, return permissionDecision: "allow" with updatedInput, and add hookSpecificOutput.additionalContext so both Claude Code and Codex CLI models can see what Nudge rewrote before the command runs.

Block rules still run after substitution, so rewritten commands remain subject to normal policy checks. nudge check explicitly ignores substitute rules because check mode scans repository files, while substitutions require a live Bash hook payload and a provider that can receive updatedInput.

Fixes #19.

Testing steps performed

$ cargo fmt --all
Warning: can't set `wrap_comments = true`, unstable features are only available in nightly channel.
Warning: can't set `wrap_comments = true`, unstable features are only available in nightly channel.
Warning: can't set `wrap_comments = true`, unstable features are only available in nightly channel.
Warning: can't set `wrap_comments = true`, unstable features are only available in nightly channel.
$ cargo test -p nudge
running 64 tests
...
test result: ok. 64 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s

running 1 test
...
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 72 tests
...
test result: ok. 72 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.79s

Doc-tests nudge

running 1 test
...
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
$ cargo run -p nudge --quiet -- claude docs >/tmp/nudge-docs.out && rg -n 'Substitution Rules|use-yarn-add|action: substitute|additionalContext|CI note: nudge check ignores substitute rules|updatedInput' /tmp/nudge-docs.out
134:Substitution Rules
136:  Use action: substitute for deterministic Bash command rewrites. Substitute rules
139:  hookSpecificOutput.additionalContext so the model sees what changed.
142:    - name: use-yarn-add
144:      action: substitute
159:  CI note: nudge check ignores substitute rules. Check mode scans repository
161:  payload and a provider that can receive updatedInput.
414:    - name: use-yarn-add
416:      action: substitute

jssblck added 2 commits May 29, 2026 13:19
Introduce action: substitute for deterministic PreToolUse Bash command rewrites. Substitute rules use regex replace templates, preserve the provider's full original tool_input, and return permissionDecision: allow with updatedInput so both Claude Code and Codex CLI can proceed without a retry loop.

Use hookSpecificOutput.additionalContext as the model-visible explanation of what Nudge rewrote, while keeping systemMessage as the user-visible audit note. Block rules still take priority after substitution, so rewritten commands remain subject to existing policy.

Update the rule docs, README, AGENTS/CLAUDE guidance, RFC notes, nudge test output, and CI check filtering so substitute rules do not require fake block messages or appear as file lint rules.

Testing: cargo fmt --all; cargo test -p nudge; cargo run -p nudge --quiet -- claude docs >/tmp/nudge-docs.out && rg -n 'Substitution Rules|use-yarn-add|action: substitute|additionalContext' /tmp/nudge-docs.out
Clarify that nudge check only evaluates file-based block rules and ignores action: substitute rules, because substitutions require a live Bash hook payload and a provider that can receive updatedInput.

Testing: cargo run -p nudge --quiet -- claude docs >/tmp/nudge-docs.out && rg -n 'CI note: nudge check ignores substitute rules|updatedInput' /tmp/nudge-docs.out; cargo test -p nudge
@jssblck jssblck merged commit 39deb49 into main May 29, 2026
4 checks passed
@jssblck jssblck deleted the jssblck/issue-19 branch May 29, 2026 21:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Substitution rules for simple mechanical replacements

1 participant