A single, portable file that captures what a project is, how it's built, and why. FAF is the schema — the fields and what they mean. YAML is the syntax —
how you write them down. Readable by humans, code, and AI assistants, .faf is the Foundational AI-context Format, registered
with IANA as application/vnd.faf+yaml.
This page covers the .faf source format and its compiled binary form, .fafb.
Two files, one source of truth
.faf— the source. Human-readable YAML.faf initcreates it,faf autoand a human complete it. The standard..fafb— the compiled form. A small, sealed binary the.fafcompiles to. The brick.
YAML is the source code; .fafb is the object file. You never edit the binary — you recompile from the .faf.
Example
A minimal .faf:
faf_version: 2.5.0
project:
name: my-app
goal: Ship a fast CLI
main_language: Rust
human_context:
who: Rust developers
what: A command-line tool
why: Speed without ceremony
stack:
build: cargo
tech_stack:
- Rust
key_files:
- src/main.rs
commands:
build: cargo build --releaseHow it's scored
A .faf is scored by counting slots. There are 33, and the list never changes — that's what makes two projects comparable.
Every slot starts empty. Three states, never a fourth:
- empty — the default. Nothing established yet.
- slotignored — not required for this
app_type. Labelled, and does not score. - populated — holds a verified fact.
app_type decides which slots are required. A CLI tool isn't asked about its CSS framework; a documentation repo isn't asked about a database. Slots the type doesn't require leave the calculation entirely — nothing is held against a project for lacking something it was never meant to have.
score = populated / active × 100 active = 33 − slotignored That's the whole calculation. No weighting, no judgement, no model. The same file scores the same everywhere, and anyone can check the arithmetic by hand.
faf-cli (MIT, free) scores 21 slots, for every app type — the whole picture for a single application. The full 33 adds twelve slots that only matter once a project becomes a monorepo or a team: how packages are organised, what orchestrates the build, how versioning and shared config work. Same file, same answer, different universe.
One caveat worth knowing: a scores block inside a .faf is a carried claim, recorded when the file was written — not a live result. A compiler copies it through unchanged. For a score you can rely on, run a scorer.
.fafb — context, compiled
.fafb is the compiled binary form of a .faf. It's modeled on IFF — the chunked format Commodore created for the Amiga in the '80s (Microsoft's RIFF and the ELF executable format use the same idea): a magic number, a set of named chunks, and a table that indexes them.
What the binary buys you:
- Two identities — a Content ID for what the AI reads, and a file digest for the whole file. Same context, same Content ID. Stamps, comments, and signatures bind to the file digest. The brick can be cached and verified without mixing those two jobs.
- O(1) lookup — the section table sits at the end of the file; a reader maps any chunk by name without scanning content.
- Prefix truncation — a shorter rendering is always a prefix of the full one. Chunks leave from the tail, whole priority tiers at a time; identity chunks always stay.
- Sealed — a CRC32 of the source
.fafis sealed into the header.
Closed canonical
The single design rule: the writer is closed, the reader is graceful.
- Writer (closed) — a compiler emits exactly the canonical chunk set, in canonical order, and nothing else. Non-canonical keys fold into the
contextchunk — preserved in full, never given a section of their own. The format has a fixed shape, the way a JPEG does. - Reader (graceful) — an unknown section name is skipped, not rejected. A future minor version can add a chunk without breaking deployed readers.
Closing the writer is what makes the brick addressable: a closed chunk set, in a fixed order. A stamp on the file never changes the Content ID.
The canonical set is 13 chunks — 11 DNA (core identity) + 2 Context — mirroring the .faf structure:
- Identity —
faf_version·project·app_type·about - Stack —
stack·tech_stack·key_files·commands - Human & structure —
human_context·monorepo·architecture - Context —
scores·context(the fold target)
The wire (v2)
A 32-byte little-endian header (magic FAFB, version, feature flags, source CRC32, and offsets), then section data in canonical order, a string table, and a 16-byte-per-entry section table at the end for O(1) access. Readers ignore unknown flag bits and skip unknown section names.
The tour → Anatomy of a Brick — nine things about those bytes, each with the run it came from.
Full specification → BINARY-FORMAT.md
Stability — wire v2 is frozen
The byte layout is immutable, enforced by a byte-exact golden-master test. New capabilities ship only as forward-compatible additions — we do not break v2. Because the .faf source is always authoritative, you recompile, never migrate. Nothing gets trapped in an old binary.
Independent writers meet on the same bytes: faf-cli (MIT, TypeScript) and the Rust compiler both hit the golden master exactly. That's a receipt against the reference fixture, earned build by build — not a theorem about every input.
Security & interop
.faf extends YAML — every .faf is a valid YAML document, so any standard YAML parser can read one; specialized parsers add validation and scoring. UTF-8, with no platform-specific path conventions in the core — portable by construction.
Treat .faf content as untrusted input. Implementations should:
- validate the YAML structure before parsing,
- sanitize file paths (no directory traversal),
- keep score and confidence values in range (0–100, 0–1.0),
- never execute code found in a
.faf.
Privacy: a .faf may carry dependencies, architecture, and workflow detail — don't put secrets in a publicly shared one.
Registration
.faf is registered with IANA as the media type application/vnd.faf+yaml (registered 2025-10-30). The IANA record is the authoritative registration; the security and interop notes above mirror its considerations. Optional parameter: version (e.g. version=1.0).
Get it
Implemented in Rust — one kernel, many shells — so the same engine runs in the CLI, the browser, and at the edge, with nothing to drift:
| Crate | What |
|---|---|
faf-kernel | parse · validate · score |
faf-fafb | the FAFb v2 binary format |
faf-rust-sdk | the facade |
faf-wasm-sdk | WASM, for the edge |
The fastest way in — one command writes (or refreshes) your .faf:
npx faf-cli autoLinks
.fafspecification — SPECIFICATION.md — the format, the 33 slots, and how a score is worked out- FAFb wire specification — BINARY-FORMAT.md — the binary container
- IANA —
application/vnd.faf+yaml - GitHub — Wolfe-Jam/faf (format) · Wolfe-Jam/faf-rust (implementation)