Hook `async` property silently ignored — postToolUse hooks block tool completion
- Vorherrschende Sprache
- Shell
- Sterne
- 11.2k
- Forks
- 1.9k
- Ø Merge
- 14 Std. 16 Min.
- Gemergte PRs (30 T.)
- 6
Beschreibung
## Describe the bug
The `async` property on command hooks in `hooks.json` is silently ignored. Hooks with `"async": true` still block tool completion because `executeHooks()` unconditionally `await`s every hook in a sequential `for` loop.
Claude Code [documents `async`](https://docs.anthropic.com/en/docs/claude-code/hooks) as a supported hook field:
> **`async`** — If `true`, runs in the background without blocking.
Since plugins share the same `hooks.json` format across both Claude Code and Copilot CLI, authors reasonably expect `"async": true` to work. Instead, it is parsed by the Zod schema (via `.passthrough()`) but never read by the execution path.
## Impact
In a real session, a `postToolUse` hook with `"async": true` blocked for **13.5 seconds** on first invocation because it triggered a package auto-update (resolving 419 packages via `uv`). This added ~14s of latency to the first tool call of the session despite the hook being marked async.
**Timeline from session events:**
```
18:57:09.756 hook.start postToolUse
18:57:22.186 [hook stdout] Resolved 419 packages in 6.91s
18:57:22.803 [hook stdout] Installed 2 packages
18:57:23.216 hook.end ← 13.46s blocked
```
## Root cause
In `sdk/index.js`, the `executeHooks` function (`Yg` in minified source):
```javascript
async function executeHooks(hooks, input, logger, hookType, emitter) {
// ...
for (let hook of hooks) {
let result = await hook(input); // ← always awaits, ignores async flag
// ...
}
}
```
And in `processToolExecutionResult`:
```javascript
await executeHooks(this.getEffectiveHooks()?.postToolUse, ...) // blocks tool completion
```
The `async` property from the hook config is never propagated to the execution layer.
## Expected behavior
When a hook specifies `"async": true`, it should run in the background without blocking tool completion — matching Claude Code's documented behavior. Ideally also support `asyncRewake` for parity.
## Workaround
Plugin authors can append `&` to the shell command to background it manually, but this loses stdout/stderr capture and exit code handling.
## Environment
- Copilot CLI: 1.0.40-2
- OS: macOS (Darwin arm64)
## Related issues
- #2893 — hooks serialized + timeout fail-open (related hook execution model concerns)
Beitragsleitfaden
Rechercherichtung
Start by tracing executeHooks in sdk/index.js and its call from processToolExecutionResult, then inspect how hook configuration reaches the execution layer. Confirm how async hooks should complete in the background and what output, errors, and tool completion should look like; done means async hooks no longer block while synchronous hooks retain their current behavior.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- javascript
- Bereich
- cli
- Issue-Typ
- Bug
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Aktivitätsstatus
- Ruhig
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 48/100