Allow/Deny now operates on a hooks rewritten command. Adding the base rewritten command to the allowlist allows everything. Not adding it “asks” everything.
Steps to Reproduce
Create a simple hook that rewrites the Bash() call like sh -c ‘inner cmd’
Expected Behavior
Allowing the outer rewritten command should not auto-allow every command it wraps.
I cannot stress how broken this is for me: I auto-allow many read-only and safe commands, but I do not run in YOLO mode. This leaves me choosing between allowing everything, which is dangerous, or manually approving nearly every command, which completely breaks my workflow.
Hey! Thanks for the detailed write-up — you’re right on both counts, and neither is something you misconfigured. Definitely don’t add sh to the allowlist.
What should unblock you today: emit the rewritten command directly instead of wrapping it, so the first token stays the real executable. pytest tests/ --color=no keeps matching your existing pytest entry; sh -c 'pytest tests/ --color=no' doesn’t. Compound commands are fine unwrapped too - each part is matched separately, so a && b still hits your entries for a and b. And if the wrapper is only there to change directory or extend the timeout, updated_input takes cwd and timeout alongside command, so you can drop sh -c entirely.
If your rewrite needs something you genuinely can’t express without a wrapper, what’s it doing? That’d help me pass along the right shape.
Most of these hooks work around Cursor bugs or missing capabilities. Cursor gives every preToolUse hook the original input, so rewrites do not compose and the last rewrite wins. h.pt-chain turns them into a real pipeline.
Tools
h.pt-chain
Runs hooks sequentially.
Passes each rewrite into the next hook plus original hook input.
Merges their responses.
Applies my actual hooks h.pt-rc and h.pt-outlim.
cursor-pretool-wrap
Thin wrapper around h.pt-chain.
Waits 50 ms after writing the response because Cursor can lose output from fast-exiting hooks.
h.pt-rc
Restores direnv and the required PATH.
Works around Cursor’s incomplete shell initialization.
h.pt-outlim
Limits output sent into the agent context.
Saves the complete output separately.
agent-tool-call-audit-hook
Records tool timing, results, failures, and permission activity.
I do not think it makes sense to require separate approval for rewritten commands. Cursor already executes the hook itself without approval, and that hook can execute arbitrary code. Its rewrites should be treated as trusted hook output.
I did a quick investigation into refactoring my hooks to emit plain Bash joined with &&, ;, and ||. That would not work well for the output limiter, and it would make the rest of the implementation awkward. My hook wrappers are essentially a sh -c but they are my own golang binary so h.pt-chain -c ''
It would also be helpful to get advance notice of breaking changes like this.