Hooks allow you to extend and customize the behavior of GitHub Copilot agents by executing custom shell commands at key points during agent execution. For a conceptual overview of hooks—including details of the available hook triggers—see About hooks for GitHub Copilot.
Prerequisite
For Windows only: The examples in this article use PowerShell. If you're using Windows, you must have PowerShell 7.0 or later installed and in your PATH. You can check your PowerShell version by running pwsh --version in a terminal. To install PowerShell, run winget install Microsoft.PowerShell then restart your terminal.
Creating a repository-level hook
-
Create a new
NAME.jsonfile (whereNAMEdescribes the purpose of the file) in the.github/hooks/folder of your repository. -
In your text editor, copy and paste the following hook template. Remove any hooks you don't plan on using from the
hooksarray.JSON { "version": 1, "hooks": { "sessionStart": [...], "sessionEnd": [...], "userPromptSubmitted": [...], "preToolUse": [...], "postToolUse": [...], "errorOccurred": [...] } }{ "version": 1, "hooks": { "sessionStart": [...], "sessionEnd": [...], "userPromptSubmitted": [...], "preToolUse": [...], "postToolUse": [...], "errorOccurred": [...] } } -
Configure your hook syntax under the
bashandpowershellkeys, or directly reference script files you have created.Note
Include both a
bashkey (with a script for Linux and macOS) and apowershellkey (for a script for Windows) to allow the hooks to run on all three operating systems. Copilot uses the appropriate key based on the user's operating system.-
This example runs a script that outputs the start date of the session to a log file using the
sessionStarthook:JSON "sessionStart": [ { "type": "command", "bash": "echo \"Session started: $(date)\" >> logs/session.log", "powershell": "Add-Content -Path logs/session.log -Value \"Session started: $(Get-Date)\"", "cwd": ".", "timeoutSec": 10 } ],"sessionStart": [ { "type": "command", "bash": "echo \"Session started: $(date)\" >> logs/session.log", "powershell": "Add-Content -Path logs/session.log -Value \"Session started: $(Get-Date)\"", "cwd": ".", "timeoutSec": 10 } ], -
This example calls out to an external
log-promptscript:JSON "userPromptSubmitted": [ { "type": "command", "bash": "./scripts/log-prompt.sh", "powershell": "./scripts/log-prompt.ps1", "cwd": "scripts", "env": { "LOG_LEVEL": "INFO" } } ],"userPromptSubmitted": [ { "type": "command", "bash": "./scripts/log-prompt.sh", "powershell": "./scripts/log-prompt.ps1", "cwd": "scripts", "env": { "LOG_LEVEL": "INFO" } } ],For a full reference on the input JSON from agent sessions along with sample scripts, see GitHub Copilot hooks reference.
-
-
Commit the file to the repository and merge it into the default branch. Your hooks will now run during agent sessions.
Creating a user-level hook
User-level hooks are configured just like repository-level hooks, but the hook files are stored locally, below your home directory.
The following examples for macOS and Windows show how to configure hooks that will play a sound and display a message box when the CLI finishes responding to a prompt, and when you quit Copilot CLI. Hooks for Linux would be similar to the macOS example, but would use Linux tools for playing sounds and displaying messages.
User-level example for macOS
-
Create a file called
notification-hooks.jsonin~/.copilot/hooks/.Note
If
COPILOT_HOMEis set, create the file in$COPILOT_HOME/hooks/. -
Copy and paste the following JSON into the file:
JSON { "version": 1, "hooks": { "agentStop": [ { "type": "command", "bash": "osascript -e 'do shell script \"afplay /System/Library/Sounds/Funk.aiff &> /dev/null &\"' -e 'display dialog \"Agent stopped.\" with title \"Hook-generated message\" buttons {\"OK\"} default button \"OK\"'", "timeoutSec": 5 } ], "sessionEnd": [ { "type": "command", "bash": "osascript -e 'do shell script \"afplay /System/Library/Sounds/Funk.aiff &> /dev/null &\"' -e 'display dialog \"Session ended.\" with title \"Hook-generated message\" buttons {\"OK\"} default button \"OK\"'", "timeoutSec": 5 } ] } }{ "version": 1, "hooks": { "agentStop": [ { "type": "command", "bash": "osascript -e 'do shell script \"afplay /System/Library/Sounds/Funk.aiff &> /dev/null &\"' -e 'display dialog \"Agent stopped.\" with title \"Hook-generated message\" buttons {\"OK\"} default button \"OK\"'", "timeoutSec": 5 } ], "sessionEnd": [ { "type": "command", "bash": "osascript -e 'do shell script \"afplay /System/Library/Sounds/Funk.aiff &> /dev/null &\"' -e 'display dialog \"Session ended.\" with title \"Hook-generated message\" buttons {\"OK\"} default button \"OK\"'", "timeoutSec": 5 } ] } } -
Start, or restart, Copilot CLI.
Note
Changes to hook configurations are loaded when the CLI starts.
-
Enter a prompt and check that you hear a sound and see a message box when the agent finishes responding, and when you quit the CLI.
-
Delete the
notification-hooks.jsonfile to remove these hooks.
User-level example for Windows
-
Create a file called
notification-hooks.jsonin%USERPROFILE%\.copilot\hooks\.Note
If
COPILOT_HOMEis set, create the file in%COPILOT_HOME%\hooks\. -
Copy and paste the following JSON into the file:
JSON { "version": 1, "hooks": { "agentStop": [ { "type": "command", "powershell": "Add-Type -AssemblyName System.Windows.Forms; [System.Media.SystemSounds]::Asterisk.Play(); [System.Windows.Forms.MessageBox]::Show('Agent stopped.', 'Hook-generated message') | Out-Null", "timeoutSec": 5 } ], "sessionEnd": [ { "type": "command", "powershell": "Add-Type -AssemblyName System.Windows.Forms; [System.Media.SystemSounds]::Asterisk.Play(); [System.Windows.Forms.MessageBox]::Show('Session ended.', 'Hook-generated message') | Out-Null", "timeoutSec": 5 } ] } }{ "version": 1, "hooks": { "agentStop": [ { "type": "command", "powershell": "Add-Type -AssemblyName System.Windows.Forms; [System.Media.SystemSounds]::Asterisk.Play(); [System.Windows.Forms.MessageBox]::Show('Agent stopped.', 'Hook-generated message') | Out-Null", "timeoutSec": 5 } ], "sessionEnd": [ { "type": "command", "powershell": "Add-Type -AssemblyName System.Windows.Forms; [System.Media.SystemSounds]::Asterisk.Play(); [System.Windows.Forms.MessageBox]::Show('Session ended.', 'Hook-generated message') | Out-Null", "timeoutSec": 5 } ] } } -
Start, or restart, Copilot CLI.
Note
Changes to hook configurations are loaded when the CLI starts.
-
Enter a prompt and check that you hear a sound and see a message box when the agent finishes responding, and when you quit the CLI.
-
Delete the
notification-hooks.jsonfile to remove these hooks.
Troubleshooting
If you run into problems using hooks, use the following table to troubleshoot.
| Issue | Action |
|---|---|
| Hooks are not executing |
|
| Hooks are timing out |
|
| Invalid JSON output |
|
Debugging
You can debug hooks using the following methods:
-
Enable verbose logging in the script to inspect the input data and trace script execution.
Shell #!/bin/bash set -x # Enable bash debug mode INPUT=$(cat) echo "DEBUG: Received input" >&2 echo "$INPUT" >&2 # ... rest of script
#!/bin/bash set -x # Enable bash debug mode INPUT=$(cat) echo "DEBUG: Received input" >&2 echo "$INPUT" >&2 # ... rest of script -
Test hooks locally by piping test input into your hook to validate its behavior:
Shell # Create test input echo '{"timestamp":1704614400000,"cwd":"/tmp","toolName":"bash","toolArgs":"{\"command\":\"ls\"}"}' | ./my-hook.sh # Check exit code echo $? # Validate output is valid JSON ./my-hook.sh | jq .# Create test input echo '{"timestamp":1704614400000,"cwd":"/tmp","toolName":"bash","toolArgs":"{\"command\":\"ls\"}"}' | ./my-hook.sh # Check exit code echo $? # Validate output is valid JSON ./my-hook.sh | jq .