Skip to content

docs: document PreToolUse hook permissionDecision "ask" behavior - #6411

Merged
wenshao merged 1 commit into
mainfrom
docs/audit-refresh-pretooluse-ask
Jul 6, 2026
Merged

docs: document PreToolUse hook permissionDecision "ask" behavior#6411
wenshao merged 1 commit into
mainfrom
docs/audit-refresh-pretooluse-ask

Conversation

@DragonnZhang

Copy link
Copy Markdown
Collaborator

What this PR does

Documents what each permissionDecision value does for a PreToolUse hook in docs/users/features/hooks.md. The doc already lists "allow", "deny", and "ask" as the allowed values but never explained their behavior — most importantly "ask", which now pauses the tool and surfaces a TUI confirmation before the tool runs, and falls back to "deny" in contexts that cannot prompt (headless --prompt runs and background subagents).

Why it's needed

A PreToolUse hook returning permissionDecision: "ask" recently changed from behaving like "deny" to actually prompting the user for confirmation. A hook author reading the docs had no way to know what "ask" does or that it degrades to "deny" in non-interactive contexts, so a security-conscious hook could not choose between "deny" and "ask" intentionally. The added description makes the three values' semantics explicit, matching the current runtime behavior.

Reviewer Test Plan

How to verify

Cross-check the added description against the source of truth:

  • "ask" bounces the tool from execution back to awaiting-approval and builds a synthetic confirmation — see bounceToAwaitingApprovalForAsk in packages/core/src/core/coreToolScheduler.ts (ProceedOnce re-executes, Cancel cancels).
  • The non-interactive fallback to deny — see canPromptForAskBounce in the same file: a non-interactive CLI (unless STREAM_JSON), background agents, and suppressed permission prompts return false, so "ask" becomes deny there.

Docs-only change — no runtime behavior is affected. No pages were added, moved, or renamed, so navigation (_meta.ts) and the qc-helper doc index are unchanged.

Evidence (Before & After)

N/A — documentation-only change.

Tested on

OS Status
🍏 macOS N/A
🪟 Windows N/A
🐧 Linux N/A

Environment (optional)

N/A

Risk & Scope

  • Main risk or tradeoff: None beyond documentation accuracy; no code paths change.
  • Not validated / out of scope: Only the PreToolUse permissionDecision semantics are documented; the decision/"ask" fields on other hook events were not expanded.
  • Breaking changes / migration notes: None.

Linked Issues

N/A

中文说明

本 PR 的作用

docs/users/features/hooks.md 中补充说明 PreToolUse 钩子的 permissionDecision 各取值的行为。文档此前已列出 "allow""deny""ask" 三个允许值,但从未说明其行为——尤其是 "ask":它现在会暂停工具调用并在 TUI 中弹出确认,在无法弹出确认的场景(headless --prompt 运行与后台子代理)中回退为 "deny"

为什么需要

PreToolUse 钩子返回 permissionDecision: "ask" 的行为近期从“等同 "deny"”变为“真正提示用户确认”。文档读者无法得知 "ask" 的作用,也不知道它在非交互场景会退化为 "deny",因此安全敏感的钩子无法有意识地在 "deny""ask" 之间选择。新增的说明使三个取值的语义明确,并与当前运行时行为一致。

复核测试计划

仅文档改动,不影响运行时行为。未新增、移动或重命名任何页面,因此导航(_meta.ts)与 qc-helper 文档索引无需改动。对照 packages/core/src/core/coreToolScheduler.ts 中的 bounceToAwaitingApprovalForAskcanPromptForAskBounce 即可核对。

证据(前后对比)

N/A —— 纯文档改动。

风险与范围

  • 主要风险:无,除文档准确性外不涉及任何代码路径。
  • 未覆盖 / 超出范围:仅记录了 PreToolUsepermissionDecision 语义,未扩展其他钩子事件上的 decision/"ask" 字段。
  • 破坏性变更 / 迁移说明:无。

Generated by Claude Code

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓ — all required sections present and filled in.

Problem: this is a docs-only gap — the hooks page lists permissionDecision values ("allow", "deny", "ask") but never explains what each one does. The "ask" value in particular has non-obvious behavior (TUI confirmation + headless fallback) that a hook author needs to understand. Real documentation gap, not theoretical.

Direction: aligned. The hooks system is on the roadmap (roadmap/hooks-events) and documenting its behavior is clearly within scope. No CHANGELOG precedent needed for docs.

Size: not applicable — docs only, no core paths touched. +6 lines, 1 file.

Approach: scope is tight and minimal. The added paragraph sits naturally between the output options list and the existing Note, explaining exactly what was missing. I verified each claim against canPromptForAskBounce and bounceToAwaitingApprovalForAsk in coreToolScheduler.ts — the descriptions of "ask" bouncing to TUI confirmation and falling back to "deny" in non-interactive/headless/background contexts match the code. Clean.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓ — 所有必填部分均已填写。

问题:纯文档缺口 — hooks 页面列出了 permissionDecision 的三个值("allow"、"deny"、"ask"),但从未解释各自的行为。尤其 "ask" 有非显而易见的行为(TUI 确认 + headless 降级),hook 作者需要了解。属于真实的文档缺失,非理论性问题。

方向:对齐。Hooks 系统在路线图中(roadmap/hooks-events),文档补充属于明确范围内。无需 CHANGELOG 先例。

规模:不适用 — 纯文档改动,未触及核心路径。+6 行,1 个文件。

方案:范围紧凑且最小化。新增段落自然地放在输出选项列表和现有 Note 之间,准确补充了缺失的说明。已对照 coreToolScheduler.ts 中的 canPromptForAskBouncebounceToAwaitingApprovalForAsk 验证——"ask" 弹回 TUI 确认、在非交互/headless/后台场景降级为 "deny" 的描述与代码一致。干净利落。

进入代码审查 🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code Review

The diff is 6 lines added to docs/users/features/hooks.md. I verified each claim against the source:

  • "allow" — straightforward, matches the existing allow path in coreToolScheduler.ts.
  • "deny" — matches createErrorResponse behavior: tool doesn't execute, error returned to model. ✓
  • "ask" — verified against bounceToAwaitingApprovalForAsk (bounces to awaiting_approval, ProceedOnce re-executes, Cancel cancels) and canPromptForAskBounce (returns false for non-interactive CLI unless STREAM_JSON/Zed integration, or when permission prompts suppressed). The headless and background-subagent fallback to "deny" is accurately described. ✓

Placement is correct — the paragraph sits between the output options list and the existing Note, which is the natural reading order.

No issues found. Clean docs-only change.

Testing

Docs-only — no runtime behavior to test. Verified the patched section renders correctly in context:

     1  ```
     2
     3  **Output Options**:
     4
     5  - `hookSpecificOutput.permissionDecision`: "allow", "deny", or "ask" (REQUIRED)
     6  - `hookSpecificOutput.permissionDecisionReason`: explanation for the decision (REQUIRED)
     7  - `hookSpecificOutput.updatedInput`: modified tool input parameters to use instead of original
     8  - `hookSpecificOutput.additionalContext`: additional context information
     9
    10  The `permissionDecision` value controls whether the tool runs:
    11
    12  - `"allow"` — run the tool without the usual approval prompt.
    13  - `"deny"` — block the tool; it does not execute and an error is returned to the model.
    14  - `"ask"` — pause and ask the user to confirm the tool call in the TUI before it runs.
         Confirming runs the tool once; declining cancels it. In contexts that cannot prompt
         for confirmation — headless (`--prompt`) runs and background subagents — `"ask"`
         falls back to `"deny"`.
    15
    16  **Note**: While standard hook output fields like `decision` and `reason` are technically
         supported by the underlying class, the official interface expects the
         `hookSpecificOutput` with `permissionDecision` and `permissionDecisionReason`.
    17
    18  **Example Output**:
中文说明

代码审查

Diff 是在 docs/users/features/hooks.md 中新增 6 行。已对照源码验证每项描述:

  • "allow" — 直接对应 coreToolScheduler.ts 中的 allow 路径。
  • "deny" — 对应 createErrorResponse 行为:工具不执行,错误返回给模型。✓
  • "ask" — 已对照 bounceToAwaitingApprovalForAsk(弹回 awaiting_approval,ProceedOnce 重新执行,Cancel 取消)和 canPromptForAskBounce(非交互 CLI 返回 false,除非 STREAM_JSON/Zed 集成,或权限提示被抑制)。headless 和后台子代理降级为 "deny" 的描述准确。✓

段落位置正确——放在输出选项列表和现有 Note 之间,符合自然阅读顺序。

未发现问题。干净的纯文档改动。

测试

纯文档——无可测试的运行时行为。已验证修补后的内容在上下文中正确渲染(见上方代码块)。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

This is a clean, focused docs PR that fills a real gap. The hooks page listed permissionDecision values without explaining what they do — especially "ask", which has non-obvious behavior (TUI bounce + headless deny fallback). Six lines, one file, nothing extraneous.

I verified every claim against coreToolScheduler.ts: the "ask" bounce logic, the canPromptForAskBounce fallback conditions, and the "deny" error path all match. The placement between the output options list and the Note reads naturally.

If I had to maintain this in six months, I'd thank the author — it's the kind of small, accurate docs contribution that saves future hook authors from guessing. Approving.

中文说明

这是一个干净、聚焦的文档 PR,填补了真实的缺口。hooks 页面列出了 permissionDecision 的值却没有解释其行为——尤其 "ask" 有非显而易见的行为(TUI 弹回 + headless 降级为 deny)。6 行,1 个文件,没有多余内容。

已对照 coreToolScheduler.ts 验证每项描述:"ask" 弹回逻辑、canPromptForAskBounce 降级条件、"deny" 错误路径均一致。段落放在输出选项列表和 Note 之间,阅读流畅。

如果六个月后要维护这段内容,我会感谢作者——这是那种小而准确的文档贡献,让未来的 hook 作者不用靠猜。批准。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@wenshao
wenshao added this pull request to the merge queue Jul 6, 2026
Merged via the queue into main with commit bcdb44c Jul 6, 2026
30 of 31 checks passed
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.

4 participants