---
title: Limits
description: What version 0.1 does not do, and where its guarantees stop.
---

## Platform

- macOS and Linux. CI runs every test on macOS (arm64), Linux (x86_64, plain checkouts; failures there do not fail the build), and Linux on btrfs and on XFS with copy-on-write required. The code is Unix-only (signals, `libc`); there is no Windows support.
- **Copy-on-write needs a file system that supports it:** APFS on macOS; btrfs or XFS with reflink on Linux (`FICLONE` reflinks), each tested in CI with copy-on-write required. Other file systems with `FICLONE`, such as bcachefs, are not tested. On ext4 and others, a workspace is a plain checkout: its files are new copies, and `[prepare]` installs dependencies again in each one. On a CI runner, ten reflink workspaces of a 30,000-file repository added no measurable disk on btrfs, against 24 MB for worktrees; on ext4 both used 1.27 GB ([Benchmarks](/benchmarks)).
- Requires git 2.38 or newer (`merge-tree --write-tree`); Zit checks and names the version it needs.

## Semantics

- **Prose merges like git.** Two edits to one Markdown section are accepted when their text merges; Zit does not judge them further. Code is stricter: two edits to one function are refused even when the text merges.
- **Adjacent insertions conflict.** Two contributors adding different lines at the same place in a list is a text conflict, as in git. In the 50-contributor simulation this was the most common remaining rejection ([Lessons](/lessons)).
- **Inferred reads match by name.** A change that mentions `Config` depends on every symbol called `Config` in any file; a method `Type::method` is depended on by code that names `Type`. Paths are not resolved. Member calls on values (`cache.get()`) are not references; member calls on imported modules (`lib.price()`, `fmt.Println`) are. It cannot see dynamic dispatch, reflection, or names built from strings.
- **Only an interface change makes a reader stale.** An inferred reader goes stale when a symbol's interface changes (its text without function bodies and comments: signatures, fields, constants), not when only a body changes. A body change that breaks a caller's behaviour is left to the checks. Declared reads (`zit read`) still see any change. The scripted benchmark's 21–23% false refusals were measured before this rule; not re-measured yet.
- **Five languages have symbol granularity**: Rust, Python, JavaScript, TypeScript/TSX, Go, plus Markdown by heading. Top-level items and methods (`Type::method`) are units; nested functions are part of their parent. Every other file (Java, C#, C++, Kotlin, Ruby, PHP, Swift, manifests, lockfiles) is one resource with no inferred reads, so semantic staleness is not detected for it; `zit record` says so for source files it cannot parse.
- **Imports are their own unit** (`path#(imports)`): two changes that both add imports compose when their text merges.
- **Renames are a delete plus an add.**
- **Check `inputs` are trusted**, not verified.
- Symlinks and submodules are whole-file resources. Git LFS is untested.

## Operations

- **Per-operation overhead is higher than raw git** because every git operation is a process (ADR 7). Numbers in [Benchmarks](/benchmarks).
- `zit status` computes every speculative change's status each time; its cost grows with their number.
- The checks of one verification run sequentially. Verification views keep ignored files between checks (ADR 10).
- **Each agent workspace is at a new path**, so on a compiled project every agent rebuilds the project once, and a shared build directory accumulates output for paths that no longer exist. Measured: about 1.9 GB after ten agents on a Rust project ([Lessons](/lessons)).
- **Claims are voluntary and local.** They are not replicated, and an agent that has neither claimed nor started writing is invisible. What open workspaces are writing is reused for up to 2 seconds, so a claim may be decided on a slightly old picture.
- `TMPDIR` is private per workspace; ports and other machine-wide state are shared between agents.
- Discarded changes stay in the object database until `git gc` removes them.
- A workspace orphaned by `SIGKILL` is listed, not cleaned up automatically.
- **Interactive `zit run` signals only the agent.** Run headless (no terminal on stdin), the agent leads its own process group, and whatever it started is stopped before its work is recorded. With a terminal, the agent must stay in the terminal's group to read it; children it leaves running are not stopped.
- `zit run` passes stdin through. Some agents (Codex) wait for stdin to close when it is not a terminal; use `</dev/null` in scripts.
- A workspace shares the repository's refs. Branches, stashes or tags an agent creates with git inside a workspace appear in the real repository.
- The terminal Ctrl-C path of `zit run` (delayed forwarding) is implemented but has no automated test; the non-terminal `SIGINT`/`SIGTERM` paths do.

- **No free-space check.** When the disk fills, git cannot write and agents' work is not landed (accepted states are not damaged). Seen once, in Lesson 02.
- **`[prepare]` needs copy-on-write to save space.** Without it, the install still runs, once per workspace.
- **Sandboxed agents need Zit's home.** Agents that sandbox their commands must be allowed to write to Zit's home (`~/.zit`), and only that: Zit never needs them to write the repository's git directory, whose hooks and config would let them run code outside the sandbox. The `codex` preset grants this repository's directory under it.
- **The presets let agents act without asking.** `claude` runs with `--permission-mode acceptEdits`, `autohand` with `--yes`, `codex` in its `workspace-write` sandbox. They edit only their workspace, but run whatever commands their own settings allow.
- **`zit clean` sees only what Zit can see.** It refuses while a workspace has a live `zit run` or unrecorded edits, or a clone or verification holds its lock; an MCP agent that has not written anything yet is invisible to it.
- **Liveness is a pid.** A workspace whose `zit run` died may look alive if its pid is reused.

## Not built

- No server, accounts or access control: whoever can write the repository's refs can accept. Agents using MCP cannot: `zit_accept` and `zit_discard` are offered only by `zit mcp --integrator`.
- No signed evidence. Check results fetched from a remote are not trusted unless you set `zit.trustFetchedEvidence` ([Another machine](/git#another-machine)); with it set, they are trusted without proof of who produced them.
- No batching: changes are verified and land one at a time ([Compared](/compare)).
- No CI integration beyond running `zit accept` in a job yourself ([Teams and review](/git#teams-and-review)).
- No replication protocol beyond `git fetch`/`git push` of `refs/zit/*`, and no automatic reconciliation of two machines that both moved current.
- No remote, container or VM materialisers.
- No dependency tracking on build artifacts, database schemas or runtime assumptions; resources are files and symbols.
- No automatic tracking of what an agent read. Reads are inferred from written code or declared.
- **Cost is what the agent reports.** Claude Code reports tokens and dollars, Codex tokens only, Autohand and Pi nothing yet. No way for an agent to set the intent of the change `zit run` records for it.
- **"Landed" means it composed and passed the checks**, not that it was good. Quality has been scored once, by a blind model judge ([Lessons](/lessons)), not by people.
- No shared place for a question about the task that every agent should see answered once.
- The largest run measured is in [Benchmarks](/benchmarks). Nothing larger is claimed.
