github / github/copilot-cli

Standalone .github/hooks/*.json postToolUse hook never fires (repo-root, non-plugin)

Open
#4,520 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area:configuration
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 sessionStart specifically, not postToolUse.
  • #2540 and #3659 cover hooks shipped inside a plugin's hooks.json, not a standalone repo-root .github/hooks/*.json file.
  • #3872 covers a mis-cased event key being silently dropped after being read; our config used the correct camelCase postToolUse key 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.json hook-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
  1. In a git repo, create .github/hooks/validate-dockerfile.json:
    {
      "version": 1,
      "hooks": {
        "postToolUse": [
          { "type": "command", "bash": "path/to/shared-script.sh", "powershell": "path/to/shared-script.ps1", "cwd": ".", "timeoutSec": 30 }
        ]
      }
    }
    
    (shape taken directly from the documented schema at https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-hooks)
  2. 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.
  3. 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.
  4. 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 matcher field.
  • Same, with --experimental passed 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 PostToolUse hook and a Copilot CLI postToolUse hook, 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.