Dipankar Sarkar

Run two AI coding agents on the same repo and the first thing that breaks is not
the code. It is coordination. Agent A starts refactoring auth. Agent B, running in
parallel, has no idea and starts the same thing. Neither remembers what it did last
session, because each one boots fresh with an empty context window. The usual fixes
are worse than the problem: a state file in the repo pollutes every diff and
conflicts on merge, and an external issue tracker means API tokens, rate limits,
and a hard dependency on the network for something that should be local.

So I built grite: an issue tracker that lives inside your git repository as an
append-only event log, with deterministic CRDT merging so two writers never
conflict. No server. No database. No merge conflicts. Just git.

The core idea: issues are events, git refs are the log

Grite does not store issues as files in your working tree. It stores them as an
append-only write-ahead log inside a git ref, refs/grite/wal. Every action, a
create, a comment, a label change, is one immutable CBOR-encoded event appended to
that log. Your working tree stays completely clean. The only tracked file grite
ever writes is AGENTS.md, and that is on purpose, so agents discover the tool
automatically.

Because the state lives in a git ref, it travels with your code. It branches when
you branch. It merges when you merge. It syncs when you git push. If you can push
to a remote, you can sync issues. There is no new account, no new infrastructure,
no new protocol to learn.

How it works

Three layers, cleanly separated.

The git WAL is the source of truth. Events are appended as CBOR chunks, each
identified by a content-addressed EventId that is a BLAKE2b hash of the event
body. Content addressing is what makes the log tamper-evident: change one byte of
an event and its ID no longer matches, which breaks the chain. Signing is optional
Ed25519 per event, so you can prove which actor created what.

The materialized view is a sled embedded key-value store that projects the
event log into current issue state. This is the cache you actually query. It
rebuilds from the WAL on startup and then updates incrementally. Deleting it is
safe, it just replays the log. The projection uses CRDT semantics, Last-Write-Wins
for scalar fields and commutative-set semantics for things like labels. That is the
whole trick behind conflict-free multi-agent editing: two agents edit the same
issue on two machines, both changes survive the merge, and the result is identical
regardless of merge order.

The CLI and optional daemon are the interface. The daemon keeps the sled view
warm and serializes writes while allowing parallel reads, but it is optional for
correctness. The CLI works standalone and auto-spawns the daemon only when it helps.

The numbers that matter when an agent is firing hundreds of queries per session:

Operation Time
Issue create ~5ms (single event append)
Issue list, 1,000 issues ~10ms (sled view query)
Full rebuild, 10,000 events ~500ms (replay entire WAL)
Snapshot rebuild ~50ms (jump to snapshot, replay delta)

The full WAL rebuild is O(n), which is why periodic snapshots exist, they cut a
cold rebuild after a clone from replaying everything down to replaying a delta.
Each actor gets its own isolated sled database, so one agent's heavy query load
never blocks another's.

Using it

The human path looks like a normal tracker, just with git semantics underneath:

cd your-project
grite init                       # creates AGENTS.md for agent discoverability

grite issue create --title "Fix race in WAL append" \
  --body "Intermittent failure under high concurrency."

grite issue list
grite issue update <id> --label bug --label concurrency
grite issue link <issue-a> blocks <issue-b>

grite sync                       # git fetch + CRDT merge, then push

Enter fullscreen mode Exit fullscreen mode

The agent path is where the design pays off. An agent claims a lock so a second
agent picks different work, then records what it learned as a durable memory issue
that the next session can read:

# Agent boots, syncs, and grabs a task
grite sync --pull
grite issue list --label "agent:todo" --json
grite issue update <id> --label "agent:in-progress"
grite lock acquire src/parser.rs --ttl 1800

# Agent stores a learning for its future self
grite issue create --title "Parser edge case: empty structs" \
  --body "The parser fails on struct {}; need to handle this." \
  --label memory

grite issue close <id>
grite sync --push

Enter fullscreen mode Exit fullscreen mode

Every command supports --json, so agents parse output instead of scraping it.
The distributed lock has a TTL lease, so a crashed agent does not hold a resource
forever. Context extraction is tree-sitter powered across 10 languages (Rust,
Python, TypeScript, JavaScript, Go, Java, C, C++, Ruby, Elixir), so an agent can
create an issue with real symbol context instead of a vague note.

Where it does not fit

Honesty is the whole point, so here is where grite is the wrong tool.

It is terminal-and-git native. There is no hosted web UI, no kanban board, no
@-mention notifications, no email digest. If your team lives in a browser-based
tracker with dashboards and non-technical stakeholders, grite will feel primitive.
It is built for people and agents who already live in the terminal.

It is repo-local by design. Cross-repo issues, an org-wide backlog spanning
dozens of services, or a public bug tracker where external users file reports, none
of that is what grite is for. Your issues are scoped to the repo they describe.

The CRDT merge is deterministic, not smart. Last-Write-Wins means if two agents set
conflicting titles, one wins by timestamp. That is correct and conflict-free, but it
is not human judgment. For fields where you actually want a human to reconcile two
edits, an automatic merge is not what you want.

And it needs git 2.38+. The daemon is optional but the git dependency is not.

Takeaways

  • Coordination state for parallel agents belongs next to the code, not on a server. Git refs give you sync, history, and offline for free.
  • An append-only event log plus a rebuildable cache is a clean split: the log is truth, the sled view is disposable speed.
  • CRDT Last-Write-Wins is what turns "two agents editing one issue" from a merge conflict into a non-event. It is deterministic, which is exactly what you want for reproducibility, and dumb, which is exactly where you still want a human.

Code, the data model, and the hashing test vectors are here:
https://github.com/neul-labs/grite

If you are running more than one coding agent against a single repo, I want to know
how you are coordinating them today. Kick the tyres, issues welcome.