syft is a version control experiment for AI-heavy development.
The short version is this: Git is good at snapshots and patches. It is less helpful when the thing you are trying to keep track of is a task, a few candidate solutions, the validation evidence, and the final promoted result.
That gap shows up fast once AI is in the loop.
You ask for a change. The model tries one path, then another. Maybe one passes tests and one almost works. Maybe both are messy in different ways. By the time you get to something worth keeping, the raw diff is only part of the story.
That is what syft is trying to hold onto.
The center of the system is a ChangeNode.
A change node ties together:
- the task
- the base snapshot
- the result snapshot
- the intent
- the semantic delta
- the validation artifacts
- the promotion state
That gives you a better unit for AI-assisted work than a commit by itself.
flowchart LR
task["Task"]
base["Base Snapshot"]
result["Result Snapshot"]
change["ChangeNode"]
semantic["Semantic Delta"]
validation["Validation Artifacts"]
promotion["Promotion Record"]
task --> change
base --> change
result --> change
change --> semantic
change --> validation
change --> promotion
Commits still matter. Diffs still matter. Git still matters. They just are not enough on their own once you have multiple attempts and tool-driven changes flying around.
This came from a pretty practical frustration.
Git can tell you what changed. It does not really tell you what the change was for, what else was tried, what evidence came with it, or why this candidate was the one that got kept.
In ordinary hand-written work, people usually patch over that with branch names, commit messages, PR descriptions, CI links, and memory.
That starts to feel thin with AI.
The pace is different. The number of candidates is different. The amount of bookkeeping goes up. You end up wanting a first-class record of intent and validation, not just a final patch.
That is the bet here.
I think syft is better than plain Git in a few specific ways.
It keeps the task attached to the change. That matters more than it sounds. A lot of AI work goes sideways because the actual goal gets separated from the patch.
It keeps validation attached to the candidate. In Git, CI sits next to the commit. Here the validation artifacts belong to the change node itself, which is a much better fit when you are comparing attempts.
It makes promotion explicit. You can have several candidate changes for one task and still make one clear decision about what actually moved forward.
It has room for semantic review. Right now that part is still small and Rust-only, but the direction is right. If a change touched a public symbol or shifted a dependency edge, the system should surface that directly.
It also fits parallel exploration better. Branches work. They just are not really the same thing as “three candidate implementations of the same intent.”
This project is still early.
It is local-first. There is no API layer, no worker system, no remote coordination, no multi-language semantic engine, and no native storage backend replacing Git.
That was deliberate.
The first job was to prove the model in a real repo with a real CLI and a real end-to-end loop. That part matters more than drawing a giant future architecture and pretending it already exists.
The current workspace supports this flow:
- initialize a
syftrepo - import a Git commit into a snapshot
- create a task
- capture a result snapshot from the worktree
- propose a change node against a base snapshot
- run validation on that result snapshot
- promote the change and optionally export it back to Git
flowchart LR
init["syft init"] --> import["repo import-git"]
import --> task["task create"]
task --> capture["snapshot capture"]
capture --> propose["change propose"]
propose --> validate["change validate"]
validate --> promote["change promote"]
promote --> git["optional Git export"]
It also has the read-side commands you need to inspect the state of the repo:
statushistorysnapshot list,show,difftask list,show,current,set-current,changeschange list,show,latest,diff,validate,promote
syft imports from Git and can export promoted snapshots back to Git.
That keeps the system usable while the model is still taking shape. It also means this can be tested in normal repos without asking anyone to buy into a full replacement story upfront.
That is intentional.
A change node is carrying more context because AI-assisted work usually needs more context. The extra weight is the point.
Everything lives under .syft/.
Metadata is in SQLite. Objects are on disk. Validation runs locally against a materialized snapshot. There is a lot less machinery here than there would be in a service-first design.
Internally this is more about tasks, snapshots, changes, and promotions than about branches.
Branches still matter at the Git boundary. They just are not the main shape of the system.
No. Not today.
Git is still the import and export layer. syft is acting more like a richer control plane on top of it.
You can get part of the way there with branches and PRs.
What they do not give you very well is a first-class record of multiple candidate implementations for one task, along with their semantic deltas, validation artifacts, and promotion state.
That is the part syft is focused on.
Because AI tends to increase the number of attempts.
Once you have a few candidate changes for one intent, plus validation output, plus some amount of semantic review, a commit log starts to feel too flat. You want something closer to a task-and-candidate graph.
Because it is still the easiest way to stay compatible with the rest of the world.
Repos, hosting, review tools, and developer habits already run through Git. Throwing that away early would make the project harder to test and easier to hand-wave.
Right now it stores repo metadata, snapshots, tasks, change nodes, validation artifacts, and promotions under .syft/.
SQLite holds the metadata. The object store holds blobs, trees, snapshot content, and full validation logs.
Because the problem being worked on first is modeling the change properly.
Remote sync, APIs, workers, and multi-user coordination are real problems. They are just later problems.
No.
It is useful, but still pretty narrow. It is Rust-only right now and meant to prove the shape of semantic review, not to claim full language coverage.
For general version control, no.
For AI-heavy change exploration, I think it is heading in a better direction because it has better places to store task intent, validation evidence, and promotion decisions.
That is still being proven. The current version is honest bootstrap software.
If you want the binary from GitHub releases, use the install scripts.
On macOS or Linux:
curl -fsSL https://raw.githubusercontent.com/chaqchase/syft/main/scripts/install.sh | shFor a specific version:
curl -fsSL https://raw.githubusercontent.com/chaqchase/syft/main/scripts/install.sh | sh -s -- v0.1.0On Windows PowerShell:
irm https://raw.githubusercontent.com/chaqchase/syft/main/scripts/install.ps1 | iexFor a specific version:
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/chaqchase/syft/main/scripts/install.ps1))) "v0.1.0"The README stays high level on purpose.
The technical detail is in docs/README.md:
- workspace and crate layout
- storage model
- CLI behavior
- development notes