Skip to content

alxayo/copilot-flight-recorder

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

copilot-flight-recorder

A full audit trail for your GitHub Copilot agent sessions. Every prompt, response, and file change is captured and committed linearly to a configurable external git repo — giving you a complete record you can review, search, or use to reproduce sessions exactly as they happened.

Viewer dashboard at: https://github.com/alxayo/copilot-flight-recorder-viewer

System Requirements

  • VS Code 1.99 or later with the GitHub Copilot Chat extension
  • Git 2.20+ available on PATH
  • jq (Linux/macOS only) — install guide
  • PowerShell 5.1+ (Windows) or Bash 4+ (Linux/macOS)
  • Operating systems: Windows, macOS, Linux

Coding Agent Compatibility

This hook system uses the VS Code Copilot Chat Hooks API, which relies on .github/hooks/copilot-audit.json and the specific hook events (SessionStart, UserPromptSubmit, PostToolUse, Stop) provided by the VS Code Copilot extension.

✅ Supported

Agent Notes
GitHub Copilot Chat (VS Code) Fully supported. All four hook events are used for complete audit coverage: session lifecycle, prompt capture, file-change diffs, and transcript export.

⚠️ Partially Compatible (requires adaptation)

Agent Why
GitHub Copilot CLI (standalone agent) Has a hooks system that loads from .github/hooks/ — the same directory this project uses — but it is not a drop-in replacement. Key incompatibilities: (1) event key names differ (sessionStart vs SessionStart, userPromptSubmitted vs UserPromptSubmit, sessionEnd vs Stop); (2) no sessionId field in any payload — session identity would need to be derived from timestamp + cwd; (3) sessionEnd carries no transcript_path, so transcript capture is unavailable; (4) file-editing tool names differ (edit, create, bash vs create_file, replace_string_in_file, etc.), breaking the PostToolUse filtering logic. A CLI-specific hooks config and updated scripts could adapt the core git/audit approach.
Anthropic Claude Code All four required events exist with identical names (SessionStart, UserPromptSubmit, PostToolUse, Stop), and session_id and transcript_path are common fields present in every event payload. However, it is not a drop-in replacement. Key incompatibilities: (1) hooks are configured in .claude/settings.json using a matcher-group structure with a command field, not in .github/hooks/copilot-audit.json with bash/powershell split keys; (2) all payload fields use snake_case (session_id, tool_name, tool_input) rather than camelCase — scripts must be updated accordingly; (3) file-editing tool names differ (Write, Edit vs create_file, replace_string_in_file, etc.), so the PostToolUse tool-name filter list must be rewritten; (4) no native PowerShell command path — a single command field runs in a shell, requiring a separate Windows adaptation strategy. The core git/audit logic could be adapted with a Claude Code-specific config and updated field parsing.
Cursor Has a full hooks system configured in .cursor/hooks.json. All four conceptually equivalent events exist: sessionStart, beforeSubmitPrompt, postToolUse, and stop. Critically, transcript_path is a common base field present in every hook payload, and conversation_id serves as the stable session identifier. However, it is not a drop-in replacement. Key incompatibilities: (1) hooks are configured in .cursor/hooks.json with a single command field, not in .github/hooks/copilot-audit.json with bash/powershell split keys; (2) event names differ (sessionStart vs SessionStart, beforeSubmitPrompt vs UserPromptSubmit); (3) all payload fields use snake_case (conversation_id, tool_name, tool_input) — scripts must be updated accordingly; (4) file-editing tool names differ (Write vs create_file, replace_string_in_file, etc.), so the postToolUse filter list must be rewritten; (5) no native PowerShell command path — single command field requires a separate Windows adaptation strategy. The core git/audit approach is fully adaptable with a Cursor-specific config.

❌ Not Supported

Agent Why
GitHub Copilot CLI extension (gh copilot) This is a separate product from the standalone Copilot CLI — a gh CLI extension for natural language shell command translation, not an agentic coding session runner. It has no hooks system and does not load .github/hooks/ configs.
Other editors/agents Any tool that does not implement the VS Code Copilot Chat Hooks specification will not work with this system.

How It Works

Four VS Code agent hooks fire during a Copilot chat session:

Hook Event What It Does
SessionStart Creates the session directory in the audit repo, commits a 000-session-start.md with metadata
UserPromptSubmit Writes the user's prompt to NNN-prompt.md, commits it
PostToolUse After a file-editing tool runs, captures git diff HEAD from the workspace and commits a NNN-changes.patch
Stop Copies the full transcript (via transcript_path) to transcript.json, commits it

Each file gets its own commit with a descriptive message like [<sessionId>] prompt: Fix the login bug….

Branching Modes

  • Flat (default): All commits go to a single branch (default main). Commit messages include the session ID for filtering.
  • Per-session: Each chat session gets its own branch named session/<sessionId>.

Audit Repo Structure

<audit-repo>/
└── sessions/
    └── <sessionId>/
        ├── 001-session-start.md
        ├── 002-prompt.md
        ├── 003-changes.patch
        ├── 003-changes.meta.json
        ├── 004-prompt.md
        ├── 005-changes.patch
        ├── 005-changes.meta.json
        └── transcript.json

Setup

  1. Clone or copy this workspace (the one containing .github/hooks/) into your project, or copy the .github/hooks/ directory into an existing project's root.

  2. Create the audit repo (a separate git repo that will hold the audit trail):

    mkdir ~/copilot-audit
    cd ~/copilot-audit
    git init
    git commit --allow-empty -m "init audit repo"
  3. Configure by copying .env.example to .env and setting at least COPILOT_AUDIT_REPO:

    cp .env.example .env
    # Edit .env:
    COPILOT_AUDIT_REPO=/home/you/copilot-audit

    Alternatively, set environment variables directly (they take priority over .env).

  4. Open the workspace in VS Code. The hooks in .github/hooks/copilot-audit.json are loaded automatically.

  5. Start a Copilot chat session. Check the GitHub Copilot Chat Hooks output channel to verify hooks are executing.

Same-Repo Audit with Git Worktrees

By default the audit trail lives in a separate git repository. If you prefer to keep everything in a single repo — your source code on main and audit data on an audit branch — you can use a git worktree.

Why a worktree?

The hooks need to git checkout the audit branch and commit files to it. If the audit repo is your main workspace directory, that checkout would switch your working tree away from your development branch, breaking your editor state and any in-progress work. A worktree gives you a second checkout directory backed by the exact same .git database, so both branches can be checked out simultaneously without interference.

One-time setup

Run these commands from your project root (e.g. C:\code\myproject):

# 1. Create an orphan "audit" branch with no files (keeps history separate from code)
git checkout --orphan audit
git rm -rf .
git commit --allow-empty -m "audit: init"
git checkout main          # switch back to your working branch

# 2. Create a worktree directory so the audit branch has its own checkout
#    Place it next to (not inside) your project directory
git worktree add ../myproject-audit audit

On Linux/macOS the commands are identical — just adjust the path style:

git worktree add ../myproject-audit audit

This creates ../myproject-audit/ checked out on the audit branch.

Configure the .env

Point COPILOT_AUDIT_REPO at the worktree directory:

# .env (in your project root)
COPILOT_AUDIT_REPO=C:\code\myproject-audit   # absolute path to the worktree
COPILOT_AUDIT_BRANCH=audit
COPILOT_AUDIT_MODE=flat
COPILOT_AUDIT_PUSH=false

On Linux/macOS:

COPILOT_AUDIT_REPO=/home/you/code/myproject-audit

How it works under the hood

myproject/                  ← your normal workspace (branch: main)
├── .git/                   ← shared git database
├── .env                    ← points COPILOT_AUDIT_REPO to the worktree
├── .github/hooks/          ← copilot-flight-recorder hooks
└── src/                    ← your source code

myproject-audit/            ← worktree checkout (branch: audit)
├── sessions/
│   └── <sessionId>/
│       ├── 001-session-start.md
│       ├── 002-prompt.md
│       ├── 003-changes.patch
│       └── transcript.json
  • Both directories share the same .git database, same remotes, same refs.
  • Commits made in either directory are immediately visible to the other.
  • Branches are independent — updating audit never touches main and vice versa.

Pushing the audit branch

You can push the audit branch from either directory at any time, regardless of which branch is checked out in the other:

# From your main workspace
git push origin audit

# Or from the worktree
git -C C:\code\myproject-audit push origin audit

To push automatically after each session, set COPILOT_AUDIT_PUSH=true in your .env.

Viewing audit history from your main workspace

Since it's the same repo, all standard git commands work:

# See audit commits
git log audit --oneline

# Show a specific session's files
git show audit:sessions/<sessionId>/001-session-start.md

# Diff between two audit commits
git diff audit~5..audit

Removing the worktree (keeping the branch)

If you no longer need the separate checkout directory:

git worktree remove ../myproject-audit

The audit branch and all its commits remain in the repo. You can recreate the worktree at any time with git worktree add.

Important notes

  • Don't nest the worktree inside your project — place it alongside (e.g. ../myproject-audit) so that your workspace's .gitignore and file watchers don't interfere with it.
  • The audit branch is an orphan branch with its own independent history. It shares no commits with main and merging it is neither required nor recommended.
  • If you use per-session mode (COPILOT_AUDIT_MODE=per-session), each session creates a session/<id> branch. These also branch off within the same repo and are visible everywhere.
  • Concurrent sessions: If multiple VS Code windows use the same worktree, commits may interleave. Use per-session mode or separate worktrees per workspace to avoid this.

Configuration

All settings can be provided as environment variables or in a .env file at the workspace root. Environment variables take priority.

Variable Description Default
COPILOT_AUDIT_REPO Required. Absolute path to the audit git repo
COPILOT_AUDIT_MODE flat or per-session flat
COPILOT_AUDIT_BRANCH Branch name for flat mode main
COPILOT_AUDIT_PUSH Auto-push after session ends (true/false) false

File-Editing Tools Tracked

The PostToolUse hook only captures diffs when these VS Code tools are used:

  • create_file
  • replace_string_in_file
  • multi_replace_string_in_file
  • edit_notebook_file
  • insert_text_in_file
  • delete_file

All other tools (terminal, search, etc.) are silently skipped.

Cross-Referencing Audit Data with Source Commits

Each PostToolUse event produces a .meta.json sidecar file alongside the .patch file, capturing workspace git state at the time of the edit:

{
  "sessionId": "a1b2c3d4",
  "filePath": "src/handler.ts",
  "workspaceHead": "abc123def456",
  "fileContentHash": "789abc012def",
  "timestamp": "2026-03-11T10:30:00.000Z",
  "toolName": "replace_string_in_file",
  "patchFile": "003-changes.patch"
}
Field Description
workspaceHead git rev-parse HEAD of the source repo at edit time — the baseline commit the .patch diff is relative to
fileContentHash git hash-object of the file after the edit — a content-addressable hash even without a commit. null for file deletions
patchFile Name of the companion .patch file containing the actual diff

How to correlate with source commits

Copilot edits files in the working tree without committing. When the user eventually commits (e.g. xyz789), its parent is the workspaceHead recorded in the metadata. To find all Copilot-driven edits that became part of a commit:

# Find the parent of a source commit
PARENT=$(git rev-parse xyz789~1)

# Find all audit metadata referencing that baseline
jq -s "[.[] | select(.workspaceHead == \"$PARENT\")]" \
  sessions/*/???-changes.meta.json

Useful queries

# All files changed by a specific session
jq -s '[.[] | select(.sessionId == "a1b2c3d4") | .filePath]' \
  sessions/*/???-changes.meta.json

# All sessions that touched a specific file
jq -s '[.[] | select(.filePath | endswith("handler.ts")) | .sessionId] | unique' \
  sessions/*/???-changes.meta.json

# Full cross-reference table
jq -s '[.[] | {sessionId, filePath, workspaceHead, toolName}]' \
  sessions/*/???-changes.meta.json

Verification

  1. Set COPILOT_AUDIT_REPO to a test git repo and open the workspace in VS Code.
  2. Start a chat session → check for 001-session-start.md in the audit repo.
  3. Send a prompt → check for 002-prompt.md.
  4. Ask Copilot to edit a file → check for 003-changes.patch.
  5. End the session → check for transcript.json.
  6. For per-session mode, set COPILOT_AUDIT_MODE=per-session and verify a session/<id> branch is created.

Security Notes

  • The .env file is git-ignored to prevent leaking local paths.
  • Hook scripts run with the same permissions as VS Code. Review them before use in shared repos.
  • Consider using chat.tools.edits.autoApprove to prevent the agent from modifying hook scripts during a session.
  • No secrets are stored in scripts — all config flows through environment variables.

Limitations

  • git diff HEAD captures cumulative workspace changes, not per-tool incremental diffs. If you make manual edits between tool uses, those appear in the patch too.
  • Brand-new untracked files (from create_file) are captured as raw content rather than unified diff format.
  • No file-locking: concurrent sessions targeting the same audit repo could interleave commits. Use per-session mode or separate audit repos to avoid this.

Plugin Installation

copilot-flight-recorder is packaged as a VS Code Agent Plugin and can be installed in several ways.

Prerequisite: Enable agent plugins in VS Code with "chat.plugins.enabled": true.

Option 1: Install from a release archive

  1. Download the latest .zip or .tar.gz from Releases.
  2. Extract to a directory (e.g. ~/.copilot-plugins/copilot-flight-recorder).
  3. Add to your VS Code settings.json:
    "chat.plugins.paths": {
      "/path/to/copilot-flight-recorder": true
    }

Option 2: Install from git (clone)

git clone https://github.com/alxayo/copilot-flight-recorder.git ~/.copilot-plugins/copilot-flight-recorder

Then add the path to chat.plugins.paths as shown above.

Option 3: Use as a marketplace source

Add the repo directly as a plugin marketplace in your VS Code settings.json:

"chat.plugins.marketplaces": ["alxayo/copilot-flight-recorder"]

VS Code will discover and offer the plugin for installation automatically.

Option 4: Use the install script

From a cloned copy of this repo:

# Linux / macOS
./scripts/install-plugin.sh

# Windows (PowerShell)
.\scripts\install-plugin.ps1

The script copies the plugin to ~/.copilot-plugins/copilot-flight-recorder and prints the settings.json snippet to activate it.

Building the Plugin Package

To create distributable archives from source:

# Linux / macOS
bash scripts/build-plugin.sh

# Windows (PowerShell)
powershell -ExecutionPolicy Bypass -File scripts\build-plugin.ps1

This produces dist/copilot-flight-recorder-<version>.zip and .tar.gz archives ready for distribution.

CI/CD

A GitHub Actions workflow (.github/workflows/release-plugin.yml) automatically:

  1. Validates the plugin structure (all required files, valid JSON)
  2. Builds the zip and tar.gz archives
  3. Publishes them as GitHub Release assets when you push a version tag:
git tag v1.0.0
git push origin v1.0.0

About

A full audit trail for your GitHub Copilot agent sessions. Every prompt, response, and file change is captured and committed linearly to a configurable external git repo — giving you a complete record you can review, search, or use to reproduce sessions exactly as they happened.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors