The part that's been keeping me up at night: this becomes critical infrastructure for multi-agent coding. When multiple agents write code in parallel (Cursor, Claude Code, Codex all ship this now), they create worktrees for isolation. But when those branches merge back, git's line-level merge breaks on cases where two agents added different functions to the same file. weave resolves these cleanly because it knows they're separate entities. 31/31 vs git's 15/31 on our benchmark.
Weave also ships as an MCP server with 14 tools, so agents can claim entities before editing, check who's touching what, and detect conflicts before they happen.
It's also based on treesitter, but probably otherwise a more baseline algorithm. I wonder if that "entity-awareness" actually then brings something to the table in addition to the AST.
edit: man, I tried searching this thread for mention of the tool for a few times, but apparently its name is not mergigraf
- do any concurrent branches touch this function?
- what new uses did this function accrete recently?
- did we create any actual merge conflicts?
Almost LSP-level querying, involving versions and branches.
Beagle is a revision control system like that [1]It is quite early stage, but the surprising finding is: instead of being a depository of source code blobs, an SCM can be the hub of all activities. Beagle's architecture is extremely open in the assumption that a lot of things can be built on top of it. Essentially, it is a key-value db, keys are URIs and values are BASON (binary mergeable JSON) [2] Can't be more open than that.
[1]: https://github.com/gritzko/librdx/tree/master/be
[2]: https://github.com/gritzko/librdx/blob/master/be/STORE.md
I haven't tried it but this sounds like it would be really valuable to me.
Given that most git conflicts are easy to solve by person who didn't involved at changes, even for a person who don't know that programming language, it's natural to let AI handle the git conflicts.
Solving a git conflict is most often a simple text manipulation without needing much of context. I see no problem current AI models can't do it.
The post links to the GitHub repo, but imo the website does a better job of explaining what it does: https://ataraxy-labs.github.io/weave/
> git merges lines. mergiraf merges tree nodes. weave merges entities. [1]
I've been using mergiraf for ~6 months and tried to use it to resolve a conflict from multiple Claude instances editing a large bash script. Sadly neither support bash out of the box, which makes me suspect that classic merge is better in this/some cases...
Will try adding the bash grammar to mergiraf or weave next time
What?
Is the idea of "multiple agents" of flesh and blood writing code that far fetched now?
Are any of these statements public, or is this all private communication?
> We are also working with GitButler team to integrate it as a research feature.
Referring to this discussion, I assume: https://github.com/gitbutlerapp/gitbutler/discussions/12274
Cheers,
Resolves merge conflicts that Git can't by understanding code structure via tree-sitter.
Git merges by comparing lines. When two branches both add code to the same file — even to completely different functions — Git sees overlapping line ranges and declares a conflict:
<<<<<<< HEAD
export function validateToken(token: string): boolean {
return token.length > 0 && token.startsWith("sk-");
}
=======
export function formatDate(date: Date): string {
return date.toISOString().split('T')[0];
}
>>>>>>> feature-branch
These are completely independent changes. There's no real conflict. But someone has to manually resolve it anyway.
This happens constantly when multiple AI agents work on the same codebase. Agent A adds a function, Agent B adds a different function to the same file, and Git halts everything for a human to intervene.
Weave replaces Git's line-based merge with entity-level merge. Instead of diffing lines, it:
The same scenario above? Weave merges it cleanly with zero conflicts — both functions end up in the output.
| Scenario | Git (line-based) | Weave (entity-level) |
|---|---|---|
| Two agents add different functions to same file | CONFLICT | Auto-resolved |
Agent A modifies foo(), Agent B adds bar() |
CONFLICT (adjacent lines) | Auto-resolved |
| Both agents modify the same function differently | CONFLICT | CONFLICT (with entity-level context) |
| One agent modifies, other deletes same function | CONFLICT (cryptic diff) | CONFLICT: function 'validateToken' (modified in ours, deleted in theirs) |
| Both agents add identical function | CONFLICT | Auto-resolved (identical content detected) |
| Both agents add different properties to same object | CONFLICT | Auto-resolved |
| Different JSON keys modified | CONFLICT | Auto-resolved |
The key difference: Git produces false conflicts on independent changes because they happen to be in the same file. Weave only conflicts on actual semantic collisions when two branches change the same entity incompatibly.
Tested on real merge commits from major open-source repositories. For each merge commit, we replay the merge with both Git and Weave, then compare against the human-authored result.
| Repository | Language | Merge Commits | Wins | Regressions | Human Match | Resolution |
|---|---|---|---|---|---|---|
| git/git | C | 1319 | 39 | 0 | 64% | 13% |
| Flask | Python | 56 | 14 | 0 | 57% | 54% |
| CPython | C/Python | 256 | 7 | 0 | 29% | 13% |
| Go | Go | 1247 | 19 | 0 | 58% | 28% |
| TypeScript | TypeScript | 2000 | 65 | 0 | 6% | 23% |
Zero regressions across all repositories. Every "win" is a place where a developer had to manually resolve a false conflict that Weave handles automatically.
When a real conflict occurs, weave gives you context that Git doesn't:
<<<<<<< ours — function `process` (both modified)
export function process(data: any) {
return JSON.stringify(data);
}
=======
export function process(data: any) {
return data.toUpperCase();
}
>>>>>>> theirs — function `process` (both modified)
You immediately know: what entity conflicted, what type it is, and why it conflicted.
TypeScript, TSX, JavaScript, Python, Go, Rust, Java, C, C++, Ruby, C#, PHP, Swift, Kotlin, Elixir, Bash, HCL/Terraform, Fortran, Vue, XML, JSON, YAML, TOML, CSV, Markdown. Falls back to standard line-level merge for unsupported file types.
brew install weave
Or build from source (requires Rust):
git clone https://github.com/Ataraxy-Labs/weave
cd weave
cargo install --path crates/weave-cli
cargo install --path crates/weave-driver
In any Git repo:
weave setup
This configures Git to use weave for all supported file types. Then use git merge as normal.
To set up for just yourself (without modifying .gitattributes), use .git/info/attributes instead:
git config merge.weave.name "Entity-level semantic merge"
git config merge.weave.driver "weave-driver %O %A %B %L %P"
echo "*.ts *.tsx *.js *.py *.go *.rs *.java *.c *.cpp *.rb *.cs merge=weave" >> .git/info/attributes
Dry-run a merge to see what weave would do:
weave-cli preview feature-branch
src/utils.ts — auto-resolved
unchanged: 2, added-ours: 1, added-theirs: 1
src/api.ts — 1 conflict(s)
✗ function `process`: both modified
✓ Merge would be clean (1 file(s) auto-resolved by weave)
weave-core # Library: entity extraction, 3-way merge algorithm, reconstruction
weave-driver # Git merge driver binary (called by git via %O %A %B %L %P)
weave-cli # CLI: `weave setup` and `weave preview`
Uses sem-core for entity extraction via tree-sitter grammars.
base
/ \
ours theirs
\ /
weave merge
The pragmatic reason weave works at the git layer: adoption. Getting people to switch merge drivers is hard enough, getting them to switch VCS is nearly impossible. So weave parses the three file versions on the fly during merge, extracts entities, resolves per-entity, and writes back a normal file that git stores as a blob. You get entity-level merging without anyone changing their workflow.
But you're pointing at the ceiling of that approach. A VCS that stores ASTs natively could answer "did any concurrent branches touch this function?" as a query, not as a computation. That's a fundamentally different capability. Beagle looks interesting, will dig into the BASON format.
We built something adjacent with sem (https://github.com/ataraxy-labs/sem) which extracts the entity dependency graph from git history. It can answer "what new uses did this function accrete" and "what's the blast radius of this change" but it's still a layer on top of git, not native storage.
The problem is that disks (and storage in general) store only bytes so you inherently need to deal with bytes at some point. You could view source code files as the serialization of the AST (or other parse tree).
This is especially apparent with LISPs and their sexprs, but equally applies to other languages too.
I built lix [0] which stores AST’s instead of blobs.
Direct AST writing works for apps that are “ast aware”. And I can confirm, it works great.
But, the all software just writes bytes atm.
The binary -> parse -> diff is too slow.
The parse and diff step need to get out of the hot path. That semi defeats the idea of a VCS that stores ASTs though.
The process of taking such a linear stream and reconstructing the arbitrary data structure used to generate it (or, in more sophisticated cases, something related to it if not identical), is deserialization. You can't send anyone a cyclic graph directly but you can send them something they can deserialize into a cyclic graph if you arrange the serialization/deserialization protocol correctly. They may deserialize it into a raw string in some programming language so they can run regexes over it. They may deserialize it into a stream of tokens. This all happens from the same source of serialized data.
So let's say we have an AST in memory. As complicated as your language likes, however recursive, however cross-"module", however bizarre it may be. But you want to store it on a disk or send it somewhere else. In that case it must be serialized and then deserialized.
What determines what the final user ends up with is not the serialization protocol. What determines what the final user ends up with is the deserialization procedure they use. They may, for instance, drop everything except some declaration of what a "package" is if they're just doing some initial scan. They may deserialize it into a compiler's AST. They may deserialize it into tree sitter's AST. They may deserialize it into some other proprietary AST used by a proprietary static code analyzer with objects designed to not just represent the code but also be immediately useful in complicated flow analyses that no other user of the data is interested in using.
The point of this seemingly rambling description of what serialization is is that
"why keep files as blobs in the first place. If a revision control system stores AST trees instead"
doesn't correspond to anything actionable or real. Structured text files are already your programming language's code stored as ASTs. The corresponding deserialization format involves "parsing" them, which is a perfectly sensible and very, very common deserialization method. For example, the HTML you are reading was deserialized into the browser's data structures, which are substantially richer than "just" an AST of HTML due to all the stuff a browser does with the HTML, with a very complicated parsing algorithm defined by the HTML standard. The textual representation may be slightly suboptimal for some purposes but they're pretty good at others (e.g., lots of regexes run against code over the years). If you want some other data structure in the consumer, the change has to happen in the code that consumes the serialized stream. There is no way to change the code as it is stored on disk to make it "more" or "less" AST-ish than it already is, and always has been.
You can see that in the article under discussion. You don't have to change the source code, which is to say, the serialized representation of code on the disk, to get this new feature. You just have to change the deserializer, in this case, to use tree sitter to parse instead of deserializing into "an array of lines which are themselves just strings except maybe we ignore whitespace for some purposes".
Once you see the source code as already being an AST, it is easy to see that there are multiple ways you could store it that could conceivably be optimized for other uses... but nothing you do to the serialization format is going to change what is possible at all, only adjust the speed at which it can be done. There is no "more AST-ish" representation that will make this tree sitter code any easier to write. What is on the disk is already maximally "AST-ish" as it is today. There isn't any "AST-ish"-ness being left on the table. The problem was always the consumers, not the representation.
And as far as I can tell, it isn't generally the raw deserialization speed nowadays that is the problem with source code. Optimizing the format for any other purpose would break the simple ability to read it is as source code, which is valuable in its own right. But then, nothing stops you from representing source code in some other way right now if you want... but that doesn't open up possibilities that were previously impossible, it just tweak how quickly some things will run.
If you have a language specific parser, you can make a merge algorithm like weave. But the bigger win isn't resolving conflicts git shows you. It's catching the ones git misses entirely. So in those cases weave is much better, and there also other things like confidence-scored conflict classification, you should try it out it improves the agents performance, especially if you are a power user.
We also handle Python class merge specifically: if both sides add different methods to the same class, weave merges them as separate inner entities rather than treating the whole class as one conflicting block. The indentation is derived from the AST structure, not from line diffing, so it can't accidentally shift a method out of its class scope.
For diffing arbitrary files outside git, we built sem (https://github.com/ataraxy-labs/sem) which does entity-level diffs. sem diff file1.py file2.py shows you which functions changed, were added, or deleted rather than line-level changes
The good part is that this research extends really good for code review because tracking entities is more semantically rich than lines.
The key difference: mergiraf matches individual AST nodes (GumTree + PCS triples). Weave matches entities (functions, classes, methods) as whole units. Simpler, faster, and conflicts are readable ("conflict in validate_token" instead of a tree of node triples).
The other big gap: weave ships as an MCP server with 14 tools for agent coordination. Agents can claim entities before editing and detect conflicts before they merge. That's the piece mergiraf doesn't have.
On bash: weave falls back to line-level for unsupported languages, so it'll work as well as git does there.
Adding a bash tree-sitter grammar would unlock entity-level merge for it. But I can work on it tonight, if you want it urgently.
Cheers,
I also think that this approach has a lot of potential. Keep up the good work sir.
Cheers,
There is room for improvement, but that is not a show-stopper so far. I plan round-tripping Linux kernel with full history, must show all the bottlenecks.
P.S. I checked lix. It uses a SQL database. That solves some things, but also creates an impedance mismatch. Must be x10 slow down at least. I use key-value and a custom binary format, so it works nice. Can go one level deeper still, use a custom storage engine, it will be even faster. Git is all custom.
We are still benchmarking it on diverse benchmarks, and working on it as a research direction. Also working on a diff viewer in rust.
These things are genuinely not letting me sleep these days.
Edit: Also, how are comments treated, in general (especially if they exist outside the structures you mentioned)? Eg. Does it somehow surface "contradictory" / conflicting edits made within comments? Or are they totally ignored?
https://x.com/agent_wrapper/status/2026937132649247118 https://x.com/omega_memory/status/2028844143867228241 https://x.com/vincentmvdm/status/2027027874134343717
Tree-sitter's error handling is constrained by its intended use in editors, so incrementality and efficiency are important. For diffing/merging, a more elaborate parsing algorithm might be better, for example one that uses an Earley/CYK-like algorithm but attempts to minimize some error term (which a dynamic programming algorithm could be naturally extended to.)
worth mentioning that mergiraf is already supported for windows. from https://github.com/Ataraxy-Labs/weave/issues/7 it looks like it's planned for weave too at some point?
E.g. I sometimes have 10+ agents kicking off changes to the same small project at the same time, and likely to all want to merge within the next 15-30 minutes. At that rate, merge conflicts happens very frequently. The agents can mostly resolve them themselves, but it wastes tokens, and time.
Fair play. Great tool.
Dude did you just call me AI generated haha, i've been actively using weave for a gui I've been building for blazingly fast diffs
https://x.com/Palanikannan_M/status/2022190215021126004
So whenever I run into bugs I patched locally in my clone, I try to let the clanker raise a pr upstream, insane how easy things are now.
GitHub’s ToS, because you suspect, so I can help you understand them.
> What violates it:
1. Automated Bulk issues/PRs, that we don't own
2. Fake Stars or Engagement Farming
3. Using Bot Accounts.
We own the repo, there's not even a single fake star, I don't even know how to create a bot account lol.> Scenario when we run out of free tokens.
Open AI and Anthropic have been sponsoring my company with credits, because I am trying to architect new software post agi world, so if I run out I will ask them for more tokens.