Skip to main content
Endor Labs hooks for GitHub Copilot send a structured event for every session, prompt, shell command, file operation, and MCP tool call. The hook covers the Copilot CLI and VS Code agent mode, and enforces your Coding Agent Governance policies locally before each action runs. Copilot on GitHub.com, such as web chat and pull request reviews, runs on GitHub’s infrastructure and is out of scope.

Before you begin

Confirm the following requirements before you install the hook:
  • An admin has completed the prerequisites, including creating an API key with the AI Audit User role.
  • The target machine runs macOS or Linux with the Copilot CLI or VS Code with Copilot installed. For Windows, generate the configuration.
  • endorctl is on PATH. This applies to the hand-written configuration below. A generated configuration installs and updates endorctl automatically at session start.
  • For the hand-written configuration, the environment that launches Copilot has these environment variables set:
    • ENDOR_API (for example, https://api.endorlabs.com)
    • ENDOR_NAMESPACE
    • ENDOR_API_CREDENTIALS_KEY
    • ENDOR_API_CREDENTIALS_SECRET
Do not export ENDOR_TOKEN in the environment that runs the hook. Hooks authenticate with the API key and secret only, and on older versions of endorctl the extra token triggered a mixed-authentication error that blocked endorctl ai-audit.
Use the following hook configuration for macOS and Linux. The single command key is also the only command key that VS Code agent mode reads. Each command sets ENDOR_AI_AUDIT_CACHE_ENABLED=true so the hook batches events locally and flushes them at Stop and SessionEnd.
On Windows, generate the file instead. PowerShell does not accept the KEY=value prefix, so the generated Windows command sets the variable inside an encoded PowerShell payload. See Generate a configuration in your browser to produce it, or use the GitHub Copilot tab under Generate a configuration manually.
Use the capitalized event names shown above on both surfaces. They make the Copilot CLI include the event name in the hook payload.The Copilot CLI reads timeoutSec and VS Code reads timeout, so the configuration sets both to the same ceiling. endorctl limits itself to 5 seconds per invocation regardless, and fails open when it reaches that limit, so the hook never holds an action for the full 30 seconds.

Install for one developer

Use this for a single-machine trial or a personal install. Both the Copilot CLI and VS Code agent mode read personal hooks.
  1. Open ~/.copilot/hooks/endor.json in a text editor. Create the file and directory if they do not exist.
  2. Paste the configuration shown in Before you begin.
  3. Save the file and start a new Copilot session.
If you set COPILOT_HOME, create the file under that directory instead.

Install for a repository

Repository hooks apply to both the Copilot CLI and VS Code agent mode, so they are the lever for covering VS Code users on a managed fleet. Add <repository>/.github/hooks/endor.json with the same configuration and commit it.

Install on a managed fleet

Copilot combines hooks from four levels: policy, user, project, and plugins. The policy level belongs to the administrator, and it is the one level a developer can’t bypass. Hooks installed there ignore disableAllHooks and run regardless of folder trust. Writing the file needs elevated privileges, so developers can’t edit it. Use your MDM, such as Jamf, Intune, Kandji, or JumpCloud, to deliver the hook file to the policy directory for each platform:
  • On macOS and Linux, deliver /etc/github-copilot/policy.d/endor.json.
  • On Windows, deliver C:\ProgramData\GitHub\Copilot\policy.d\endor.json.
Own the file as root with mode 0644. Copilot reads it as the developer’s user, so mode 0600 blocks it. Only the Copilot CLI reads the policy level. VS Code agent mode reads hooks from the workspace .github/hooks directory, the user ~/.copilot/hooks directory, chat.hookFilesLocations, and plugins. None of those paths belongs to the administrator, and the VS Code ChatHooks enterprise policy only turns hooks on or off. Cover VS Code agent mode by committing the repository-level file to the repositories your developers work in. Treat that coverage as best effort until GitHub ships a managed hook path for VS Code. Generate the policy file with the in-browser generator instead of maintaining it by hand. The generated file bakes the credentials into every hook command, so managed machines don’t need the four environment variables. It also adds a bootstrap that installs and updates endorctl at session start. See Deploy Copilot policy hooks to deliver the file to the policy directory. See Keep a fleet current with the scheduled runner to deliver it with the runner.
On macOS, environment variables set in ~/.zshrc reach apps launched from a terminal but not apps launched from Spotlight. Ship the variables through your MDM payload (for example, a launchctl setenv profile or an ~/.zprofile snippet) for full coverage.
If your MDM’s deployment script rejects the inline JSON payload, encode the configuration in Base64 in the script, and decode it on the target machine. This avoids the quoting and escaping issues that some MDMs introduce when publishing JSON.

Copilot hook events used by Coding Agent Governance

The following table lists every event the hook processes. The hook accepts and ignores Copilot events outside this set, such as SubagentStart, SubagentStop, PreCompact, and errorOccurred, if a configuration registers them. An older configuration keeps working, but those events record nothing. Enforcement hooks fail open. If the hook itself errors out, Copilot allows the action rather than blocking it and keeps working. The usual cause is a missing binary. An unreadable local policy cache does not disable enforcement, because the hook falls back to the built-in system policies. A successfully evaluated Block policy still stops the action. On a policy match at PreToolUse, a Block policy denies the tool call. An Ask Permission policy prompts the developer in VS Code agent mode only. The Copilot CLI honors deny but not ask, so on CLI sessions an Ask Permission policy lets the call proceed and records it, the same way Alert behaves. An Alert policy lets the call proceed and records it on both surfaces. Session start is not a blocking point for Copilot. A session-level policy match surfaces as a governance notice in the session instead.

Tune the hook

For an audit-only rollout, set ENDOR_AI_AUDIT_NO_BLOCKING=true in the GitHub Copilot hook environment. endorctl ai-audit then downgrades every Block action to Alert at evaluation time. For Cursor, set it in the shell that launches the IDE. For Claude Code, set it in the env block of settings.json. Policies still record violations under Policy Violations, but the hook never denies a action. Use audit-only mode to seed a new policy without interrupting developers, then unset the variable when you’re ready to enforce. Any value that Go parses as a bool (such as true, 1, or t) turns the option on. Unset, empty, or unparseable values keep enforcement on.

Verify hooks are firing

  1. Start a session in GitHub Copilot and ask the agent to run a benign shell command, such as ls.
  2. Select Agent Governance from the left sidebar, then select Inventory. The page opens on the Workstation Inventory tab.
  3. Confirm the developer’s GitHub Copilot row shows a recent value under Last Active.
If no row appears, see Troubleshoot a quiet machine.

What developers see when a policy fires

When a policy with the Block action matches an event, the hook returns a deny response to GitHub Copilot. GitHub Copilot stops the action and surfaces the User Message to the developer when the hook response can carry it. A response that carries a message also explains that a governance policy denied the action and tells the agent not to work around the block. When a policy with the Ask Permission action matches, GitHub Copilot asks the developer to confirm or deny, where it can pause at that event. Where it cannot, the outcome depends on the event. Endor Labs records the match under Policy Violations as Ask either way. See Enforcement behavior to review the per-agent behavior. When a policy with the Alert action matches, the hook allows the action to proceed. Endor Labs records the event under Policy Violations for your security team to review.

Troubleshoot a quiet machine

Run these checks if a developer’s actions never appear under Workstation Inventory or Policy Violations:
  • Confirm the developer has started at least one session. With the event cache enabled, the hook batches events and flushes them within about 30 seconds of hook activity. A full flush runs at session start and end. Inventory Sessions, Last Active, and counts can therefore lag the newest actions by that interval.
  • Hook errors fail open. If the hook cannot run or reach the Endor Labs API, GitHub Copilot allows the action. The event is missing from inventory rather than surfacing an error. The remaining checks rule out the common causes.
  • Confirm endorctl is on PATH in the environment that runs the hook. The hook fails silently if the binary is not found. Run endorctl version from the same shell to verify.
  • Confirm only one endorctl installation is active. If endorctl ai-audit fails with Failed with non-blocking status code: No stderr output, conflicting installations are the likely cause, such as an npx-provisioned endorctl alongside a Homebrew install. Keep one installation method per machine, remove the others, then run endorctl version to confirm.
  • Confirm ENDOR_API, ENDOR_NAMESPACE, ENDOR_API_CREDENTIALS_KEY, and ENDOR_API_CREDENTIALS_SECRET are set for the process that runs the hook. Cursor reads them from the shell that launched it. Claude Code reads them from the env block in settings.json.
  • Confirm ENDOR_TOKEN is not also exported alongside your Coding Agent Governance API key credentials in the hook environment. Hooks rely only on ENDOR_API_CREDENTIALS_KEY and ENDOR_API_CREDENTIALS_SECRET. ENDOR_TOKEN is redundant and, on older versions of endorctl, triggered a mixed-authentication error that blocked endorctl ai-audit.
  • Confirm the API key has the AI Audit User role and has not expired.
  • Confirm the developer restarted GitHub Copilot after the hooks file changed. GitHub Copilot reads the configuration at session start.
  • Confirm the developer restarted GitHub Copilot after a policy edit. The local policy cache refreshes at session start.
  • Confirm the JSON file parses. A trailing comma silently disables every hook in the file.
  • Confirm the Endor Labs API is reachable from the environment that runs the hook. Network failures appear as gaps in the inventory.

Next steps

With hooks deployed, continue with the following pages: