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 awaits every hook in a sequential for loop.
Claude Code documents async 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):
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:
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
Describe the bug
The
asyncproperty on command hooks inhooks.jsonis silently ignored. Hooks with"async": truestill block tool completion becauseexecuteHooks()unconditionallyawaits every hook in a sequentialforloop.Claude Code documents
asyncas a supported hook field:Since plugins share the same
hooks.jsonformat across both Claude Code and Copilot CLI, authors reasonably expect"async": trueto work. Instead, it is parsed by the Zod schema (via.passthrough()) but never read by the execution path.Impact
In a real session, a
postToolUsehook with"async": trueblocked for 13.5 seconds on first invocation because it triggered a package auto-update (resolving 419 packages viauv). This added ~14s of latency to the first tool call of the session despite the hook being marked async.Timeline from session events:
Root cause
In
sdk/index.js, theexecuteHooksfunction (Ygin minified source):And in
processToolExecutionResult:The
asyncproperty 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 supportasyncRewakefor 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
Related issues