{"slug": "two-coding-agents-editing-the-same-issue-no-merge-conflict-here-is-how-git-refs", "title": "Two coding agents editing the same issue, no merge conflict. Here is how git refs make that work", "summary": "A developer built `grite`, an issue tracker that lives inside a git repository as an append-only event log with deterministic CRDT merging, eliminating merge conflicts when multiple AI coding agents edit the same issue. The system stores events in a git ref (`refs/grite/wal`) and uses a materialized view via sled for fast queries, enabling conflict-free multi-agent editing without a server or database.", "body_md": "Run two AI coding agents on the same repo and the first thing that breaks is not\n\nthe code. It is coordination. Agent A starts refactoring auth. Agent B, running in\n\nparallel, has no idea and starts the same thing. Neither remembers what it did last\n\nsession, because each one boots fresh with an empty context window. The usual fixes\n\nare worse than the problem: a state file in the repo pollutes every diff and\n\nconflicts on merge, and an external issue tracker means API tokens, rate limits,\n\nand a hard dependency on the network for something that should be local.\n\nSo I built `grite`\n\n: an issue tracker that lives inside your git repository as an\n\nappend-only event log, with deterministic CRDT merging so two writers never\n\nconflict. No server. No database. No merge conflicts. Just git.\n\nGrite does not store issues as files in your working tree. It stores them as an\n\nappend-only write-ahead log inside a git ref, `refs/grite/wal`\n\n. Every action, a\n\ncreate, a comment, a label change, is one immutable CBOR-encoded event appended to\n\nthat log. Your working tree stays completely clean. The only tracked file grite\n\never writes is `AGENTS.md`\n\n, and that is on purpose, so agents discover the tool\n\nautomatically.\n\nBecause the state lives in a git ref, it travels with your code. It branches when\n\nyou branch. It merges when you merge. It syncs when you `git push`\n\n. If you can push\n\nto a remote, you can sync issues. There is no new account, no new infrastructure,\n\nno new protocol to learn.\n\nThree layers, cleanly separated.\n\nThe **git WAL** is the source of truth. Events are appended as CBOR chunks, each\n\nidentified by a content-addressed `EventId`\n\nthat is a BLAKE2b hash of the event\n\nbody. Content addressing is what makes the log tamper-evident: change one byte of\n\nan event and its ID no longer matches, which breaks the chain. Signing is optional\n\nEd25519 per event, so you can prove which actor created what.\n\nThe **materialized view** is a `sled`\n\nembedded key-value store that projects the\n\nevent log into current issue state. This is the cache you actually query. It\n\nrebuilds from the WAL on startup and then updates incrementally. Deleting it is\n\nsafe, it just replays the log. The projection uses CRDT semantics, Last-Write-Wins\n\nfor scalar fields and commutative-set semantics for things like labels. That is the\n\nwhole trick behind conflict-free multi-agent editing: two agents edit the same\n\nissue on two machines, both changes survive the merge, and the result is identical\n\nregardless of merge order.\n\nThe **CLI and optional daemon** are the interface. The daemon keeps the sled view\n\nwarm and serializes writes while allowing parallel reads, but it is optional for\n\ncorrectness. The CLI works standalone and auto-spawns the daemon only when it helps.\n\nThe numbers that matter when an agent is firing hundreds of queries per session:\n\n| Operation | Time |\n|---|---|\n| Issue create | ~5ms (single event append) |\n| Issue list, 1,000 issues | ~10ms (sled view query) |\n| Full rebuild, 10,000 events | ~500ms (replay entire WAL) |\n| Snapshot rebuild | ~50ms (jump to snapshot, replay delta) |\n\nThe full WAL rebuild is O(n), which is why periodic snapshots exist, they cut a\n\ncold rebuild after a clone from replaying everything down to replaying a delta.\n\nEach actor gets its own isolated sled database, so one agent's heavy query load\n\nnever blocks another's.\n\nThe human path looks like a normal tracker, just with `git`\n\nsemantics underneath:\n\n```\ncd your-project\ngrite init                       # creates AGENTS.md for agent discoverability\n\ngrite issue create --title \"Fix race in WAL append\" \\\n  --body \"Intermittent failure under high concurrency.\"\n\ngrite issue list\ngrite issue update <id> --label bug --label concurrency\ngrite issue link <issue-a> blocks <issue-b>\n\ngrite sync                       # git fetch + CRDT merge, then push\n```\n\nThe agent path is where the design pays off. An agent claims a lock so a second\n\nagent picks different work, then records what it learned as a durable memory issue\n\nthat the next session can read:\n\n```\n# Agent boots, syncs, and grabs a task\ngrite sync --pull\ngrite issue list --label \"agent:todo\" --json\ngrite issue update <id> --label \"agent:in-progress\"\ngrite lock acquire src/parser.rs --ttl 1800\n\n# Agent stores a learning for its future self\ngrite issue create --title \"Parser edge case: empty structs\" \\\n  --body \"The parser fails on struct {}; need to handle this.\" \\\n  --label memory\n\ngrite issue close <id>\ngrite sync --push\n```\n\nEvery command supports `--json`\n\n, so agents parse output instead of scraping it.\n\nThe distributed lock has a TTL lease, so a crashed agent does not hold a resource\n\nforever. Context extraction is tree-sitter powered across 10 languages (Rust,\n\nPython, TypeScript, JavaScript, Go, Java, C, C++, Ruby, Elixir), so an agent can\n\ncreate an issue with real symbol context instead of a vague note.\n\nHonesty is the whole point, so here is where grite is the wrong tool.\n\nIt is terminal-and-git native. There is no hosted web UI, no kanban board, no\n\n@-mention notifications, no email digest. If your team lives in a browser-based\n\ntracker with dashboards and non-technical stakeholders, grite will feel primitive.\n\nIt is built for people and agents who already live in the terminal.\n\nIt is repo-local by design. Cross-repo issues, an org-wide backlog spanning\n\ndozens of services, or a public bug tracker where external users file reports, none\n\nof that is what grite is for. Your issues are scoped to the repo they describe.\n\nThe CRDT merge is deterministic, not smart. Last-Write-Wins means if two agents set\n\nconflicting titles, one wins by timestamp. That is correct and conflict-free, but it\n\nis not human judgment. For fields where you actually want a human to reconcile two\n\nedits, an automatic merge is not what you want.\n\nAnd it needs git 2.38+. The daemon is optional but the git dependency is not.\n\nCode, the data model, and the hashing test vectors are here:\n\n[https://github.com/neul-labs/grite](https://github.com/neul-labs/grite)\n\nIf you are running more than one coding agent against a single repo, I want to know\n\nhow you are coordinating them today. Kick the tyres, issues welcome.", "url": "https://wpnews.pro/news/two-coding-agents-editing-the-same-issue-no-merge-conflict-here-is-how-git-refs", "canonical_source": "https://dev.to/dipankar_sarkar/two-coding-agents-editing-the-same-issue-no-merge-conflict-here-is-how-git-refs-make-that-work-325k", "published_at": "2026-07-25 15:24:15+00:00", "updated_at": "2026-07-25 16:02:10.246530+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents"], "entities": ["grite", "sled", "BLAKE2b", "Ed25519", "CBOR"], "alternates": {"html": "https://wpnews.pro/news/two-coding-agents-editing-the-same-issue-no-merge-conflict-here-is-how-git-refs", "markdown": "https://wpnews.pro/news/two-coding-agents-editing-the-same-issue-no-merge-conflict-here-is-how-git-refs.md", "text": "https://wpnews.pro/news/two-coding-agents-editing-the-same-issue-no-merge-conflict-here-is-how-git-refs.txt", "jsonld": "https://wpnews.pro/news/two-coding-agents-editing-the-same-issue-no-merge-conflict-here-is-how-git-refs.jsonld"}}