{"vulnerability": "CVE-2026-44243", "sightings": [{"uuid": "13527e32-082a-4edc-8cc4-a00ed1bf5d52", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-44243", "type": "seen", "source": "https://bsky.app/profile/cve.skyfleet.blue/post/3mlc5bswnv72i", "content": "CVE-2026-44243 - GitPython: Path traversal in GitPython reference APIs allows arbitrary file write and delete outside the repository\nCVE ID : CVE-2026-44243\n \n Published : May 7, 2026, 7:16 p.m. | 1\u00a0hour, 9\u00a0minutes ago\n \n Description : GitPython is a python library used to int...", "creation_timestamp": "2026-05-07T21:17:43.039530Z"}, {"uuid": "1d55cda5-7a7f-47d3-90fe-fa163d62321e", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-44243", "type": "seen", "source": "https://gist.github.com/trippersham/98c56220f8edca1dd84337d7c1d67182", "content": "# Artifacts Feature: Comprehensive Research Document\n\n**Date:** 2026-05-12\n**Author:** Tripp Wickersham + Claude (Socratic Deep Research)\n**Status:** Research Complete, Ready for Implementation Planning\n**Repository:** raepartners/claude-code-marketplace\n**Feature:** Artifacts \u2014 file-level observability for AI agent work\n\n---\n\n## Executive Summary\n\nThis document captures the full research process for Lightfield's Artifacts feature: the ability to view the actual files an AI agent produced alongside the behavioral trust signals (traces) that prove the quality of that work.\n\n**The core capability:** Present to a user the state of any file an agent touched, at any meaningful boundary (commit, task completion, idle transition), with full diff history \u2014 even when the original agent session, daemon, or git repo is no longer available.\n\n**The core constraint:** Do not store customer source code on rae's servers. Code must stay in the customer's own infrastructure.\n\n### Research Journey\n\nWe explored four storage architectures, pressure-tested each against real-world git behaviors, and arrived at a design through iterative elimination:\n\n1. **SQLite blob store** \u2014 Rejected. Reinvents git's content-addressable storage, creates a separate copy of customer code that becomes a security/compliance liability in SaaS mode.\n2. **In-repo git refs** (`refs/rae/*` in user's repo) \u2014 Explored deeply, empirically verified. Works well but leaks into `git log --all` and git GUIs. Since a shadow repo is needed anyway for external files, routing everything through it is cleaner.\n3. **Shadow bare repo** (`~/.rae/artifacts.git`) with alternates \u2014 **Recommended.** 100% opacity, automatic deduplication via alternates, self-contained exports via `git repack`, zero interference with user's git workflow.\n4. **Hybrid per-repo + shadow** \u2014 Explored but rejected in favor of shadow-for-everything. The per-repo approach's dedup advantage turns out to be free via alternates anyway.\n\n### Key Findings\n\n- **Git's `hash-object -w` respects alternates on write** \u2014 identical content is not duplicated. This was the surprising finding that made shadow-repo-for-everything viable without dedup loss.\n- **`git repack -a` internalizes alternate objects** \u2014 enables self-contained archival. Snapshots can survive the deletion of the original repo.\n- **Snapshots survive all standard git operations** (gc, rebase, reset, amend, cherry-pick, worktree removal). Empirically verified across 11 experiments.\n- **Storage overhead is negligible** \u2014 50 snapshots x 20 files = 110KB packed, thanks to delta compression.\n- **Alternates + GC = data loss risk** \u2014 Objects accessed only via alternates can be pruned by the source repo's gc. Mitigation: copy-on-snapshot to internalize objects at creation time.\n- **No interference from stacking tools** \u2014 Graphite and GitHub Stacks use standard branches. No custom refs conflict with `refs/rae/`.\n- **Root commit hash is the most stable repo identifier** \u2014 Immutable, identical across clones/worktrees/moves, works offline.\n\n### Recommended Architecture\n\n```\n~/.rae/artifacts.git                              # Single bare repo, all snapshots\n\u251c\u2500\u2500 objects/\n\u2502   \u251c\u2500\u2500 info/alternates                           # Points to user repos (dedup + live reads)\n\u2502   \u251c\u2500\u2500 pack/                                     # Internalized snapshot objects\n\u2502   \u2514\u2500\u2500                            # New snapshot objects before gc\n\u2514\u2500\u2500 refs/rae/\n    \u2514\u2500\u2500 /\n        \u251c\u2500\u2500 000                                   # Snapshot at boundary 1\n        \u251c\u2500\u2500 001                                   # Snapshot at boundary 2\n        \u2514\u2500\u2500 latest                                # Pointer to most recent\n\n~/.rae/artifacts.db                               # SQLite index\n\u251c\u2500\u2500 artifact_sessions                             # session \u2192 repos, refs, metadata\n\u2514\u2500\u2500 artifact_file_refs                            # session \u2192 file paths, blob SHAs, metadata\n```\n\n**Security model:** The SQLite index stores only references (commit SHAs, blob SHAs, file paths, metadata). File content lives in git objects \u2014 either in the shadow repo's own packfiles (self-contained) or accessible via alternates to user repos. In SaaS mode, only the index syncs to the server. Content never leaves the user's machine.\n\n---\n\n## Table of Contents\n\n1. [Problem Statement](#1-problem-statement)\n2. [Prior Art Survey](#2-prior-art-survey)\n3. [Existing Infrastructure Audit](#3-existing-infrastructure-audit)\n4. [Architecture Options Explored](#4-architecture-options-explored)\n5. [Security and Compliance Analysis](#5-security-and-compliance-analysis)\n6. [Recommended Architecture](#6-recommended-architecture)\n7. [Git Library Selection](#7-git-library-selection)\n8. [Multi-Repo and External File Handling](#8-multi-repo-and-external-file-handling)\n9. [Worktrees and Stacking Tools](#9-worktrees-and-stacking-tools)\n10. [Stable Repository Identity](#10-stable-repository-identity)\n11. [Empirical Verification: In-Repo Approach](#11-empirical-verification-in-repo-approach)\n12. [Empirical Verification: Shadow Repo Approach](#12-empirical-verification-shadow-repo-approach)\n13. [Durability Analysis](#13-durability-analysis)\n14. [Implementation Phasing](#14-implementation-phasing)\n15. [Open Questions](#15-open-questions)\n\n---\n\n## 1. Problem Statement\n\n### What We're Building\n\nAn \"Artifacts\" feature for Lightfield that lets users interact with the outputs of their AI agents (files on disk) alongside the trust signals (behavioral proof in traces) in a single view.\n\n### Capabilities Required\n\n1. **File state at a point in time** \u2014 Show what a file looked like at a specific commit, task boundary, or idle transition\n2. **Diff between any two states** \u2014 Compare file content across boundaries\n3. **Offline review** \u2014 Review artifacts without an active connection to the daemon or the original git repo\n4. **Trust signal linkage** \u2014 Connect each file change back to the span/trace that caused it\n5. **Coverage of non-tracked files** \u2014 Capture agent scratch work (plans, temp files, configs) that may not be in the user's git history\n\n### Design Constraints\n\n1. **Don't reinvent git** \u2014 Use git's existing content-addressable storage rather than building a parallel blob store\n2. **Don't store customer code on our servers** \u2014 Code stays in the customer's git infrastructure; we store only references\n3. **Don't interfere with the user's workflow** \u2014 Invisible to normal git commands, doesn't affect push/pull/branch/log\n4. **Minimize homebrew** \u2014 It's what we do with the capability that matters, not the plumbing\n\n---\n\n## 2. Prior Art Survey\n\n### Cursor Agent-Trace (v0.1.0)\n\nAn open specification for tracing AI-generated code attribution. Key design choices:\n\n- **Content hashes, not content** \u2014 Stores SHA hashes of file content, not the content itself. Enables attribution tracking without storing code.\n- **Storage-agnostic** \u2014 Deliberately does not prescribe storage. Traces can live in local files, git notes, databases, or other systems.\n- **Line-range attribution** \u2014 Each trace record maps code ranges (startLine/endLine) to conversations and contributors.\n- **Multi-VCS support** \u2014 Works with Git, Jujutsu, and Mercurial.\n\n**Relevance:** Our snapshot architecture is structurally compatible. We could emit agent-trace records as a byproduct of our snapshot commits.\n\n### VS Code Timeline API\n\nExtension-based provider model where extensions register `TimelineProvider` for document sets. VS Code calls all registered providers in parallel when the active editor changes.\n\n- Built-in Git extension contributes commit history per file\n- Multi-provider architecture: results merged, failures isolated\n- Point-in-time viewing via click-to-diff\n\n**Relevance:** The multi-provider pattern is a good model for Lightfield's Artifacts tab \u2014 showing agent traces alongside git history.\n\n### Agent Observability Tools\n\n| Tool | Stores Code? | Links to Git? | Approach |\n|------|-------------|---------------|----------|\n| **LangSmith/Langfuse** | Tool I/O only | No | Trace hierarchy |\n| **Datadog APM** | No | Source code integration (links to repo) | Reference-only |\n| **Sentry** | Stack trace context | Source maps (uploaded) | Content stored, encrypted |\n| **Augment Code** | Per-agent worktrees | Structural isolation | Attribution via workspace |\n| **Tabnine** | Zero retention | No | Process transiently |\n\n**Key gap:** No mainstream tool natively links OTel traces to git commits/diffs. This is whitespace that rae can fill.\n\n### Browser-Embeddable Git Tools\n\n| Tool | Type | Viability |\n|------|------|-----------|\n| **isomorphic-git** | Pure JS git for Node + browser | Viable for client-side file retrieval |\n| **wasm-git** | libgit2 compiled to WASM | Heavy, requires WebWorker |\n| **Monaco Editor** | Diff view, syntax highlighting | Excellent renderer, no git awareness |\n| **react-diff-view** | Diff rendering (already in Lightfield) | Already integrated |\n\n**Decision:** We don't need client-side git. The daemon proxies git operations; the frontend is a viewer.\n\n---\n\n## 3. Existing Infrastructure Audit\n\n### What Lightfield Already Captures\n\nThe codebase has a surprisingly rich foundation for Artifacts:\n\n| Capability | Location | Detail |\n|---|---|---|\n| **File paths per tool use** | `content_blocks.file_path` | Every Read/Write/Edit/Glob/Grep stores the target path |\n| **Before/after diffs** | `content_blocks.diff_old/new/unified` | Edit tool captures old-string \u2192 new-string |\n| **Git commits linked to spans** | `commits` + `commit_spans` tables | Hash, branch, message, insertions/deletions, parsed from Bash tool output |\n| **VCS context per session** | `span_attributes` | `vcs.ref.head.name`, `vcs.repository.url.full`, `rae.workspace.directory`, `rae.vcs.worktree` |\n| **Diff rendering** | `DiffDisplay` + `react-diff-view` | Working component in trace view |\n| **File access tracking** | Thrash detector `ResourceAccessDetector` | Sliding window of file_path fingerprints for behavioral analysis |\n| **Task lifecycle** | `tasks` + `task_spans` + `task_events` | TodoWrite/TaskCreate events with status transitions |\n| **Idle transitions** | `session_actor_transitions` | Actor state changes (user/agent/model) with timestamps |\n\n### What's Missing\n\n1. **Session-level file ledger** \u2014 No aggregation of \"all files this session touched\"\n2. **Git-level file content** \u2014 We have Edit tool string diffs, but not `git show` output or file-at-commit snapshots\n3. **Snapshot storage** \u2014 No mechanism to persist file state at boundaries\n4. **Artifacts view** \u2014 No UI tab for browsing files\n\n### Boundary Detection (Already Built)\n\nAll three boundary types emit events that the daemon already processes:\n\n| Boundary | Source | Event |\n|---|---|---|\n| **Commit** | `_commit_extractor.py` in normalizer | `commits` table insert |\n| **Task completion** | TodoWrite/TaskCreate processing | `task_events` with `event_type='task_finished'` |\n| **Idle transition** | `IdleClassifierIntegration` | `session_actor_transitions` insert |\n\nNo new detection logic is needed. Snapshot creation hooks into existing events.\n\n---\n\n## 4. Architecture Options Explored\n\n### Option A: SQLite Blob Store\n\nStore file content as compressed BLOBs in rae's SQLite database, with content-addressable deduplication via SHA-256 hashing.\n\n```sql\nCREATE TABLE file_blobs (\n    content_hash TEXT PRIMARY KEY,\n    content BLOB NOT NULL,          -- zlib-compressed\n    size_bytes INTEGER NOT NULL,\n    is_binary INTEGER NOT NULL DEFAULT 0\n);\n\nCREATE TABLE file_snapshots (\n    id INTEGER PRIMARY KEY,\n    boundary_type TEXT NOT NULL,\n    boundary_ref TEXT NOT NULL,\n    session_id INTEGER NOT NULL,\n    file_path TEXT NOT NULL,\n    content_hash TEXT NOT NULL REFERENCES file_blobs(content_hash),\n    captured_at_unix_nano INTEGER NOT NULL\n);\n```\n\n**Pros:**\n- Self-contained in existing rae.db\n- Works with existing archive/export system\n- Simple implementation\n\n**Cons:**\n- **Reinvents git's content-addressable storage**\n- Creates a separate copy of customer code (security concern in SaaS mode)\n- No delta compression across snapshots (git's packfile format handles this natively)\n- Database bloat (~700KB-2MB per session, multiplied across all sessions)\n\n**Verdict:** Rejected. Storing code blobs is both redundant (git already does this) and a liability (compliance exposure).\n\n### Option B: In-Repo Git Refs (`refs/rae/*`)\n\nStore snapshots as git commits in the user's own repository under a custom ref namespace.\n\n```\nuser-repo/.git/\n  refs/rae/\n    sessions/\n      /\n        latest          \u2192 snapshot commit\n```\n\nUsing `git hash-object -w` + `git mktree` + `git commit-tree` + `git update-ref`.\n\n**Pros:**\n- Free deduplication with tracked files (same object store)\n- Native `git diff` between user commits and snapshots\n- No additional infrastructure\n- Handles untracked/gitignored files via `hash-object`\n\n**Cons:**\n- **Visible in `git log --all`** \u2014 Git GUIs (GitKraken, SourceTree, VS Code Git Graph) show orphan commits by default\n- **`git push --mirror`** would push `refs/rae/*` to remote\n- Writes objects into user's `.git` (opinionated, may violate org policies)\n- Doesn't handle files outside any git repo (needs a separate mechanism anyway)\n\n**Empirically verified:** All 11 experiments passed. See [Section 11](#11-empirical-verification-in-repo-approach).\n\n**Verdict:** Viable and well-tested, but the opacity gap is real. Since a shadow repo is needed anyway for external files, it's cleaner to route everything through it.\n\n### Option C: Shadow Bare Repo (`~/.rae/artifacts.git`)\n\nA dedicated bare git repository that stores all snapshots, using alternates to deduplicate with user repos.\n\n```\n~/.rae/artifacts.git/              # bare repo\n  objects/\n    info/alternates                # points to user repos\n  refs/rae/\n    /\n      000, 001, ..., latest\n```\n\n**Pros:**\n- **100% opacity** \u2014 Nothing in user's `.git`, nothing in `git log --all`, nothing in git GUIs\n- **Automatic deduplication** \u2014 `hash-object -w` respects alternates (empirically verified)\n- **Self-contained exports** \u2014 `git repack -a` internalizes alternate objects\n- **Handles all file types** \u2014 Repo files, external files, temp files all stored naturally\n- **Single storage location** \u2014 One place to query, gc, archive\n\n**Cons:**\n- Alternates management (paths can go stale if repos move/delete)\n- Cross-repo `git diff` requires alternates to be active\n- One additional step: copy-on-snapshot to protect against user repo GC\n\n**Empirically verified:** All tests passed. See [Section 12](#12-empirical-verification-shadow-repo-approach).\n\n**Verdict: Recommended.** The dedup-via-alternates discovery eliminated the main advantage of in-repo refs. Shadow repo gives full opacity with equivalent performance.\n\n### Option D: Hybrid Per-Repo + Shadow (Explored, Simplified to C)\n\nOriginally proposed: per-repo refs for in-repo files, shadow repo only for external files. During analysis, we realized that since alternates provide free dedup, there's no benefit to splitting storage. Shadow-for-everything is simpler and gives better opacity.\n\n---\n\n## 5. Security and Compliance Analysis\n\n### The Core Concern\n\nLightfield ships in two modes:\n1. **Local mode** \u2014 SQLite DB on user's machine\n2. **SaaS mode** \u2014 Data on rae's servers\n\nStoring snapshots of customer source code on our servers is a major security and compliance liability.\n\n### Compliance Framework Impact\n\n| Framework | If We Store Code | If We Store Only Refs |\n|---|---|---|\n| **SOC 2** | Must demonstrate AES-256 encryption, RBAC, audit logging for code content. Expands audit scope significantly. | Minimal impact. Hashes and metadata are not sensitive data. |\n| **GDPR** | Article 17 Right to Erasure applies to any stored code. Must delete within ~1 month, from all systems including backups. | Does not apply to anonymous technical metadata (hashes, paths). |\n| **HIPAA** | If code contains PHI (test fixtures, config referencing patient DBs), full BAA and encryption requirements apply. | No PHI in hashes. |\n| **Enterprise DLP** | Source code classified as confidential IP. Storage triggers DLP alerts and procurement friction. | Hashes don't trigger DLP. Clean story for enterprise sales. |\n\n### Industry Pattern: Reference, Don't Store\n\n| Tool | Stores Code? | Pattern |\n|---|---|---|\n| Cursor agent-trace | Content hashes only | Reference-only by design |\n| Datadog APM | No \u2014 links to repos | Source code integration |\n| Tabnine | Zero cloud retention | Process transiently |\n| GitHub Copilot | No persistent storage | Ephemeral context windows |\n| Sentry | Yes (source maps) | Encrypted, with clear deletion paths |\n\nThe industry consensus is clear: store references, not content. The exceptions (Sentry) have explicit encryption and retention policies.\n\n### Git as the Security Boundary\n\nBy using git as the storage backend:\n\n1. **Code never leaves user infrastructure** \u2014 Objects live in `.git` directories on the user's machine\n2. **Access control is delegated** \u2014 Existing git permissions apply\n3. **Cryptographic integrity** \u2014 SHA-256 content addressing, tamper-evident\n4. **Deletion is user-controlled** \u2014 `git gc` or repo deletion removes code; rae only has dangling refs\n5. **SaaS sync is metadata-only** \u2014 Commit SHAs, blob SHAs, file paths, timestamps. No content.\n\n### What Lives Where\n\n| Data Type | Local Mode | SaaS Mode | Rationale |\n|---|---|---|---|\n| Commit/blob SHAs | Local DB | Sync to SaaS | Pure identifiers |\n| File paths | Local DB | Sync to SaaS | Structure, not content |\n| Line counts, sizes, language | Local DB | Sync to SaaS | Aggregate metadata |\n| Timestamps | Local DB | Sync to SaaS | Standard telemetry |\n| **File content** | Local git | **NEVER** | Core security boundary |\n| **Diffs** | Local cache | **NEVER** | Contains actual code |\n| **API keys in code** | **NEVER** | **NEVER** | Must redact before any storage |\n\n---\n\n## 6. Recommended Architecture\n\n### Storage Layout\n\n```\n~/.rae/\n\u251c\u2500\u2500 artifacts.git/                                # Bare repo, all snapshots\n\u2502   \u251c\u2500\u2500 objects/\n\u2502   \u2502   \u251c\u2500\u2500 info/alternates                       # Paths to user repos\n\u2502   \u2502   \u2514\u2500\u2500 pack/                                 # Internalized + delta-compressed objects\n\u2502   \u251c\u2500\u2500 refs/rae/\n\u2502   \u2502   \u251c\u2500\u2500 /\n\u2502   \u2502   \u2502   \u251c\u2500\u2500 000                               # First snapshot commit\n\u2502   \u2502   \u2502   \u251c\u2500\u2500 001                               # Second snapshot\n\u2502   \u2502   \u2502   \u2514\u2500\u2500 latest                            # \u2192 most recent\n\u2502   \u2502   \u2514\u2500\u2500 /\n\u2502   \u2502       \u2514\u2500\u2500 ...\n\u2502   \u2514\u2500\u2500 config                                    # gc.auto=0, core.bare=true\n\u2502\n\u2514\u2500\u2500 artifacts.db                                  # SQLite index (metadata only)\n```\n\n### Snapshot Commit Structure\n\nEach snapshot is a git commit with a tree of file blobs and a JSON commit message:\n\n```\ncommit \ntree \nparent     # Chains snapshots for session history\nauthor rae  \ncommitter rae  \n\n{\"boundary\":\"commit\",\"session_id\":\"abc123\",\"commit_sha\":\"a3b3a44e\",\"files\":15}\n```\n\nThe tree contains all files touched since the last snapshot:\n\n```\n100644 blob     src/main.py\n100644 blob     src/utils.py\n100644 blob     external/_home/.claude/plans/design.md\n```\n\nFiles outside any git repo are stored under an `external/` prefix with normalized paths.\n\n### Snapshot Workflow\n\n```python\nasync def create_snapshot(\n    session_id: str,\n    files: list[Path],\n    boundary_type: str,\n    boundary_ref: str,\n    repo_path: Path | None,\n) -&gt; str:\n    shadow = Path.home() / \".rae/artifacts.git\"\n    env = {\"GIT_DIR\": str(shadow)}\n\n    # 1. Ensure shadow repo exists and alternate is registered\n    init_shadow_repo(shadow)\n    if repo_path:\n        ensure_alternate(shadow, resolve_objects_dir(repo_path))\n\n    # 2. Batch hash files (dedup via alternates is automatic)\n    blob_shas = await batch_hash_objects(shadow, files)\n\n    # 3. Build tree\n    tree_sha = await create_tree(shadow, files, blob_shas)\n\n    # 4. Create commit with parent chain\n    parent = await get_latest_ref(shadow, f\"refs/rae/{session_id}/latest\")\n    metadata = {\"boundary\": boundary_type, \"ref\": boundary_ref, ...}\n    commit_sha = await create_commit(shadow, tree_sha, parent, json.dumps(metadata))\n\n    # 5. Copy objects into shadow repo (durability \u2014 survives user's gc)\n    await copy_reachable_objects(shadow, commit_sha)\n\n    # 6. Update refs\n    seq = await get_next_seq(shadow, session_id)\n    await update_ref(shadow, f\"refs/rae/{session_id}/{seq:03d}\", commit_sha)\n    await update_ref(shadow, f\"refs/rae/{session_id}/latest\", commit_sha)\n\n    # 7. Update index\n    await update_index(session_id, boundary_type, boundary_ref, commit_sha, files)\n\n    return commit_sha\n```\n\n### Index Schema (SaaS-Safe Metadata)\n\n```sql\n-- Session-level artifact tracking\nCREATE TABLE artifact_sessions (\n    session_id TEXT PRIMARY KEY,\n    repo_id TEXT,                    -- Stable repo identity (root commit hash[:12])\n    repo_path TEXT,                  -- Last known path (informational)\n    snapshot_count INTEGER DEFAULT 0,\n    first_snapshot_at INTEGER,       -- unix_nano\n    latest_snapshot_at INTEGER,      -- unix_nano\n    latest_ref TEXT                  -- refs/rae//latest\n);\n\n-- Per-file references (no content, only pointers)\nCREATE TABLE artifact_file_refs (\n    id INTEGER PRIMARY KEY,\n    session_id TEXT NOT NULL REFERENCES artifact_sessions(session_id),\n    snapshot_seq INTEGER NOT NULL,   -- 000, 001, etc.\n    boundary_type TEXT NOT NULL,     -- 'commit' | 'task' | 'idle'\n    boundary_ref TEXT NOT NULL,\n    file_path TEXT NOT NULL,\n    blob_sha TEXT NOT NULL,          -- Git blob hash\n    size_bytes INTEGER,\n    language TEXT,\n    operation TEXT,                  -- 'created' | 'modified' | 'deleted' | 'read'\n    captured_at_unix_nano INTEGER NOT NULL,\n    UNIQUE(session_id, snapshot_seq, file_path)\n);\n\nCREATE INDEX idx_artifact_files_session ON artifact_file_refs(session_id);\nCREATE INDEX idx_artifact_files_path ON artifact_file_refs(file_path);\nCREATE INDEX idx_artifact_files_blob ON artifact_file_refs(blob_sha);\n```\n\n### Content Retrieval\n\n```python\nasync def get_file_content(session_id: str, file_path: str, snapshot_seq: int) -&gt; dict:\n    shadow = Path.home() / \".rae/artifacts.git\"\n    ref = f\"refs/rae/{session_id}/{snapshot_seq:03d}\"\n\n    # Try shadow repo (covers both internalized objects and alternate-accessible objects)\n    try:\n        content = await git_show(shadow, f\"{ref}:{file_path}\")\n        return {\"content\": content, \"source\": \"shadow_repo\"}\n    except GitError:\n        pass\n\n    # Object not available (repo deleted, gc'd, alternate removed)\n    return {\"content\": None, \"source\": \"unavailable\"}\n```\n\n### Lifecycle Operations\n\n| Operation | Command | When |\n|---|---|---|\n| **Init** | `git init --bare ~/.rae/artifacts.git` | Daemon startup (idempotent) |\n| **Add alternate** | Append to `objects/info/alternates` | First snapshot for a new repo |\n| **Validate alternates** | Check path existence, remove stale | Periodic (daily) |\n| **GC** | `GIT_DIR=~/.rae/artifacts.git git gc` | Periodic (weekly) |\n| **Archive session** | `git repack -a -d` then `git bundle create` | On-demand export |\n| **Delete session** | `git update-ref -d` per ref, then gc | Session retention policy |\n\n---\n\n## 7. Git Library Selection\n\n### Comparison\n\n| Library | Async? | Dependencies | Reliability | Recommendation |\n|---|---|---|---|---|\n| **subprocess + git CLI** | Native (`asyncio.create_subprocess_exec`) | git binary (always available) | Reference implementation | **Recommended** |\n| **pygit2** (libgit2) | Sync only (`run_in_executor`) | Native library, version-pinned | Battle-tested | Viable but heavyweight |\n| **GitPython** | Sync only | git binary | **CVEs:** path traversal (CVE-2026-44243), command injection (CVE-2026-42215) | **Avoid** |\n| **dulwich** | Sync only | Pure Python | Slower, some edge case gaps | Viable for constrained envs |\n\n### Rationale for subprocess\n\n1. **Native async** \u2014 `asyncio.create_subprocess_exec()` is first-class; no thread pool overhead\n2. **Zero dependencies** \u2014 git is already installed (Claude Code requires it)\n3. **Worktree support** \u2014 Just set `cwd`; git resolves everything\n4. **Batch performance** \u2014 `git hash-object -w --stdin-paths` hashes 50 files in 28ms\n5. **Safety** \u2014 git's internal path handling is safe within repos; we add validation on top\n\n### Safety Wrapper\n\n```python\nasync def safe_git_show(shadow_git: Path, ref: str, file_path: str) -&gt; bytes:\n    \"\"\"Retrieve file content with path validation.\"\"\"\n    normalized = Path(file_path).as_posix()\n    if normalized.startswith('/') or '..' in Path(normalized).parts:\n        raise ValueError(f\"Invalid path: {file_path}\")\n\n    proc = await asyncio.create_subprocess_exec(\n        'git', 'show', f'{ref}:{normalized}',\n        stdout=asyncio.subprocess.PIPE,\n        stderr=asyncio.subprocess.PIPE,\n        env={\"GIT_DIR\": str(shadow_git)},\n    )\n    stdout, stderr = await proc.communicate()\n\n    if proc.returncode != 0:\n        raise GitError(stderr.decode())\n    return stdout\n```\n\n---\n\n## 8. Multi-Repo and External File Handling\n\n### The Problem\n\nA single agent session can touch files across multiple storage domains:\n\n```\nSession touches:\n  \u251c\u2500\u2500 packages/rae/src/rae/core/models.py          \u2190 inside primary repo\n  \u251c\u2500\u2500 apps/lightfield-local/src/App.tsx             \u2190 same repo, different area\n  \u251c\u2500\u2500 ~/.claude/plans/2026-05-12/design.md          \u2190 outside ALL repos\n  \u251c\u2500\u2500 ~/.rae/enrichment-registry.json               \u2190 outside ALL repos\n  \u251c\u2500\u2500 /tmp/scratch-analysis.py                      \u2190 ephemeral, outside repos\n  \u2514\u2500\u2500 ../sibling-repo/shared/types.ts               \u2190 different repo entirely\n```\n\n### Solution: Single Shadow Repo + Alternates\n\nAll files \u2014 regardless of origin \u2014 are stored in `~/.rae/artifacts.git`. User repos are registered as alternates for deduplication. External files are stored directly.\n\n```\n~/.rae/artifacts.git/objects/info/alternates:\n  /Users/tripp/Code/rae-monorepo/.git/objects\n  /Users/tripp/Code/sibling-repo/.git/objects\n```\n\n### Path Normalization for External Files\n\n| Actual Path | Normalized Path in Tree |\n|---|---|\n| `~/.claude/plans/foo.md` | `external/_home/.claude/plans/foo.md` |\n| `~/.rae/config.json` | `external/_home/.rae/config.json` |\n| `/tmp/scratch.py` | `external/_tmp/scratch.py` |\n| `../sibling-repo/types.ts` | `repos/sibling-repo/types.ts` |\n\nThe `external/` prefix and `_` root markers make the origin explicit and the mapping reversible.\n\n### Multi-Repo Session Tracking\n\nWhen a session touches multiple repos, the index records all of them:\n\n```sql\nINSERT INTO artifact_sessions (session_id, repo_id, repo_path, ...)\nVALUES ('abc123', 'cb9738e0dd21', '/Users/tripp/Code/rae-monorepo', ...);\n\n-- Additional repos tracked via a join table if needed,\n-- or encoded in commit message metadata\n```\n\nThe snapshot tree for a multi-repo session contains files from all repos, organized by path. The shadow repo's alternates provide read access to all of them.\n\n### Alternates Management\n\n| Event | Action |\n|---|---|\n| New session starts | Add repo's objects dir as alternate (if not already present) |\n| Repo path changes | Detect via `git cat-file -e` failure; update alternate path |\n| Repo deleted | Log warning; internalized objects still available; new reads fail gracefully |\n| Periodic maintenance | Validate all alternate paths; remove stale entries; `repack` if needed |\n\n---\n\n## 9. Worktrees and Stacking Tools\n\n### Git Worktrees: No Additional Complexity\n\nAll worktrees share a single object store at `/.git/objects`. Verified against the rae-monorepo itself (61+ worktrees, all sharing one objects dir).\n\n| Concern | Status | Detail |\n|---|---|---|\n| Object store location | **Shared** | `git rev-parse --git-common-dir` returns main repo's `.git` from any worktree |\n| Multiple worktree sessions | **Safe** | Concurrent snapshot writes are atomic (file-level locking) |\n| Worktree removal | **Safe** | Alternate points to main repo's objects, not worktree directory |\n| Worktree-local refs | **No conflict** | `refs/worktree/` is per-worktree; our `refs/rae/` is in shadow repo |\n\n**Path resolution:** From any worktree or main repo:\n```bash\nobjects_dir=$(git -C  rev-parse --git-common-dir)/objects\n```\n\n### Graphite: No Impact\n\n- Uses **standard git branches**, not custom refs\n- Stack metadata in `.git/.graphite_metadata.db` (SQLite inside `.git`)\n- Heavy rebasing (`gt restack`) rewrites user commits, but our snapshots use our own commits in shadow.git \u2014 immune to user-side rebases\n- Fully compatible with worktrees (verified empirically)\n\n### GitHub Stacked PRs: No Impact\n\n- Private preview (April 2026), uses standard git branches\n- Stack metadata in `.git/gh-stack` (JSON, not committed)\n- No custom refs conflicting with `refs/rae/`\n\n### Worktree Snapshot Timing\n\nThe critical concern: worktrees are cleaned up after agent sessions end. The daemon must snapshot before cleanup.\n\n**Defense in depth (four layers):**\n\n| Layer | What | When | Coverage |\n|---|---|---|---|\n| 1. Edit traces | `content_blocks.diff_old/diff_new` | Every Edit tool call | All edited files (partial content) |\n| 2. Commit snapshots | `hash-object` + `commit-tree` at commit boundaries | Each commit (worktree definitely alive) | All committed files |\n| 3. Idle transition snapshot | Hook into `IdleClassifierIntegration.on_transition` | Session goes idle | Uncommitted changes |\n| 4. Parent repo fallback | Objects from worktree persist in shared `.git/objects` | After worktree removal, before gc | Committed objects |\n\n**Key finding:** Claude Code uses `git worktree remove` (not `rm -rf`), which refuses to delete dirty worktrees. Objects are written to the shared store. The race window is narrower than initially feared.\n\n**Design decision:** Snapshot on every commit (Layer 2) is the primary mechanism. The idle-transition snapshot (Layer 3) is a bonus for uncommitted state.\n\n---\n\n## 10. Stable Repository Identity\n\n### The Problem\n\nThe ref schema `refs/rae//latest` needs a way to associate sessions with repos. The repo identity must be stable across: disk moves, clones, worktrees, remote URL changes.\n\n### Recommendation: Root Commit Hash\n\n```python\ndef get_repo_id(repo_path: Path) -&gt; str:\n    \"\"\"Stable 12-char repo identifier from root commit.\"\"\"\n    result = subprocess.run(\n        [\"git\", \"-C\", str(repo_path), \"rev-list\", \"--max-parents=0\", \"HEAD\"],\n        capture_output=True, text=True,\n    )\n    roots = sorted(result.stdout.strip().split(\"\\n\"))\n    root = roots[0]  # Lexicographic sort for multi-root repos\n    return hashlib.sha256(root.encode()).hexdigest()[:12]\n```\n\n| Property | Root Commit Hash | Remote URL | Path | Generated UUID |\n|---|---|---|---|---|\n| Survives disk move | Yes | Yes | **No** | Yes |\n| Survives clone | Yes | Yes | **No** | **No** |\n| Same across worktrees | Yes | Yes | **No** | **No** |\n| Works offline | Yes | **No** (no remote) | Yes | Yes |\n| Works without commits | **No** | Depends | Yes | Yes |\n\n**Fallback chain:**\n1. Root commit SHA \u2192 sha256[:12] (99%+ of repos)\n2. Normalized remote URL \u2192 sha256[:12] (empty repo with remote)\n3. Generated UUID in `git config rae.repoid` (no commits, no remote)\n\n**Collision resistance:** 12 hex chars = 48 bits. P(collision) at 10K repos = 0.000018%.\n\n---\n\n## 11. Empirical Verification: In-Repo Approach\n\n**Test environment:** `/tmp/rae-git-snapshot-test-1778616662`\n\n### Experiment 1: Basic Snapshot Creation \u2014 PASS\n\nCreated a git repo with tracked files, `.gitignore`, gitignored files, and an external file. Used `git hash-object -w` \u2192 `git mktree` \u2192 `git commit-tree` \u2192 `git update-ref refs/rae/sessions/test-session-1/latest`.\n\n**Results:**\n- All files (tracked, untracked, gitignored, external) successfully hashed as blobs\n- Tree created with full hierarchy\n- Commit created with JSON metadata in message\n- `git show refs/rae/sessions/test-session-1/latest` \u2014 works\n- `git log` \u2014 does NOT show snapshot\n- `git branch -a` \u2014 no rae branches\n- `git status` \u2014 unchanged\n\n### Experiment 2: Opaqueness to User \u2014 PARTIAL\n\n| Command | Shows Rae Commits? |\n|---|---|\n| `git log --oneline` | No |\n| `git log --all --oneline` | **Yes** |\n| `git branch -a` | No |\n| `git tag` | No |\n| `git stash list` | No |\n| `git status` | No |\n| `git diff` | No |\n| `git for-each-ref` | Yes (shows `refs/rae/*`) |\n| `git for-each-ref refs/heads/ refs/tags/` | No |\n\n**Caveat:** `git log --all` includes `refs/rae/*` commits. Mitigated by `--exclude='refs/rae/*'`, but git GUIs use `--all` by default. This was a key factor in choosing the shadow repo approach.\n\n### Experiment 3: Normal Dev Flow Non-Interference \u2014 PASS\n\nTested all standard git operations. Snapshot ref and objects survived every one:\n\n- Modify/stage/commit: Unaffected\n- Branch create/switch: Persists\n- Rebase: Survives\n- `git gc`: Survives\n- `git gc --prune=now`: Survives\n- `git gc --aggressive`: Survives\n- `git commit --amend`: Unaffected\n- `git reset --hard HEAD~1`: Unaffected\n- Cherry-pick: No interference\n\n### Experiment 4: Untracked and Gitignored Files \u2014 PASS\n\n- `git hash-object -w` stores gitignored files without tracking them\n- `git status` unchanged (files still show as ignored/untracked)\n- `git ls-files` does not list them\n- After deleting gitignored file from disk, `git cat-file -p ` still retrieves content\n\n### Experiment 5: External Files (Outside Repo) \u2014 PASS\n\n- Hashed `/tmp/rae-external-file.txt` from within the repo\n- Blob stored in `.git/objects`\n- Included in snapshot tree under `external/` prefix\n- Deleted original from `/tmp`\n- `git show refs/rae/.../latest:external/rae-external-file.txt` \u2014 still works\n\n### Experiment 6: Snapshot Chaining \u2014 PASS\n\nCreated 3 chained snapshots (each with `parent` pointing to previous):\n\n- `git log refs/rae/sessions/test-session-1/latest` shows full history\n- `git diff snapshot1..snapshot3 --stat` shows cumulative changes\n- `git diff-tree --no-commit-id --name-only -r ` lists changed files\n\n### Experiment 7: Worktree Behavior \u2014 PASS\n\n- Created worktree, made snapshot from it\n- Ref visible from main repo\n- Objects in main repo's `.git/objects` (shared store)\n- Removed worktree \u2014 ref and all objects persist\n\n### Experiment 8: Concurrent Operations \u2014 PASS\n\nTwo parallel snapshot creations for different sessions. Both completed, `git fsck` clean.\n\n### Experiment 9: Clone Behavior \u2014 PASS\n\n| Clone Type | Includes `refs/rae/*`? |\n|---|---|\n| `git clone` | No (desired) |\n| `git clone --mirror` | Yes |\n| `git fetch origin refs/rae/*:refs/rae/*` | Yes (explicit transfer) |\n\n### Experiment 10: Cleanup \u2014 PASS\n\n- `git update-ref -d refs/rae/sessions/concurrent-1/latest`\n- `git gc --prune=now`\n- Objects properly reclaimed\n- Other refs unaffected\n\n### Experiment 11: Size Impact \u2014 PASS\n\n| State | .git Size |\n|---|---|\n| Baseline | 144KB |\n| After 50 snapshots x 20 files (loose) | 4.6MB |\n| After `git gc` (packed) | 296KB |\n\n**~8KB per snapshot after packing.** Delta compression across similar tree structures is extremely effective.\n\n---\n\n## 12. Empirical Verification: Shadow Repo Approach\n\n**Test environment:** `/tmp/rae-shadow-repo-test-1778618092`\n\n### Test 1-2: Alternates Read Access \u2014 PASS\n\nShadow bare repo successfully reads all objects from user repo via alternates:\n- Commits: `git cat-file -p ` \u2014 works\n- Blobs: `git cat-file -p ` \u2014 works\n- Trees: `git cat-file -p ` \u2014 works\n\n### Test 3: Deduplication on Write \u2014 PASS (Surprising)\n\n**Key finding:** `git hash-object -w` respects alternates for deduplication.\n\nWhen content already exists via alternate:\n- Returns same SHA\n- Does NOT create duplicate object in shadow.git\n- Object exists only in user repo's objects dir\n\nWhen content is new (not in any alternate):\n- Creates object in shadow.git\n- Returns new SHA\n\n**This was the finding that made shadow-repo-for-everything viable without dedup loss.**\n\n### Test 4: Snapshot Commits Referencing Alternate Objects \u2014 PASS\n\nCreated tree in shadow.git using blob SHAs from user repo. Created commit. `git show :` works via alternates.\n\n### Test 5: Cross-Repo Diff \u2014 PASS\n\n`git diff-tree -p  ` works when alternates are configured. Git resolves both trees transparently.\n\n### Test 6: Alternate Removal and Restoration \u2014 PASS\n\n- Remove alternate \u2192 user objects inaccessible (expected)\n- Shadow-only objects still work\n- Restore alternate \u2192 access restored immediately\n\n### Test 7: `git repack -a` Internalization \u2014 PASS (Critical for Archival)\n\nAfter `git repack -a -d`:\n- Objects from alternates are copied into shadow.git's packfiles\n- Removing alternate afterward \u2014 objects STILL accessible\n- Shadow repo becomes self-contained\n\n**This is the archival mechanism.** `repack` + `git bundle create` produces a fully portable export.\n\n### Test 8: Multiple Alternates \u2014 PASS\n\nTwo user repos as alternates. Created snapshot tree referencing blobs from both. Cross-repo diff works.\n\n### Test 9: Full Workflow with GIT_DIR \u2014 PASS\n\nComplete snapshot workflow using only `GIT_DIR=shadow.git` environment variable. User's `.git` never touched.\n\n### Test 10: Batch Performance \u2014 PASS\n\n| Method | Time (50 files) | Speedup |\n|---|---|---|\n| Individual `hash-object` calls | 485ms | baseline |\n| Batch `--stdin-paths` | 28ms | **17x faster** |\n\nAlternate resolution adds no measurable overhead.\n\n### Test 11: Ref Namespacing \u2014 PASS\n\nHierarchical refs (`refs/rae//`) work. `git for-each-ref` supports path-based filtering and glob patterns.\n\n### Test 12: Worktree Objects via Alternates \u2014 PASS\n\nObjects created in worktrees are accessible via alternate to main repo (shared object store).\n\n### Test 13: GC with Alternates \u2014 PASS\n\n`git gc` works correctly. Warning about bitmap writing is benign. Shadow-only objects packed normally. Alternate objects remain accessible.\n\n### Test 14: Concurrent Writes \u2014 PASS\n\n5 parallel writers creating 100 refs total. Zero corruption. `git fsck --full` clean.\n\n### Test 15: Size \u2014 PASS\n\n100 snapshots across 3 repos, 20 files each: **60KB packed**. Comparable to in-repo (56KB).\n\n---\n\n## 13. Durability Analysis\n\n### Durability Matrix\n\n| Scenario | Refs Survive? | Objects Survive? | Risk Level |\n|---|---|---|---|\n| `git rebase` / `rebase -i` (user's repo) | N/A (refs in shadow) | Yes (internalized) | Safe |\n| `git push --force` (user's repo) | N/A | Yes | Safe |\n| `git gc` / `gc --aggressive` (user's repo) | N/A | Yes (copy-on-snapshot) | Safe |\n| `git gc` (shadow repo) | Yes | Yes (reachable from refs) | Safe |\n| `git fetch --prune` | N/A | Yes | Safe |\n| `git worktree remove` | Yes | Yes (shared object store) | Safe |\n| `rm -rf ` | Yes | Yes | Safe |\n| Concurrent sessions | Yes (atomic updates) | Yes | Safe |\n| Shallow clone | N/A | Yes | Safe |\n| `git filter-branch --all` (user's repo) | N/A | Yes (copy-on-snapshot) | Safe |\n| User repo deleted | Yes (in shadow) | **Depends** on copy-on-snapshot | Low (mitigated) |\n| Shadow repo deleted | **No** | **No** | High (user data loss) |\n| Shadow repo GC prunes unreferenced objects | Refs protect | Yes | Safe |\n\n### The Copy-on-Snapshot Requirement\n\nWithout copy-on-snapshot, objects accessed only via alternates can be pruned by the user repo's gc. This was empirically confirmed: aggressive GC in user repo made shadow.git unable to access alternate-dependent objects.\n\n**Mitigation:** After creating each snapshot commit, copy its reachable objects into shadow.git's own storage. This makes the snapshot self-contained. Alternates then serve only as a live-read optimization, not a durability mechanism.\n\n### Backup Considerations\n\n`~/.rae/artifacts.git` should be included in the user's backup strategy. It's the single point of failure for all artifact data. A `git bundle create` of the entire shadow repo provides a complete portable backup.\n\n---\n\n## 14. Implementation Phasing\n\n### Phase 1: Core Snapshot Infrastructure\n\n- Shadow repo init (`~/.rae/artifacts.git`)\n- `GitClient` wrapper (subprocess-based, async)\n- `SnapshotService` with async queue\n- Commit-boundary snapshots (hook into existing `commit_extractor`)\n- SQLite index (`~/.rae/artifacts.db`)\n- Basic API: list snapshots, get file content\n\n### Phase 2: Full Boundary Support + External Files\n\n- Task-boundary snapshots (hook into task event extraction)\n- Idle-boundary snapshots (hook into `IdleClassifierIntegration.on_transition`)\n- External file support (path normalization, direct storage in shadow repo)\n- Alternates management (add, validate, remove stale)\n\n### Phase 3: API + Frontend\n\n- Diff computation API (between any two snapshots)\n- Capability discovery endpoint (is git available for this session?)\n- Artifacts tab in Lightfield (file tree + timeline + diff viewer)\n- Span-to-file linking (bidirectional navigation between trace and artifacts)\n\n### Phase 4: Multi-Repo + Lifecycle\n\n- Multi-repo session tracking\n- Merged view reconstruction\n- `rae artifacts gc` command\n- `rae artifacts export` (session \u2192 git bundle)\n- Retention policies tied to session lifecycle\n- Agent-trace format export (Cursor compatibility)\n\n---\n\n## 15. Open Questions\n\n1. **Snapshot granularity at non-commit boundaries:** For task and idle boundaries, which files to snapshot? All files touched since last snapshot? Or only files with unsaved changes?\n\n2. **Large binary files:** Should images, PDFs, compiled artifacts be included in snapshots? Recommendation: exclude by default, opt-in via config, with a size cap.\n\n3. **Sensitive file filtering:** Should we honor `.gitignore` by default for what to snapshot? Or snapshot everything the agent touches (since gitignored files like plans are often the most interesting artifacts)?\n\n4. **Agent-trace emission:** Should we emit Cursor-compatible agent-trace records as a byproduct? If so, at what boundary?\n\n5. **Retention lifecycle:** Should snapshot retention mirror session retention? Or should snapshots have their own TTL?\n\n6. **Shadow repo backup:** Should the daemon warn users if `~/.rae/artifacts.git` is not backed up? Or is this out of scope?\n\n---\n\n## Appendix A: Key File Paths in Codebase\n\n### Backend (Python) \u2014 Relevant to Implementation\n\n| File | Relevance |\n|---|---|\n| `packages/rae/src/rae/db/models/core.py` | ContentBlockModel with `file_path`, `diff_old/new` |\n| `packages/rae/src/rae/db/models/commits.py` | CommitModel, CommitSpanModel |\n| `packages/rae/src/rae/db/models/tasks.py` | TaskModel, TaskSpanModel, task events |\n| `packages/rae/src/rae/db/models/idle.py` | Session actor transitions |\n| `packages/rae/src/rae/integrations/claude_code/_commit_extractor.py` | Git commit parsing from Bash output |\n| `packages/rae/src/rae/integrations/claude_code/_work_context.py` | VCS metadata extraction |\n| `packages/rae/src/rae/lightfield/enricher/integration.py` | EnricherIntegration pattern |\n| `packages/rae/src/rae/lightfield/idle/integration.py` | IdleClassifierIntegration with `on_transition` |\n| `packages/rae/src/rae/lightfield/server/routes.py` | Litestar API endpoints |\n| `packages/rae/src/rae/core/archive/` | Archive layer system (for export) |\n\n### Frontend (TypeScript) \u2014 Relevant to Artifacts Tab\n\n| File | Relevance |\n|---|---|\n| `apps/lightfield-local/app/types.ts` | TypeScript interfaces |\n| `apps/lightfield-local/app/routes/sessions/$sessionId/trace.tsx` | Existing trace view (model for Artifacts tab) |\n| `apps/lightfield-local/app/components/trace/renderers/diff-display.tsx` | Existing diff rendering |\n| `apps/lightfield-local/app/components/content-blocks/DiffViewer.tsx` | Existing diff component |\n\n## Appendix B: Research Sources\n\n### Specifications\n- [Cursor agent-trace spec (v0.1.0)](https://github.com/cursor/agent-trace)\n- [Agent-trace website](https://agent-trace.dev/)\n\n### Tools and Libraries\n- [isomorphic-git](https://isomorphic-git.org/)\n- [wasm-git](https://github.com/petersalomonsen/wasm-git)\n- [Monaco Editor IDiffEditorOptions](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor_editor_api.editor.IDiffEditorOptions.html)\n\n### Security and Compliance\n- [SOC 2 Compliance - Sprinto](https://sprinto.com/blog/soc-2-requirements/)\n- [GDPR Right to Erasure - Article 17](https://gdpr-info.eu/art-17-gdpr/)\n- [Tabnine zero-knowledge architecture](https://www.tabnine.com/)\n- [Datadog Sensitive Data Scanner](https://docs.datadoghq.com/security/sensitive_data_scanner/)\n\n### Agent Observability\n- [Augment Code observability guide](https://www.augmentcode.com/guides/agent-observability-for-ai-coding)\n- [AgentPrism (Evil Martians)](https://evilmartians.com/chronicles/debug-ai-fast-agent-prism-open-source-library-visualize-agent-traces)\n- [Replay MCP](https://www.replay.io/)\n\n### Git Internals\n- [Git Internals - Git Objects](https://git-scm.com/book/en/v2/Git-Internals-Git-Objects)\n- [Git Hash Function Transition](https://git-scm.com/docs/hash-function-transition)\n- [VS Code Timeline API PR #89262](https://github.com/microsoft/vscode/pull/89262)\n", "creation_timestamp": "2026-05-12T21:03:25.000000Z"}]}