Standalone .github/hooks/*.json postToolUse hook never fires (repo-root, non-plugin)
Nobody has claimed this yet.
- Dominant language
- Shell
- Stars
- 11.2k
- Forks
- 1.9k
- Avg merge
- 14h 16m
- Merged PRs (30d)
- 6
Description
Describe the bug
A postToolUse hook defined in a standalone, repo-root .github/hooks/*.json file (not shipped as part of a plugin) never fires. This isn't a config error being silently dropped in the way #3872 describes -- the debug log shows no trace of the hook file being discovered or read at all, not even a rejection.
This is adjacent to several existing reports but distinct from each:
- #1730 covers
sessionStartspecifically, notpostToolUse. - #2540 and #3659 cover hooks shipped inside a plugin's
hooks.json, not a standalone repo-root.github/hooks/*.jsonfile. - #3872 covers a mis-cased event key being silently dropped after being read; our config used the correct camelCase
postToolUsekey per the documented schema, and the loader appears to never reach it at all. - #4001 is a related but distinct symptom on the separate
.claude/settings.jsonhook-consumption path (wrong shell, missing env var) -- in our own testing, Copilot CLI didn't attempt to run that hook either, rather than running it incorrectly.
Affected version
@github/copilot (npm) 1.0.80, Windows 11. Confirmed reproducing on Linux as well (WSL2 Ubuntu 24.04, 1.0.83) — see update below.
Steps to reproduce the behavior
- In a git repo, create
.github/hooks/validate-dockerfile.json:
(shape taken directly from the documented schema at https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-hooks){ "version": 1, "hooks": { "postToolUse": [ { "type": "command", "bash": "path/to/shared-script.sh", "powershell": "path/to/shared-script.ps1", "cwd": ".", "timeoutSec": 30 } ] } } - The referenced script is instrumented to append its real invocation (stdin, argv, cwd, env) to a log file, so firing can be verified directly rather than inferred.
- Start a non-interactive session (
copilot -p --allow-all-tools "edit the Dockerfile to add one line") that edits a file matching a tool call the hook should intercept. - The edit succeeds. The log file is never created -- the hook script is never invoked.
Repeated across 4 independent variations on Windows, all with the same result (hook never fires):
- Baseline config as above, no
matcherfield. - Same, with
--experimentalpassed at launch. - Same, with an explicit
"matcher": "*"field added (in case an absent matcher means "match nothing" rather than "match everything"). - Same, but the triggering edit made via the Write tool (creating the file) instead of Edit (modifying an existing file), to rule out a tool-specific gap.
~/.copilot/logs/process-*.log for the Windows runs shows a NativeHookPipelineProcessor registered for postToolExecution in general, but contains zero references to validate-dockerfile.json, .github/hooks, or any hook-discovery trace for the test repo -- consistent with the hook file never being read, not merely filtered out after being read (which is what #3872's fix would surface as a debug-level "ignoring unknown event" line; no such line appears here either).
Update (see comment below for full detail): re-tested on Linux (WSL2 Ubuntu 24.04, 1.0.83) with the same log-level rigor as the Windows finding above -- 3 independent runs, all with complete ~/.copilot/logs/process-*.log showing normal session completion, zero hook-discovery trace in any of them. Confirmed not Windows-specific. (A first Linux attempt, noted in this section previously, had been inconclusive due to an incomplete session; that ambiguity is resolved by the re-test.)
Expected behavior
A postToolUse hook in a standalone repo-root .github/hooks/*.json file, using the documented schema, should fire on a matching tool call -- the same way it does for Claude Code's equivalent PostToolUse hook in .claude/settings.json, which was verified firing correctly in the same test session as a control.
Additional context
- Found while verifying whether a single validator script could be shared across a Claude Code
PostToolUsehook and a Copilot CLIpostToolUsehook, for a cross-tool developer tooling project. - Confirmed not Windows-specific -- see the Linux re-test note above.
- This report was drafted with AI assistance (Claude Code) based on a live, instrumented reproduction; happy to provide the raw log files or test fixtures if useful for triage.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing with .github/hooks/validate-dockerfile.json and inspect the complete ~/.copilot/logs/process-*.log output. Trace the NativeHookPipelineProcessor and the standalone .github/hooks discovery path, then verify that a matching postToolUse edit invokes the instrumented script and produces a discovery trace.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- shell
- Domain
- cli, developer-experience
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100