# How Mitts works
This document describes the build and cache protocol as implemented. Each
section names the module that owns the behavior. Where the implementation has
a known gap, the gap is stated next to the rule it weakens.
## 1. Principles
1. **A cache hit needs a complete key.** Every input that can change an output
must be part of the action key. An input Mitts cannot see is a reason to
rebuild, never a reason to reuse.
2. **Shared objects are immutable.** Published store objects are read-only and
verified by hash before use. Workspaces get their own copies or reflinks.
3. **The language core is neutral.** The store, action cache, locks and GC know
nothing about Cargo. The Rust adapter turns a Cargo workspace into actions;
the C adapter does the same for `Mitts.toml`.
4. **Cargo stays the contract.** `Cargo.toml` and `Cargo.lock` are read as is.
Mitts never writes a lockfile of its own.
## 2. Pipeline
```
resolve → fetch → plan → key → execute → publish → record fast path
```
| Resolve | Reuse `Cargo.lock` when it matches the manifests; otherwise resolve against the crates.io sparse index and write a standard `Cargo.lock`. | `adapter/rust/resolver.rs`, `sparse_index.rs`, `lockfile.rs` |
| Fetch | Download missing `.crate` archives in parallel, verify their SHA-256 from `Cargo.lock`, unpack once per machine. | `adapter/rust/fetcher.rs`, `core/source_store.rs` |
| Plan | Build compilation units (lib, bin, test, build script, proc macro) with features, targets and dependency edges. | `adapter/rust/planner.rs`, `features.rs`, `target_filter.rs` |
| Key | Derive one action key per unit in topological order. | `adapter/rust/key.rs`, `core/action_cache.rs` |
| Execute | Run the unit DAG in parallel; restore hits, compile misses. | `adapter/rust/dag_runner.rs`, `dag_scheduler.rs`, `dag_unit.rs` |
| Publish | Store outputs in the CAS and record the action cache entry. | `core/cas.rs`, `core/action_cache.rs` |
## 3. Action keys
An action key is `SHA-256` over a canonical text payload:
```
toolchain: <rustc -vV>
target: <target triple>
features: <sorted feature list>
sources: <sorted (path, content hash) pairs>
deps: <sorted (dependency unit, dependency action key) pairs>
```
- **Sources.** For a registry dependency, the package files downloaded with the
package. For workspace units, input tracking is isolated at the unit level:
- *Package common inputs*: manifests (`Cargo.toml`), lockfiles (`Cargo.lock`),
applicable configs (`.cargo/config.toml`, `clippy.toml`), and package root files
(including `build.rs`).
- *Unit coarse inputs*: library and binary units track the `src/` directory;
integration tests, benchmarks, and examples track only their declared `src_path`
(or `<dir>/**` for multi-file runner suites). Editing an integration test never
cascades invalidations to sibling tests or the library crate.
- *Extra inputs*: files read by the compiler outside the unit's coarse set
(such as `tests/support/`, `#[path]` targets, `include_str!`, `include_bytes!`)
are extracted from `rustc` dep-info (`.d`) and recorded in the action manifest,
ensuring precise invalidation without over-invalidating unrelated units.
- **Environment.** `CARGO_*`, `RUST_*`, `RUSTFLAGS`, `RUSTDOCFLAGS`,
`RUSTC_WRAPPER`, `RUSTC_WORKSPACE_WRAPPER`, `TARGET`, `HOST` and `PROFILE`
enter the flags. Variables read through `env!` / `option_env!` are discovered
per unit and keyed with their values, with `<unset>` recorded explicitly.
- **Dependencies.** A unit's key includes its dependencies' keys, not their
output bytes. A change anywhere below a unit changes its key.
Workspace crates compile with `--remap-path-prefix=<workspace_root>/=` to
stabilize compiler diagnostics, `file!()`, panic locations, and debuginfo to relative
paths (e.g. `src/main.rs`), maintaining full Cargo parity and terminal/IDE clickability.
Units that do not read `CARGO_MANIFEST_DIR` at compile time, do not have a custom `build.rs`,
do not depend on a proc macro the project declared impure, and reside within the
workspace root receive path-independent action keys with `REMAP_PATH_PREFIX=relative`
and `MANIFEST_DIR_REL=<rel>`, enabling 100% cache hits across independent checkouts,
clones, and agent worktrees.
Crates that read `CARGO_MANIFEST_DIR` via `env!` / `option_env!`, define `build.rs`,
depend on a declared impure proc macro, or reside outside the workspace root
(`../shared`) conservatively retain the local absolute path in their action key.
Proc macros are pure by default. A project lists the ones that read package files or
the package path while expanding (`sqlx`, `askama`, `rust-embed`, a local derive) under
`[workspace.metadata.mitts] impure-proc-macros` in the root `Cargo.toml`
(`adapter/rust/project_config.rs`); their direct dependents are then keyed on the whole
package tree, so an edited template invalidates them, and on the absolute path.
There is no built-in list: a macro Mitts does not know is treated like any other.
As an additional defense-in-depth safeguard before publishing to the CAS, Mitts scans
all generated artifacts for the byte sequence of the workspace root path; if found, the artifact
is never published under the path-independent key.
For debuggers (`lldb`/`gdb`), relative source paths resolve naturally when running from
the workspace directory; if debugging from an external directory, target source mapping
can be configured via `settings set target.source-map "" <workspace_root>`.
## 4. Store layout
```