For the complete documentation index, see llms.txt. This page is also available as Markdown.

Copilot Hooks

Akto Guardrails for GitHub Copilot provides security validation for AI-assisted development across VS Code and the CLI. It intercepts prompts when submitted and tool executions before and after they run, validates against security policies, blocks risky behavior, and reports events to your Akto dashboard.

Key Features

  • Zero Installation - No standalone apps to install

  • Transparent Integration - Uses GitHub Copilot's native hook mechanism in both VS Code and CLI

  • Real-time Tool Blocking - Can block dangerous tool executions before they run

  • Centralized Monitoring - All events reported to Akto dashboard

  • Agent Registration - Automatically registers the device (ID + username) with Akto on first hook invocation

  • Flexible Deployment - Supports Argus and Atlas modes

  • Configurable Behavior - Blocking or observation modes

  • Cross-platform - Full support for macOS, Linux, and Windows (including Azure Virtual Desktop)

  • ⚠️ Prompt Monitoring Only - GitHub Copilot limitation prevents blocking prompts at submission

How Hooks Works

GitHub Copilot's hook system executes custom scripts at three critical points in both VS Code and the CLI:

3 Hook Points:

  1. userPromptSubmitted - Monitors prompts when submitted to Copilot (reporting only, cannot block)

  2. preToolUse - Validates tool use before execution and can block dangerous operations

  3. postToolUse - Ingests tool execution results for monitoring and audit

File Structure

Key Files:

  • Wrapper scripts (.sh / .ps1): Set environment variables, invoke Python scripts

    • ⚠️ Contains AKTO_DATA_INGESTION_URL placeholder - Must be set to your Akto instance URL

    • ⚠️ Contains AKTO_API_TOKEN placeholder - Must be set for agent registration

    • .sh used on macOS/Linux; .ps1 used on Windows

  • Python scripts (.py): Core validation logic and Akto API communication

  • akto_machine_id.py: Generates unique device identifiers — uses Windows registry (MachineGuid) on Windows, IOPlatformUUID on macOS, /etc/machine-id on Linux

  • akto_heartbeat.py: Sends agent registration (device ID, username, OS) to Akto on each hook invocation, rate-limited to once per 30 seconds via a local timestamp cache

  • hooks.json: Links hooks to wrapper scripts — uses bash key on macOS/Linux and powershell key on Windows

Note: hooks.json is loaded from the project root's .github/hooks/ directory.

Setup Guide

Prerequisites

  • GitHub Copilot CLI installed and authenticated — run copilot (macOS/Linux) or copilot.exe (Windows) to verify

  • VS Code with the GitHub Copilot extension (for VS Code hook support)

  • Akto instance URL

  • Python 3

macOS / Linux: bash or zsh

Windows: PowerShell 5.1+ (built-in on Windows 10/11, including Azure Virtual Desktop pooled sessions)

Project-level Installation

Install hooks inside a specific repository at <project-root>/.github/hooks/. Copilot CLI auto-loads hooks.json from this location when you run copilot from the project root. These hooks only fire for Copilot CLI sessions launched from this repository.

Use this approach when hooks should only apply inside one repository — e.g. committed alongside the codebase as a per-project security control. For machine-wide coverage that applies to every Copilot CLI session regardless of directory, see Global (User-level) Installation below.

1

Create the Hooks Directory

macOS / Linux:

Windows (PowerShell):

2

Download Hook Scripts

macOS / Linux:

Windows (PowerShell):

3

Configure URLs and API Token ⚠️ CRITICAL STEP

macOS / Linux — automated replacement:

Windows (PowerShell) — automated replacement:

Manual replacement (alternative):

Edit each wrapper script and replace the two placeholders with your actual values.

Files to update on macOS/Linux:

  • akto-validate-prompt-wrapper.sh

  • akto-validate-pre-tool-wrapper.sh

  • akto-validate-post-tool-wrapper.sh

Files to update on Windows:

  • akto-validate-prompt-wrapper.ps1

  • akto-validate-pre-tool-wrapper.ps1

  • akto-validate-post-tool-wrapper.ps1

4

Verify hooks.json Configuration

The hooks.json file should already be configured after downloading. Verify it contains all three hooks:

Windows note: The powershell key is used automatically on Windows. The .ps1 wrapper sets all required environment variables before invoking the Python script — equivalent to what the .sh wrappers do on macOS/Linux.

Note: timeoutSec is in seconds (30 = 30 seconds). Hooks are loaded from .github/hooks/hooks.json in the directory you run copilot from.

5

Configure Hook Behavior (Optional)

Edit wrapper scripts to customize:

macOS / Linux — in each *-wrapper.sh:

Windows — in each *-wrapper.ps1:

Mode Options:

  • Argus: Standard validation and reporting

  • Atlas: Includes device-specific metadata

Sync Mode:

  • true: Validates in real-time; preToolUse blocks dangerous tool executions

  • false: Monitoring only; all tool executions pass through but are logged

6

Verify Installation

macOS / Linux:

Windows (PowerShell):

Check logs to confirm hooks are working:

macOS / Linux:

Windows (PowerShell):

Global (User-level) Installation

The project-level install above applies only inside the repo it lives in. To apply Akto Guardrails to every Copilot CLI session on your machine — regardless of which directory you launch from — install hooks once at the user level. Wrappers live at ~/.github/hooks/ and are registered directly in ~/.copilot/config.json (no per-repo hooks.json).

Use the project-level install when hooks should only apply inside one repository (e.g. committed as a per-project security control). Use the user-level install below when every Copilot CLI invocation on your machine should go through Akto Guardrails.

1

Create the Global Hooks Directory

macOS / Linux:

Windows (PowerShell):

2

Download Hook Scripts

Download the eight hook files into the directory you just created. Do not download hooks.json — user-level hooks are defined directly in ~/.copilot/config.json (step 4 below), not in a separate hooks.json file.

Files you will download (all from https://raw.githubusercontent.com/akto-api-security/akto/master/apps/mcp-endpoint-shield/github-cli-hooks/):

#
macOS / Linux
Windows

1

akto-validate-prompt-wrapper.sh

akto-validate-prompt-wrapper.ps1

2

akto-validate-prompt.py

akto-validate-prompt.py

3

akto-validate-pre-tool-wrapper.sh

akto-validate-pre-tool-wrapper.ps1

4

akto-validate-pre-tool.py

akto-validate-pre-tool.py

5

akto-validate-post-tool-wrapper.sh

akto-validate-post-tool-wrapper.ps1

6

akto-validate-post-tool.py

akto-validate-post-tool.py

7

akto_machine_id.py

akto_machine_id.py

8

akto_heartbeat.py

akto_heartbeat.py

macOS / Linux — copy the entire block below, paste it into your terminal, press Enter:

Confirm all 8 files landed in the directory:

Windows (PowerShell) — copy the entire block below, paste it into PowerShell, press Enter:

Confirm all 8 files landed in the directory:

3

Configure Wrappers ⚠️ CRITICAL STEP

Each of the three wrapper scripts you downloaded has four things that need to be set before Copilot CLI can run them. The block below handles all four in one shot.

What the block does:

  1. Replaces {{AKTO_DATA_INGESTION_URL}} inside the wrappers with your Akto instance URL.

  2. Replaces {{AKTO_API_TOKEN}} inside the wrappers with your Akto API token.

  3. Changes the relative ./.github/hooks/akto-validate-*.py reference inside each wrapper to an absolute path (e.g. /Users/you/.github/hooks/akto-validate-*.py). User-level wrappers are invoked from whatever directory the user launched Copilot CLI from, so relative paths would not resolve.

  4. Adds export AKTO_CONNECTOR="github_copilot_cli" (or $env:AKTO_CONNECTOR on Windows). Without this the connector defaults to vscode and CLI traffic is mis-attributed in the Akto dashboard.

macOS / Linux — first, edit the two values at the top of the block (AKTO_URL and AKTO_API_TOKEN) with your real Akto instance URL and API token. Then copy the entire block, paste it into your terminal, and press Enter:

Confirm no placeholders are left and the wrappers look correct:

Windows (PowerShell) — first, edit the two values at the top of the block ($AKTO_URL and $AKTO_API_TOKEN) with your real Akto instance URL and API token. Then copy the entire block, paste it into PowerShell, and press Enter:

Confirm no placeholders are left:

4

Register Hooks in ~/.copilot/config.json

User-level hooks are declared directly in the Copilot CLI user config at ~/.copilot/config.json. There is no separate hooks.json file at the user level, and the hooks object here has no outer version wrapper (that version wrapper is only for repository-level .github/hooks/*.json).

The block below backs up your existing config.json to config.json.bak, then merges in the three Akto hooks (preserving any other keys you already have such as trusted_folders, loggedInUsers, banner, etc).

Requires jq on macOS/Linux (usually preinstalled; if not: brew install jq on macOS, sudo apt install jq on Ubuntu/Debian). Windows uses PowerShell's built-in ConvertFrom-Json / ConvertTo-Json — no extra install.

macOS / Linux — copy the entire block below, paste it into your terminal, press Enter:

Verify the hooks section was written correctly:

Windows (PowerShell) — copy the entire block below, paste it into PowerShell, press Enter:

Verify the hooks section was written correctly:

Reference — what the resulting hooks section in ~/.copilot/config.json should look like (macOS/Linux example):

5

Verify Installation

Three checks in order: validate the config file, run one hook manually end-to-end, then launch Copilot CLI from a directory that is not an Akto-hooked repo so you can confirm hooks fire globally.

Check 1 — Validate the hooks block in ~/.copilot/config.json.

macOS / Linux:

Windows (PowerShell):

Expected: the three events (userPromptSubmitted, preToolUse, postToolUse) each pointing at your absolute wrapper paths.

Check 2 — Run the pre-tool hook manually with a deliberately-flagged payload. The hook should exit 0 and print a JSON permissionDecision: "deny" object to stdout.

macOS / Linux:

Expected output (roughly):

Windows (PowerShell):

Check 3 — Launch Copilot CLI from any directory (e.g. /tmp on macOS/Linux, $env:TEMP on Windows) to prove hooks fire regardless of project. Submit a test prompt that includes an email address, or ask Copilot to run a shell command that would print one, and watch the logs fill up in real time.

Open a second terminal and tail the logs:

macOS / Linux:

Windows (PowerShell):

Then in your first terminal:

macOS / Linux:

Windows (PowerShell):

You should see Connector: github_copilot_cli and guardrail verdicts appearing in the log files for every prompt and tool call — confirming hooks are active globally and not scoped to a project.

Configuration Reference

Wrapper Script Variables

Variable
Required
Default
Description

AKTO_DATA_INGESTION_URL

✅ Yes

Your Akto instance URL for event ingestion

AKTO_API_TOKEN

✅ Yes

Akto API token used to authenticate heartbeat

MODE

No

argus

argus or atlas

AKTO_SYNC_MODE

No

true

true = blocking, false = observe only

AKTO_TIMEOUT

No

5

Request timeout in seconds

DEVICE_ID

No

auto-detected

Override the machine ID

LOG_DIR

No

~/akto/.github/akto/copilot/logs

Log directory

LOG_LEVEL

No

INFO

Log level (DEBUG, INFO, WARNING, ERROR)

DATABASE_ABSTRACTOR_SERVICE_URL

No

https://cyborg.akto.io

Override cyborg URL — self-hosted deployments only

Environment Variables (Optional)

Override defaults via environment variables (e.g. in ~/.bashrc or ~/.zshrc):

Agent Registration

Each hook automatically registers the device with Akto on first invocation (and refreshes every 30 seconds). This mirrors the heartbeat mechanism used by the mcp-endpoint-shield Go agent.

What is registered:

Field
Value

moduleType

GITHUB_COPILOT_CLI_HOOKS

name

Machine ID (hardware-based, persistent)

additionalData.username

System username

additionalData.os

Operating system (Windows, Darwin, Linux)

additionalData.connector

github_copilot_cli or vscode

How machine ID is resolved by platform:

Platform
Source

Windows

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid (registry)

macOS

IOPlatformUUID via ioreg

Linux

/etc/machine-id

Fallback

MAC address via uuid.getnode()

Rate limiting: Registration is sent at most once every 30 seconds. The timestamp is cached in <log_dir>/last_heartbeat. The persistent agent ID is stored in <log_dir>/agent_id — this ID survives across hook invocations so the device appears as a single registered agent in the Akto dashboard.

Troubleshooting

Hooks Not Executing

Ingestion URL Not Configured

macOS / Linux:

Windows (PowerShell):

Windows: Hooks Not Running

Step 1 — Verify .ps1 wrapper files were downloaded:

If missing, re-run the Windows download step above.

Step 2 — Unblock downloaded files:

Files downloaded via Invoke-WebRequest are marked as "from the internet" by Windows. Under RemoteSigned execution policy (default on Windows 10/11), these are blocked. Run:

Step 3 — Check execution policy:

The hooks.json already includes -ExecutionPolicy Bypass in the powershell command, which overrides the policy per-invocation regardless of system settings.

Check Logs for Errors

Events Not in Dashboard

Hook Timing Out

Increase timeoutSec in hooks.json (value in seconds, e.g. "timeoutSec": 60). Ensure AKTO_DATA_INGESTION_URL is reachable from your machine.

Permission Denied on Scripts

Uninstallation

Complete Removal

Selective Removal (Keep Logs)

Backup Before Removal

Verify Removal

Enterprise Deployment

Automated Deployment Script

macOS / Linux:

Windows (PowerShell) — works on Azure Virtual Desktop pooled sessions:

Deploy to developers (Windows):

Quick Setup Summary

Resources

Last updated