exact
AGENTS.md4.3k starsChanged 3 days agoMITView on GitHub
Building an app with Exact rather than working on it? This checkout is the version to use: Exact has no releases, tags or npm package, and an app uses the checkout by path. Make it with bun scripts/exact.mjs new <path>. A website (pages served to a browser) reads only docs/start-here-site.md; any other app reads docs/start-here.md. That guide is the only required reading (LLP 1115 D7). The rest (docs/contract-for-agents.md, docs/agent-pitfalls.md, docs/contract-grammar.md, docs/reference.md) is lookup only, by the section its table names:…
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,439 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository9 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- llp-adoptSkill
- llp-createSkill
- llp-maintainSkill
- llp-orientSkill
- llp-reviewSkill
- llp-super-refineSkill
- orchestrateSkill
- panelSkill
The file
We split this AGENTS.md into the rules it gives an agent
7 rules. About 0 are common, 5 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 13
Feedback (required when building an app): When a doc was wrong or missing, a workaround was needed, something took several tries or a …
- Distinctive: line 62
Write with clarity of mind.
- Distinctive: line 73
Before opening a PR or pushing to main, do an editing pass: reread the prose you added or changed as a reader new to the work would, and …
- Distinctive: line 89
Every source file ≤ 1,500 lines.
- Very specific: line 91
The only blocking gate is
bun scripts/gate.mjs: Run it, push, and fix what the hourly lane attributes to you. - Distinctive: line 161
Verify by running, never by grepping.
- Distinctive: line 238
Never git stash. Kill only PIDs you recorded.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Agent instructions
Building an app with Exact rather than working on it? This checkout is the version to use:
Exact has no releases, tags or npm package, and an app uses the checkout by path. Make it with
bun scripts/exact.mjs new <path>. A website (pages served to a browser) reads only
docs/start-here-site.md; any other app reads docs/start-here.md. That guide is the only
required reading (LLP 1115 D7). The rest (docs/contract-for-agents.md, docs/agent-pitfalls.md, docs/contract-grammar.md,
docs/reference.md) is lookup only, by the section its table names: do not read the long
guides front to back. docs/recipes/ answers the common questions in one short file each,
contract vocab <name> answers for any tag or property, every bun exact.mjs <verb>
--help names its flags, and apps/shelf is a whole app to grep.
Feedback (required when building an app). When a doc was wrong or missing, a workaround was
needed, something took several tries or a command confused you, record it from the app's directory:
bun exact.mjs feedback note "<what happened>". It attaches exact2's commit and the last command's exit
code, never output or code. It goes to Expo only as bun exact.mjs feedback status says (skip it under never);
EXACT_FEEDBACK=0 stops it on the machine (docs/diary.md).
Working on exact2 itself: read rules/RULES.md and rules/DEFERRED.md first; they bind and this file does not.
The design record, the LLP corpus, is private: clone expo/exact-llp into llp/, which this
repository ignores (a worktree links its checkout's: ln -s <checkout>/llp llp); there llp/1000-exact2-root.explainer.md is the map. Code and docs cite LLPs by
number (LLP 1115 D7), and a reader without the corpus learns only that the decision is recorded.
Push an LLP before the code that cites it. docs/agent-pitfalls.md lists verified
footguns in writing apps here; add to it when you hit one. Design documents under llp/research/
are the predecessor's — research, never authority.
Write the web, ship the platform
LLP 1115 (Charlie, 2026-10-09; James's "no tells"). What the author writes is CSS: the vocabulary, the layout model, the dev loop. What the author leaves unsaid is the platform's: controls, colour, type, motion, gestures, presentation, haptics, keyboard and accessibility come out as a hand-built UIKit/SwiftUI app following Apple's guidelines would have them (AppKit on the Mac, and each platform likewise). What the author writes wins. Precedence: author > platform > CSS default. One test settles a dispute: would someone who knows the platform notice? If so it is a tell, and the platform's answer wins; judge against a hand-built screen on the same OS version, not against Chrome.
So layout stays CSS (users cannot perceive it): a bare node is display: block,
box-sizing: content-box, flex-direction: row, flex-shrink: 1, and the web is the
layout parity oracle — a kernel that disagrees with a bare <div> reintroduces the
four-disagreeing-default-layers bug class the predecessor had (an unavoidable deviation is
declared in llp/1001-kernel-v1.spec.md). Names stay CSS (they are what the author writes):
object-fit, text-overflow, line-clamp, not resizeMode, ellipsizeMode,
numberOfLines; where a common reset (normalize.css, Tailwind's preflight) differs from the
raw default, its behaviour is a familiar path too (LLP 1104 D4). Unsaid presentation is the
platform's: a color a bar button only inherits from the page leaves UIKit's tint. Agents
writing apps should therefore say less — structure (a header's heading and buttons, a
tablist, an alertdialog) and leave colours, fonts and metrics to the platform.
Numeric typography
On graphical hosts, use tabular digits for numeric columns and values that change in place. Use default spacing for prose, ordinary labels and static standalone statistics. Apply it to numeric text, keeping the platform font. See the guidance and limits.
Writing
For all prose, always: comments, commit messages, guides, LLPs, issues and PR text. This
section binds (rules/RULES.md, "Agents").
- Write with clarity of mind. A reader should understand it on first reading and find nothing ambiguous.
- Say what the reader needs to know about the topic and nothing more. Do not recount history or keep a diary; an alternative not chosen earns a line when it explains the choice.
- Cite sources where they help: standard specifications, and host platform API documentation and guidelines.
- Comments should communicate information that cannot be easily inferred from the code. Judiciously omit or remove comments or parts of comments that do not clearly explain anything that is not already communicated by the code, though take care not to delete comments with meaningful marginal value.
- Before opening a PR or pushing to main, do an editing pass: reread the prose you added or changed as a reader new to the work would, and hold each line to the points above.
Working here
- Tooling runs on Bun (pinned in
package.json);bun install --frozen-lockfile. Rolldown remains the app bundler. Node and npm are not required. - The web artifacts (
app.wasm, the Markdown editor, text flow) build with a pinned nightly (WEB_TOOLCHAINinscripts/app.mjs) that builds std for size; everything else isrust-toolchain.toml's stable, which the gate and hourly lane use. That stable moves to each Rust release within two weeks, with the lints the release adds fixed or allowed in the same commit (LLP 1153.003 D6.1).build.mjsnames the install commands when the nightly or itsrust-srcis missing. kernel/tables/schema.jsonis the one declaration authority;kernel/build.rsgenerates from it. Edit the table, never generated code.- Every source file ≤ 1,500 lines. Stage (
git add -A) before running the gate; caps reads tracked files. - Writing or changing a test: read
docs/testing.md(waits, isolation, coverage, measuring). - The only blocking gate is
bun scripts/gate.mjs. Run it, push, and fix what the hourly lane attributes to you. Its warm budget after a one-crate edit is 30 s. It runs format, caps, boot, an incremental Cargo check of default members, and small Rust and Bun unit suites. Every part runs after failures and prints its time. A cold checkout must provision and compile its dependencies first. - Everything else runs hourly:
bun scripts/async.mjschecks origin/main's newest tip over all commits since its last run. It runs the full build, default-member tests, workspace check and clippy, format, caps, boot and wasm check;affected.mjsselects the other Cargo and Bun suites, app drives, macOS and UIKit XCTests, conformance and Apple platform builds. The quick difftest runs each hour; the longer semantics checks reuse passing input fingerprints. Every suite runs at least daily. New failures are bisected independently through affected commits with the failing suites and their prerequisite builds; the actual parent must pass. A probe that cannot finish names its range without assigning blame. Logs and attribution are in the lane'starget/async/, local issues and git notes (refs/notes/async,async2). - The hourly lane also installs tvOS and builds
Linux, Windows x64 and ARM64, and Weatherlight's Android APK. It needs the Rust
cross targets, Zig, pinned Hermes bundles, Android SDK/NDK and JDK.
--tier 2runs only these platform checks in a separate worktree. A cross-target compile proves compilation; presentation and input need the native hardware. - A green Cargo check proves compilation, not an app's behavior. The hourly lane
builds and drives affected apps and runs the platform tests. Use
scripts/agent.mjsor the app itself to investigate a behavior; the driver commands are below. bun scripts/affected.mjslists the test suites a branch's changes can affect (the working tree included) and the command for each;--runruns the Cargo and Bun ones, and--why <suite>says why one was selected. A suite reads its Cargo dependencies, its imports and what its tests name. Shared code that names an app or a host only builds what its caller asks for, so a Shelf change runs Shelf's tests and a Linux host change runs no XCTest. A change to Swift test files alone runs only the XCTest classes they reach (--only). A read that nothing names can escape the selection;--audit <suite>runs a suite with the units outside its inputs unreadable to look for one (docs/testing.md). Advice, not a check.- An unset
EXACT_UPDATE_TRUSTbakes development trust, which checks only an origin named byEXACT_UPDATE_ORIGIN.EXACT_UPDATE_TRUST=productionnative bakes require an authenticatedEXACT_UPDATE_RECEIPTor explicit new-streamEXACT_UPDATE_GENESIS=1(README). - An app outside this repo (one
bun scripts/exact.mjs new <path>made) builds, runs, and is driven through these same scripts withEXACT_APP_DIRset —scripts/app.mjsis the one place that knows; itsexact.mjssets it. exact2 is consumed there by path. Whatexact newwrites (itsAGENTS.md,exact.mjsverbs,app.json$schema) is LLP 1086. - The web build,
bun host/web/build.mjs <app>, makes the JS target (LLP 1071: the plan compiled to one ES module over a ~20 KB runtime,host/web-js); what it refuses fails the build. A game builds the wasm target (LLP 1071 §8), and--wasmis the internal flag for the uses below. The dev loop, the agent's web host, the smoke's app drive and metrics run what the build makes: on the JS target an edit rebuilds and reloads the page, carrying compatible state and, while the logic is unchanged, settled answers. A native client opening the dev URL is forwarded to the resident loop's producers (dev.mjs --wasm, started at its first request). Delivery bakes the web crate without its wasm for the native streams and publishes the JS build of that bake's plan as the web root; the smoke's bare-plan fixtures and conformance's oracle stay--wasm(LLP 1071 §7, "Retiring the wasm target on the web"). - The dev loop is
bun host/web/dev.mjs: editapps/caltrain/app.contractor its data crate, the page rebuilds and reloads (--wasm: the resident loop restarts the plan in place in ~20 ms).bun scripts/metrics.mjsprints every number (--longadds the macOS build and boot, and the loop's own budgets: the warm gate, touch one line, test what you changed;--web-bytesprints only the bytes each web app ships against its budget, in seconds, before and after a cut). macOS:bun host/apple/build.mjs --run; iOS:bun host/apple/build.mjs --ios --run(a simulator;--simorEXACT_SIMpicks one); tvOS:bun host/apple/build.mjs --tvos --run(an Apple TV simulator; LLP 1008 §9;--tvos --no-installcompiles it with none, which the hourly lane runs after a change to Swift it shares with iOS);--device --runon a connected iPhone (signed with a team profile on this Mac);--hostalso builds the sample host (LLP 1031 D10), the native app that embeds two sessions, whichbun scripts/smoke.mjs hostdrives andscripts/agent.mjs host --session a …addresses;--ios --hostis the same fixture on a simulator, driven bysmoke.mjs host-iosandagent.mjs host-ios. The Swift is one package,host/apple/Package.swift:ExactKit(session, view, app owner — what an embedder links) and the executables as adapters over it.apps/<name>/app.jsonis the app manifest (LLP 1030 D2): the bundle id, name, host files, and deploy policy come from it, never from a crate name. - The hourly lane runs
cargo run -p contract-difftest -- quickand the longer Contract semantics checks (semantics/README.md). Non-default crates and hosts run their affected tests there too; a local full-workspace build is not a gate. - Verify by running, never by grepping. Fix loops get three rounds, then stop and say so.
- Land it (LLP 1176; Charlie, 2026-11-14: "just land stuff, we can fix it later if it breaks
something"). When your change passes the gate on your own tree, merge it yourself, at
once, as a squash, and fix forward what it breaks. Do not hold it for a main that moved
during the checks, for a failure main already has (say so where its owner will see it), or
for a second pass after a rebase with no conflict. A pull request that
rules/RULES.mdsays needs a human's approval still does. Give each change in flight its own warm worktree. - To see a change work, drive the app:
bun scripts/agent.mjs <web|macos|ios|linux> tree "tap change-station" "type station-search Palo" "clock +60000" state logs "screenshot out.png"— the ten operations of LLP 1012 and LLP 1079 (perf: a subtree's work by plan site,perf <target> during "<op>" …for the difference a drive made, andperf frames,perf frames live <ms>for a game's frame pacing; a development build writes a trace on ⌥⌘T (macOS), ⌥⇧T (web), the dev menu's Save Trace (iOS) orSIGUSR1(macOS, the iOS simulator, Linux), whichbun scripts/agent.mjs trace <file>reads,trace --pid <pid>asks a running app for, andtrace --phonecopies off a phone;--plan <dir>joins another build's source map), the same on every host, with the clock in your hands (clock settleinstead of waiting;"screenshot out.png over 600 every 50"films motion on it as a contact sheet,.apngto play). The driver refuses a build older than its sources and names the rebuild (LLP 1012.001.000).bun scripts/smoke.mjs <web|macos|ios|linux|host>is the whole app driven that way. The Linux host (cargo build --profile host-dev -p caltrain-linux: a development build, asbuild.mjsmakes for Apple;--releaseis the one that ships) runs headless anywhere, macOS included.host-devcompiles incrementally unless the shell exportsCARGO_INCREMENTAL=0, which a hand-run cargo obeys (a touched kernel line is then 17 s, not 6) andbuild.mjsoverrides, saying so. - The terminal host (LLP 1101):
cargo build --profile host-dev -p harness-terminal, then./target/host-dev/harnessruns the coding harness in this terminal (inline;--fullscreenfor the alternate screen), orexact-terminal <entry.contract>any terminal entry. After--driveit runs the operations headless (--size 80x24 --drive type prompt "hi" key Enter until "…" print); headless, the frames go into a terminal emulator (vt100) andprint,screenshotread its screen (print --allthe scrollback,documentthe whole laid-out document). With--print,--json, or a pipe on stdin or stdout, an entry runs once and exits (LLP 1101.003:harness --print --prompt "…",exact-terminal apps/todo/terminal.contract --json /done); the other words are its location (--help). Develop it inhost-dev: a debug build lays out a long document hundreds of times slower.exact-terminalis indefault-members(tests/it/screen.rsdrives inline mode through the emulator);harness-datais not, so the hourly lane runscargo test -p harness-datawhen the harness changes.examples/replay.rsreplays a recorded session through the same emulator. The LLP reader is the other terminal app (LLP 1101.004):cargo build --profile host-dev -p llp-terminal, then./target/host-dev/llp [llp/ or a document]. - Delivery (LLP 1030.000):
bun scripts/deploy.mjs <app> [--origin <dir>]prints the classifier's table (a dry run);--yespublishes the web root and signed bundles per stream throughscripts/origin.mjs;keygen <id>makes a signing key (the private half never enters the repo).bun scripts/smoke.mjs deploydrives it; on a Mac it signs production macOS Rust modules, so setEXACT_RUST_SIGN_IDENTITYto an identity listed bysecurity find-identity -v -p codesigning(an Apple Development one does). Its first deploy builds every release bundle cold; the rest reuse that cache. A native host opens its update store at launch and checks after first pixel (EXACT_UPDATE_ORIGIN=<url>points a dev build at a directoryserve.mjsserves;state.deliveryshows what it did).bun scripts/push.mjs <app> [--watch]publishes an edit to installed release binaries as a signed update in about a second, from the stream a deploy or a production build started;deploy.activate: "immediate"applies it while the app is open. A channel's origin"appdrop"is AppDrop's, named after the signing key: no account, no server. Moving a stream to a new origin, pass--seq-abovethe old origin's seq. QUEUE.mdis what would make sense to do next. Add a line when you find something worth doing; delete it when it lands. It decides nothing.- An app under
apps/keeps a diary, as an appexact newmade does (docs/diary.md, "What to keep": the header, then Rough, Lean in, Needed and Checkpoints). Write it as you work, atapps/<app>/diary/<YYYY-MM-DD>-<topic>.md, and commit it with the change: it is how the team sees where building on Exact was rough, including what you fixed in exact2 to get past it. The app's name may appear; secrets and personal data may not. Nothing is sent: the repository is the record. - Each worktree builds into its own
target/: never symlink or share another checkout's (the scripts refuse); a privateCARGO_TARGET_DIRoutside every checkout is fine. What a development Apple build takes from the machine instead: the host's two Rust modules, by the SHA-256 of every input (~/.cache/exact/apple-modules,host/apple/modules.mjs), and, into atarget/that has compiled nothing, the registry crates another build compiled and, for an app, the checkout's own crates another app of the checkout compiled, which Cargo then accepts or not by its own fingerprints (~/.cache/exact/apple-crates,host/apple/crates.mjs). A development web build takes the compiler and the leaf wasm modules the same way (~/.cache/exact/web-modules,host/web-js/module.mjs;bun host/web-js/module.mjs --prebuildwarms a builder for its checkout's sources). Deleting any of these directories only costs the next first build its time. - Never
git stash. Kill only PIDs you recorded. Agents remove apparatus freely and add none without a human saying so. - Optional capability is a separate artifact loaded on demand (the GPU module) or another executor (the browser, for motion on the web) — never a cargo feature on a core crate. Each crate depends on strictly less than the one above it; there is no build matrix.
The Snapback client (snapback4/) is not in this repository, and Exact works without it: an app that
asks for Snapback is told the client is missing. A checkout that has it there uses published
snapback4@0.4.33 and the matching immutable Rust revision in snapback4/Cargo.toml; rebuild an
app’s device with bun exact.mjs snapback --rebuild after changing these pins.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

