Architecture
This page describes AGIT's internal architecture and design decisions.
Overview
AGIT creates a "Neural Graph" that runs parallel to Git's commit graph:
Git Graph Neural Graph
───────── ────────────
commit e8d4f1a ←───→ neural a3f7b2c
│ │
commit c2f1a9b ←───→ neural b5d8e3a
│ │
commit ... ←───→ neural ...
Components
Storage Layer (V2 Git-Native)
AGIT uses a hybrid storage approach that leverages Git infrastructure:
Git-managed (shared via push/pull):
.git/
├── refs/agit/ # Custom ref namespace for neural commits
│ └── heads/ # Neural branch pointers
│ ├── main # Points to latest neural commit on main
│ └── feature # Points to latest neural commit on feature
└── objects/ # Neural commit objects stored in Git ODB
Local state (not shared):
.agit/
├── HEAD # Current branch reference
├── index # Staging area (JSONL)
├── staged-index # Frozen staging (before commit)
├── stash/ # Per-branch index stash
│ ├── main/index
│ └── feature/index
└── search_index/ # Full-text search index (Tantivy)
Custom Git Refs
Neural commit refs are stored under .git/refs/agit/heads/ using Git native ref system. This enables:
- Push/Pull support: Refs sync automatically with
git pushandgit fetch - Branch tracking: Each Git branch has a corresponding neural branch
- Team collaboration: Neural history is shared like regular Git refs
Object Store
Neural commit objects are stored in Git object database:
.git/objects/
├── a3/
│ └── f7b2c... # Neural commit object
├── b5/
│ └── d8e3a... # Trace blob
Content is JSON, stored using Git content-addressable system.
Index (Staging Area)
The index is a JSONL file (one JSON object per line):
{"role":"user","category":"intent","content":"Fix bug","timestamp":"2024-01-15T10:30:00Z","file":"/src/auth.rs","line":42}
{"role":"ai","category":"reasoning","content":"Add null check","timestamp":"2024-01-15T10:31:00Z"}
Each entry includes:
role- "user" or "ai"category- "intent", "reasoning", or "error"content- The thought contenttimestamp- ISO 8601 timestampfile- Optional: source file path where thought originatedline- Optional: line number in source file
This format is:
- Append-only during a session
- Human-readable
- Easy to parse
Per-Branch Index Stashing
When switching branches, the current index is stashed:
.agit/stash/
├── main/index # Stashed thoughts for 'main'
├── feature-x/index # Stashed thoughts for 'feature-x'
└── bugfix/index # Stashed thoughts for 'bugfix'
This preserves pending thoughts per branch, preventing context bleeding when switching between work.
Search Index
AGIT uses Tantivy for full-text search:
.agit/search_index/
├── meta.json
└── segments/
└── ...
The search index:
- Is stored locally (not synced between machines)
- Auto-updates on commit
- Incrementally updates after pull
- Can be manually rebuilt with
agit search rebuild
MCP Server
The MCP server implements JSON-RPC 2.0 over stdio:
AI Editor ──── stdin/stdout ──── agit server
(JSON-RPC 2.0)
Available tools:
agit_log_step- Record a thought (supportsrepo_pathfor cross-repo validation)agit_get_status- Get current statusagit_get_file_history- Get history for a fileagit_get_relevant_context- Search past reasoningagit_get_recent_summaries- Get recent commit summariesagit_read_roadmap- Read project roadmap
Synthesizer
The synthesizer creates summaries from staging entries:
pub fn synthesize(entries: &[IndexEntry]) -> String {
let intent = find_last_intent(entries);
let reasoning = find_last_reasoning(entries);
match (intent, reasoning) {
(Some(i), Some(r)) => format!("Intent: {}. Plan: {}.", i, r),
(Some(i), None) => format!("Intent: {}.", i),
(None, Some(r)) => format!("Plan: {}.", r),
(None, None) => "Manual update.".to_string(),
}
}
This is deterministic - no LLM calls. The AI editor does the "thinking", AGIT just synthesizes.
Commit Pipeline
The commit pipeline:
- Read entries from index
- Check for semantic conflicts (ghost commits)
- Synthesize summary
- Create trace blob (full JSONL)
- Create commit object
- Update search index
- Update refs
- Clear index
pub fn execute(&mut self, message: &str, summary: &str) -> Result<CommitResult> {
// 1. Read staging
let entries = self.index_store.read_all()?;
// 2. Check conflicts (unless --force)
if !force {
check_for_conflicts(&entries)?;
}
// 3. Create trace blob
let trace = format_trace(&entries);
let trace_hash = self.object_store.write(&trace)?;
// 4. Create commit
let commit = NeuralCommit {
message: message.to_string(),
summary: summary.to_string(),
git_commit: self.git_repo.head_commit_hash()?,
parent: self.head_store.read()?,
trace_hash,
timestamp: Utc::now(),
};
// 5. Write commit object
let hash = self.object_store.write(&commit.to_json())?;
// 6. Index for search
search::index_entries(&agit_dir, &entries)?;
// 7. Update refs
self.ref_store.write("main", &hash)?;
self.head_store.write(&hash)?;
// 8. Clear staging
self.index_store.clear()?;
Ok(CommitResult { neural_hash: hash, git_hash: commit.git_commit })
}
Git Workflow Resilience
AGIT handles complex Git workflows automatically:
Amend Detection
When git commit --amend changes a commit hash, AGIT detects this by comparing:
- Author email
- First line of commit message
- Timestamp (within 60 seconds)
If detected, the neural commit is migrated to the new hash.
Rewind Recovery
When git reset --hard rewinds history, AGIT:
- Detects the linked commit is no longer reachable
- Walks backwards through neural history
- Finds the nearest valid ancestor
- Updates the branch ref
Orphaned commits are preserved (not deleted) for potential recovery.
Merge/Rebase Guard
During merge or rebase, AGIT enters read-only mode:
- Detects
.git/MERGE_HEADor.git/rebase-merge/ - Blocks
record,add,commitcommands - Shows warnings in
status
Design Principles
1. Git-Native
AGIT integrates deeply with Git:
- Uses
.git/refs/agit/*for branch refs - Stores objects in Git object database
- Syncs via standard
git push/git pull - Local state in
.agit/(not synced)
2. Deterministic
No LLM calls in AGIT itself:
- AI editors do the reasoning
- AGIT just stores and synthesizes
- Reproducible behavior
3. Simple Storage
Content-addressable store with JSON:
- Easy to debug
- Human-readable
- No complex database
4. Atomic Operations
File operations are atomic:
- Write to temp file first
- Rename to final location
- Safe concurrent access
Data Flow
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ AI Editor │──MCP───▶│ AGIT Server │──write─▶│ .agit/ │
│ (Cursor) │ │ │ │ index │
└─────────────┘ └─────────────┘ └─────────────┘
│
▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ User │──CLI───▶│agit commit │──read──▶│ .git/refs/ │
│ │ │ │ │ agit/heads/ │
└─────────────┘ └─────────────┘ └─────────────┘
Security
- No shell command execution with user input
- Input validation on all parameters
- File locking for concurrent access
- Atomic writes prevent corruption
See Also
- Philosophy - Why AGIT exists
- MCP Integration - Protocol details
- Git Resilience - Handling complex Git workflows