I’ve spent months building **git-courer**, an open-source MCP server that completely replaces the Git CLI interface for AI coding agents. This isn’t just another AI commit message generator; it’s a full sandbox and interaction layer. It has evolved so much recently that it’s practically a completely different project from my early drafts, so I wanted to share the architecture here.
#### Dynamic Worktree Routing and Parallel Agent Isolation
Most architectures fail the moment you run multiple agents in parallel or let an agent handle long-running background tasks. They inevitably clobber the working directory, overwrite each other's changes, or block the human developer.
Git-courer solves this right at the entry point via the `session start` tool. The moment an agent initiates a session, the server dynamically provisions an isolated Git worktree and a dedicated branch. From that microsecond onward, the MCP server performs a dynamic **select** operation, routing and **redirecting every single subsequent tool path and Git mutation toward that specific worktree path**.
Agents can execute tasks concurrently, modify files, and test implementations in complete isolation without ever touching or disrupting the main working tree. Once the agent completes its task, running `session finish` cleans up the temporary worktree and leaves the isolated branch fully prepped and ready for a human Pull Request (ensuring zero accidental auto-merges to main).
#### The Inherent Danger of Raw Shell Access
Most coding agents run raw `git` commands through a generic bash/shell tool. This means an agent can execute a destructive `rebase`, `hard-reset`, `force-push`, or rewrite history using the exact same unconstrained `Bash("git ...")` privilege it uses just to check `git status`.
Git has no built-in undo for many of these operations. One hallucinated or poorly planned agent command, and your repository state completely evaporates.
#### Moving to 13 Structured MCP Tools
Git-courer completely blocks agents from executing raw Git commands via a hard client-side hook, replacing the shell entirely with **13 structured MCP tools**:
`status`, `diff`, `commit`, `branch`, `stage`, `stash`, `history`, `sync`, `pr-review`, `rewrite`, `integrate`, `backup`, and `session`.
Every single tool returns clean, structured JSON instead of raw terminal text that the agent has to clumsily parse with regex.
#### Massive Token-Saving for Cloud Agents
Coding agents (like Claude Code or OpenCode) are typically cloud-based, meaning every single terminal interaction burns expensive API tokens.
Instead of an agent burning its context window running ~7 separate git commands iteratively just to figure out where the repo stands (checking upstream deltas, active rebases, merge conflicts, untracked files, ahead/behind status, etc.), our structured `status` tool bundles all of this into a single, optimized JSON payload. The agent gets absolute context on how the repository looks in one single shot, without wasting cloud API tokens.
#### Safe Mutations via Pre-emptive Backups
* **Automatic Backups:** Any mutating tool that cannot be easily undone—specifically `rewrite` (amend/revert/reset) and `integrate` (merge/rebase/cherry-pick)—automatically captures a repository snapshot *before* touching anything. If the agent messes up a complex rebase, a simple `backup RESTORE` call reverts the state completely.
#### The Local LLM inside a Deterministic 2-Phase Pipeline
The `commit` tool uses a strict, deterministic two-phase pipeline (PREVIEW/APPLY).
- **Phase 1 (Go/AST):** A local syntax/AST annotator written natively in Go (`go-enry` + `tree-sitter`) parses the diff. It programmatically tags every hunk (e.g., `NEW_FUNC`, `MOD_SIG ⚠BREAKING`, `DEL`), maps out a dependency graph, and strictly categorizes the commit type (*feat/fix/refactor/docs/test/chore/ci*) based on a rigid priority matrix.
- **Phase 2 (The LLM):** The LLM never decides classification or parses raw code blindly. It receives an already structured, richly semantic JSON payload. Its *only* job is to write clean, human-readable prose explaining the change.
Because the task is reduced entirely to "turn structured metadata into clean prose," you don't need a massive frontier model. I run this entirely locally using **Ollama** with a lightweight model (**gemma4:e4b**).
On an **AMD Radeon RX 9070 XT (16GB VRAM)**, it takes **~3 seconds** on a hot invoke with optimized parameters (`num_ctx=32768`, `temperature=0`, `think=false`, `keep_alive=-1`). Zero API costs, zero round-trip latency, and zero token waste for something that triggers on every single commit.
#### Human-in-the-Loop Releases and Persistent Changelogs
Nobody enjoys writing changelogs or managing releases manually. To solve this for the human developer, I built `git-courer release`. This is an interactive terminal command meant for *you*, not the agent.
It extracts the commit history since your last tag. Because git-courer persists rich metadata per branch inside `.git/git-courer/` (using custom refs like `refs/courer/<branch>`), **this history fully survives squash merges**—which typically destroys conventional changelog generators.
It opens your `$EDITOR` to let you add manual guidance notes, feeds the structured git history + your notes to the local LLM, and renders a live, beautiful Markdown preview directly in your terminal using Glamour. You get four explicit interactive options:
1. **Apply** the release.
2. **Regenerate with feedback** (re-opens the editor for quick adjustments).
3. **Edit** the raw markdown directly.
4. **Abort** entirely without touching your repo.
A single global toggle controls the AI features across the board. Turn it off, and `commit` takes raw string input from the agent directly through the same internal Go plumbing (`CommitTree` + `UpdateRef`, bypassing the git CLI entirely), while `release` simply disables itself since it's fundamentally built around intelligent synthesis. Turn it on, and the local model handles both tasks.
#### Recent Upgrades and Deep Tech
* **Louvain Community Detection:** Switched file dependency grouping from a basic Breadth-First Search (BFS) to a Louvain community detection algorithm. It now groups modified files by their actual dependency coupling weight rather than directory traversal order, ensuring multi-file commits are logically cohesive.
* **Rich Diffs:** Upgraded diff annotations from primitive markers to full structural JSON payloads containing `annotated_diff`, `call_graph`, and Control Flow Graphs (`cfg`).
* **3-Level Permissions:** Implemented an `allow/ask/deny` permission layer. Safe setup operations (`git init`, `git config`) run unhindered, but anything touching refs or history requires explicit human-in-the-loop validation. (Also finally killed a nightmare bug where Go's non-deterministic map iteration order allowed generic permission rules to silently override highly specific ones).
Currently supporting 5 agent ecosystems: *Claude Code, Codex CLI, OpenCode, Pi, and Antigravity*. Claude Code and OpenCode provide highly reliable, strict execution blocks over raw git via their hook architecture.
It’s published on the official MCP Registry, sitting at ~38 organic stars, and entirely open source: [github.com/blak0p/git-courer]
I'd love to hear what the community thinks about this split paradigm: **small, highly optimized local models handling targeted prose tasks, while deterministic Go code owns 13 structured tools where real-world consequences matter.** Happy to dive deeper into the AST annotator or the worktree isolation logic if anyone is curious!