Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

whogitit is a tool for tracking AI-generated code at line-level granularity. It tells you exactly which lines were written by AI, which were modified by humans, and what prompts generated them.

Why whogitit?

As AI coding assistants become integral to development workflows, understanding the origin of code becomes increasingly important:

  • Transparency: Know exactly what percentage of your codebase was AI-generated
  • Accountability: Track which prompts led to specific code changes
  • Code Review: Quickly identify AI-generated sections that may need extra scrutiny
  • Compliance: Meet organizational requirements for AI usage disclosure
  • Learning: Understand how AI suggestions were modified and improved by humans

Key Features

  • Line-level attribution - Track whether each line is AI-generated, human-modified, or original
  • Prompt preservation - Store the prompts that generated code alongside commits
  • Three-way diff analysis - Accurate attribution even when you edit AI code before committing
  • Git-native storage - Uses git notes that travel with your repository
  • Claude Code integration - Automatic capture via hooks
  • GitHub Action - PR comments showing AI attribution summaries with prompts
  • Privacy protection - Automatic redaction of API keys, passwords, and sensitive data
  • Data retention policies - Configurable age limits and auto-purge for compliance
  • Audit logging - Track deletions, exports, and configuration changes
  • Export capabilities - Bulk export attribution data as JSON or CSV

How It Works

whogitit uses a dual-hook capture system integrated with Claude Code:

  1. PreToolUse Hook - Captures the file state before any AI edit
  2. PostToolUse Hook - Records the change and extracts the prompt from the session transcript

When you commit, whogitit performs a three-way diff analysis comparing:

  • The original content (before AI edits)
  • The AI-generated content (after each AI edit)
  • The final committed content (after any human modifications)

This analysis determines the attribution for each line, which is stored as a git note attached to the commit.

Attribution Types

SymbolSourceDescription
AIGenerated by AI, unchanged
AIModifiedGenerated by AI, then edited by human
+HumanAdded by human after AI edits
OriginalExisted before AI session
?UnknownCould not determine source

Next Steps

Installation

Prerequisites

  • Git (2.25 or later)
  • jq - JSON processor used by capture hook
    • macOS: brew install jq
    • Linux: apt install jq or dnf install jq
  • Claude Code - For automatic AI attribution capture

macOS / Linux:

curl -sSL https://github.com/dotsetlabs/whogitit/releases/latest/download/install.sh | sh

Windows (PowerShell):

irm https://github.com/dotsetlabs/whogitit/releases/latest/download/install.ps1 | iex

This downloads the latest pre-built binary and installs it to ~/.cargo/bin.

Install via Cargo

If you have Rust installed:

cargo install whogitit

Install from Source

For development or to build from the latest code:

Prerequisites: Rust 1.70 or later

# Clone the repository
git clone https://github.com/dotsetlabs/whogitit
cd whogitit

# Install to ~/.cargo/bin
cargo install --path .

Verify Installation

whogitit --version

You should see output like:

whogitit 0.2.0

The easiest way to set up whogitit is with the automated setup command:

1. Run global setup (once)

whogitit setup

This automatically:

  • Installs the capture hook script to ~/.claude/hooks/
  • Configures Claude Code’s ~/.claude/settings.json with required hooks
  • Creates a backup of your existing settings

Note: After running whogitit setup, you must also run whogitit init in each repository where you want to track AI attribution. The global hooks only activate for initialized repositories.

2. Initialize your repository

cd your-project
whogitit init

This installs git hooks for the repository:

  • post-commit - Attaches attribution data to commits
  • pre-push - Automatically pushes git notes with your code
  • post-rewrite - Preserves notes during rebase and amend

3. Verify setup

whogitit doctor

This checks all configuration and shows any issues:

[OK] whogitit binary: Installed and running
[OK] Capture hook: Installed at ~/.claude/hooks/whogitit-capture.sh
[OK] Hook permissions: Executable
[OK] Claude Code settings: Hooks configured
[OK] Required tools (jq): Available
[OK] Repository hooks: Initialized in current repo

All checks passed! whogitit is properly configured.

Manual Setup (Alternative)

If you prefer manual configuration or need to customize the setup:

1. Copy the hook script

mkdir -p ~/.claude/hooks
cp hooks/whogitit-capture.sh ~/.claude/hooks/
chmod +x ~/.claude/hooks/whogitit-capture.sh

2. Configure Claude Code

Add the following to ~/.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "WHOGITIT_HOOK_PHASE=pre ~/.claude/hooks/whogitit-capture.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "WHOGITIT_HOOK_PHASE=post ~/.claude/hooks/whogitit-capture.sh"
          }
        ]
      }
    ]
  }
}

Note: The hook captures Edit, Write, and Bash tool uses. Bash commands that modify files (like sed, echo >, etc.) are also tracked.

3. Initialize a Repository

In each repository where you want to track AI attribution:

cd your-project
whogitit init

Verify Setup

After setup, you can verify everything is working:

# Run the doctor command for comprehensive checks
whogitit doctor

# Or check manually:
# Check that hooks are installed
ls -la .git/hooks/post-commit .git/hooks/pre-push

# Check git notes configuration
git config --get-all remote.origin.fetch | grep whogitit

Next Steps

Quick Start

This guide will get you tracking AI-generated code in under 5 minutes.

1. Install whogitit

# Install whogitit (if not already done)
cargo install --path /path/to/whogitit

2. Run Global Setup (once)

whogitit setup

This configures Claude Code integration automatically.

3. Initialize Your Repository

cd your-project
whogitit init

4. Verify Setup

whogitit doctor

You should see all checks passing.

5. Write Some Code with Claude

Use Claude Code to make changes to your project. For example:

> Add a function that validates email addresses

Claude will edit or create files. whogitit automatically captures:

  • The file content before the edit
  • The file content after the edit
  • The prompt you used

6. Check Pending Attribution

Before committing, see what whogitit has captured:

whogitit status

Output:

Pending AI attribution:
  Session: 7f3a-4b2c-9d1e-8a7b
  Files: 2
  Edits: 3
  Lines: 45

Run 'git commit' to finalize attribution.

7. Commit Your Changes

Commit as normal:

git add .
git commit -m "Add email validation"

The post-commit hook automatically:

  1. Analyzes the pending changes
  2. Performs three-way diff analysis
  3. Attaches attribution data as a git note

8. View Attribution

See AI attribution for a file

whogitit blame src/validation.rs

Output:

 LINE   │ COMMIT  │ AUTHOR     │ SRC │ CODE
─────────────────────────────────────────────────────────────────────────────────────
    1   │ a1b2c3d │ Greg King  │  ●  │ use regex::Regex;
    2   │ a1b2c3d │ Greg King  │  ●  │
    3   │ a1b2c3d │ Greg King  │  ●  │ pub fn validate_email(email: &str) -> bool {
    4   │ a1b2c3d │ Greg King  │  ◐  │     let pattern = r"^[a-zA-Z0-9._%+-]+@";  // simplified
    5   │ a1b2c3d │ Greg King  │  ●  │     let re = Regex::new(pattern).unwrap();
    6   │ a1b2c3d │ Greg King  │  ●  │     re.is_match(email)
    7   │ a1b2c3d │ Greg King  │  ●  │ }
─────────────────────────────────────────────────────────────────────────────────────
Legend: ● AI (6) ◐ AI-modified (1)
AI involvement: 100% (7 of 7 lines)

See the commit summary

whogitit show HEAD

Output:

Commit: a1b2c3d
Session: 7f3a-4b2c-9d1e-8a7b
Model: claude-opus-4-5-20251101
Started: 2026-01-30T14:23:17Z

Prompts used:
  #0: "Add a function that validates email addresses..."

Files with AI changes:
  src/validation.rs (6 AI, 1 modified) - 7 total lines

Summary:
  6 AI-generated lines
  1 AI line modified by human

Find the prompt that generated a line

whogitit prompt src/validation.rs:3

Output:

╔════════════════════════════════════════════════════════════════════╗
║  PROMPT #0 in session 7f3a-4b2c-9d1e...                            ║
║  Model: claude-opus-4-5-20251101 | 2026-01-30T14:23:17Z            ║
╠════════════════════════════════════════════════════════════════════╣
║  Add a function that validates email addresses                      ║
╚════════════════════════════════════════════════════════════════════╝

Files affected by this prompt:
  - src/validation.rs

9. Push with Attribution

When you push, git notes are automatically included:

git push

The pre-push hook handles git push origin refs/notes/whogitit automatically.

What’s Next?

Core Concepts

Understanding these concepts will help you get the most out of whogitit.

Line Attribution

whogitit tracks the origin of every line in your codebase. Each line is classified into one of five categories:

SourceSymbolDescription
AIGenerated by AI and committed unchanged
AIModifiedGenerated by AI, then edited by a human before commit
Human+Written by a human after AI edits in the same session
OriginalExisted before the AI session started
Unknown?Attribution could not be determined

Why “AIModified” Matters

The distinction between AI and AIModified is crucial:

  • AI (): The AI wrote this and you accepted it as-is
  • AIModified (): The AI wrote something, but you improved or corrected it

This helps identify code that was reviewed and refined versus code that was accepted wholesale.

Three-Way Diff Analysis

whogitit uses a sophisticated three-way diff algorithm to accurately attribute lines, even when you modify AI-generated code before committing.

The Three States

  1. Original - The file content before any AI edits in this session
  2. AI Snapshot - The file content after each AI edit
  3. Final - The content at commit time

How It Works

Original Content          AI Generates           You Modify            Final Commit
      │                        │                      │                      │
      ▼                        ▼                      ▼                      ▼
┌──────────┐            ┌──────────┐            ┌──────────┐            ┌──────────┐
│ line 1   │            │ line 1   │            │ line 1   │            │ line 1   │
│ line 2   │     ──►    │ NEW LINE │     ──►    │ NEW LINE │     ──►    │ NEW LINE │ ● AI
│ line 3   │            │ line 2   │            │ EDITED   │            │ EDITED   │ ◐ AIModified
│          │            │ line 3   │            │ MY LINE  │            │ MY LINE  │ + Human
│          │            │          │            │ line 2   │            │ line 2   │ ─ Original
│          │            │          │            │ line 3   │            │ line 3   │ ─ Original
└──────────┘            └──────────┘            └──────────┘            └──────────┘

By comparing all three states, whogitit determines:

  • Lines that appeared in AI snapshots and remained unchanged → AI
  • Lines that appeared in AI snapshots but were modified → AIModified
  • Lines you added that weren’t in AI snapshots → Human
  • Lines that existed before AI edits → Original

Sessions and Prompts

Sessions

A session represents a continuous period of working with an AI assistant. Each session has:

  • Session ID: A unique identifier
  • Model: The AI model used (e.g., claude-opus-4-5-20251101)
  • Start time: When the session began
  • Prompts: All the prompts used during the session

Prompts

Each prompt you give to the AI is captured and stored with:

  • Index: The order within the session (0, 1, 2, …)
  • Text: The actual prompt (with sensitive data redacted)
  • Affected files: Which files were changed as a result

Git Notes Storage

whogitit stores attribution data in git notes, a built-in git feature for attaching metadata to commits.

Why Git Notes?

  • Native to git: No external database required
  • Travels with the repo: Notes can be pushed/fetched like branches
  • Non-invasive: Doesn’t modify commit history or clutter logs
  • Standard tooling: Can be inspected with normal git commands

The Notes Ref

Attribution is stored under refs/notes/whogitit:

# View raw attribution for a commit
git notes --ref=whogitit show HEAD

# List all commits with attribution
git notes --ref=whogitit list

Pending Buffer

Before a commit, whogitit stores captured changes in a pending buffer (.whogitit-pending.json). This file:

  • Accumulates all file edits during a session
  • Stores complete content snapshots for three-way diff
  • Is processed and cleared when you commit
  • Can be cleared manually with whogitit clear

Pending Buffer Lifecycle

Claude Code Edit
       │
       ▼
PreToolUse Hook ──► Save "before" snapshot
       │
       ▼
   AI makes edit
       │
       ▼
PostToolUse Hook ──► Save "after" snapshot + prompt
       │
       ▼
.whogitit-pending.json (accumulates)
       │
       ▼ (git commit)
       │
Post-commit Hook ──► Three-way analysis ──► Git Note
       │
       ▼
Pending buffer cleared

Privacy and Redaction

Prompts may contain sensitive information. whogitit automatically redacts:

  • API keys and secrets
  • AWS credentials
  • Private keys
  • Bearer tokens
  • GitHub tokens
  • Email addresses
  • Passwords

See Privacy & Redaction for details on configuring redaction patterns.

Next Steps

CLI Commands

whogitit provides a comprehensive CLI for viewing and managing AI attribution data.

Command Overview

Core Attribution Commands

CommandDescription
blameShow AI attribution for each line of a file
showView attribution summary for a commit
promptView the prompt that generated specific lines
summaryGenerate summary for a commit range (PRs)
statusCheck pending attribution changes

Developer Integration Commands

CommandDescription
annotationsGenerate GitHub Checks API annotations
pagerAnnotate git diff output with AI markers

Data Management Commands

CommandDescription
exportExport attribution data as JSON/CSV
retentionManage data retention policies
auditView the audit log
clearDiscard pending changes without committing

Setup Commands

CommandDescription
setupConfigure Claude Code integration (one-time)
doctorVerify whogitit configuration
initInitialize whogitit in a repository
copy-notesCopy attribution between commits

Privacy Commands

CommandDescription
redact-testTest redaction patterns against text/files

Quick Reference

Viewing Attribution

# See AI attribution for a file
whogitit blame src/main.rs

# Show only AI-generated lines
whogitit blame src/main.rs --ai-only

# View commit summary
whogitit show HEAD

# Find prompt that generated a line
whogitit prompt src/main.rs:42

# Summarize a PR
whogitit summary --base main --format markdown

Developer Integration

# Generate GitHub Checks annotations for CI
whogitit annotations --base main --head HEAD

# Use as git pager for AI-annotated diffs
git config --global core.pager "whogitit pager"
git diff | whogitit pager

# Create git aliases
git config --global alias.ai-diff '!git diff | whogitit pager --no-pager'

Managing Data

# Check pending changes
whogitit status

# Clear pending without committing
whogitit clear

# Export all attribution data
whogitit export -o attribution.json

# Preview retention policy
whogitit retention preview

Setup Commands

# One-time global setup (configures Claude Code)
whogitit setup

# Verify all configuration
whogitit doctor

# Initialize repository hooks
whogitit init

# Initialize even if global setup incomplete
whogitit init --force

# Copy attribution (after cherry-pick or manual rebase recovery)
whogitit copy-notes <old-sha> <new-sha>
whogitit copy-notes <old-sha> <new-sha> --dry-run

Privacy Testing

# Test redaction patterns
whogitit redact-test --text "api_key=secret123"

# List available patterns
whogitit redact-test --list-patterns

# Show what would be redacted
whogitit redact-test --file .env --matches-only

Global Options

All commands support these options:

OptionDescription
--helpShow help for any command
--versionShow version information

Output Formats

Many commands support multiple output formats:

FormatFlagUse Case
Pretty(default)Human-readable terminal output
JSON--format jsonMachine parsing, scripts
Markdown--format markdownDocumentation, PR comments
CSV--format csvSpreadsheets, data analysis

Exit Codes

CodeMeaning
0Success
1General error
2Invalid arguments

Next Steps

Explore each command in detail:

Core Commands

Developer Integration

Data & Privacy

Setup

  • setup - Global configuration
  • doctor - Configuration check
  • init - Repository setup
  • copy-notes - Copy attribution between commits

blame

Show AI attribution for each line of a file, similar to git blame but with AI source information.

Synopsis

whogitit blame [OPTIONS] <FILE>

Description

The blame command displays each line of a file with its attribution status, showing whether the line was:

  • Written by AI and unchanged ()
  • Written by AI and modified by a human ()
  • Added by a human after AI edits (+)
  • Original content that existed before AI edits ()

Arguments

ArgumentDescription
<FILE>Path to the file to blame

Options

OptionDescription
--revision <REF>Blame at a specific git revision (default: HEAD)
--format <FORMAT>Output format: pretty (default), json
--ai-onlyShow only AI-generated lines
--human-onlyShow only human-written lines

Examples

Basic Usage

whogitit blame src/main.rs

Output:

 LINE   │ COMMIT  │ AUTHOR     │ SRC │ CODE
─────────────────────────────────────────────────────────────────────────────────────
    1   │ a1b2c3d │ Greg King  │  ─  │ use std::io;
    2   │ d4e5f6g │ Greg King  │  ●  │ use anyhow::Result;
    3   │ d4e5f6g │ Greg King  │  ●  │ use serde::{Deserialize, Serialize};
    4   │ d4e5f6g │ Greg King  │  ◐  │ use chrono::Utc;  // modified
    5   │ h8i9j0k │ Greg King  │  +  │ // Added by human
─────────────────────────────────────────────────────────────────────────────────────
Legend: ● AI (2) ◐ AI-modified (1) + Human (1) ─ Original (1)
AI involvement: 60% (3 of 5 lines)

Blame at a Specific Revision

whogitit blame --revision v1.0.0 src/main.rs

Show Only AI Lines

whogitit blame --ai-only src/main.rs

JSON Output

whogitit blame --format json src/main.rs

Output:

{
  "file": "src/main.rs",
  "revision": "a1b2c3d",
  "lines": [
    {
      "line_number": 1,
      "commit": "a1b2c3d",
      "author": "Greg King",
      "source": "Original",
      "content": "use std::io;"
    },
    {
      "line_number": 2,
      "commit": "d4e5f6g",
      "author": "Greg King",
      "source": "AI",
      "content": "use anyhow::Result;"
    }
  ],
  "summary": {
    "ai_lines": 2,
    "ai_modified_lines": 1,
    "human_lines": 1,
    "original_lines": 1,
    "ai_percentage": 60.0
  }
}

Understanding the Output

Column Descriptions

ColumnDescription
LINELine number in the file
COMMITShort SHA of the commit that introduced this line
AUTHORGit author who committed this line
SRCAttribution source symbol
CODEThe actual line content

Attribution Symbols

SymbolMeaning
AI-generated, unchanged
AI-generated, then modified by human
+Human-written (after AI session)
Original (existed before AI session)
?Unknown (attribution could not be determined)

Summary Statistics

The footer shows:

  • Count of each attribution type
  • AI involvement percentage (AI + AIModified lines / total lines)

Notes

  • If a file has no AI attribution data, the command falls back to standard git blame output with all lines marked as Original ()
  • The --ai-only and --human-only flags are mutually exclusive
  • Line numbers start at 1, matching most editor conventions

See Also

  • show - View commit-level attribution summary
  • prompt - Find the prompt that generated a line

show

View AI attribution summary for a specific commit.

Synopsis

whogitit show [OPTIONS] [COMMIT]

Description

The show command displays a detailed summary of AI attribution for a commit, including:

  • Session information (ID, model, timestamp)
  • All prompts used
  • Per-file breakdown of attribution
  • Overall statistics

Arguments

ArgumentDescription
[COMMIT]Git commit reference (default: HEAD)

Options

OptionDescription
--format <FORMAT>Output format: pretty (default), json, markdown

Examples

Basic Usage

whogitit show HEAD

Output:

Commit: d4e5f6g
Session: 7f3a-4b2c-9d1e-8a7b
Model: claude-opus-4-5-20251101
Started: 2026-01-30T14:23:17Z

Prompts used:
  #0: "Add error handling with anyhow..."
  #1: "Implement the serialize trait..."

Files with AI changes:
  src/auth.rs (25 AI, 3 modified, 2 human) - 45 total lines
  src/main.rs (10 AI, 5 original) - 15 total lines

Summary:
  35 AI-generated lines
  3 AI lines modified by human
  2 human-added lines
  5 original/unchanged lines

Show a Specific Commit

whogitit show abc1234

JSON Output

whogitit show --format json HEAD

Output:

{
  "commit": "d4e5f6gabcdef1234567890",
  "session": {
    "session_id": "7f3a-4b2c-9d1e-8a7b",
    "model": {
      "id": "claude-opus-4-5-20251101",
      "provider": "anthropic"
    },
    "started_at": "2026-01-30T14:23:17Z"
  },
  "prompts": [
    {
      "index": 0,
      "text": "Add error handling with anyhow...",
      "affected_files": ["src/auth.rs", "src/main.rs"]
    }
  ],
  "files": [
    {
      "path": "src/auth.rs",
      "ai_lines": 25,
      "ai_modified_lines": 3,
      "human_lines": 2,
      "original_lines": 15,
      "total_lines": 45
    }
  ],
  "summary": {
    "total_ai_lines": 35,
    "total_ai_modified_lines": 3,
    "total_human_lines": 2,
    "total_original_lines": 5
  }
}

Markdown Output

whogitit show --format markdown HEAD

Useful for including in documentation or PR descriptions.

Output Details

Session Information

FieldDescription
SessionUnique identifier for the AI session
ModelAI model used (e.g., claude-opus-4-5-20251101)
StartedWhen the session began

Prompts Section

Lists all prompts used during the session, with:

  • Index number (for reference with whogitit prompt)
  • Truncated prompt text
  • Files affected by each prompt

Files Section

For each file with AI changes:

  • File path
  • Line counts by attribution type
  • Total lines

Summary Section

Aggregate statistics across all files:

  • Total AI-generated lines
  • Total AI-modified lines
  • Total human-added lines
  • Total original lines

Notes

  • If a commit has no AI attribution, the command will indicate this
  • Prompts are shown truncated; use whogitit prompt for full text
  • The commit can be specified as SHA, branch name, tag, or any git revision

See Also

  • blame - Line-level attribution for a file
  • prompt - View full prompt text
  • summary - Attribution for a range of commits

prompt

View the prompt that generated specific lines of code.

Synopsis

whogitit prompt [OPTIONS] <FILE:LINE>

Description

The prompt command retrieves and displays the prompt that was used to generate a specific line of code. This helps you understand the context and intent behind AI-generated code.

Arguments

ArgumentDescription
<FILE:LINE>File path and line number (e.g., src/main.rs:42)

Options

OptionDescription
--revision <REF>Look up prompt at a specific revision (default: HEAD)
--format <FORMAT>Output format: pretty (default), json

Examples

Basic Usage

whogitit prompt src/main.rs:42

Output:

╔════════════════════════════════════════════════════════════════════╗
║  PROMPT #2 in session 7f3a-4b2c-9d1e...                            ║
║  Model: claude-opus-4-5-20251101 | 2026-01-30T14:23:17Z            ║
╠════════════════════════════════════════════════════════════════════╣
║  Add JWT token generation with 24-hour expiration. Use the         ║
║  jsonwebtoken crate. The function should take a user_id and        ║
║  return a Result<String>.                                          ║
╚════════════════════════════════════════════════════════════════════╝

Files affected by this prompt:
  - src/auth.rs
  - src/main.rs

At a Specific Revision

whogitit prompt --revision v1.0.0 src/auth.rs:15

JSON Output

whogitit prompt --format json src/main.rs:42

Output:

{
  "prompt": {
    "index": 2,
    "text": "Add JWT token generation with 24-hour expiration. Use the jsonwebtoken crate. The function should take a user_id and return a Result<String>.",
    "affected_files": ["src/auth.rs", "src/main.rs"]
  },
  "session": {
    "session_id": "7f3a-4b2c-9d1e-8a7b",
    "model": "claude-opus-4-5-20251101",
    "started_at": "2026-01-30T14:23:17Z"
  },
  "line": {
    "file": "src/main.rs",
    "line_number": 42,
    "source": "AI",
    "content": "    let token = generate_jwt(user_id)?;"
  }
}

Output Details

Prompt Box

The pretty output displays:

  • Prompt index number (within the session)
  • Session ID (truncated)
  • Model used
  • Timestamp
  • Full prompt text

Affected Files

Lists all files that were modified as a result of this prompt. This helps you understand the scope of changes a single prompt triggered.

Use Cases

Understanding AI-Generated Code

When reviewing code and you see an AI attribution symbol, use prompt to understand why the AI wrote it that way:

# See the blame first
whogitit blame src/auth.rs
#   42   │ abc1234 │ Greg King  │  ●  │     let expiry = Utc::now() + Duration::hours(24);

# Look up the prompt
whogitit prompt src/auth.rs:42

Code Review

During code review, quickly check what prompts led to specific changes:

# Find AI lines in a changed file
whogitit blame --ai-only src/api.rs

# Check prompts for interesting lines
whogitit prompt src/api.rs:55

Debugging

If AI-generated code isn’t working as expected, the prompt can reveal misunderstood requirements:

# What was the AI asked to do?
whogitit prompt src/buggy_function.rs:10

Notes

  • If the line is not AI-generated (Original or Human), the command will indicate this
  • Prompts may be redacted if they contained sensitive information
  • The prompt index can be used to cross-reference with whogitit show output

See Also

  • blame - Find AI-generated lines
  • show - See all prompts for a commit

summary

Generate an AI attribution summary for a range of commits, ideal for pull requests.

Synopsis

whogitit summary [OPTIONS]

Description

The summary command aggregates AI attribution data across multiple commits, producing a comprehensive report suitable for pull request descriptions or compliance documentation.

The output focuses on additions (lines added in the commit range), making it directly comparable to what you see in a PR diff.

Options

OptionDescription
--base <REF>Base branch/commit to compare against (default: main)
--head <REF>Head branch/commit (default: HEAD)
--format <FORMAT>Output format: pretty (default), json, markdown

Examples

Basic Usage

whogitit summary --base main

Output:

AI Attribution Summary
======================

Commits analyzed: 5 (3 with AI attribution)

Lines Added:
  +145 AI-generated (72.5%)
  +12 AI-modified by human (6.0%)
  +43 Human-written (21.5%)
  +200 Total additions

AI involvement: 78.5% of additions are AI-generated

Files Changed:
  src/auth.rs +80 (90% AI) (new)
  src/main.rs +45 (70% AI)
  src/jwt.rs +75 (80% AI) (new)

Models used:
  - claude-opus-4-5-20251101

Markdown Output (for PRs)

whogitit summary --base main --format markdown

Output:

## 🤖🤖 AI Attribution Summary

This PR adds **+200** lines with AI attribution across **3** files.

### Additions Breakdown

| Metric | Lines | % of Additions |
|--------|------:|--------------:|
| 🟢 AI-generated | +145 | 72.5% |
| 🟡 AI-modified by human | +12 | 6.0% |
| 🔵 Human-written | +43 | 21.5% |
| **Total additions** | **+200** | **100%** |

**AI involvement: 78.5%** of additions are AI-generated

### Files Changed

| File | +Added | AI | Human | AI % | Status |
|------|-------:|---:|------:|-----:|--------|
| `src/auth.rs` | +80 | 72 | 8 | 90% | New |
| `src/main.rs` | +45 | 32 | 13 | 71% | Modified |
| `src/jwt.rs` | +75 | 53 | 22 | 71% | New |

### Models Used

- claude-opus-4-5-20251101

JSON Output

whogitit summary --base main --format json
{
  "commits_analyzed": 5,
  "commits_with_ai": 3,
  "additions": {
    "total": 200,
    "ai": 145,
    "ai_modified": 12,
    "human": 43
  },
  "ai_percentage": 78.5,
  "files": [
    {
      "path": "src/auth.rs",
      "additions": 80,
      "ai_additions": 72,
      "ai_lines": 70,
      "ai_modified_lines": 2,
      "human_lines": 8,
      "ai_percent": 90.0,
      "is_new_file": true
    },
    ...
  ],
  "models": ["claude-opus-4-5-20251101"]
}

Custom Range

# Compare feature branch to develop
whogitit summary --base develop --head feature/auth

# Specific commit range
whogitit summary --base abc1234 --head def5678

Output Details

Additions Breakdown

The summary focuses on lines added in the commit range:

MetricDescription
AI-generatedLines written by AI, unchanged at commit time
AI-modified by humanLines written by AI, then edited before commit
Human-writtenLines added by humans (not from AI)
Total additionsSum of all added lines (maps to + in git diff)
AI involvement(AI + AI-modified) / Total additions × 100%

Files Changed

Per-file breakdown showing:

  • File path
  • Lines added (+Added)
  • AI contributions (AI + AI-modified)
  • Human contributions
  • AI percentage for that file
  • Status: “New” (file created) or “Modified” (file existed)

Why Diff-Focused?

Previous versions showed “Original/unchanged” lines, which included lines that existed before the PR. This was confusing because:

  • It didn’t map to what reviewers see in the PR diff
  • Percentages didn’t reflect the actual changes being reviewed
  • Large existing files would dilute the AI percentage

The new format shows only additions, making it directly comparable to git diff --stat.

Use Cases

Pull Request Descriptions

Generate markdown summary to paste into PR description:

whogitit summary --base main --format markdown | pbcopy

CI/CD Integration

The GitHub Action uses this command to generate PR comments automatically. See CI/CD Integration.

Compliance Reporting

Export JSON for compliance documentation:

whogitit summary --base main --format json > pr-attribution.json

Notes

  • Commits without AI attribution are counted but contribute 0 to AI metrics
  • The --base ref should be an ancestor of --head
  • Empty commit ranges produce a summary with all zeros
  • The output focuses on additions only; deleted lines are not attributed

See Also

status

Check pending AI attribution changes before committing.

Synopsis

whogitit status

Description

The status command shows the current state of the pending buffer, which accumulates AI attribution data during your Claude Code session. This helps you understand what will be attached to your next commit.

Examples

With Pending Changes

whogitit status

Output:

Pending AI attribution:
  Session: 7f3a-4b2c-9d1e-8a7b
  Files: 3
  Edits: 7
  Lines: 145
  Age: 2 hours ago

Run 'git commit' to finalize attribution.

No Pending Changes

whogitit status

Output:

No pending AI attribution.

Stale Pending Buffer

If the pending buffer is older than the configured threshold (analysis.max_pending_age_hours, default 24), a warning is displayed:

Pending AI attribution:
  Session: 7f3a-4b2c-9d1e-8a7b
  Files: 3
  Edits: 7
  Lines: 145
  Age: 2 days ago

⚠️  Warning: This pending buffer is stale (> 24 hours old).
   Run 'whogitit clear' if these changes are no longer relevant.

Output Details

FieldDescription
SessionThe AI session ID
FilesNumber of files with captured changes
EditsTotal number of edit operations captured
LinesApproximate lines affected
AgeHow long since the first capture

Use Cases

Pre-Commit Check

Before committing, verify what attribution data will be attached:

whogitit status
git status
git commit -m "Add new feature"

Debugging Hook Issues

If attribution isn’t being captured, check if any data is pending:

# Make an edit with Claude Code
# Then check status
whogitit status

# If empty, hooks may not be configured correctly

Clearing Stale Data

If you’ve been working but don’t want to commit the AI attribution:

whogitit status
# Shows stale pending data

whogitit clear
# Clears the pending buffer

whogitit status
# No pending AI attribution.

clear

Discard pending changes without committing:

whogitit clear

This removes the .whogitit-pending.json file, discarding all captured attribution data for the current session.

init

If status shows issues, reinitialize:

whogitit init

This reinstalls hooks and reconfigures git.

Notes

  • The pending buffer is stored in .whogitit-pending.json in your repository root
  • This file is typically in .gitignore and should not be committed
  • The pending buffer is automatically cleared after a successful commit

See Also

annotations

Generate annotations for GitHub Checks API integration.

Usage

whogitit annotations [OPTIONS]

Description

The annotations command generates annotation data suitable for the GitHub Checks API. This is primarily used in CI/CD pipelines to display AI attribution information directly in the GitHub PR diff view.

Annotations appear as colored markers in the “Files changed” tab, showing which lines were AI-generated and the prompts used.

Options

Core Options

OptionDescription
--base <COMMIT>Base commit (exclusive). Defaults to first commit if not specified
--head <COMMIT>Head commit (inclusive). Default: HEAD
--format <FORMAT>Output format: github-checks (default) or json
--max-annotations <N>Maximum annotations to output. Default: 50 (GitHub API limit)
--ai-onlyOnly annotate pure AI lines (not AI-modified)

Consolidation Options

OptionDescription
--consolidate <MODE>Consolidation mode: auto (default), file, or lines
--consolidate-threshold <THRESHOLD>AI coverage threshold for auto mode (0.0-1.0). Default: 0.7
--consolidate-prompt-limit <N>Max prompts for auto-consolidation. Default: 3
--min-lines <N>Minimum AI lines to create a line-level annotation. Default: 1

Filtering Options

OptionDescription
--min-ai-lines <N>Minimum AI lines for a file to be annotated. Default: 3
--min-ai-percent <N>Minimum AI percentage for a file to be annotated (0.0-100.0). Default: 5.0
--diff-onlyOnly annotate lines within the PR diff (requires --base)

Grouping and Sorting Options

OptionDescription
--group-ai-typesGroup AI and AIModified lines together in annotations
--sort-by <MODE>Sort files by: coverage (default), lines, or alpha

Consolidation Modes

Auto (default)

Smart consolidation that chooses between file-level and line-level annotations based on AI coverage:

  • File-level annotation when:

    • File is new (no original lines), OR
    • AI coverage >= threshold (default 70%) AND prompts <= prompt limit (default 3)
  • Line-level annotations otherwise

File

Creates one annotation per file, summarizing all AI attribution.

whogitit annotations --consolidate file

Lines

Creates granular line-level annotations, grouping consecutive AI lines from the same prompt.

whogitit annotations --consolidate lines

Annotation Prioritization

When more annotations are generated than --max-annotations allows, annotations are scored and prioritized by:

  1. AI coverage (up to 40 points) - Higher AI percentage scores higher
  2. AI line count (up to 30 points) - More AI lines score higher (capped at 100)
  3. New file bonus (15 points) - Files created entirely by AI
  4. In-diff bonus (15 points) - Lines within the PR diff

The highest-scoring annotations are kept.

Examples

Basic usage (for GitHub Actions)

whogitit annotations --base ${{ github.event.pull_request.base.sha }} --head ${{ github.sha }}

JSON output for debugging

whogitit annotations --format json

File-level consolidation for cleaner diffs

whogitit annotations --consolidate file --base main

Custom threshold and prompt limit

# Consolidate at 50%+ AI coverage with up to 5 prompts
whogitit annotations --consolidate-threshold 0.5 --consolidate-prompt-limit 5

Filter to significant files only

# Only annotate files with at least 10 AI lines and 20% AI coverage
whogitit annotations --min-ai-lines 10 --min-ai-percent 20.0

Annotate only lines in the PR diff

whogitit annotations --base main --diff-only

Group AI and AI-modified lines together

# Creates fewer, larger annotations
whogitit annotations --group-ai-types

Sort by AI line count instead of coverage

whogitit annotations --sort-by lines

Output Format

GitHub Checks Format

{
  "annotations": [
    {
      "path": "src/main.rs",
      "start_line": 42,
      "end_line": 48,
      "annotation_level": "notice",
      "title": "AI Generated (7 lines)",
      "message": "Model: claude-opus-4-5-20251101 | Session: 2024-01-15\n\n**Breakdown:** 5 AI, 2 AI-modified, 0 human, 0 original\n\n**Prompt:** Add error handling with retry logic...",
      "raw_details": "Add error handling with retry logic..."
    }
  ],
  "summary": {
    "files_analyzed": 5,
    "models": ["claude-opus-4-5-20251101", "claude-sonnet-4-20250514"],
    "session_range": "2024-01-15 to 2024-01-20"
  }
}

JSON Format

Same structure but without GitHub-specific formatting constraints.

Shallow Clone Handling

When running in a shallow clone (common in CI), the command automatically:

  • Detects the shallow clone
  • Switches to file-level consolidation mode
  • Displays a warning message

This ensures annotations work even with limited git history.

GitHub Actions Integration

See the CI/CD Integration guide for complete GitHub Actions workflow examples.

- name: Generate annotations
  run: |
    ANNOTATIONS=$(whogitit annotations \
      --base ${{ github.event.pull_request.base.sha }} \
      --min-ai-lines 5 \
      --sort-by coverage)
    echo "$ANNOTATIONS" > annotations.json

- name: Create Check Run
  uses: actions/github-script@v7
  with:
    script: |
      const fs = require('fs');
      const output = JSON.parse(fs.readFileSync('annotations.json'));
      // ... create check run with output.annotations

See Also

pager

Annotate git diff output with AI attribution markers.

Usage

git diff | whogitit pager [OPTIONS]

Description

The pager command reads git diff output from stdin and annotates added lines with AI attribution markers. This provides inline visibility into which diff lines were AI-generated directly in your terminal.

Options

OptionDescription
--no-colorDisable colored output
-v, --verboseShow detailed attribution info (model, timestamps)
--no-pagerOutput directly to stdout instead of through pager

Attribution Markers

Added lines are prefixed with attribution markers:

MarkerColorMeaning
GreenAI-generated line, unchanged
YellowAI-generated line, modified by human
(none)-Human-written or original line

Setup

Option 1: Replace default git pager

Configure git to use whogitit for all diff output:

git config --global core.pager "whogitit pager"

Option 2: Create git aliases

Create specific aliases for AI-annotated commands:

git config --global alias.ai-diff '!git diff | whogitit pager --no-pager'
git config --global alias.ai-show '!git show "$@" | whogitit pager --no-pager'
git config --global alias.ai-log '!git log -p "$@" | whogitit pager --no-pager'

Examples

Basic usage

git diff HEAD~1 | whogitit pager

Compare branches

git diff main..feature | whogitit pager

Verbose output

git diff | whogitit pager --verbose

Output includes edit IDs and similarity percentages for AI-modified lines.

Pipe to less manually

git diff | whogitit pager --no-pager | less -R

The -R flag tells less to interpret color codes.

View commit with attribution

git show abc123 | whogitit pager

Output Example

diff --git a/src/main.rs b/src/main.rs
@@ -40,4 +45,8 @@ impl Server {
● +    fn handle_error(e: Error) -> Result<()> {
● +        log::error!("Failed: {}", e);
● +        retry_with_backoff(|| reconnect())
● +    }
◐ +    // Added timeout handling
  +    const TIMEOUT: u64 = 30;  // Human-added

Troubleshooting

Annotations not appearing

  1. Ensure attribution data exists:

    whogitit blame <file>
    
  2. Fetch git notes:

    git fetch origin refs/notes/whogitit:refs/notes/whogitit
    
  3. Verify whogitit is in PATH:

    which whogitit
    

Colors not working

If colors don’t appear in your pager:

# Use -R flag with less
git diff | whogitit pager --no-pager | less -R

# Or disable colors
git diff | whogitit pager --no-color

Slow performance on large diffs

For very large diffs, the pager needs to look up attribution for each file. Consider using --no-pager and piping through head to preview:

git diff | whogitit pager --no-pager | head -100

See Also

export

Export AI attribution data for multiple commits in JSON or CSV format.

Synopsis

whogitit export [OPTIONS]

Description

The export command extracts attribution data from git notes and outputs it in a structured format suitable for analysis, reporting, or archival purposes.

Options

OptionDescription
--format <FORMAT>Output format: json (default), csv
--since <DATE>Only include commits after this date (YYYY-MM-DD)
--until <DATE>Only include commits before this date (YYYY-MM-DD)
-o, --output <FILE>Output file (default: stdout)
--full-promptsInclude full prompt text (default: truncated to 100 chars)
--prompt-max-len <N>Max prompt length when not using –full-prompts (default: 100)

Examples

Basic JSON Export

whogitit export

Output (to stdout):

{
  "export_version": 1,
  "exported_at": "2026-01-30T15:00:00Z",
  "date_range": null,
  "commits": [
    {
      "commit_id": "abc123def456...",
      "commit_short": "abc123d",
      "message": "Add user authentication",
      "author": "Greg King",
      "committed_at": "2026-01-30T14:30:00Z",
      "session_id": "7f3a-4b2c-9d1e-8a7b",
      "model": "claude-opus-4-5-20251101",
      "ai_lines": 145,
      "ai_modified_lines": 12,
      "human_lines": 43,
      "original_lines": 50,
      "files": ["src/auth.rs", "src/main.rs"],
      "prompts": [
        {
          "index": 0,
          "text": "Add user authentication with bcrypt...",
          "affected_files": ["src/auth.rs"]
        }
      ]
    }
  ],
  "summary": {
    "total_commits": 10,
    "commits_with_ai": 7,
    "total_ai_lines": 523,
    "total_ai_modified_lines": 45,
    "total_human_lines": 128,
    "total_original_lines": 89,
    "total_prompts": 15
  }
}

Export to File

whogitit export -o attribution-data.json

Output:

Exported 10 commits to attribution-data.json

CSV Format

whogitit export --format csv -o attribution.csv

CSV columns:

  • commit_id
  • commit_short
  • message
  • author
  • committed_at
  • session_id
  • model
  • ai_lines
  • ai_modified_lines
  • human_lines
  • original_lines
  • files_count
  • prompts_count

Date Filtering

# Last 30 days
whogitit export --since 2026-01-01

# Specific range
whogitit export --since 2026-01-01 --until 2026-01-31

# Q4 2025
whogitit export --since 2025-10-01 --until 2025-12-31 -o q4-2025.json

Full Prompts

# Include complete prompt text
whogitit export --full-prompts -o full-export.json

# Custom truncation length
whogitit export --prompt-max-len 200 -o export.json

Output Details

JSON Schema

{
  export_version: number,      // Schema version (currently 1)
  exported_at: string,         // ISO 8601 timestamp
  date_range: {                // null if no date filter
    since: string | null,
    until: string | null
  },
  commits: [CommitExport],     // Array of commit data
  summary: ExportSummary       // Aggregate statistics
}

Summary Statistics

FieldDescription
total_commitsNumber of commits with attribution in range
commits_with_aiCommits that have AI-generated lines
total_ai_linesSum of AI lines across all commits
total_ai_modified_linesSum of AI-modified lines
total_human_linesSum of human-added lines
total_original_linesSum of original lines
total_promptsTotal number of prompts used

Use Cases

Compliance Reporting

Generate monthly AI usage reports:

whogitit export \
  --since 2026-01-01 \
  --until 2026-01-31 \
  --full-prompts \
  -o january-2026-ai-report.json

Data Analysis

Export to CSV for spreadsheet analysis:

whogitit export --format csv -o data.csv

Then open in Excel, Google Sheets, or analyze with pandas.

Backup/Archival

Periodically export all attribution data:

whogitit export --full-prompts -o "backup-$(date +%Y%m%d).json"

CI Integration

Export as part of release process:

# In CI pipeline
whogitit export --since "$LAST_RELEASE_DATE" -o release-attribution.json

Notes

  • Only commits with attribution in git notes are included
  • Commits are sorted by date (newest first)
  • Prompts are redacted according to privacy settings
  • Large exports may take time; consider date filtering

See Also

retention

Manage data retention policies for AI attribution data.

Synopsis

whogitit retention <SUBCOMMAND>

Description

The retention command helps you manage the lifecycle of AI attribution data, allowing you to preview and apply retention policies that automatically clean up old data while preserving important commits.

Subcommands

SubcommandDescription
configShow current retention settings
previewPreview what would be deleted
applyApply retention policy (dry-run by default)

Subcommand: config

Show the current retention configuration:

whogitit retention config

Output:

Current Retention Configuration
==================================================
Config file: /path/to/repo/.whogitit.toml

max_age_days: 365
auto_purge: false
retain_refs: refs/heads/main
min_commits: 100

Example configuration:

# .whogitit.toml
[retention]
max_age_days = 365
auto_purge = false
retain_refs = ["refs/heads/main"]
min_commits = 100

Subcommand: preview

Preview what would be deleted based on current policy:

whogitit retention preview

Output:

Retention Policy Preview
==================================================
Max age: 365 days
Retained refs: refs/heads/main
Min commits to keep: 100

● 95 commits to keep
● 12 commits to delete

Commits that would be deleted:
  abc1234 Fix typo in readme (2024-08-15) - would be deleted
  def5678 Update dependencies (2024-07-22) - would be deleted
  ...

Run 'whogitit retention apply --execute' to delete these.

Subcommand: apply

Apply the retention policy:

# Dry-run (default)
whogitit retention apply

# Actually delete
whogitit retention apply --execute

# With reason for audit log
whogitit retention apply --execute --reason "Quarterly cleanup"

Options

OptionDescription
--executeActually delete (without this, does a dry-run)
--reason <TEXT>Reason for deletion (recorded in audit log)

Dry-Run Output

Preview: 12 commits would be deleted (dry-run)
Run with --execute to actually delete.

Execute Output

Done: Deleted attribution for 12 commits
Reason: Quarterly cleanup

Configuration

Retention is configured in .whogitit.toml:

[retention]
# Delete attribution older than this many days
max_age_days = 365

# Automatically purge on each commit (default: false)
auto_purge = false

# Never delete attribution for commits reachable from these refs
retain_refs = ["refs/heads/main", "refs/heads/release"]

# Keep at least this many commits regardless of age
min_commits = 100

Configuration Options

OptionTypeDefaultDescription
max_age_daysnumbernoneDelete data older than N days
auto_purgebooleanfalsePurge automatically on commit (post-commit hook)
retain_refsarray["refs/heads/main"]Refs to always preserve
min_commitsnumber100Minimum commits to keep (newest by commit time)

Retention Logic

The retention policy applies these rules in order:

  1. Age filter: Identify commits older than max_age_days
  2. Ref protection: Exclude commits reachable from retain_refs
  3. Minimum guarantee: Keep at least min_commits (newest by commit time)

Example Scenario

Configuration:

[retention]
max_age_days = 180
retain_refs = ["refs/heads/main"]
min_commits = 50

Repository has:

  • 200 commits with attribution
  • 80 commits older than 180 days
  • 60 of those old commits are on main branch

Result:

  • 60 old commits on main: kept (ref protection)
  • 20 old commits not on main: deleted
  • 120 recent commits: kept (within age limit)
  • Final count: 180 commits kept, 20 deleted

Use Cases

Quarterly Cleanup

# Preview first
whogitit retention preview

# Apply with audit trail
whogitit retention apply --execute --reason "Q1 2026 cleanup"

Compliance Requirements

If your organization requires data to be deleted after a certain period:

[retention]
max_age_days = 365  # 1 year retention
retain_refs = []    # No exceptions
min_commits = 0     # Delete all old data

Preserve Release History

Keep attribution for all released versions:

[retention]
max_age_days = 90
retain_refs = [
  "refs/heads/main",
  "refs/tags/v1.0.0",
  "refs/tags/v2.0.0"
]

Notes

  • Deletion is permanent - there’s no undo
  • Deleted attribution is logged in the audit log (if enabled)
  • The --execute flag is required to actually delete data
  • Use preview liberally before applying

See Also

audit

View the audit log for compliance and tracking purposes.

Synopsis

whogitit audit [OPTIONS]

Description

The audit command displays a log of significant events related to AI attribution data, including deletions, exports, configuration changes, and redactions. This supports compliance requirements and helps track data lifecycle.

Options

OptionDescription
--since <DATE>Only show events after this date (YYYY-MM-DD)
--event-type <TYPE>Filter by event type
--jsonOutput as JSON
--limit <N>Show last N events (default: 50)

Event Types

TypeDescription
deleteAttribution data was deleted
exportData was exported
retention_applyRetention policy was applied
config_changeConfiguration was modified
redactionSensitive data was redacted

Examples

View Recent Events

whogitit audit

Output:

Audit Log
============================================================
2026-01-30 14:23:15 delete commit:abc123d user:greg - Retention policy
2026-01-30 14:23:15 delete commit:def5678 user:greg - Retention policy
2026-01-28 10:15:00 export commits:45 format:json user:greg
2026-01-25 09:00:00 retention commits:12 user:greg - Quarterly cleanup
2026-01-20 16:30:00 config user:greg - Updated max_age_days
2026-01-15 11:45:00 redaction pattern:API_KEY redactions:3

Filter by Event Type

whogitit audit --event-type delete

Output:

Audit Log
============================================================
2026-01-30 14:23:15 delete commit:abc123d user:greg - Retention policy
2026-01-30 14:23:15 delete commit:def5678 user:greg - Retention policy
2026-01-15 09:00:00 delete commit:ghi9012 user:greg - Manual deletion

Filter by Date

whogitit audit --since 2026-01-01

JSON Output

whogitit audit --json

Output:

[
  {
    "timestamp": "2026-01-30T14:23:15Z",
    "event": "Delete",
    "details": {
      "commit": "abc123def456...",
      "user": "greg",
      "reason": "Retention policy"
    }
  },
  {
    "timestamp": "2026-01-28T10:15:00Z",
    "event": "Export",
    "details": {
      "commit_count": 45,
      "format": "json",
      "user": "greg"
    }
  }
]

Show More Events

whogitit audit --limit 100

Output Details

Event Fields

FieldDescription
TimestampWhen the event occurred
Event typeCategory of event (color-coded)
DetailsEvent-specific information
ReasonUser-provided reason (if any)

Event-Specific Details

Delete events:

  • commit: The commit SHA whose attribution was deleted
  • user: Who performed the deletion
  • reason: Why it was deleted

Export events:

  • commit_count: Number of commits exported
  • format: Export format (json/csv)
  • user: Who performed the export

Retention events:

  • commits: Number of commits affected
  • user: Who applied the policy
  • reason: Provided reason

Config events:

  • user: Who changed the config
  • Details of what changed

Redaction events:

  • pattern_name: Which pattern matched
  • redaction_count: How many matches were redacted

Enabling Audit Logging

Audit logging must be enabled in configuration:

# .whogitit.toml
[privacy]
audit_log = true

If not enabled, the command will prompt you:

No audit log found.
Enable audit logging in .whogitit.toml: [privacy]
audit_log = true

Audit Log Storage

The audit log is stored in .whogitit/audit.jsonl in your repository. Each line is a JSON object representing one event. Each event includes prev_hash and event_hash fields to form a tamper‑evident chain. The event hash includes the previous hash, so any reordering or tampering will cause verification to fail. If any line is malformed, chain verification fails rather than silently skipping it.

# View raw audit log
cat .whogitit/audit.jsonl

Use Cases

Compliance Review

Generate audit report for a time period:

whogitit audit --since 2026-01-01 --json > q1-audit.json

Investigate Deletions

Find out what was deleted and why:

whogitit audit --event-type delete --limit 100

Track Configuration Changes

See who changed settings:

whogitit audit --event-type config_change

Monitor Redactions

Check what sensitive data is being caught:

whogitit audit --event-type redaction

Notes

  • Audit logging is disabled by default for privacy
  • The audit log itself is not automatically purged
  • Consider including .whogitit/audit.jsonl in backups
  • Events are appended in real-time
  • If the audit log contains malformed JSON, audit commands will return an error until it is fixed

See Also

clear

Discard pending attribution changes without committing.

Usage

whogitit clear

Description

The clear command removes the pending buffer file (.whogitit-pending.json) without creating a commit. This discards all captured AI attribution data from the current session.

When to Use

Use clear when you want to:

  • Abandon an AI-assisted session - You’ve decided not to commit the AI-generated changes
  • Start fresh - Reset the attribution state before a new session
  • Fix a stale buffer - The pending buffer is outdated or corrupted
  • Testing - Clear state during development/testing

What Gets Cleared

The command removes:

  • All captured file snapshots
  • Session metadata (session ID, model, timestamps)
  • Prompt history for the session
  • File edit histories

Examples

Discard pending changes

# Check what's pending
whogitit status

# Discard everything
whogitit clear

After a git reset

If you’ve reset your git state and the pending buffer is now stale:

git reset --hard HEAD~1
whogitit clear

Relationship to Git

The clear command only affects whogitit’s pending buffer. It does not:

  • Modify any files in your working directory
  • Affect git’s staging area or commit history
  • Remove any existing git notes

To discard both git changes and whogitit attribution:

git checkout -- .           # Discard file changes
whogitit clear              # Discard attribution

Pending Buffer

The pending buffer is stored at .whogitit-pending.json in your repository root. This file:

  • Is created automatically during Claude Code sessions
  • Should be in your .gitignore
  • Is cleared after successful commits (by the post-commit hook)
  • Can be manually inspected for debugging

See Also

  • status - View pending changes before clearing
  • post-commit - How attribution is finalized

setup

Configure Claude Code integration for whogitit.

Usage

whogitit setup

Description

The setup command performs one-time global configuration to integrate whogitit with Claude Code. This command should be run once after installing whogitit, before initializing any repositories.

What It Does

  1. Installs capture hook script

    • Creates ~/.claude/hooks/ directory if needed
    • Writes whogitit-capture.sh to ~/.claude/hooks/
    • Sets executable permissions
  2. Configures Claude Code settings

    • Creates ~/.claude/settings.json if it doesn’t exist
    • Adds PreToolUse and PostToolUse hook configuration
    • Preserves existing settings (creates backup at settings.json.backup)

Example Output

Setting up whogitit for Claude Code...

  Installed capture hook to ~/.claude/hooks/whogitit-capture.sh
  Configured Claude Code hooks in ~/.claude/settings.json
    (Previous settings backed up to settings.json.backup)

Global setup complete!

Next steps:
  1. Run 'whogitit init' in each repository you want to track
  2. Use Claude Code normally - AI attribution will be captured automatically

Run 'whogitit doctor' to verify your configuration at any time.

Re-running Setup

It’s safe to run setup multiple times:

  • If the hook script is already installed and current, it will be skipped
  • If settings are already configured, they won’t be duplicated

After Setup

After running setup, initialize each repository where you want to track AI attribution:

cd your-project
whogitit init

See Also

doctor

Check whogitit configuration and diagnose issues.

Usage

whogitit doctor

Description

The doctor command performs a comprehensive check of your whogitit configuration. It verifies that all components are properly installed and configured, and provides hints for fixing any issues found.

What It Checks

CheckDescription
whogitit binaryConfirms the binary is installed and running
Capture hookVerifies hook script exists at ~/.claude/hooks/whogitit-capture.sh
Hook permissionsConfirms the hook script is executable
Claude Code settingsChecks that ~/.claude/settings.json has whogitit hooks configured
Required toolsVerifies jq is installed (required by capture hook)
Repository hooksIf in a git repo, checks that post-commit and pre-push hooks are installed
Attribution notesIf notes exist, checks for orphaned notes (attached to deleted commits)

Example Output

All Checks Passing

Checking whogitit configuration...

[OK] whogitit binary: Installed and running
[OK] Capture hook: Installed at /Users/you/.claude/hooks/whogitit-capture.sh
[OK] Hook permissions: Executable
[OK] Claude Code settings: Hooks configured
[OK] Required tools (jq): Available
[OK] Repository hooks: Initialized in current repo
[OK] Attribution notes: 42 notes, all valid

All checks passed! whogitit is properly configured.

With Issues

Checking whogitit configuration...

[OK] whogitit binary: Installed and running
[FAIL] Capture hook: Not installed
   Fix: Run 'whogitit setup' to install
[FAIL] Hook permissions: Hook not installed
   Fix: Run 'whogitit setup'
[FAIL] Claude Code settings: whogitit hooks not configured
   Fix: Run 'whogitit setup' to configure
[OK] Required tools (jq): Available
[FAIL] Repository hooks: Not initialized in current repo
   Fix: Run 'whogitit init' in this repository

Some checks failed. Run 'whogitit setup' to fix configuration issues.

Fixing Issues

Most issues can be fixed automatically:

  1. Global configuration issues (hook, settings):

    whogitit setup
    
  2. Repository-specific issues (git hooks):

    whogitit init
    
  3. Missing jq:

    • macOS: brew install jq
    • Ubuntu/Debian: apt install jq
    • Fedora: dnf install jq

When to Run Doctor

Run whogitit doctor when:

  • After initial installation to verify setup
  • When attribution isn’t being captured
  • After upgrading whogitit
  • When debugging issues

Exit Codes

CodeMeaning
0All checks passed or completed with warnings

See Also

init

Initialize whogitit in a git repository.

Usage

whogitit init [OPTIONS]

Description

The init command sets up whogitit in the current git repository by installing git hooks and configuring note fetching.

This command should be run once per repository after the global setup command has been run.

Options

OptionDescription
--forceSkip global setup check and proceed anyway

What It Does

  1. Installs post-commit hook (.git/hooks/post-commit)

    • Finalizes AI attribution after each commit
    • Attaches attribution data as git notes
  2. Installs pre-push hook (.git/hooks/pre-push)

    • Automatically pushes git notes with regular pushes
    • Ensures attribution travels with your code
  3. Installs post-rewrite hook (.git/hooks/post-rewrite)

    • Preserves attribution during git rebase
    • Preserves attribution during git commit --amend
    • Automatically copies notes from old to new commit SHAs
  4. Configures git fetch

    • Adds fetch refspec for refs/notes/whogitit
    • Notes are automatically fetched on git fetch/git pull
  5. Updates git exclude

    • Adds whogitit local artifacts to .git/info/exclude
    • Prevents accidental commits of .whogitit-pending.json and .whogitit/

Examples

Standard initialization

cd your-project
whogitit init

Force initialization

Skip the global setup check (useful in CI or when you know what you’re doing):

whogitit init --force

Prerequisites

Before running init, you should:

  1. Run whogitit setup (one-time global setup)
  2. Be in a git repository

If global setup hasn’t been run, init will warn you and suggest running setup first. Use --force to bypass this check.

Hook Details

post-commit hook

The post-commit hook:

  • Runs whogitit post-commit after each commit
  • Processes the pending buffer (.whogitit-pending.json)
  • Creates git notes with attribution data
  • Clears the pending buffer

pre-push hook

The pre-push hook:

  • Runs before each push
  • Pushes refs/notes/whogitit to the remote
  • Ensures attribution notes travel with commits

post-rewrite hook

The post-rewrite hook:

  • Runs after git rebase and git commit --amend
  • Receives old→new SHA mappings on stdin
  • Copies attribution notes to the new commits
  • Reports how many notes were preserved

Idempotency

The init command is idempotent - running it multiple times is safe. It will:

  • Update hooks if they exist
  • Add the fetch refspec if not already present
  • Not duplicate any configuration

Troubleshooting

“Not in a git repository”

Ensure you’re in a directory with a .git folder:

git status  # Should show repository status

“Global setup not complete”

Run the global setup first:

whogitit setup
whogitit init

Or use --force if you want to skip the check.

Hooks not running

Check hook permissions:

ls -la .git/hooks/post-commit
chmod +x .git/hooks/post-commit

See Also

  • setup - Global setup (run before init)
  • doctor - Diagnose configuration issues
  • Hook System - Technical hook details

copy-notes

Copy AI attribution from one commit to another.

Usage

whogitit copy-notes <SOURCE> <TARGET> [OPTIONS]

Description

The copy-notes command copies attribution data from a source commit to a target commit. This is useful for:

  • Recovering attribution after cherry-pick operations
  • Manually fixing attribution after complex rebases
  • Copying attribution when the post-rewrite hook wasn’t installed

Arguments

ArgumentDescription
SOURCESource commit SHA (the commit with attribution)
TARGETTarget commit SHA (the commit to copy attribution to)

Options

OptionDescription
--dry-runShow what would be copied without actually copying

Examples

Copy attribution after cherry-pick

Cherry-pick doesn’t automatically transfer attribution:

# Cherry-pick a commit
git cherry-pick abc123

# Copy the attribution to the new commit
whogitit copy-notes abc123 HEAD

Preview before copying

whogitit copy-notes abc123 def456 --dry-run
# Would copy attribution: abc123 -> def456

Batch copy after rebase

If you rebased without the post-rewrite hook installed:

# Save old commits before rebase
git log --format='%H' main..HEAD > /tmp/old-commits.txt

# After rebase, save new commits
git log --format='%H' main..HEAD > /tmp/new-commits.txt

# Copy notes for each pair
paste /tmp/old-commits.txt /tmp/new-commits.txt | while read old new; do
  whogitit copy-notes "$old" "$new"
done

Automatic Preservation

For most rebase and amend operations, you don’t need this command. The post-rewrite hook (installed by whogitit init) automatically preserves attribution during:

  • git rebase
  • git commit --amend

Use copy-notes only for:

  • Cherry-pick operations (not covered by post-rewrite hook)
  • Repositories where post-rewrite hook wasn’t installed
  • Manual recovery scenarios

Exit Codes

CodeMeaning
0Success (or source has no attribution)
1Error (invalid commit, repository issues)

See Also

redact-test

Test redaction patterns against text or files.

Usage

whogitit redact-test [OPTIONS]

Description

The redact-test command allows you to test whogitit’s privacy redaction system against sample text or files. This helps verify that sensitive data will be properly redacted before being stored in git notes.

Options

OptionDescription
--text <TEXT>Text to test redaction on (conflicts with --file)
--file <FILE>File to read and test redaction on (conflicts with --text)
--matches-onlyShow only matches without redacting
--auditShow audit trail of redactions
--list-patternsList available redaction patterns
--jsonOutput as JSON

Built-in Patterns

whogitit includes patterns for common sensitive data:

PatternDescription
API_KEYGeneric API keys (api_key, apikey, secret, token)
AWS_KEYAWS access keys (AKIA...)
PRIVATE_KEYPEM-encoded private keys
BEARER_TOKENBearer authentication tokens
GITHUB_TOKENGitHub tokens (ghp_, gho_, ghs_, ghr_)
SLACK_TOKENSlack tokens (xoxb-, xoxp-, xoxa-)
STRIPE_KEYStripe API keys (sk_live_, pk_live_)
PASSWORDPassword patterns in config-like contexts
EMAILEmail addresses
SSNSocial Security Numbers

Examples

Test text inline

whogitit redact-test --text "My API key is api_key=sk-1234567890"

Output:

Redacted output:
My API key is api_key=[REDACTED]

Test a file

whogitit redact-test --file .env

List available patterns

whogitit redact-test --list-patterns

Output:

Available Redaction Patterns
==================================================
API_KEY          Generic API key patterns
AWS_KEY          AWS access key IDs
PRIVATE_KEY      PEM private keys
...

Show matches only

See what would be redacted without showing the redacted output:

whogitit redact-test --text "email: user@example.com, key: sk-123" --matches-only

Output:

Sensitive data 2 found:

  EMAIL            user@example.com
  API_KEY          sk-123

Audit trail

See detailed information about each redaction:

whogitit redact-test --text "password=secret123" --audit

Output:

Audit Trail: 1 redactions made:

  Pattern: PASSWORD  Range: (9, 18)  Preview: secret123

Redacted output:
password=[REDACTED]

JSON output

whogitit redact-test --text "token=abc123" --json

Output:

{
  "input_length": 12,
  "output": "token=[REDACTED]",
  "match_count": 1,
  "matches": ["API_KEY"]
}

Custom Patterns

You can add custom redaction patterns in .whogitit.toml:

[privacy]
audit_log = true

[[privacy.custom_patterns]]
name = "INTERNAL_ID"
pattern = "INTERNAL-\\d+"
description = "Internal tracking IDs"

[[privacy.custom_patterns]]
name = "COMPANY_SECRET"
pattern = "ACME-[A-Z0-9]+"
description = "Company-specific secrets"

Then test your custom patterns:

whogitit redact-test --text "Reference: INTERNAL-12345" --list-patterns

Disabling Patterns

Disable built-in patterns you don’t need:

[privacy]
disabled_patterns = ["EMAIL", "SSN"]

See Also

Configuration

whogitit is configured via a TOML file (.whogitit.toml) in your repository root or globally at ~/.config/whogitit/config.toml.

Configuration File Location

whogitit looks for configuration in this order:

  1. Repository-local: .whogitit.toml in the repository root
  2. Global: ~/.config/whogitit/config.toml
  3. Defaults: Built-in default values

Repository-local configuration takes precedence over global configuration.

If a configuration file is present but invalid, CLI commands will return an error so you can fix it. Hook-based capture will log a warning and fall back to defaults to avoid breaking your workflow.

Complete Configuration Reference

# .whogitit.toml

[privacy]
# Enable/disable redaction (default: true)
enabled = true

# Use built-in redaction patterns (default: true)
use_builtin_patterns = true

# Disable specific built-in patterns by name
disabled_patterns = ["EMAIL"]

# Enable audit logging (default: false)
audit_log = true

# Add custom redaction patterns
[[privacy.custom_patterns]]
name = "INTERNAL_ID"
pattern = "INTERNAL-\\d+"
description = "Internal tracking IDs"

[[privacy.custom_patterns]]
name = "PROJECT_SECRET"
pattern = "PROJ_[A-Z0-9]{16}"
description = "Project-specific secrets"

[retention]
# Maximum age of attribution data in days
max_age_days = 365

# Automatically purge old data on commit (default: false)
auto_purge = false

# Never delete attribution for commits reachable from these refs
retain_refs = ["refs/heads/main", "refs/heads/release"]

# Keep at least this many commits regardless of age
min_commits = 100

[analysis]
# Maximum pending buffer age in hours (default: 24)
max_pending_age_hours = 24

# Similarity threshold for AIModified detection (default: 0.6)
similarity_threshold = 0.6

Privacy Section

enabled

[privacy]
enabled = true  # default

Master switch for redaction. When false, no redaction is performed.

use_builtin_patterns

[privacy]
use_builtin_patterns = true  # default

Whether to use the built-in redaction patterns. See Privacy & Redaction for the full list.

Analysis Section

max_pending_age_hours

[analysis]
max_pending_age_hours = 24  # default

Controls when the pending buffer is considered stale (used by whogitit status and warnings).

similarity_threshold

[analysis]
similarity_threshold = 0.6  # default

Similarity threshold for detecting AI‑modified lines. Lower values are more aggressive.

disabled_patterns

[privacy]
disabled_patterns = ["EMAIL", "PHONE"]

Disable specific built-in patterns by name. Available patterns:

NameDescription
API_KEYGeneric API keys
AWS_ACCESS_KEYAWS access key IDs
AWS_SECRET_KEYAWS secret access keys
BEARER_TOKENBearer tokens in headers
CREDIT_CARDCredit card numbers
EMAILEmail addresses
GITHUB_TOKENGitHub personal access tokens
GOOGLE_API_KEYGoogle API keys
JWTJSON Web Tokens
PASSWORDPassword patterns
PHONEPhone numbers
PRIVATE_KEYPrivate key blocks
SLACK_TOKENSlack tokens
SSNSocial Security Numbers

audit_log

[privacy]
audit_log = true

Enable logging of significant events (deletions, exports, etc.) for compliance. Events are logged to .whogitit/audit.jsonl.

custom_patterns

[[privacy.custom_patterns]]
name = "PATTERN_NAME"
pattern = "regex-pattern-here"
description = "Optional description"

Add custom redaction patterns. Each pattern needs:

FieldRequiredDescription
nameYesUnique identifier (appears in audit log)
patternYesRegular expression to match
descriptionNoHuman-readable description

Retention Section

max_age_days

[retention]
max_age_days = 365

Delete attribution data older than this many days. Set to null or omit for no age limit.

auto_purge

[retention]
auto_purge = false  # default

When true, automatically apply retention policy after each commit via the post-commit hook. Use with caution.

retain_refs

[retention]
retain_refs = ["refs/heads/main"]  # default

Git refs whose commits should never have their attribution deleted, regardless of age. Useful for preserving history on main branches.

Format: Full ref names like refs/heads/main, refs/tags/v1.0.0.

min_commits

[retention]
min_commits = 100  # default

Minimum number of commits to keep regardless of age. Prevents accidental deletion of all attribution data. When enforcing this minimum, whogitit keeps the newest commits by commit time.

Example Configurations

Minimal (Defaults)

# No configuration needed - defaults are sensible

Privacy-Focused

[privacy]
enabled = true
audit_log = true

[[privacy.custom_patterns]]
name = "EMPLOYEE_ID"
pattern = "EMP\\d{6}"
description = "Employee IDs"

[retention]
max_age_days = 90
min_commits = 50

Enterprise Compliance

[privacy]
enabled = true
audit_log = true

# Custom patterns for internal systems
[[privacy.custom_patterns]]
name = "INTERNAL_API"
pattern = "int-api-[a-f0-9]{32}"

[[privacy.custom_patterns]]
name = "CUSTOMER_ID"
pattern = "CUST-\\d{8}"

[retention]
max_age_days = 365
auto_purge = false
retain_refs = [
  "refs/heads/main",
  "refs/heads/production",
  "refs/heads/staging"
]
min_commits = 500

Open Source Project

[privacy]
enabled = true
# Disable email redaction for open source
disabled_patterns = ["EMAIL"]

[retention]
# Keep everything
max_age_days = null

Validating Configuration

Use the retention config command to verify your configuration is loaded correctly:

whogitit retention config

Test redaction patterns:

whogitit redact-test "Test string with api_key=secret123"

Environment Variables

Some settings can be overridden via environment variables:

VariableDescription
WHOGITIT_CONFIGPath to configuration file
WHOGITIT_BINPath to whogitit binary (used by hooks)

See Also

Privacy & Redaction

whogitit automatically redacts sensitive information from prompts before storing them in git notes. This protects credentials, personal information, and other secrets that might accidentally appear in your prompts.

How Redaction Works

When a prompt is captured, whogitit scans it against a set of patterns and replaces matches with [REDACTED]:

Before:

Add authentication using api_key = sk-12345abcdef

After (stored):

Add authentication using api_key = [REDACTED]

Built-in Patterns

whogitit includes patterns for common sensitive data:

Credentials

PatternExamples
API_KEYapi_key=xxx, apikey: xxx, secret=xxx
AWS_ACCESS_KEYAKIA... (20 chars)
AWS_SECRET_KEY40-character base64 strings
BEARER_TOKENBearer eyJ..., Authorization: Bearer
GITHUB_TOKENghp_xxx, gho_xxx, ghs_xxx, ghr_xxx
GOOGLE_API_KEYAIza...
SLACK_TOKENxoxb-xxx, xoxp-xxx
JWTeyJ... JSON Web Tokens
PASSWORDpassword=xxx, passwd: xxx
PRIVATE_KEY-----BEGIN.*PRIVATE KEY----- blocks

Personal Information

PatternExamples
EMAILuser@example.com
PHONE(555) 123-4567, +1-555-123-4567
SSN123-45-6789
CREDIT_CARD4111-1111-1111-1111

Testing Redaction

Use redact-test to see how your text would be redacted:

whogitit redact-test "Connect using api_key=sk-secret123 and email user@example.com"

Output:

Original:
  Connect using api_key=sk-secret123 and email user@example.com

Redacted:
  Connect using api_key=[REDACTED] and email [REDACTED]

Patterns matched:
  - API_KEY (1 match)
  - EMAIL (1 match)

Testing Files

whogitit redact-test --file config.example.txt

Custom Patterns

Add organization-specific patterns in .whogitit.toml:

[privacy]
# Custom patterns
[[privacy.custom_patterns]]
name = "INTERNAL_ID"
pattern = "INT-[A-Z0-9]{8}"
description = "Internal system IDs"

[[privacy.custom_patterns]]
name = "EMPLOYEE_ID"
pattern = "EMP\\d{6}"
description = "Employee identification numbers"

[[privacy.custom_patterns]]
name = "DATABASE_URL"
pattern = "postgres://[^\\s]+"
description = "PostgreSQL connection strings"

Pattern Syntax

Patterns use Rust regex syntax (similar to PCRE):

SyntaxMeaning
\dDigit
\wWord character
\sWhitespace
[A-Z]Character class
+One or more
*Zero or more
{n}Exactly n times
{n,m}Between n and m times
(?i)Case insensitive

Testing Custom Patterns

After adding patterns, verify they work:

whogitit redact-test "Reference INT-ABC12345 for employee EMP123456"

Disabling Patterns

If a built-in pattern is too aggressive, disable it:

[privacy]
disabled_patterns = ["EMAIL", "PHONE"]

Common reasons to disable:

PatternWhy Disable
EMAILOpen source projects where contributor emails are public
PHONEFalse positives with version numbers or IDs

Disabling Redaction

To disable redaction entirely:

[privacy]
enabled = false

Warning: Disabling redaction may expose sensitive data in your git history. Only do this if you’re certain no sensitive data will appear in prompts.

Audit Trail

When audit logging is enabled, redaction events are recorded:

[privacy]
audit_log = true

View redaction events:

whogitit audit --event-type redaction

Output:

2026-01-30 14:23:15 redaction pattern:API_KEY redactions:2
2026-01-30 14:20:00 redaction pattern:EMAIL redactions:1

Best Practices

1. Test Before Production

Before enabling whogitit on a project, test redaction with representative prompts:

# Test various scenarios
whogitit redact-test "Your typical prompt with api_key=xxx"

2. Add Organization Patterns

Identify internal secret formats and add patterns:

[[privacy.custom_patterns]]
name = "ACME_API_KEY"
pattern = "acme_[a-f0-9]{32}"
description = "ACME Corp API keys"

3. Review Periodically

Check the audit log for missed patterns:

whogitit audit --event-type redaction --limit 100

If certain patterns are matching frequently, they’re working. If sensitive data is getting through, add new patterns.

4. Use Environment Variables

Instead of including secrets in prompts, reference environment variables:

Instead of:

Connect to postgres://user:password@host/db

Use:

Connect using the DATABASE_URL environment variable

5. Enable Audit Logging

For compliance-sensitive projects:

[privacy]
audit_log = true

Limitations

  • Redaction is pattern-based and cannot catch everything
  • Novel secret formats may not be detected
  • Context-dependent secrets (e.g., “the password is banana”) are not detected
  • Redaction is one-way - original text cannot be recovered

See Also

Daily Development Workflow

This guide covers how to use whogitit as part of your everyday development workflow with Claude Code.

Typical Session

1. Start Coding with Claude

Open your project and start working with Claude Code:

> Add a function to validate email addresses

Claude edits your files. Behind the scenes, whogitit’s hooks capture:

  • The file state before each edit
  • The file state after each edit
  • The prompt from the session transcript

2. Review and Modify

Review Claude’s changes. Make any modifications you want:

#![allow(unused)]
fn main() {
// Claude wrote:
fn validate_email(email: &str) -> bool {
    email.contains('@')
}

// You improve it:
fn validate_email(email: &str) -> bool {
    let pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
    regex::Regex::new(pattern).unwrap().is_match(email)
}
}

These modifications will be tracked as AIModified lines.

3. Add Your Own Code

Write additional code yourself:

#![allow(unused)]
fn main() {
// You add:
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_valid_email() {
        assert!(validate_email("test@example.com"));
    }
}
}

This will be tracked as Human lines.

4. Check Status Before Committing

whogitit status

Output:

Pending AI attribution:
  Session: 7f3a-4b2c-9d1e-8a7b
  Files: 1
  Edits: 2
  Lines: 15

Run 'git commit' to finalize attribution.

5. Commit

git add src/validation.rs
git commit -m "Add email validation with tests"

The post-commit hook automatically:

  1. Analyzes the pending changes
  2. Creates attribution data
  3. Attaches it as a git note
  4. Clears the pending buffer

6. Verify Attribution

whogitit blame src/validation.rs
 LINE   │ COMMIT  │ AUTHOR     │ SRC │ CODE
───────────────────────────────────────────────────────────────────
    1   │ a1b2c3d │ Greg King  │  ◐  │ fn validate_email(email: &str) -> bool {
    2   │ a1b2c3d │ Greg King  │  ◐  │     let pattern = r"^[a-zA-Z0-9...
    3   │ a1b2c3d │ Greg King  │  ◐  │     regex::Regex::new(pattern)...
    4   │ a1b2c3d │ Greg King  │  ◐  │ }
    5   │ a1b2c3d │ Greg King  │  +  │
    6   │ a1b2c3d │ Greg King  │  +  │ #[cfg(test)]
    7   │ a1b2c3d │ Greg King  │  +  │ mod tests {
...

Multiple Edits Per Commit

Working on Multiple Files

Claude Code often edits multiple files. All changes within a session are tracked together:

> Add user authentication with login and registration endpoints

This might touch:

  • src/auth.rs (new file)
  • src/main.rs (add routes)
  • src/db.rs (add user model)

All are captured with the same session ID and prompt.

Multiple Prompts

If you give Claude multiple prompts before committing:

> Add the User struct
> Now add password hashing
> Add email verification

Each prompt is recorded separately. You can trace which prompt generated which code:

whogitit show HEAD
Prompts used:
  #0: "Add the User struct..."
  #1: "Now add password hashing..."
  #2: "Add email verification..."
whogitit prompt src/auth.rs:15

Shows which specific prompt generated line 15.

Discarding AI Changes

Sometimes you don’t want to keep AI-generated changes. You have options:

Discard Everything

# Discard git changes
git checkout .

# Clear whogitit pending buffer
whogitit clear

Keep Changes, Discard Attribution

If you want to keep the code but not track it as AI-generated:

# Clear the pending buffer
whogitit clear

# Commit without attribution
git add .
git commit -m "Changes without AI tracking"

Partial Commit

Stage only specific files:

git add src/auth.rs
git commit -m "Add authentication"
# Only auth.rs gets attribution from pending buffer

Pushing Changes

When you push, git notes are included automatically:

git push

The pre-push hook runs:

git push origin refs/notes/whogitit

Tips

Check Status Often

Get in the habit of checking whogitit status alongside git status:

git status && whogitit status

Clear Stale Data

If you’ve been experimenting but don’t want to commit:

whogitit clear

Verify After Major Changes

After significant AI-assisted work, verify attribution looks correct:

whogitit blame src/new_feature.rs

Use Meaningful Commits

Since whogitit tracks at the commit level, meaningful atomic commits help:

# Good: One feature per commit
git commit -m "Add email validation"
git commit -m "Add phone validation"

# Less good: Multiple unrelated changes
git commit -m "Add validation and fix typo and update deps"

See Also

Code Review Workflow

whogitit enhances code review by providing visibility into AI-generated code. This guide covers best practices for reviewing PRs with AI attribution.

Reviewing a Pull Request

1. Get the PR Summary

First, get an overview of AI involvement:

# Fetch and checkout the PR
git fetch origin pull/123/head:pr-123
git checkout pr-123

# Get attribution summary
whogitit summary --base main

Output:

AI Attribution Summary
======================

Commits analyzed: 5 (3 with AI attribution)

Overview:
  AI-generated lines:     145 (58.0%)
  AI-modified by human:    12 (4.8%)
  Human-added lines:       43 (17.2%)
  Original/unchanged:      50 (20.0%)

AI involvement: 62.8% of changed lines

This tells you:

  • How much of the PR was AI-assisted
  • Whether the author modified AI output (AIModified)
  • How much was purely human-written

2. Identify AI-Generated Files

See which files have the most AI involvement:

whogitit show HEAD~2..HEAD

Or blame specific files:

whogitit blame --ai-only src/auth.rs

3. Review AI-Generated Code

AI-generated code () deserves extra scrutiny for:

Security Issues:

  • SQL injection vulnerabilities
  • XSS in templates
  • Hardcoded secrets (should be redacted, but check)
  • Insecure defaults

Logic Errors:

  • Off-by-one errors
  • Incorrect boundary conditions
  • Missing error handling

Style Issues:

  • Non-idiomatic patterns
  • Inconsistent naming
  • Missing documentation

4. Review Human Modifications

Lines marked AIModified () were AI-generated then changed. These are interesting because:

  • The author saw something to improve
  • They might have caught an AI mistake
  • Or they might have introduced a new issue

Look at what changed:

whogitit prompt src/auth.rs:15

Compare the prompt to the actual code - does the modification make sense?

5. Review Prompts

Understanding what the author asked for helps contextualize the code:

whogitit show HEAD

Good prompts lead to better AI output. Consider:

  • Was the prompt clear and specific?
  • Did it mention edge cases?
  • Did it specify error handling?

Review Checklist

For AI-Generated Lines ()

  • Does the code actually do what the prompt asked?
  • Are there security vulnerabilities?
  • Is error handling appropriate?
  • Are there obvious logic errors?
  • Does it follow project conventions?
  • Are there unnecessary dependencies?

For AI-Modified Lines ()

  • Why was modification needed?
  • Does the modification fix a real issue?
  • Is the modification correct?
  • Should similar patterns elsewhere be checked?

For Human Lines (+)

  • Standard code review practices apply
  • Does it integrate well with AI-generated code?
  • Are there gaps in AI-generated code that human code fills?

Common Patterns

Good Signs

  • High AIModified percentage: Author is reviewing and improving AI output
  • Human tests for AI code: Author is verifying AI behavior
  • Clear prompts: Author knew what they wanted
  • Incremental prompts: Complex features built step-by-step

Warning Signs

  • 100% AI, no modifications: Author may not have reviewed carefully
  • Complex logic with no tests: AI-generated logic should be tested
  • Security-sensitive code: Extra scrutiny needed
  • Vague prompts: “Make it work” leads to unpredictable code

Leaving Feedback

Reference AI Attribution

When commenting, reference the attribution:

This AI-generated code (lines 15-30) doesn't handle the case where
`user_id` is None. The prompt asked for "user authentication" but
didn't specify guest user handling.

Suggest Prompt Improvements

If the issue stems from the prompt:

The AI generated this based on "Add authentication". For future
features, consider more specific prompts like "Add JWT authentication
with 24-hour token expiry and refresh token support".

Ask About Modifications

If AIModified code is unclear:

Line 42 was modified from AI output. Could you explain what the
original AI generated and why you changed it?

GitHub Action Integration

For automated PR comments with AI attribution summaries, see CI/CD Integration.

The action adds a comment like:

## 🤖 AI Attribution Summary

This PR contains **3** of **5** commits with AI-assisted changes.

| Metric | Lines | Percentage |
|--------|------:|----------:|
| AI-generated | 145 | 58.0% |
| AI-modified | 12 | 4.8% |
| Human-added | 43 | 17.2% |

Team Policies

Consider establishing team guidelines:

Minimum Review for AI Code

PRs with >50% AI-generated code require:
- Two reviewers
- Explicit security review
- Test coverage for AI-generated functions

Prompt Documentation

For significant AI-generated features, include the prompts in PR description:
- What prompts were used
- Why that approach was chosen
- What modifications were made

Attribution in Commit Messages

Commits with significant AI involvement should note it:

git commit -m "Add email validation

AI-assisted: 80% of validation logic
Human-modified: regex pattern
Human-added: test cases"

See Also

CI/CD Integration

Integrate whogitit with your CI/CD pipeline to automatically add AI attribution summaries to pull requests.

GitHub Action

Basic Setup

Create .github/workflows/ai-attribution.yml:

name: AI Attribution Summary

on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read
  pull-requests: write

jobs:
  analyze:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          ref: ${{ github.event.pull_request.head.sha }}

      - name: Fetch git notes
        run: |
          git fetch origin refs/notes/whogitit:refs/notes/whogitit || true
        continue-on-error: true

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/bin/
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ runner.os }}-cargo-whogitit-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: |
            ${{ runner.os }}-cargo-whogitit-

      - name: Install whogitit
        run: |
          if ! command -v whogitit &> /dev/null; then
            cargo install --git https://github.com/dotsetlabs/whogitit
          fi

      - name: Generate summary
        id: summary
        run: |
          BASE_SHA="${{ github.event.pull_request.base.sha }}"

          # Generate markdown summary
          SUMMARY=$(whogitit summary --base "$BASE_SHA" --format markdown 2>/dev/null || echo "")

          if [ -n "$SUMMARY" ]; then
            # Save to file for the comment step
            echo "$SUMMARY" > attribution-summary.md
            echo "has_attribution=true" >> $GITHUB_OUTPUT
          else
            echo "has_attribution=false" >> $GITHUB_OUTPUT
          fi

      - name: Comment on PR
        if: steps.summary.outputs.has_attribution == 'true'
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const summary = fs.readFileSync('attribution-summary.md', 'utf8');

            // Find existing comment
            const { data: comments } = await github.rest.issues.listComments({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
            });

            const botComment = comments.find(c =>
              c.user.type === 'Bot' &&
              c.body.includes('AI Attribution Summary')
            );

            const body = `## 🤖 AI Attribution Summary\n\n${summary}\n\n---\n*Generated by [whogitit](https://github.com/dotsetlabs/whogitit)*`;

            if (botComment) {
              await github.rest.issues.updateComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: botComment.id,
                body: body
              });
            } else {
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                body: body
              });
            }

Example PR Comment

The action posts a comment like:


🤖 AI Attribution Summary

This PR contains 3 of 5 commits with AI-assisted changes.

Overview

MetricLinesPercentage
🟢 AI-generated14558.0%
🟡 AI-modified by human124.8%
🔵 Human-added4317.2%
⚪ Original/unchanged5020.0%
Total250100%

AI involvement: 62.8% of changed lines

Commits with AI Attribution

CommitMessageAIModifiedHumanFiles
abc1234Add user authentication453102
def5678Implement JWT tokens1009333

Prompts Used (2)

Add user authentication with bcrypt password hashing...
Add user authentication with bcrypt password hashing. Create a User struct
with email and password_hash fields. Implement register and login functions
that return Result types.

Caching Strategy

The workflow caches:

  • Cargo registry and indices
  • Compiled binaries
  • whogitit itself

This significantly speeds up subsequent runs.

Handling Missing Notes

Git notes may not exist if:

  • The contributor didn’t push notes
  • Notes haven’t been fetched yet
  • The commits have no AI attribution

The workflow handles this gracefully:

- name: Fetch git notes
  run: git fetch origin refs/notes/whogitit:refs/notes/whogitit || true
  continue-on-error: true

Branch Protection

Consider adding AI attribution requirements:

# In a separate check job
- name: Check AI disclosure
  run: |
    AI_PERCENT=$(whogitit summary --base main --format json | jq '.summary.ai_percentage')
    if (( $(echo "$AI_PERCENT > 80" | bc -l) )); then
      echo "::warning::This PR has >80% AI-generated code. Ensure thorough review."
    fi

GitLab CI

For GitLab, create .gitlab-ci.yml:

ai-attribution:
  stage: review
  image: rust:latest
  only:
    - merge_requests
  before_script:
    - cargo install --git https://github.com/dotsetlabs/whogitit
    - git fetch origin refs/notes/whogitit:refs/notes/whogitit || true
  script:
    - |
      SUMMARY=$(whogitit summary --base $CI_MERGE_REQUEST_TARGET_BRANCH_NAME --format markdown)
      if [ -n "$SUMMARY" ]; then
        echo "$SUMMARY" > attribution.md
        # Post to MR via GitLab API
      fi
  artifacts:
    paths:
      - attribution.md

Jenkins

For Jenkins pipelines:

pipeline {
    agent any
    stages {
        stage('AI Attribution') {
            when {
                changeRequest()
            }
            steps {
                sh '''
                    git fetch origin refs/notes/whogitit:refs/notes/whogitit || true
                    whogitit summary --base origin/main --format markdown > attribution.md
                '''
                script {
                    def summary = readFile('attribution.md')
                    if (summary.trim()) {
                        // Post comment via GitHub/GitLab API
                    }
                }
            }
        }
    }
}

Custom Integrations

Slack Notification

#!/bin/bash
SUMMARY=$(whogitit summary --base main --format json)
AI_PERCENT=$(echo "$SUMMARY" | jq '.summary.ai_percentage')

if (( $(echo "$AI_PERCENT > 50" | bc -l) )); then
  curl -X POST "$SLACK_WEBHOOK" \
    -H 'Content-type: application/json' \
    -d "{\"text\": \"PR #$PR_NUMBER has ${AI_PERCENT}% AI-generated code\"}"
fi

Export for Analytics

# In CI, export attribution data for each release
whogitit export \
  --since "$LAST_RELEASE_DATE" \
  --format json \
  -o "attribution-$VERSION.json"

# Upload to S3 or analytics platform
aws s3 cp "attribution-$VERSION.json" "s3://metrics/ai-attribution/"

See Also

Team Collaboration

Best practices for using whogitit across a development team.

Setting Up for Teams

1. Repository Configuration

Add whogitit configuration to your repository:

# .whogitit.toml
[privacy]
enabled = true
audit_log = true

# Add organization-specific patterns
[[privacy.custom_patterns]]
name = "INTERNAL_API_KEY"
pattern = "company-api-[a-f0-9]{32}"

[retention]
max_age_days = 365
retain_refs = ["refs/heads/main", "refs/heads/develop"]
min_commits = 500

Commit this file so all team members use the same settings.

2. Documentation

Add setup instructions to your project README or CONTRIBUTING.md:

## AI Attribution Setup

This project uses whogitit to track AI-generated code.

### Setup
1. Install whogitit: `cargo install --git https://github.com/dotsetlabs/whogitit`
2. Initialize: `whogitit init`
3. Configure Claude Code hooks (see [installation docs])

### Pushing Notes
Attribution notes are automatically pushed with `git push`.

To manually push: `git push origin refs/notes/whogitit`

3. CI Integration

Add the GitHub Action to automatically comment on PRs. See CI/CD Integration.

Fetching Team Attribution

When cloning or fetching:

# Clone with notes
git clone --config remote.origin.fetch='+refs/notes/*:refs/notes/*' <repo-url>

# Or fetch notes manually
git fetch origin 'refs/notes/*:refs/notes/*'

After whogitit init, this is configured automatically.

Team Policies

AI Disclosure Policy

Define when AI attribution is required:

## AI Code Policy

1. **All AI-assisted code must be attributed**
   - whogitit must be initialized in your local repo
   - Push git notes with every PR

2. **Review requirements by AI percentage**
   - <25% AI: Standard review
   - 25-75% AI: Two reviewers required
   - >75% AI: Security review required

3. **Sensitive areas require human code**
   - Authentication/authorization
   - Payment processing
   - PII handling

Commit Message Guidelines

Encourage including AI context in commit messages:

## Commit Messages

For AI-assisted commits, optionally include:

feat: Add email validation

Prompts used:

  • “Add email validation using regex”
  • “Add test cases for edge cases”

Human modifications:

  • Improved regex pattern
  • Added international domain support

Code Review Standards

Define review expectations:

## Reviewing AI Code

When reviewing PRs with AI attribution:

1. Check the AI Attribution Summary comment
2. Focus extra attention on `●` (pure AI) lines
3. Verify `◐` (modified) lines make sense
4. Ensure tests cover AI-generated logic
5. Check for common AI pitfalls:
   - Hallucinated APIs
   - Security vulnerabilities
   - Non-idiomatic patterns

Metrics and Reporting

Weekly AI Usage Report

Generate team-wide metrics:

#!/bin/bash
# weekly-report.sh

echo "# AI Usage Report - Week of $(date +%Y-%m-%d)"
echo

# Fetch latest
git fetch --all

# Get stats for the week
whogitit export \
  --since "$(date -d '7 days ago' +%Y-%m-%d)" \
  --format json \
  -o /tmp/weekly.json

# Summarize
jq '{
  total_commits: .summary.total_commits,
  ai_lines: .summary.total_ai_lines,
  human_lines: .summary.total_human_lines,
  ai_percentage: ((.summary.total_ai_lines + .summary.total_ai_modified_lines) * 100 /
    (.summary.total_ai_lines + .summary.total_ai_modified_lines + .summary.total_human_lines))
}' /tmp/weekly.json

Dashboard Integration

Export data for dashboards:

# Export for Grafana/DataDog
whogitit export --format json | \
  jq -c '.commits[] | {
    timestamp: .committed_at,
    ai_lines: .ai_lines,
    human_lines: .human_lines
  }' | \
  while read line; do
    curl -X POST "https://metrics.example.com/ingest" -d "$line"
  done

Handling Edge Cases

Contributor Without whogitit

If a contributor doesn’t have whogitit set up:

# Their commits will have no attribution
# This is visible in PR summaries as "commits without attribution"

# After merging, you can optionally add a note:
git notes --ref=whogitit add -m '{"schema_version":2,"session":{"session_id":"unknown"},"prompts":[],"files":[]}' <commit>

Rebasing and Attribution

With whogitit init, the post-rewrite hook automatically preserves attribution during rebase:

# Ensure hooks are installed
whogitit init

# Rebase as normal - notes are preserved automatically
git rebase main
# Output: whogitit: Preserved attribution for 3 commit(s)

For cherry-pick (not covered by the hook):

whogitit copy-notes <original-sha> <cherry-picked-sha>

Squash Merging

Squash merging creates new commits without notes. Options:

  1. Merge commits instead: Preserves individual commit notes
  2. Generate summary: Add a note to the squash commit summarizing attribution
  3. Accept loss: For small PRs, the PR comment serves as record

Security Considerations

Redaction Review

Periodically review what’s being redacted:

whogitit audit --event-type redaction --limit 100

Ensure sensitive patterns are being caught.

Access Control

Git notes can contain prompts. Consider:

  • Are prompts themselves sensitive?
  • Should notes be in a separate repo?
  • Do you need fine-grained access control?

Audit Trail

For compliance, enable audit logging:

[privacy]
audit_log = true

And periodically archive:

cp .whogitit/audit.jsonl "audit-backup-$(date +%Y%m%d).jsonl"

Training and Onboarding

New Developer Checklist

## AI Attribution Setup Checklist

- [ ] Install whogitit
- [ ] Run `whogitit init` in each project
- [ ] Configure Claude Code hooks
- [ ] Make a test commit and verify `whogitit blame`
- [ ] Review team AI policies

Common Issues

Document solutions to common problems:

## Troubleshooting

**No attribution data after commit**
- Check `whogitit status` before committing
- Verify hooks are installed: `ls .git/hooks/post-commit`
- Check Claude Code hooks in `~/.claude/settings.json`

**Notes not pushing**
- Manually push: `git push origin refs/notes/whogitit`
- Check pre-push hook: `cat .git/hooks/pre-push`

**Missing attribution on clone**
- Fetch notes: `git fetch origin refs/notes/whogitit:refs/notes/whogitit`

See Also

Architecture

This document describes the internal architecture of whogitit.

System Overview

┌─────────────────────────────────────────────────────────────────────────┐
│                           Claude Code Session                            │
│                                                                          │
│    User Prompt ──► Claude ──► Edit/Write Tool ──► File Modified          │
│                                     │                                    │
└─────────────────────────────────────┼────────────────────────────────────┘
                                      │
                    ┌─────────────────┴─────────────────┐
                    │                                   │
                    ▼                                   ▼
            ┌──────────────┐                    ┌──────────────┐
            │ PreToolUse   │                    │ PostToolUse  │
            │    Hook      │                    │    Hook      │
            └──────┬───────┘                    └──────┬───────┘
                   │                                   │
                   │ Save "before"                     │ Save "after"
                   │ snapshot                          │ + prompt
                   │                                   │
                   ▼                                   ▼
            ┌─────────────────────────────────────────────────┐
            │              Pending Buffer                      │
            │         (.whogitit-pending.json)                 │
            │                                                  │
            │  • File snapshots (before/after each edit)      │
            │  • Session metadata                              │
            │  • Prompts from transcript                       │
            └─────────────────────────────────────────────────┘
                                      │
                                      │ git commit
                                      ▼
            ┌─────────────────────────────────────────────────┐
            │              Post-Commit Hook                    │
            │                                                  │
            │  1. Read pending buffer                          │
            │  2. Read committed file content                  │
            │  3. Three-way diff analysis                      │
            │  4. Generate AIAttribution                       │
            │  5. Store as git note                            │
            │  6. Clear pending buffer                         │
            └─────────────────────────────────────────────────┘
                                      │
                                      ▼
            ┌─────────────────────────────────────────────────┐
            │                 Git Notes                        │
            │         (refs/notes/whogitit)                    │
            │                                                  │
            │  Commit A ──► AIAttribution JSON                 │
            │  Commit B ──► AIAttribution JSON                 │
            │  Commit C ──► AIAttribution JSON                 │
            └─────────────────────────────────────────────────┘

Module Structure

src/
├── capture/           # Hook handlers and pending buffer
│   ├── hook.rs        # CaptureHook - PreToolUse/PostToolUse handling
│   ├── pending.rs     # PendingBuffer - temporary storage
│   ├── snapshot.rs    # Data structures for file snapshots
│   ├── threeway.rs    # Three-way diff algorithm
│   └── diff.rs        # Diff utilities
│
├── core/              # Attribution data models
│   ├── attribution.rs # AIAttribution, PromptInfo, SessionMetadata
│   └── blame.rs       # AIBlamer - combines git blame with notes
│
├── storage/           # Persistence layer
│   ├── notes.rs       # NotesStore - git notes read/write
│   ├── trailers.rs    # Git trailer generation
│   └── audit.rs       # AuditLog, AuditEvent
│
├── privacy/           # Data protection
│   ├── redaction.rs   # Redactor - pattern-based redaction
│   └── config.rs      # Configuration loading
│
├── cli/               # Command implementations
│   ├── blame.rs       # whogitit blame
│   ├── show.rs        # whogitit show
│   ├── prompt.rs      # whogitit prompt
│   ├── summary.rs     # whogitit summary
│   ├── export.rs      # whogitit export
│   ├── retention.rs   # whogitit retention
│   ├── audit.rs       # whogitit audit
│   ├── redact.rs      # whogitit redact-test
│   ├── copy.rs        # whogitit copy-notes
│   └── output.rs      # Output formatting
│
├── lib.rs             # Library exports
└── main.rs            # CLI entry point

Core Components

CaptureHook

Handles Claude Code hook events:

#![allow(unused)]
fn main() {
pub struct CaptureHook {
    repo_root: PathBuf,
    pending_store: PendingStore,
}

impl CaptureHook {
    pub fn handle_pre_tool_use(&self, input: &HookInput) -> Result<()>;
    pub fn handle_post_tool_use(&self, input: &HookInput) -> Result<()>;
}
}
  • PreToolUse: Saves file content before AI edit
  • PostToolUse: Saves file content after AI edit, extracts prompt from transcript

PendingBuffer

Accumulates changes during a session:

#![allow(unused)]
fn main() {
pub struct PendingBuffer {
    pub schema_version: u8,
    pub session: SessionMetadata,
    pub files: HashMap<String, FileEditHistory>,
    pub prompts: Vec<PromptInfo>,
}
}

Stored as JSON in .whogitit-pending.json.

ThreeWayAnalyzer

Core attribution algorithm:

#![allow(unused)]
fn main() {
pub struct ThreeWayAnalyzer;

impl ThreeWayAnalyzer {
    pub fn analyze(
        original: &str,
        ai_snapshots: &[ContentSnapshot],
        final_content: &str,
    ) -> Vec<LineAttribution>;
}
}

Compares:

  1. Original content (before AI session)
  2. AI snapshots (after each AI edit)
  3. Final content (at commit time)

Produces per-line attribution.

AIAttribution

Final attribution data structure:

#![allow(unused)]
fn main() {
pub struct AIAttribution {
    pub schema_version: u8,
    pub session: SessionMetadata,
    pub prompts: Vec<PromptInfo>,
    pub files: Vec<FileAttribution>,
}

pub struct FileAttribution {
    pub path: String,
    pub lines: Vec<LineAttribution>,
}

pub struct LineAttribution {
    pub line_number: u32,
    pub source: LineSource,
    pub prompt_index: Option<u32>,
}
}

NotesStore

Git notes persistence:

#![allow(unused)]
fn main() {
pub struct NotesStore<'repo> {
    repo: &'repo Repository,
}

impl NotesStore {
    pub fn store_attribution(&self, commit: Oid, attr: &AIAttribution) -> Result<()>;
    pub fn fetch_attribution(&self, commit: Oid) -> Result<Option<AIAttribution>>;
    pub fn copy_attribution(&self, from: Oid, to: Oid) -> Result<()>;
    pub fn list_attributed_commits(&self) -> Result<Vec<Oid>>;
}
}

Redactor

Privacy protection:

#![allow(unused)]
fn main() {
pub struct Redactor {
    patterns: Vec<CompiledPattern>,
}

impl Redactor {
    pub fn redact(&self, text: &str) -> String;
    pub fn redact_with_audit(&self, text: &str) -> RedactionResult;
}
}

Data Flow Details

1. Capture Phase

Claude Code Edit
       │
       ▼
┌─────────────────────────────────────────┐
│           whogitit-capture.sh           │
│                                         │
│  • Reads hook JSON from stdin           │
│  • Determines hook phase (pre/post)     │
│  • Extracts file path and tool name     │
│  • Calls whogitit capture --stdin       │
└─────────────────────────────────────────┘
       │
       ▼
┌─────────────────────────────────────────┐
│           CaptureHook                    │
│                                         │
│  Pre: Read current file → save snapshot │
│  Post: Read file → save snapshot        │
│        Read transcript → extract prompt │
│        Update pending buffer            │
└─────────────────────────────────────────┘

2. Commit Phase

git commit
       │
       ▼
┌─────────────────────────────────────────┐
│         post-commit hook                 │
│                                         │
│  Calls: whogitit post-commit            │
└─────────────────────────────────────────┘
       │
       ▼
┌─────────────────────────────────────────┐
│         CaptureHook                      │
│                                         │
│  1. Load pending buffer                 │
│  2. Get commit info (SHA, files)        │
│  3. For each file:                      │
│     a. Get committed content            │
│     b. Get original + AI snapshots      │
│     c. Run ThreeWayAnalyzer             │
│  4. Build AIAttribution                 │
│  5. Redact prompts                      │
│  6. Store as git note                   │
│  7. Clear pending buffer                │
└─────────────────────────────────────────┘

3. Query Phase

whogitit blame file.rs
       │
       ▼
┌─────────────────────────────────────────┐
│           AIBlamer                       │
│                                         │
│  1. Run git blame on file               │
│  2. For each blamed commit:             │
│     a. Fetch AIAttribution from note    │
│     b. Look up line attribution         │
│  3. Merge git blame + AI attribution    │
│  4. Return enriched blame               │
└─────────────────────────────────────────┘

Three-Way Diff Algorithm

The three-way diff is the core of accurate attribution:

Original (O)     AI Edit (A)      Final (F)       Attribution
============     ===========      =========       ===========
line 1           line 1           line 1          Original (in O, unchanged)
line 2           NEW LINE         NEW LINE        AI (in A, not in O, unchanged in F)
                 line 2           MODIFIED        AIModified (in A, modified in F)
line 3           line 3           MY LINE         Human (not in O or A, in F)
                                  line 3          Original (in O, unchanged)

Algorithm steps:

  1. Diff O→A: Find lines added by AI
  2. Diff A→F: Find lines modified by human
  3. Diff O→F: Find lines added by human (not via AI)
  4. Classify each line in F:
    • In O and unchanged → Original
    • Added in A, unchanged in F → AI
    • Added in A, modified in F → AIModified
    • Not in O or A → Human

See Also

Data Formats

This document describes the JSON schemas used by whogitit.

AIAttribution (Git Notes)

The primary data structure stored in git notes:

{
  "schema_version": 2,
  "session": {
    "session_id": "7f3a4b2c-9d1e-8a7b-c3d4-e5f6a7b8c9d0",
    "model": {
      "id": "claude-opus-4-5-20251101",
      "provider": "anthropic"
    },
    "started_at": "2026-01-30T14:23:17Z",
    "cwd": "/path/to/project"
  },
  "prompts": [
    {
      "index": 0,
      "text": "Add user authentication with bcrypt...",
      "affected_files": ["src/auth.rs", "src/main.rs"],
      "timestamp": "2026-01-30T14:23:45Z"
    }
  ],
  "files": [
    {
      "path": "src/auth.rs",
      "lines": [
        {"line_number": 1, "source": "AI", "prompt_index": 0},
        {"line_number": 2, "source": "AI", "prompt_index": 0},
        {"line_number": 3, "source": "AIModified", "prompt_index": 0},
        {"line_number": 4, "source": "Human", "prompt_index": null},
        {"line_number": 5, "source": "Original", "prompt_index": null}
      ],
      "summary": {
        "ai_lines": 2,
        "ai_modified_lines": 1,
        "human_lines": 1,
        "original_lines": 1
      }
    }
  ]
}

Schema Fields

FieldTypeDescription
schema_versionnumberFormat version (currently 2)
sessionobjectAI session information
promptsarrayPrompts used in this commit
filesarrayPer-file attribution

Session Object

FieldTypeDescription
session_idstringUnique session identifier
model.idstringModel identifier
model.providerstringModel provider
started_atstringISO 8601 timestamp
cwdstringWorking directory

Prompt Object

FieldTypeDescription
indexnumberOrder within session
textstringPrompt text (may be redacted)
affected_filesarrayFiles changed by this prompt
timestampstringWhen prompt was given

LineAttribution Object

FieldTypeDescription
line_numbernumber1-indexed line number
sourcestringAI, AIModified, Human, Original, Unknown
prompt_indexnumber|nullIndex of generating prompt

PendingBuffer

Temporary storage during editing session:

{
  "schema_version": 2,
  "session": {
    "session_id": "7f3a4b2c-9d1e-8a7b-c3d4-e5f6a7b8c9d0",
    "model": {
      "id": "claude-opus-4-5-20251101",
      "provider": "anthropic"
    },
    "started_at": "2026-01-30T14:23:17Z",
    "cwd": "/path/to/project"
  },
  "files": {
    "src/auth.rs": {
      "original_content": "// Original file content\n...",
      "edits": [
        {
          "content": "// After first AI edit\n...",
          "prompt_index": 0,
          "timestamp": "2026-01-30T14:23:45Z",
          "tool": "Edit"
        },
        {
          "content": "// After second AI edit\n...",
          "prompt_index": 1,
          "timestamp": "2026-01-30T14:25:00Z",
          "tool": "Write"
        }
      ]
    }
  },
  "prompts": [
    {
      "index": 0,
      "text": "Add user authentication...",
      "affected_files": ["src/auth.rs"],
      "timestamp": "2026-01-30T14:23:45Z"
    }
  ]
}

FileEditHistory

FieldTypeDescription
original_contentstringFile content before AI session
editsarraySequence of AI edits

AIEdit

FieldTypeDescription
contentstringFile content after this edit
prompt_indexnumberWhich prompt triggered this
timestampstringWhen edit occurred
toolstringEdit or Write

Export Format

Output of whogitit export:

{
  "export_version": 1,
  "exported_at": "2026-01-30T15:00:00Z",
  "date_range": {
    "since": "2026-01-01",
    "until": "2026-01-31"
  },
  "commits": [
    {
      "commit_id": "abc123def456789...",
      "commit_short": "abc123d",
      "message": "Add user authentication",
      "author": "Greg King",
      "committed_at": "2026-01-30T14:30:00Z",
      "session_id": "7f3a4b2c-9d1e-8a7b-c3d4-e5f6a7b8c9d0",
      "model": "claude-opus-4-5-20251101",
      "ai_lines": 145,
      "ai_modified_lines": 12,
      "human_lines": 43,
      "original_lines": 50,
      "files": ["src/auth.rs", "src/main.rs"],
      "prompts": [
        {
          "index": 0,
          "text": "Add user authentication...",
          "affected_files": ["src/auth.rs"]
        }
      ]
    }
  ],
  "summary": {
    "total_commits": 10,
    "commits_with_ai": 7,
    "total_ai_lines": 523,
    "total_ai_modified_lines": 45,
    "total_human_lines": 128,
    "total_original_lines": 89,
    "total_prompts": 15
  }
}

Annotations Output Format

Output of whogitit annotations --format github-checks:

{
  "annotations": [
    {
      "path": "src/main.rs",
      "start_line": 42,
      "end_line": 48,
      "annotation_level": "notice",
      "title": "AI Generated (7 lines)",
      "message": "Model: claude-opus-4-5-20251101 | Session: 2024-01-15\n\n**Breakdown:** 5 AI, 2 AI-modified, 0 human, 0 original\n\n**Prompt:** Add error handling...",
      "raw_details": "Add error handling with retry logic..."
    }
  ],
  "summary": {
    "files_analyzed": 5,
    "models": ["claude-opus-4-5-20251101", "claude-sonnet-4-20250514"],
    "session_range": "2024-01-15 to 2024-01-20"
  }
}

Annotation Object

FieldTypeDescription
pathstringFile path relative to repository root
start_linenumberStarting line number (1-indexed)
end_linenumberEnding line number (inclusive)
annotation_levelstringAlways notice for AI attribution
titlestringShort title (e.g., “AI Generated (7 lines)”)
messagestringDetailed message with model, breakdown, and prompt
raw_detailsstring|nullFull prompt text (optional)

Summary Object

FieldTypeDescription
files_analyzednumberNumber of files with AI attribution
modelsarrayAll AI models used across the commits
session_rangestring|nullDate range (e.g., “2024-01-15 to 2024-01-20”)

Annotation Title Formats

Source TypeTitle Format
AI“AI Generated (N lines)”
AIModified“AI Modified (N lines)”
AIRelated (grouped)“AI Related (N lines: X AI, Y AI-modified)”
File-level (new)“New file (N lines) generated by AI”
File-level (existing)“X% AI-generated (N of M lines)”

Audit Log Format

Each line in .whogitit/audit.jsonl is a JSON object, including prev_hash and event_hash fields for tamper‑evident chaining:

event_hash is computed over the event content including prev_hash, so any reordering or tampering breaks the chain. Malformed lines cause verification to fail.

{"timestamp":"2026-01-30T14:23:15Z","event":"Delete","details":{"commit":"abc123d","user":"greg","reason":"Retention policy"}}
{"timestamp":"2026-01-28T10:15:00Z","event":"Export","details":{"commit_count":45,"format":"json","user":"greg"}}
{"timestamp":"2026-01-25T09:00:00Z","event":"RetentionApply","details":{"commits":12,"user":"greg","reason":"Quarterly"}}
{"timestamp":"2026-01-20T16:30:00Z","event":"ConfigChange","details":{"user":"greg","field":"max_age_days"}}
{"timestamp":"2026-01-15T11:45:00Z","event":"Redaction","details":{"pattern_name":"API_KEY","redaction_count":3}}

Event Types

TypeDescriptionDetails Fields
DeleteAttribution deletedcommit, user, reason
ExportData exportedcommit_count, format, user
RetentionApplyRetention policy appliedcommits, user, reason
ConfigChangeConfiguration changeduser, field
RedactionSensitive data redactedpattern_name, redaction_count

Configuration Format

.whogitit.toml:

[privacy]
enabled = true
use_builtin_patterns = true
disabled_patterns = ["EMAIL"]
audit_log = true

[[privacy.custom_patterns]]
name = "INTERNAL_ID"
pattern = "INT-[A-Z0-9]{8}"
description = "Internal IDs"

[retention]
max_age_days = 365
auto_purge = false
retain_refs = ["refs/heads/main"]
min_commits = 100

See Configuration for full reference.

Hook Input Format

JSON passed to hooks via stdin:

{
  "tool_name": "Edit",
  "tool_input": {
    "file_path": "/path/to/file.rs",
    "old_string": "...",
    "new_string": "..."
  },
  "transcript_path": "/tmp/claude-transcript-xyz.jsonl"
}

For Write tool:

{
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.rs",
    "content": "..."
  },
  "transcript_path": "/tmp/claude-transcript-xyz.jsonl"
}

Version History

VersionChanges
2Current version. Full content snapshots.
1Initial version. Diff-based storage. (deprecated)

See Also

Git Notes Storage

whogitit stores attribution data using git’s built-in notes feature. This page explains how notes work and how whogitit uses them.

What Are Git Notes?

Git notes are metadata attached to commits without modifying the commits themselves. They’re stored in a separate ref namespace and can be pushed/fetched independently.

Key characteristics:

  • Non-invasive: Don’t modify commit SHAs
  • Portable: Can be shared via push/fetch
  • Flexible: Any data can be attached
  • Native: Built into git, no external dependencies

whogitit’s Notes Ref

Attribution is stored under refs/notes/whogitit:

# View notes ref
git show-ref | grep whogitit
# abc123def456... refs/notes/whogitit

# List all notes
git notes --ref=whogitit list
# abc123... def456...   (note hash, commit hash)
# ghi789... jkl012...

Viewing Notes

Raw Note Content

# View note for HEAD
git notes --ref=whogitit show HEAD

# View note for specific commit
git notes --ref=whogitit show abc123

# Pretty-print JSON
git notes --ref=whogitit show HEAD | jq .

Using whogitit

# Formatted view
whogitit show HEAD

# JSON output
whogitit show --format json HEAD

How Notes Are Created

Automatic (Post-Commit Hook)

The post-commit hook creates notes automatically:

# In .git/hooks/post-commit
whogitit post-commit

This:

  1. Reads the pending buffer
  2. Analyzes changes
  3. Creates the note

Manual (Advanced)

# Add a note manually
git notes --ref=whogitit add -m '{"schema_version":2,...}' abc123

# Edit existing note
git notes --ref=whogitit edit abc123

# Remove a note
git notes --ref=whogitit remove abc123

# Copy a note
git notes --ref=whogitit copy abc123 def456

Pushing Notes

Notes must be pushed separately from branches:

Automatic (Pre-Push Hook)

After whogitit init, notes are pushed automatically:

git push  # Triggers pre-push hook
# Hook runs: git push origin refs/notes/whogitit

Manual

git push origin refs/notes/whogitit

Force Push (Caution)

If notes diverge:

git push origin refs/notes/whogitit --force

Fetching Notes

Automatic Configuration

whogitit init configures automatic fetching:

# Check configuration
git config --get-all remote.origin.fetch | grep notes
# +refs/notes/whogitit:refs/notes/whogitit

With this config, git fetch includes notes.

Manual

# Fetch notes explicitly
git fetch origin refs/notes/whogitit:refs/notes/whogitit

# Fetch all notes
git fetch origin 'refs/notes/*:refs/notes/*'

Notes and Rebasing

When rebasing, commits get new SHAs. The post-rewrite hook (installed by whogitit init) automatically preserves notes.

Run whogitit init to install the post-rewrite hook:

whogitit init

After this, notes are automatically preserved during:

  • git rebase
  • git commit --amend

You’ll see a message like:

whogitit: Preserved attribution for 3 commit(s)

Manual Copy (Cherry-pick or Recovery)

For cherry-pick (not covered by post-rewrite hook) or manual recovery:

# Using whogitit command
whogitit copy-notes <old-sha> <new-sha>

# Or using git directly
git notes --ref=whogitit copy <old-sha> <new-sha>

Batch Recovery

If you rebased without the hook installed:

# Before rebase, save commits
git log --format='%H' main..HEAD > /tmp/old-commits

# After rebase
git log --format='%H' main..HEAD > /tmp/new-commits

# Copy notes
paste /tmp/old-commits /tmp/new-commits | while read old new; do
  whogitit copy-notes "$old" "$new"
done

Notes and Merge/Squash

Merge Commits

Merge commits don’t automatically get notes. The individual commits retain their notes.

Squash Merging

Squash creates a new commit, losing individual notes. Options:

  1. Use regular merge to preserve notes
  2. Manually create a summary note for the squash
  3. Accept that the PR comment serves as record

Storage Details

Notes Tree Structure

refs/notes/whogitit/
├── ab/
│   ├── c123...  → note for commit abc123...
│   └── d456...  → note for commit abd456...
├── cd/
│   └── e789...  → note for commit cde789...
...

Notes are stored as blobs in the git object database.

Note Size

Each note is a JSON blob. Typical sizes:

  • Small commit (1 file, 20 lines): ~500 bytes
  • Medium commit (5 files, 100 lines): ~2-5 KB
  • Large commit (20 files, 500 lines): ~10-20 KB

Storage Efficiency

Git compresses notes like any other objects. Similar notes compress well together.

Garbage Collection

Notes are git objects and subject to garbage collection:

# Notes blobs without refs will be collected
git gc

# Prune unreferenced notes
git gc --prune=now

Notes attached to existing commits are protected.

Backup and Recovery

Backup Notes

# Clone just the notes
git clone --bare <repo> --single-branch --branch refs/notes/whogitit notes-backup

# Or export
whogitit export --full-prompts -o backup.json

Restore Notes

# Push notes from backup
cd notes-backup
git push <repo> refs/notes/whogitit:refs/notes/whogitit

Troubleshooting

Notes Not Showing

# Check if notes exist locally
git notes --ref=whogitit list

# If empty, fetch
git fetch origin refs/notes/whogitit:refs/notes/whogitit

# Check remote
git ls-remote origin refs/notes/whogitit

Notes Diverged

# See what's different
git log refs/notes/whogitit..origin/refs/notes/whogitit

# Pull remote (may need merge)
git fetch origin refs/notes/whogitit
git update-ref refs/notes/whogitit FETCH_HEAD

Corrupted Note

# Remove and recreate
git notes --ref=whogitit remove <commit>
# Pending buffer is gone, so attribution is lost for that commit

See Also

Hook System

whogitit uses two hook systems: Claude Code hooks for capturing changes, and git hooks for processing commits.

Overview

┌─────────────────────────────────────────────────────────────────┐
│                      Claude Code Hooks                          │
│                                                                 │
│  PreToolUse (Edit|Write|Bash)  ──►  Save "before" state        │
│  PostToolUse (Edit|Write|Bash) ──►  Save "after" state + prompt│
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
                    .whogitit-pending.json
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                        Git Hooks                                │
│                                                                 │
│  post-commit   ──►  Analyze pending buffer, create attribution │
│  pre-push      ──►  Push notes alongside code                  │
│  post-rewrite  ──►  Preserve notes during rebase/amend         │
└─────────────────────────────────────────────────────────────────┘

Claude Code Hooks

Automatic Configuration

The easiest way to configure Claude Code hooks is using the setup command:

whogitit setup

This automatically:

  • Installs the capture script to ~/.claude/hooks/whogitit-capture.sh
  • Configures ~/.claude/settings.json with the required hooks
  • The capture script is embedded in the whogitit binary, so no source files are needed

Manual Configuration

If you prefer manual configuration, add to ~/.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "WHOGITIT_HOOK_PHASE=pre ~/.claude/hooks/whogitit-capture.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "WHOGITIT_HOOK_PHASE=post ~/.claude/hooks/whogitit-capture.sh"
          }
        ]
      }
    ]
  }
}

Matched Tools

ToolDescription
EditModifies existing files
WriteCreates or overwrites files
BashShell commands (may modify files)

Hook Input

Hooks receive JSON on stdin:

{
  "tool_name": "Edit",
  "tool_input": {
    "file_path": "/path/to/file.rs",
    "old_string": "original text",
    "new_string": "replacement text"
  },
  "transcript_path": "/tmp/claude-transcript-xyz.jsonl"
}

Capture Script

The capture script (hooks/whogitit-capture.sh) handles:

  1. Parsing hook input - Extracts tool name, file path
  2. Phase routing - PreToolUse vs PostToolUse
  3. File tracking - Edit/Write: single file, Bash: all modified files
  4. Prompt extraction - Reads transcript JSONL
  5. Calling whogitit - whogitit capture --stdin

PreToolUse Flow

1. Hook receives JSON with tool_name and file_path
2. If Edit/Write: save current file content as "before" snapshot
3. If Bash: snapshot all dirty files in repo

PostToolUse Flow

1. Hook receives JSON with tool_name, file_path, transcript_path
2. If Edit/Write: save file content as "after" snapshot
3. If Bash: compare file states, detect which changed
4. Read transcript to extract user prompt
5. Update pending buffer with edit and prompt

Environment Variables

VariableDescription
WHOGITIT_HOOK_PHASEpre or post
WHOGITIT_BINPath to whogitit binary
WHOGITIT_HOOK_DEBUGEnable debug logging

Debug Logging

# Enable debug mode
export WHOGITIT_HOOK_DEBUG=1

# Logs go to
.whogitit/state/hook-debug.log
.whogitit/state/hook-errors.log

Git Hooks

post-commit

Created by whogitit init in .git/hooks/post-commit:

#!/bin/bash
# whogitit post-commit hook

if command -v whogitit &> /dev/null; then
    whogitit post-commit 2>/dev/null || true
elif [[ -x "$HOME/.cargo/bin/whogitit" ]]; then
    "$HOME/.cargo/bin/whogitit" post-commit 2>/dev/null || true
fi

This hook:

  1. Runs after every commit
  2. Processes the pending buffer
  3. Creates git note with attribution
  4. Clears pending buffer
  5. Applies retention policy automatically if retention.auto_purge = true

pre-push

Created by whogitit init in .git/hooks/pre-push:

#!/bin/bash
# whogitit pre-push hook

# Prevent recursion
[[ "$WHOGITIT_PUSHING_NOTES" == "1" ]] && exit 0

remote="$1"

# Only push notes if they exist
if git notes --ref=whogitit list &>/dev/null; then
    WHOGITIT_PUSHING_NOTES=1 git push "$remote" refs/notes/whogitit 2>/dev/null || true
fi

This hook:

  1. Runs before every push
  2. Pushes notes to the same remote
  3. Handles errors gracefully

post-rewrite

Created by whogitit init in .git/hooks/post-rewrite:

#!/bin/bash
# whogitit post-rewrite hook
# Preserves AI attribution notes during rebase/amend

copied=0
while read -r old_sha new_sha extra; do
  [[ -z "$old_sha" || -z "$new_sha" ]] && continue
  if git notes --ref=whogitit show "$old_sha" &>/dev/null; then
    git notes --ref=whogitit copy "$old_sha" "$new_sha" 2>/dev/null && copied=$((copied + 1))
  fi
done

[[ $copied -gt 0 ]] && echo "whogitit: Preserved attribution for $copied commit(s)"

This hook:

  1. Runs after git rebase and git commit --amend
  2. Receives old→new SHA mappings on stdin
  3. Copies notes from old commits to new commits
  4. Reports how many notes were preserved

Installing Hooks

Automatic

whogitit init

Installs all three git hooks (post-commit, pre-push, post-rewrite) and configures notes fetching.

Manual Git Hooks

# post-commit
cat > .git/hooks/post-commit << 'EOF'
#!/bin/bash
whogitit post-commit 2>/dev/null || true
EOF
chmod +x .git/hooks/post-commit

# pre-push
cat > .git/hooks/pre-push << 'EOF'
#!/bin/bash
[[ "$WHOGITIT_PUSHING_NOTES" == "1" ]] && exit 0
git push "$1" refs/notes/whogitit 2>/dev/null || true
EOF
chmod +x .git/hooks/pre-push

Manual Claude Hooks

The recommended method is whogitit setup, which extracts the embedded capture script.

For manual installation from source:

mkdir -p ~/.claude/hooks
cp /path/to/whogitit/hooks/whogitit-capture.sh ~/.claude/hooks/
chmod +x ~/.claude/hooks/whogitit-capture.sh

Then edit ~/.claude/settings.json as shown above.

Coexistence with Other Hooks

Appending to Existing Hooks

whogitit init detects existing hooks and appends:

# Existing hook
#!/bin/bash
run-tests.sh

# whogitit appends:

# whogitit post-commit hook
if command -v whogitit &> /dev/null; then
    whogitit post-commit 2>/dev/null || true
fi

Hook Managers

If using a hook manager (husky, pre-commit, etc.), add whogitit commands:

Husky:

# .husky/post-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

# Your hooks
npm test

# whogitit
whogitit post-commit 2>/dev/null || true

pre-commit:

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: whogitit
        name: whogitit attribution
        entry: whogitit post-commit
        language: system
        stages: [post-commit]
        always_run: true

Troubleshooting

Run Doctor First

The doctor command checks all hook configuration automatically:

whogitit doctor

Hooks Not Running

# Check Claude hooks config
cat ~/.claude/settings.json | jq '.hooks'

# Check git hooks
ls -la .git/hooks/post-commit .git/hooks/pre-push

# Verify executability
file .git/hooks/post-commit
# Should say "executable"

No Attribution Being Captured

# Run doctor for quick diagnosis
whogitit doctor

# Or check manually:
# Check if whogitit is in PATH
which whogitit

# Check capture hook
ls -la ~/.claude/hooks/whogitit-capture.sh

# Check debug logs
cat .whogitit/state/hook-debug.log
cat .whogitit/state/hook-errors.log

Notes Not Pushing

# Check pre-push hook exists
cat .git/hooks/pre-push

# Manual push
git push origin refs/notes/whogitit

# Check remote
git ls-remote origin refs/notes/whogitit

See Also

Troubleshooting

Common issues and their solutions.

Tip: Run whogitit doctor first to diagnose most configuration issues automatically.

Installation Issues

whogitit command not found

Symptoms:

bash: whogitit: command not found

Solutions:

  1. Check if installed:

    ls ~/.cargo/bin/whogitit
    
  2. Add cargo bin to PATH:

    # Add to ~/.bashrc or ~/.zshrc
    export PATH="$HOME/.cargo/bin:$PATH"
    
    # Reload
    source ~/.bashrc
    
  3. Reinstall:

    cargo install --path /path/to/whogitit --force
    

Build fails

Symptoms:

error[E0433]: failed to resolve: could not find `xyz` in `abc`

Solutions:

  1. Update Rust:

    rustup update stable
    
  2. Clean and rebuild:

    cargo clean
    cargo build --release
    
  3. Check dependencies:

    cargo update
    

Capture Issues

No attribution data after commit

Symptoms:

  • whogitit status shows “No pending AI attribution”
  • whogitit show HEAD shows no attribution

Quick Fix:

Run the doctor command to diagnose:

whogitit doctor

If doctor shows issues, run setup to fix them:

whogitit setup

Manual Solutions:

  1. Check Claude hooks are configured:

    cat ~/.claude/settings.json | jq '.hooks'
    

    Should show PreToolUse and PostToolUse entries.

  2. Check capture script exists:

    ls -la ~/.claude/hooks/whogitit-capture.sh
    
  3. Check capture script is executable:

    chmod +x ~/.claude/hooks/whogitit-capture.sh
    
  4. Check debug logs:

    cat .whogitit/state/hook-debug.log
    cat .whogitit/state/hook-errors.log
    
  5. Verify whogitit binary path:

    # In capture script, check WHOGITIT_BIN
    which whogitit
    

Pending buffer not updating

Symptoms:

  • Making edits with Claude but whogitit status shows old data

Solutions:

  1. Check you’re in a git repo:

    git rev-parse --show-toplevel
    
  2. Check pending file location:

    ls -la .whogitit-pending.json
    
  3. Clear stale data and try again:

    whogitit clear
    

Only some files tracked

Symptoms:

  • Some AI edits are tracked, others aren’t

Solutions:

  1. Check tool matcher in settings.json:

    "matcher": "Edit|Write|Bash"
    

    Make sure all relevant tools are included.

  2. For Bash commands: The hook tracks file changes. Ensure the files exist before the command.

Git Hooks Issues

post-commit hook not running

Symptoms:

  • Commits work but no attribution is created

Solutions:

  1. Check hook exists:

    ls -la .git/hooks/post-commit
    
  2. Check hook is executable:

    chmod +x .git/hooks/post-commit
    
  3. Check hook content:

    cat .git/hooks/post-commit
    

    Should contain whogitit post-commit.

  4. Reinstall hooks:

    whogitit init
    

pre-push hook failing

Symptoms:

error: failed to push some refs to 'origin'

Solutions:

  1. Push notes manually:

    git push origin refs/notes/whogitit
    
  2. Check for notes divergence:

    git fetch origin refs/notes/whogitit
    git log refs/notes/whogitit..FETCH_HEAD
    
  3. Force push notes (caution):

    git push origin refs/notes/whogitit --force
    

Notes Issues

Notes not visible after clone

Symptoms:

  • Cloned repo, but whogitit blame shows no AI attribution

Solutions:

  1. Fetch notes:

    git fetch origin refs/notes/whogitit:refs/notes/whogitit
    
  2. Verify notes exist on remote:

    git ls-remote origin refs/notes/whogitit
    
  3. Configure auto-fetch:

    git config --add remote.origin.fetch '+refs/notes/whogitit:refs/notes/whogitit'
    

Notes missing after rebase

Symptoms:

  • After rebasing, attribution data is gone

Cause: Git notes are attached to specific commit SHAs. Rebase creates new SHAs.

Solutions:

  1. Install the post-rewrite hook (recommended):

    whogitit init
    

    This installs a post-rewrite hook that automatically preserves attribution during rebase and amend operations. Run this once per repository.

  2. Manually copy notes after the fact:

    whogitit copy-notes <old-sha> <new-sha>
    
  3. For cherry-pick (not covered by hook):

    whogitit copy-notes <original-sha> <cherry-picked-sha>
    

Corrupt note data

Symptoms:

Error: invalid JSON in note

Solutions:

  1. View raw note:

    git notes --ref=whogitit show <commit> | cat
    
  2. Remove corrupt note:

    git notes --ref=whogitit remove <commit>
    
  3. Recreate if pending buffer exists: Not possible after buffer is cleared.

Output Issues

JSON parse errors

Symptoms:

Error: expected value at line 1 column 1

Solutions:

  1. Check for empty output:

    whogitit show HEAD 2>&1 | head -1
    
  2. Verify note exists:

    git notes --ref=whogitit show HEAD
    

Blame shows all “Unknown”

Symptoms:

  • whogitit blame shows ? for all lines

Cause:

  • File not in any commit with attribution
  • Attribution data doesn’t include this file

Solutions:

  1. Check if file has attribution:

    whogitit show HEAD | grep -i "filename"
    
  2. Check commit history:

    git log --oneline -- <file>
    

Performance Issues

Slow blame on large files

Symptoms:

  • whogitit blame takes long time on large files

Solutions:

  1. Use --revision to limit scope:

    whogitit blame --revision HEAD~10 <file>
    
  2. Use JSON output for scripting:

    whogitit blame --format json <file>
    

Large pending buffer

Symptoms:

  • .whogitit-pending.json is very large

Solutions:

  1. Commit more frequently: Pending buffer grows with each edit.

  2. Clear and restart:

    whogitit clear
    

Getting Help

Run Doctor First

The doctor command checks all configuration automatically:

whogitit doctor

It verifies:

  • whogitit binary is installed
  • Capture hook is installed and executable
  • Claude Code settings are configured
  • Required tools (jq) are available
  • Repository hooks are installed (if in a git repo)

If any checks fail, it provides fix hints.

Debug Mode

Enable verbose logging:

# For capture hook
export WHOGITIT_HOOK_DEBUG=1

# Then use Claude Code, check:
cat .whogitit/state/hook-debug.log

Reporting Issues

When reporting issues, include:

  1. whogitit version:

    whogitit --version
    
  2. OS and shell:

    uname -a
    echo $SHELL
    
  3. Relevant logs:

    cat .whogitit/state/hook-debug.log
    cat .whogitit/state/hook-errors.log
    
  4. Steps to reproduce

Report at: https://github.com/dotsetlabs/whogitit/issues

See Also

FAQ

Frequently asked questions about whogitit.

General

What is whogitit?

whogitit is a tool that tracks AI-generated code at the line level. It tells you which lines were written by AI, which were modified by humans, and what prompts generated them.

Why track AI-generated code?

  • Transparency: Know exactly what percentage of your codebase was AI-generated
  • Code Review: Identify AI-generated sections that may need extra scrutiny
  • Compliance: Meet organizational requirements for AI usage disclosure
  • Learning: Understand how AI suggestions were modified by humans
  • Debugging: When something breaks, know if AI wrote it and what prompt was used

Does whogitit work with ChatGPT/Copilot/other AI tools?

Currently, whogitit is designed for Claude Code integration. It uses Claude Code’s hook system to capture changes. Support for other tools may be added in the future.

Is whogitit open source?

Yes. whogitit is available at https://github.com/dotsetlabs/whogitit under the MIT license.

Usage

Do I need to do anything special when coding?

No. Once set up, whogitit works automatically:

  1. You use Claude Code normally
  2. Hooks capture your changes
  3. You commit normally
  4. Attribution is attached to the commit

What happens if I modify AI-generated code?

whogitit tracks this! Lines modified by humans after AI generation are marked as AIModified (◐) rather than AI (●). This shows that a human reviewed and changed the code.

Can I use whogitit without Claude Code?

The capture system is designed for Claude Code hooks. Without Claude Code, you can still:

  • View attribution from commits made by others
  • Manually add attribution (advanced)
  • Use the CLI tools for analysis

Does whogitit slow down my workflow?

The overhead is minimal:

  • Hooks run in milliseconds
  • Post-commit analysis is fast (typically <1 second)
  • No impact on normal git operations

Privacy

Are my prompts stored publicly?

Prompts are stored in git notes, which are pushed with your repository. If your repo is public, prompts are visible. However:

  • Sensitive data is automatically redacted
  • You can add custom redaction patterns
  • You can disable prompt storage entirely

What gets redacted automatically?

  • API keys and secrets
  • AWS credentials
  • Private keys
  • Bearer tokens
  • GitHub tokens
  • Email addresses
  • Passwords
  • Credit card numbers
  • Social Security Numbers

Can I disable redaction?

Yes, but it’s not recommended:

# .whogitit.toml
[privacy]
enabled = false

Can I add custom redaction patterns?

Yes:

[[privacy.custom_patterns]]
name = "MY_SECRET"
pattern = "my-secret-[a-f0-9]{32}"
description = "My custom secrets"

Data Storage

Where is attribution data stored?

Attribution is stored as git notes under refs/notes/whogitit. This is a standard git feature - notes are stored in the git object database.

Does attribution increase repository size?

Slightly. Each attributed commit adds a small JSON blob (typically 1-10 KB). For most projects, this is negligible.

What happens if I delete a branch?

Git notes are attached to commits, not branches. If commits are garbage-collected, their notes go too. If commits are still reachable, notes remain.

Can I delete attribution data?

Yes:

# Single commit
git notes --ref=whogitit remove <commit>

# Using retention policy
whogitit retention apply --execute

Git Operations

Does attribution survive rebasing?

Yes! Run whogitit init to install the post-rewrite hook that automatically preserves notes during rebase and amend operations.

For cherry-pick, manually copy: whogitit copy-notes <old> <new>

Does attribution survive squash merging?

No. Squash creates a new commit. The individual commit notes are not combined. Consider using regular merge to preserve notes.

Can I cherry-pick commits with attribution?

Cherry-pick creates new commits. Attribution doesn’t automatically transfer. Use the copy-notes command:

whogitit copy-notes <original-sha> <cherry-picked-sha>

How do I share attribution with my team?

Attribution is stored in git notes, which are pushed/fetched:

# Push
git push origin refs/notes/whogitit

# Fetch (configured automatically by `whogitit init`)
git fetch origin refs/notes/whogitit:refs/notes/whogitit

Troubleshooting

Why isn’t whogitit tracking my repository?

whogitit only tracks attribution in repositories that have been explicitly initialized. Run whogitit init in your repository to enable tracking.

Why is there no attribution after my commit?

Common causes:

  1. Claude Code hooks not configured
  2. whogitit init not run in the repo
  3. Capture script not executable
  4. Edits made outside Claude Code

See Troubleshooting for details.

Why are some lines marked “Unknown”?

This happens when:

  • The file wasn’t included in the AI session
  • Attribution data is corrupted or missing
  • The line existed before whogitit was set up

Why don’t I see attribution after cloning?

Git notes need to be fetched separately:

git fetch origin refs/notes/whogitit:refs/notes/whogitit

Can I fix incorrect attribution?

Attribution can be edited (it’s just JSON in git notes):

git notes --ref=whogitit edit <commit>

But be careful - manual edits can cause inconsistencies.

Advanced

Can I use whogitit in CI/CD?

Yes! See CI/CD Integration. Common uses:

  • Add attribution summaries to PR comments
  • Enforce review policies based on AI percentage
  • Export metrics for dashboards

Can I query attribution programmatically?

Yes:

# JSON output
whogitit blame --format json file.rs
whogitit show --format json HEAD
whogitit summary --format json

# Export
whogitit export --format json

Can I integrate with other tools?

whogitit outputs standard JSON. Integrate with:

  • Dashboards (Grafana, DataDog)
  • Code quality tools
  • Custom scripts
  • Slack/Teams notifications

How do I contribute to whogitit?

See the repository at https://github.com/dotsetlabs/whogitit:

  • Report issues
  • Submit pull requests
  • Improve documentation

See Also