preToolUse hook returning 'allow' should short-circuit built-in tool dialogs like exit_plan_mode
- Langage dominant
- Shell
- Étoiles
- 11.2k
- Forks
- 1.9k
- Merge moyen
- 14 h 16 min
- PR mergées (30 j)
- 6
Description
## Summary
When a `preToolUse` hook returns `permissionDecision: "allow"` for the `exit_plan_mode` tool, the built-in plan approval dialog still appears, requiring the user to manually click through it. This makes it impossible for hooks to fully automate plan approval, even though `"deny"` already fully short-circuits tool execution.
## Current behavior
1. `preToolUse` hook fires for `exit_plan_mode`
2. Hook returns `{ "permissionDecision": "allow" }` -- this only answers "yes, this tool may run"
3. The tool executes and calls `requestExitPlanMode()` internally
4. The plan approval dialog (`exit_plan_mode.requested`) appears anyway
5. User must manually approve a second time
`"deny"` works perfectly -- the tool never executes, no dialog appears. But `"allow"` is effectively a no-op for tools that have their own built-in interaction dialogs.
## Use case
I build [Plannotator](https://github.com/ramos/plannotator), a visual plan review UI for agentic coding tools. My `preToolUse` hook intercepts `exit_plan_mode`, opens a rich review interface, collects the user's decision, and returns `"allow"` or `"deny"` with feedback. The deny path works great. But on approval, users still have to click through the CLI's plan dialog -- making the approval flow feel redundant.
Hook config:
```json
{
"hooks": {
"preToolUse": [
{
"type": "command",
"bash": "$HOME/.local/bin/plannotator copilot-plan",
"timeoutSec": 345600
}
]
}
}
```
## Proposed solution
Allow `preToolUse` hooks returning `"allow"` for tools with built-in dialogs (like `exit_plan_mode`) to supply the dialog response, skipping the dialog entirely. For example:
```json
{
"permissionDecision": "allow",
"exitPlanModeResponse": {
"approved": true,
"selectedAction": "interactive",
"autoApproveEdits": false
}
}
```
Alternatively, any of these would also work:
- A dedicated `preExitPlanMode` hook type in `QueryHooks` with `ExitPlanModeResponse` as its output type
- A general `preInteraction` hook that fires before any blocking dialog on the `InteractionManager`
- Treating `preToolUse` `"allow"` on `exit_plan_mode` as implicit plan approval (using defaults for `selectedAction`, etc.)
## Why this matters
The current behavior is asymmetric: `"deny"` gives hooks full control, but `"allow"` still forces a manual step. Extensions that implement their own review UI (with richer context, annotations, sharing, etc.) cannot fully replace the built-in dialog on the approval path. This limits the extensibility that the hook system otherwise enables well.
For provenance purposes, this issue was AI assisted.
- not spam though, also the person who authored [this issue](https://github.com/anthropics/claude-code/issues/712).
Guide de contribution
Ouvrir le guide de contribution
Évaluation
Cette issue n'a pas encore été évaluée.