Hooks

Hooks

1. Overview

GitHub Copilot Hooks are a powerful feature that allows you to execute custom shell commands at key lifecycle points during an agent's execution. They enable you to automate workflows, enforce security policies, and integrate Copilot more deeply with your project’s environment.

Key Benefits:

  • Security: Block dangerous commands (e.g., rm -rf) before they run.

  • Quality Control: Automatically run linters or formatters after Copilot edits code.

  • Custom Context: Inject project-specific data (API keys, versions, environment info) into the agent's conversation.

  • Audit Logging: Keep a record of every prompt and tool invocation for compliance.

2. Hook Lifecycle Events

Hooks are triggered at specific "strategic points." Understanding these events is critical for choosing where to place your automation.

Hook Event

When It Fires

Example Use Case

sessionStart

When a new agent session begins.

Initialize environment, log user entry.

userPromptSubmitted

After the user sends a message.

Audit requests or inject system-level instructions.

preToolUse

Before the agent runs a tool (terminal, edit, etc.).

Critical for Security: Deny or approve commands.

postToolUse

After a tool execution finishes.

Run npm test or prettier after a code change.

agentStop

When the agent finishes its response.

Cleanup or status reporting.

errorOccurred

When something goes wrong.

Log errors to an external monitoring service.

3. Creating and Configuring Hooks

Step 1: File Location

Hooks are defined in JSON files. For repository-wide settings that work for the whole team, create them in:

{your-repo}/.github/hooks/my-hooks.json

Step 2: Configuration Format

Your JSON file must follow this structure:

{ "version": 1, "hooks": { "preToolUse": [ { "type": "command", "bash": "./scripts/security-check.sh", "powershell": "./scripts/security-check.ps1", "cwd": "scripts", "timeoutSec": 15 } ] } }

Key Properties:

  • bash / powershell: Paths to your scripts. Copilot will use the appropriate one based on the OS.

  • cwd: The directory the script runs in (relative to repo root).

  • timeoutSec: Defaults to 30s. Keep hooks fast to avoid lagging the UI.

4. How Hooks Interact with Data

Hooks are not just "fire and forget" scripts; they receive and return JSON.

Input (Standard In)

Every hook receives a JSON object via stdin. For example, a preToolUse hook receives:

{ "tool_name": "runTerminalCommand", "tool_input": { "command": "npm install" }, "cwd": "/path/to/project" }

Output (Standard Out)

Your script should output JSON to tell Copilot what to do next.

Example: Blocking a Command

If your script detects a dangerous command, output this:

{ "hookSpecificOutput": { "permissionDecision": "deny", "permissionDecisionReason": "Destructive commands are not allowed in this repo." } }

Example: Adding Context

In a sessionStart hook, you can inject info:

{ "hookSpecificOutput": { "additionalContext": "Important: This project uses Python 3.11 and requires strict type hinting." } }

5. Best Practices & Security

  1. Fail Safely: If your script crashes, Copilot might block execution. Ensure your scripts handle their own errors.

  2. Performance: Keep hooks under 2–5 seconds. If a hook takes too long, users will feel the latency in their chat experience.

  3. No Secrets: Never log environment variables or tokens to standard output/logs that Copilot might see.

6. Troubleshooting

  • Executable Permissions: Ensure your scripts have execution rights (chmod +x script.sh).

  • Verbose Logging: In your script, you can pipe debug info to stderr (e.g., echo "Debug info" >&2) to see it without interfering with the JSON output on stdout.

  • Local Testing: You can test your scripts manually by piping a mock JSON object into them:

    echo '{"tool_name":"bash"}' | ./my-hook.sh