Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture

This document describes the internal architecture of whogitit.

System Overview

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

Module Structure

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

Core Components

CaptureHook

Handles Claude Code hook events:

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

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

PendingBuffer

Accumulates changes during a session:

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

Stored as JSON in .whogitit-pending.json.

ThreeWayAnalyzer

Core attribution algorithm:

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

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

Compares:

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

Produces per-line attribution.

AIAttribution

Final attribution data structure:

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

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

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

NotesStore

Git notes persistence:

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

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

Redactor

Privacy protection:

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

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

Data Flow Details

1. Capture Phase

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

2. Commit Phase

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

3. Query Phase

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

Three-Way Diff Algorithm

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

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

Algorithm steps:

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

See Also