Here is a scenario every developer using Claude Code, Cursor, or Aider knows too well:
You prompt your AI agent across 7 iterations. Turns 1 to 6 are solid—models are written, database queries work, and tests pass. On Turn 7, you ask for a minor optimization. The agent goes rogue, touches 12 files, breaks imports, and introduces a nasty regression.
Now you're stuck:
-
git restore .fixes the bug, but destroys all the good work from Turns 1 to 6. -
git commitafter every turn fills your Git log with 15 junk commits ("fix typo", "try again", "revert previous"). - Throwaway branches cause stash conflicts, clutter your repo, and force your IDE language server to re-index.
edio fixes this completely.
What is edio?
edio does not replace Git. It is a single Go binary that works inside your existing .git folder.
It creates an isolated Shadow Commit DAG (refs/edio/*) using low-level Git plumbing. Every time an agent makes an edit, edio takes an invisible turn snapshot in the background.
- Your staging area (
.git/index) is never touched. - Your active branch and
HEADnever move. -
Turn 7 breaks? Run
edio restore 6(or pressrin the TUI). Your workspace rolls back to Turn 6 in 5 milliseconds. -
Done with the feature? Run
edio accept "feat: add auth". All 7 turns are squashed into one clean commit on your current branch.
60-Second Quickstart
GitHub: github.com/devxdh/edio
1. Install
# macOS / Linux via Homebrew
brew install devxdh/tap/edio
# Or direct install
curl -fsSL https://raw.githubusercontent.com/devxdh/edio/main/install.sh | bash
# Or via Go
go install github.com/devxdh/edio/cmd/edio@latest
2. Initialize in your repo
cd /path/to/your/repo
edio init
This automatically configures:
-
Built-in MCP Server: Auto-injected into
.cursor/mcp.json,.vscode/mcp.json, and.gemini/settings.jsonso models take snapshots and rollbacks autonomously. -
Claude Code Lifecycle Hooks: Auto-injected into
.claude/settings.jsonto snapshot after every prompt turn. -
EDIO.mdRules: Instructs scanning LLMs to useediosnapshots instead of polluting rawgit commit.
3. Everyday Workflow
# 1. Take a snapshot (if running manually or via CLI)
edio snapshot -m "added token validation"
# 2. Open the split-pane dashboard
edio ui
# -> Use j/k to navigate turns, Tab to scroll diffs, press 'r' to rollback instantly.
# 3. Roll back from CLI (full workspace or a single file)
edio restore 6
edio restore 6 -f middleware.go
# 4. Squash session into your active branch
edio accept "feat(auth): implement token validation and tests"
Complete Command Reference
| Command | Flags | What it does |
|---|---|---|
edio init |
— | Sets up .git/edio/, auto-configures MCP servers and Claude hooks. |
edio snapshot |
-m "<msg>" |
Captures an isolated shadow snapshot of current workspace. |
edio run <cmd> |
— | Runs any CLI agent command (e.g. edio run aider) and auto-snapshots on exit. |
edio ui |
— | Opens interactive split-pane TUI (view diffs + 1-key instant rollback). |
edio restore <turn> |
-f <file> |
Rolls back workspace (or a single file) to any previous turn. |
edio log |
-p |
Lists turn history for the active session (-p for patch diffs). |
edio diff [turn] |
-f <file> |
Shows colorized diff for a turn or specific file. |
edio accept "<msg>" |
— | Squashes all session turns into one clean commit on active branch. |
edio gc |
-d <days> |
Prunes abandoned shadow sessions older than 10 days (active session is protected). |
edio mcp |
— | Starts the Model Context Protocol JSON-RPC server. |
Under the Hood: How edio Works Internally
If you're wondering how edio records commits, computes diffs, and rolls back files without touching .git/index or moving your branch, here is the technical breakdown.
It all comes down to Git plumbing.
Standard porcelain commands (git add, git commit) couple the working directory, staging area, and branch references together. edio bypasses porcelain entirely and works directly with low-level Git object primitives.
User Workspace ──► Staged via Temporary Index ──► git write-tree ──► Tree Object (SHA)
(GIT_INDEX_FILE) (In .git/objects)
│
▼ (Deleted immediately)
Primary .git/index stays clean!
1. Zero-Pollution Snapshotting (pkg/gitengine/tree.go)
Standard git add overwrites your staging index. If you already had files staged for a personal commit, an agent snapshot would wipe that out.
edio avoids this by isolating the index with the GIT_INDEX_FILE environment variable:
// 1. Create a unique scratchpad index inside .git/
tempIndexPath := filepath.Join(gitDir, fmt.Sprintf("edio_index_%d_%s.tmp", time.Now().UnixNano(), hex.EncodeToString(randBytes)))
defer os.Remove(tempIndexPath)
env := []string{fmt.Sprintf("GIT_INDEX_FILE=%s", tempIndexPath)}
// 2. Populate scratchpad from current HEAD and stage workspace changes
runGitWithEnv(env, "read-tree", "HEAD")
runGitWithEnv(env, "add", "-A")
// 3. Write directory tree directly into Git object storage
treeSHA, _ := runGitWithEnv(env, "write-tree")
-
Zero index pollution: The real
.git/indexis never touched. -
Native
.gitignoresupport:git add -Arespects all ignore rules. - Instant cleanup: The temporary index file is deleted immediately.
2. The Shadow Commit DAG (pkg/session/session.go)
To link turns together without moving HEAD or creating temporary branches, edio uses git commit-tree:
func CommitTree(treeSHA, parentSHA, message string) (string, error) {
args := []string{"commit-tree", treeSHA, "-m", message}
if parentSHA != "" {
args = append(args, "-p", parentSHA)
}
return RunGit(args...)
}
Snapshots are stored under a private reference namespace:
refs/edio/active/<session_id>/<turn_number>-
refs/edio/active/<session_id>/current
Main Branch (refs/heads/main)
● Commit A (HEAD) ──────────────────────────────────────────────► ● Commit B (Accepted)
▲
Shadow DAG (refs/edio/active/sess_123/*) │
● Turn 1 ────► ● Turn 2 ────► ● Turn 3 ────► ... ────► ● Turn N ────┘
Because standard Git tools only look at refs/heads/* and refs/tags/*, your shadow DAG is invisible to git log, git branch, and remote pushes.
3. Atomic Promotion on accept (cmd/edio/accept.go)
When you run edio accept "<commit_message>":
-
Extracts Latest Tree: Reads the tree object from
sess.LatestSHA^{tree}. -
Creates Official Commit: Runs
git commit-treewith the latest tree and the active branchHEADas its parent. -
Advances Branch: Updates
refs/heads/<current_branch>directly to the new commit SHA. -
Syncs Index: Runs
git read-tree HEADto synchronize the staging index cleanly. -
Archives Session: Moves pointers to
refs/edio/archive/and prunes sessions older than 10 days in the background.
4. Storage & Safety Guarantees
- No Storage Bloat: Unchanged files share existing Git object hashes. Abandoned sessions older than 10 days are pruned automatically.
- Active Session Lock: The active session is strictly protected from garbage collection.
- Pure Git Storage: 100% native Git objects. No SQLite, no custom daemons, no external databases.
Summary
edio gives you the safety of micro-versioning with the cleanliness of a single linear commit:
- Instant rollbacks: Revert full workspace or single files to any turn in milliseconds.
-
Zero pollution: Leaves
.git/indexand branch history 100% untouched. Automatic agent support: Built-in MCP server, Claude Code hooks, and CLI wrappers.
GitHub: Source Code
License: MIT
Top comments (0)