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:
- PreToolUse Hook - Captures the file state before any AI edit
- 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
| Symbol | Source | Description |
|---|---|---|
● | AI | Generated by AI, unchanged |
◐ | AIModified | Generated by AI, then edited by human |
+ | Human | Added by human after AI edits |
─ | Original | Existed before AI session |
? | Unknown | Could not determine source |
Next Steps
- Installation - Get whogitit set up
- Quick Start - Start tracking in 5 minutes
- Core Concepts - Understand how attribution works
Installation
Prerequisites
- Git (2.25 or later)
- jq - JSON processor used by capture hook
- macOS:
brew install jq - Linux:
apt install jqordnf install jq
- macOS:
- Claude Code - For automatic AI attribution capture
Quick Install (Recommended)
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
Quick Setup (Recommended)
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.jsonwith required hooks - Creates a backup of your existing settings
Note: After running
whogitit setup, you must also runwhogitit initin 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 commitspre-push- Automatically pushes git notes with your codepost-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
- Continue to Quick Start to see whogitit in action
- Learn about Core Concepts to understand how attribution works
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:
- Analyzes the pending changes
- Performs three-way diff analysis
- 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?
- Learn about Core Concepts
- Explore all CLI Commands
- Set up CI/CD Integration for PR comments
- Configure Privacy & Redaction rules
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:
| Source | Symbol | Description |
|---|---|---|
| AI | ● | Generated by AI and committed unchanged |
| AIModified | ◐ | Generated by AI, then edited by a human before commit |
| Human | + | Written by a human after AI edits in the same session |
| Original | ─ | Existed 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
- Original - The file content before any AI edits in this session
- AI Snapshot - The file content after each AI edit
- 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
- Explore the CLI Commands
- Learn about Configuration options
- Understand the Architecture in depth
CLI Commands
whogitit provides a comprehensive CLI for viewing and managing AI attribution data.
Command Overview
Core Attribution Commands
| Command | Description |
|---|---|
blame | Show AI attribution for each line of a file |
show | View attribution summary for a commit |
prompt | View the prompt that generated specific lines |
summary | Generate summary for a commit range (PRs) |
status | Check pending attribution changes |
Developer Integration Commands
| Command | Description |
|---|---|
annotations | Generate GitHub Checks API annotations |
pager | Annotate git diff output with AI markers |
Data Management Commands
| Command | Description |
|---|---|
export | Export attribution data as JSON/CSV |
retention | Manage data retention policies |
audit | View the audit log |
clear | Discard pending changes without committing |
Setup Commands
| Command | Description |
|---|---|
setup | Configure Claude Code integration (one-time) |
doctor | Verify whogitit configuration |
init | Initialize whogitit in a repository |
copy-notes | Copy attribution between commits |
Privacy Commands
| Command | Description |
|---|---|
redact-test | Test 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:
| Option | Description |
|---|---|
--help | Show help for any command |
--version | Show version information |
Output Formats
Many commands support multiple output formats:
| Format | Flag | Use Case |
|---|---|---|
| Pretty | (default) | Human-readable terminal output |
| JSON | --format json | Machine parsing, scripts |
| Markdown | --format markdown | Documentation, PR comments |
| CSV | --format csv | Spreadsheets, data analysis |
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Invalid arguments |
Next Steps
Explore each command in detail:
Core Commands
- blame - Line-level attribution
- show - Commit summaries
- prompt - Prompt lookup
- summary - PR summaries
Developer Integration
- annotations - GitHub Checks API
- pager - Git diff annotations
Data & Privacy
- export - Data export
- retention - Data retention
- audit - Audit log
- redact-test - Privacy testing
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
| Argument | Description |
|---|---|
<FILE> | Path to the file to blame |
Options
| Option | Description |
|---|---|
--revision <REF> | Blame at a specific git revision (default: HEAD) |
--format <FORMAT> | Output format: pretty (default), json |
--ai-only | Show only AI-generated lines |
--human-only | Show 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
| Column | Description |
|---|---|
| LINE | Line number in the file |
| COMMIT | Short SHA of the commit that introduced this line |
| AUTHOR | Git author who committed this line |
| SRC | Attribution source symbol |
| CODE | The actual line content |
Attribution Symbols
| Symbol | Meaning |
|---|---|
● | 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-onlyand--human-onlyflags are mutually exclusive - Line numbers start at 1, matching most editor conventions
See Also
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
| Argument | Description |
|---|---|
[COMMIT] | Git commit reference (default: HEAD) |
Options
| Option | Description |
|---|---|
--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
| Field | Description |
|---|---|
| Session | Unique identifier for the AI session |
| Model | AI model used (e.g., claude-opus-4-5-20251101) |
| Started | When 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 promptfor 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
| Argument | Description |
|---|---|
<FILE:LINE> | File path and line number (e.g., src/main.rs:42) |
Options
| Option | Description |
|---|---|
--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 showoutput
See Also
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
| Option | Description |
|---|---|
--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:
| Metric | Description |
|---|---|
| AI-generated | Lines written by AI, unchanged at commit time |
| AI-modified by human | Lines written by AI, then edited before commit |
| Human-written | Lines added by humans (not from AI) |
| Total additions | Sum 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
--baseref 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
- show - Single commit attribution
- export - Bulk data export
- CI/CD Integration - Automated PR comments
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
| Field | Description |
|---|---|
| Session | The AI session ID |
| Files | Number of files with captured changes |
| Edits | Total number of edit operations captured |
| Lines | Approximate lines affected |
| Age | How 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.
Related Commands
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.jsonin your repository root - This file is typically in
.gitignoreand should not be committed - The pending buffer is automatically cleared after a successful commit
See Also
- Quick Start - Basic workflow
- Hook System - How capture works
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
| Option | Description |
|---|---|
--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-only | Only annotate pure AI lines (not AI-modified) |
Consolidation Options
| Option | Description |
|---|---|
--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
| Option | Description |
|---|---|
--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-only | Only annotate lines within the PR diff (requires --base) |
Grouping and Sorting Options
| Option | Description |
|---|---|
--group-ai-types | Group 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:
- AI coverage (up to 40 points) - Higher AI percentage scores higher
- AI line count (up to 30 points) - More AI lines score higher (capped at 100)
- New file bonus (15 points) - Files created entirely by AI
- 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
- summary - PR summary in Markdown format
- CI/CD Integration - Full workflow examples
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
| Option | Description |
|---|---|
--no-color | Disable colored output |
-v, --verbose | Show detailed attribution info (model, timestamps) |
--no-pager | Output directly to stdout instead of through pager |
Attribution Markers
Added lines are prefixed with attribution markers:
| Marker | Color | Meaning |
|---|---|---|
● | Green | AI-generated line, unchanged |
◐ | Yellow | AI-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
-
Ensure attribution data exists:
whogitit blame <file> -
Fetch git notes:
git fetch origin refs/notes/whogitit:refs/notes/whogitit -
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
- blame - Line-by-line attribution
- Git Integration - Complete git setup guide
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
| Option | Description |
|---|---|
--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-prompts | Include 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_idcommit_shortmessageauthorcommitted_atsession_idmodelai_linesai_modified_lineshuman_linesoriginal_linesfiles_countprompts_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
| Field | Description |
|---|---|
total_commits | Number of commits with attribution in range |
commits_with_ai | Commits that have AI-generated lines |
total_ai_lines | Sum of AI lines across all commits |
total_ai_modified_lines | Sum of AI-modified lines |
total_human_lines | Sum of human-added lines |
total_original_lines | Sum of original lines |
total_prompts | Total 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
- summary - Quick summary without full data
- retention - Managing data lifecycle
- Privacy & Redaction - Understanding redacted content
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
| Subcommand | Description |
|---|---|
config | Show current retention settings |
preview | Preview what would be deleted |
apply | Apply 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
| Option | Description |
|---|---|
--execute | Actually 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
| Option | Type | Default | Description |
|---|---|---|---|
max_age_days | number | none | Delete data older than N days |
auto_purge | boolean | false | Purge automatically on commit (post-commit hook) |
retain_refs | array | ["refs/heads/main"] | Refs to always preserve |
min_commits | number | 100 | Minimum commits to keep (newest by commit time) |
Retention Logic
The retention policy applies these rules in order:
- Age filter: Identify commits older than
max_age_days - Ref protection: Exclude commits reachable from
retain_refs - 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
--executeflag is required to actually delete data - Use
previewliberally before applying
See Also
- Configuration - Full configuration reference
- audit - View deletion audit trail
- export - Backup data before deletion
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
| Option | Description |
|---|---|
--since <DATE> | Only show events after this date (YYYY-MM-DD) |
--event-type <TYPE> | Filter by event type |
--json | Output as JSON |
--limit <N> | Show last N events (default: 50) |
Event Types
| Type | Description |
|---|---|
delete | Attribution data was deleted |
export | Data was exported |
retention_apply | Retention policy was applied |
config_change | Configuration was modified |
redaction | Sensitive 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
| Field | Description |
|---|---|
| Timestamp | When the event occurred |
| Event type | Category of event (color-coded) |
| Details | Event-specific information |
| Reason | User-provided reason (if any) |
Event-Specific Details
Delete events:
commit: The commit SHA whose attribution was deleteduser: Who performed the deletionreason: Why it was deleted
Export events:
commit_count: Number of commits exportedformat: Export format (json/csv)user: Who performed the export
Retention events:
commits: Number of commits affecteduser: Who applied the policyreason: Provided reason
Config events:
user: Who changed the config- Details of what changed
Redaction events:
pattern_name: Which pattern matchedredaction_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.jsonlin 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
- retention - Data retention management
- Privacy & Redaction - Redaction configuration
- Configuration - Enabling audit logging
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
-
Installs capture hook script
- Creates
~/.claude/hooks/directory if needed - Writes
whogitit-capture.shto~/.claude/hooks/ - Sets executable permissions
- Creates
-
Configures Claude Code settings
- Creates
~/.claude/settings.jsonif it doesn’t exist - Adds PreToolUse and PostToolUse hook configuration
- Preserves existing settings (creates backup at
settings.json.backup)
- Creates
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 - Verify configuration
- Installation - Full installation guide
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
| Check | Description |
|---|---|
| whogitit binary | Confirms the binary is installed and running |
| Capture hook | Verifies hook script exists at ~/.claude/hooks/whogitit-capture.sh |
| Hook permissions | Confirms the hook script is executable |
| Claude Code settings | Checks that ~/.claude/settings.json has whogitit hooks configured |
| Required tools | Verifies jq is installed (required by capture hook) |
| Repository hooks | If in a git repo, checks that post-commit and pre-push hooks are installed |
| Attribution notes | If 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:
-
Global configuration issues (hook, settings):
whogitit setup -
Repository-specific issues (git hooks):
whogitit init -
Missing jq:
- macOS:
brew install jq - Ubuntu/Debian:
apt install jq - Fedora:
dnf install jq
- macOS:
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
| Code | Meaning |
|---|---|
| 0 | All checks passed or completed with warnings |
See Also
- setup - Configure Claude Code integration
- Troubleshooting - Common issues and solutions
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
| Option | Description |
|---|---|
--force | Skip global setup check and proceed anyway |
What It Does
-
Installs post-commit hook (
.git/hooks/post-commit)- Finalizes AI attribution after each commit
- Attaches attribution data as git notes
-
Installs pre-push hook (
.git/hooks/pre-push)- Automatically pushes git notes with regular pushes
- Ensures attribution travels with your code
-
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
- Preserves attribution during
-
Configures git fetch
- Adds fetch refspec for
refs/notes/whogitit - Notes are automatically fetched on
git fetch/git pull
- Adds fetch refspec for
-
Updates git exclude
- Adds whogitit local artifacts to
.git/info/exclude - Prevents accidental commits of
.whogitit-pending.jsonand.whogitit/
- Adds whogitit local artifacts to
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:
- Run
whogitit setup(one-time global setup) - 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-commitafter 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/whogititto the remote - Ensures attribution notes travel with commits
post-rewrite hook
The post-rewrite hook:
- Runs after
git rebaseandgit 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
| Argument | Description |
|---|---|
SOURCE | Source commit SHA (the commit with attribution) |
TARGET | Target commit SHA (the commit to copy attribution to) |
Options
| Option | Description |
|---|---|
--dry-run | Show 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 rebasegit 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
| Code | Meaning |
|---|---|
| 0 | Success (or source has no attribution) |
| 1 | Error (invalid commit, repository issues) |
See Also
- init - Install hooks including post-rewrite
- Git Notes Storage - How attribution is stored
- Troubleshooting - Common issues
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
| Option | Description |
|---|---|
--text <TEXT> | Text to test redaction on (conflicts with --file) |
--file <FILE> | File to read and test redaction on (conflicts with --text) |
--matches-only | Show only matches without redacting |
--audit | Show audit trail of redactions |
--list-patterns | List available redaction patterns |
--json | Output as JSON |
Built-in Patterns
whogitit includes patterns for common sensitive data:
| Pattern | Description |
|---|---|
API_KEY | Generic API keys (api_key, apikey, secret, token) |
AWS_KEY | AWS access keys (AKIA...) |
PRIVATE_KEY | PEM-encoded private keys |
BEARER_TOKEN | Bearer authentication tokens |
GITHUB_TOKEN | GitHub tokens (ghp_, gho_, ghs_, ghr_) |
SLACK_TOKEN | Slack tokens (xoxb-, xoxp-, xoxa-) |
STRIPE_KEY | Stripe API keys (sk_live_, pk_live_) |
PASSWORD | Password patterns in config-like contexts |
EMAIL | Email addresses |
SSN | Social 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
- Privacy & Redaction - Full privacy configuration guide
- Configuration -
.whogitit.tomlreference
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:
- Repository-local:
.whogitit.tomlin the repository root - Global:
~/.config/whogitit/config.toml - 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:
| Name | Description |
|---|---|
API_KEY | Generic API keys |
AWS_ACCESS_KEY | AWS access key IDs |
AWS_SECRET_KEY | AWS secret access keys |
BEARER_TOKEN | Bearer tokens in headers |
CREDIT_CARD | Credit card numbers |
EMAIL | Email addresses |
GITHUB_TOKEN | GitHub personal access tokens |
GOOGLE_API_KEY | Google API keys |
JWT | JSON Web Tokens |
PASSWORD | Password patterns |
PHONE | Phone numbers |
PRIVATE_KEY | Private key blocks |
SLACK_TOKEN | Slack tokens |
SSN | Social 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:
| Field | Required | Description |
|---|---|---|
name | Yes | Unique identifier (appears in audit log) |
pattern | Yes | Regular expression to match |
description | No | Human-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:
| Variable | Description |
|---|---|
WHOGITIT_CONFIG | Path to configuration file |
WHOGITIT_BIN | Path to whogitit binary (used by hooks) |
See Also
- Privacy & Redaction - Detailed redaction information
- retention - Retention policy management
- audit - Viewing audit logs
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
| Pattern | Examples |
|---|---|
| API_KEY | api_key=xxx, apikey: xxx, secret=xxx |
| AWS_ACCESS_KEY | AKIA... (20 chars) |
| AWS_SECRET_KEY | 40-character base64 strings |
| BEARER_TOKEN | Bearer eyJ..., Authorization: Bearer |
| GITHUB_TOKEN | ghp_xxx, gho_xxx, ghs_xxx, ghr_xxx |
| GOOGLE_API_KEY | AIza... |
| SLACK_TOKEN | xoxb-xxx, xoxp-xxx |
| JWT | eyJ... JSON Web Tokens |
| PASSWORD | password=xxx, passwd: xxx |
| PRIVATE_KEY | -----BEGIN.*PRIVATE KEY----- blocks |
Personal Information
| Pattern | Examples |
|---|---|
user@example.com | |
| PHONE | (555) 123-4567, +1-555-123-4567 |
| SSN | 123-45-6789 |
| CREDIT_CARD | 4111-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):
| Syntax | Meaning |
|---|---|
\d | Digit |
\w | Word character |
\s | Whitespace |
[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:
| Pattern | Why Disable |
|---|---|
| Open source projects where contributor emails are public | |
| PHONE | False 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
- Configuration - Full configuration reference
- audit - Viewing redaction audit trail
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:
- Analyzes the pending changes
- Creates attribution data
- Attaches it as a git note
- 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
- Quick Start - Basic setup
- Code Review - Reviewing AI-generated code
- Core Concepts - Understanding attribution
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 - Automated PR comments
- Team Collaboration - Team workflows
- summary - Summary command reference
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
| Metric | Lines | Percentage |
|---|---|---|
| 🟢 AI-generated | 145 | 58.0% |
| 🟡 AI-modified by human | 12 | 4.8% |
| 🔵 Human-added | 43 | 17.2% |
| ⚪ Original/unchanged | 50 | 20.0% |
| Total | 250 | 100% |
AI involvement: 62.8% of changed lines
Commits with AI Attribution
| Commit | Message | AI | Modified | Human | Files |
|---|---|---|---|---|---|
abc1234 | Add user authentication | 45 | 3 | 10 | 2 |
def5678 | Implement JWT tokens | 100 | 9 | 33 | 3 |
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
- summary - Summary command reference
- export - Export command reference
- Team Collaboration - Team policies
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:
- Merge commits instead: Preserves individual commit notes
- Generate summary: Add a note to the squash commit summarizing attribution
- 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
- CI/CD Integration - Automated PR comments
- Code Review - Review practices
- Configuration - Team-wide settings
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:
- Original content (before AI session)
- AI snapshots (after each AI edit)
- 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:
- Diff O→A: Find lines added by AI
- Diff A→F: Find lines modified by human
- Diff O→F: Find lines added by human (not via AI)
- 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 - JSON schemas
- Git Notes Storage - Notes implementation
- Hook System - Hook details
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
| Field | Type | Description |
|---|---|---|
schema_version | number | Format version (currently 2) |
session | object | AI session information |
prompts | array | Prompts used in this commit |
files | array | Per-file attribution |
Session Object
| Field | Type | Description |
|---|---|---|
session_id | string | Unique session identifier |
model.id | string | Model identifier |
model.provider | string | Model provider |
started_at | string | ISO 8601 timestamp |
cwd | string | Working directory |
Prompt Object
| Field | Type | Description |
|---|---|---|
index | number | Order within session |
text | string | Prompt text (may be redacted) |
affected_files | array | Files changed by this prompt |
timestamp | string | When prompt was given |
LineAttribution Object
| Field | Type | Description |
|---|---|---|
line_number | number | 1-indexed line number |
source | string | AI, AIModified, Human, Original, Unknown |
prompt_index | number|null | Index 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
| Field | Type | Description |
|---|---|---|
original_content | string | File content before AI session |
edits | array | Sequence of AI edits |
AIEdit
| Field | Type | Description |
|---|---|---|
content | string | File content after this edit |
prompt_index | number | Which prompt triggered this |
timestamp | string | When edit occurred |
tool | string | Edit 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
| Field | Type | Description |
|---|---|---|
path | string | File path relative to repository root |
start_line | number | Starting line number (1-indexed) |
end_line | number | Ending line number (inclusive) |
annotation_level | string | Always notice for AI attribution |
title | string | Short title (e.g., “AI Generated (7 lines)”) |
message | string | Detailed message with model, breakdown, and prompt |
raw_details | string|null | Full prompt text (optional) |
Summary Object
| Field | Type | Description |
|---|---|---|
files_analyzed | number | Number of files with AI attribution |
models | array | All AI models used across the commits |
session_range | string|null | Date range (e.g., “2024-01-15 to 2024-01-20”) |
Annotation Title Formats
| Source Type | Title 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
| Type | Description | Details Fields |
|---|---|---|
Delete | Attribution deleted | commit, user, reason |
Export | Data exported | commit_count, format, user |
RetentionApply | Retention policy applied | commits, user, reason |
ConfigChange | Configuration changed | user, field |
Redaction | Sensitive data redacted | pattern_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
| Version | Changes |
|---|---|
| 2 | Current version. Full content snapshots. |
| 1 | Initial version. Diff-based storage. (deprecated) |
See Also
- Architecture - System design
- Git Notes Storage - Notes implementation
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:
- Reads the pending buffer
- Analyzes changes
- 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.
Automatic Preservation (Recommended)
Run whogitit init to install the post-rewrite hook:
whogitit init
After this, notes are automatically preserved during:
git rebasegit 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:
- Use regular merge to preserve notes
- Manually create a summary note for the squash
- 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
- Architecture - System design
- Data Formats - JSON schemas
- Troubleshooting - Common issues
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.jsonwith 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
| Tool | Description |
|---|---|
Edit | Modifies existing files |
Write | Creates or overwrites files |
Bash | Shell 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:
- Parsing hook input - Extracts tool name, file path
- Phase routing - PreToolUse vs PostToolUse
- File tracking - Edit/Write: single file, Bash: all modified files
- Prompt extraction - Reads transcript JSONL
- 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
| Variable | Description |
|---|---|
WHOGITIT_HOOK_PHASE | pre or post |
WHOGITIT_BIN | Path to whogitit binary |
WHOGITIT_HOOK_DEBUG | Enable 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:
- Runs after every commit
- Processes the pending buffer
- Creates git note with attribution
- Clears pending buffer
- 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:
- Runs before every push
- Pushes notes to the same remote
- 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:
- Runs after
git rebaseandgit commit --amend - Receives old→new SHA mappings on stdin
- Copies notes from old commits to new commits
- 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
- Installation - Setup instructions
- Architecture - System design
- Troubleshooting - Common issues
Troubleshooting
Common issues and their solutions.
Tip: Run
whogitit doctorfirst to diagnose most configuration issues automatically.
Installation Issues
whogitit command not found
Symptoms:
bash: whogitit: command not found
Solutions:
-
Check if installed:
ls ~/.cargo/bin/whogitit -
Add cargo bin to PATH:
# Add to ~/.bashrc or ~/.zshrc export PATH="$HOME/.cargo/bin:$PATH" # Reload source ~/.bashrc -
Reinstall:
cargo install --path /path/to/whogitit --force
Build fails
Symptoms:
error[E0433]: failed to resolve: could not find `xyz` in `abc`
Solutions:
-
Update Rust:
rustup update stable -
Clean and rebuild:
cargo clean cargo build --release -
Check dependencies:
cargo update
Capture Issues
No attribution data after commit
Symptoms:
whogitit statusshows “No pending AI attribution”whogitit show HEADshows 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:
-
Check Claude hooks are configured:
cat ~/.claude/settings.json | jq '.hooks'Should show PreToolUse and PostToolUse entries.
-
Check capture script exists:
ls -la ~/.claude/hooks/whogitit-capture.sh -
Check capture script is executable:
chmod +x ~/.claude/hooks/whogitit-capture.sh -
Check debug logs:
cat .whogitit/state/hook-debug.log cat .whogitit/state/hook-errors.log -
Verify whogitit binary path:
# In capture script, check WHOGITIT_BIN which whogitit
Pending buffer not updating
Symptoms:
- Making edits with Claude but
whogitit statusshows old data
Solutions:
-
Check you’re in a git repo:
git rev-parse --show-toplevel -
Check pending file location:
ls -la .whogitit-pending.json -
Clear stale data and try again:
whogitit clear
Only some files tracked
Symptoms:
- Some AI edits are tracked, others aren’t
Solutions:
-
Check tool matcher in settings.json:
"matcher": "Edit|Write|Bash"Make sure all relevant tools are included.
-
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:
-
Check hook exists:
ls -la .git/hooks/post-commit -
Check hook is executable:
chmod +x .git/hooks/post-commit -
Check hook content:
cat .git/hooks/post-commitShould contain
whogitit post-commit. -
Reinstall hooks:
whogitit init
pre-push hook failing
Symptoms:
error: failed to push some refs to 'origin'
Solutions:
-
Push notes manually:
git push origin refs/notes/whogitit -
Check for notes divergence:
git fetch origin refs/notes/whogitit git log refs/notes/whogitit..FETCH_HEAD -
Force push notes (caution):
git push origin refs/notes/whogitit --force
Notes Issues
Notes not visible after clone
Symptoms:
- Cloned repo, but
whogitit blameshows no AI attribution
Solutions:
-
Fetch notes:
git fetch origin refs/notes/whogitit:refs/notes/whogitit -
Verify notes exist on remote:
git ls-remote origin refs/notes/whogitit -
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:
-
Install the post-rewrite hook (recommended):
whogitit initThis installs a
post-rewritehook that automatically preserves attribution during rebase and amend operations. Run this once per repository. -
Manually copy notes after the fact:
whogitit copy-notes <old-sha> <new-sha> -
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:
-
View raw note:
git notes --ref=whogitit show <commit> | cat -
Remove corrupt note:
git notes --ref=whogitit remove <commit> -
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:
-
Check for empty output:
whogitit show HEAD 2>&1 | head -1 -
Verify note exists:
git notes --ref=whogitit show HEAD
Blame shows all “Unknown”
Symptoms:
whogitit blameshows?for all lines
Cause:
- File not in any commit with attribution
- Attribution data doesn’t include this file
Solutions:
-
Check if file has attribution:
whogitit show HEAD | grep -i "filename" -
Check commit history:
git log --oneline -- <file>
Performance Issues
Slow blame on large files
Symptoms:
whogitit blametakes long time on large files
Solutions:
-
Use
--revisionto limit scope:whogitit blame --revision HEAD~10 <file> -
Use JSON output for scripting:
whogitit blame --format json <file>
Large pending buffer
Symptoms:
.whogitit-pending.jsonis very large
Solutions:
-
Commit more frequently: Pending buffer grows with each edit.
-
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:
-
whogitit version:
whogitit --version -
OS and shell:
uname -a echo $SHELL -
Relevant logs:
cat .whogitit/state/hook-debug.log cat .whogitit/state/hook-errors.log -
Steps to reproduce
Report at: https://github.com/dotsetlabs/whogitit/issues
See Also
- Installation - Setup guide
- Hook System - Hook details
- FAQ - Common questions
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:
- You use Claude Code normally
- Hooks capture your changes
- You commit normally
- 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:
- Claude Code hooks not configured
whogitit initnot run in the repo- Capture script not executable
- 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
- Troubleshooting - Problem solutions
- Core Concepts - How it works
- Architecture - Technical details