# 08 — Project structure: the writeonce monorepo Canonical map of the repository: what every root directory is and who writes to it. Companion to [`CLAUDE.md`](../CLAUDE.md) (working rules), the status board ([`00-status.md`](stories/00-status.md)), and the story arc ([`stories/language-runtime-database/00-story.md`](stories/language-runtime-database/00-story.md)). writeonce is **one compiled language, one runtime, one embedded database, one binary**: OCaml `woc` compiles `.wo` source to a `.wob` image, the C `wovm` runs it, and `woc ` bakes the two into a single standalone executable. The prior Rust `wo` runtime was removed 2026-08-18 (see [`plan/discarded.md`](plan/discarded.md)); the tree below is only the current project. ## The one-page map ``` writeonce-all/ ├── compiler/ OCaml `woc` — lexer→parser→types→gcinfer→owner→emit; produces the compiler binary ├── runtime/ C `wovm` — the register VM that runs .wob images (src/); retired io_uring reference (wo-rt.c, bench/) ├── database/ C embedded engine — class-shaped tables, secondary indexes, typed WAL + recovery ├── tests/ corpus/ — conformance fixtures: run / compile-fail / trap / gc (+ five reserved, still empty) ├── scripts/ the corpus runner, packaging, linkcheck, and one acceptance script per sample ├── bench/ baseline.json (the db-bench gate's thresholds) + results/ + compare/ (Go+SQLite peer) ├── docs/ ALL documentation: numbered docs, stories/, plan/, examples/, guides/, superpowers/ ├── dist/ `just dist` output: writeonce--linux-amd64.tar.gz + .sha256 ├── .github/ workflows/release.yml — builds, verifies and publishes on a `v*` tag push ├── .claude/ agents/ — project subagent definitions (see docs/guides/codd-subagent.md) ├── .dev/ gitignored per-developer links + reference study trees (v1 crates, colibri, llama-cpp) ├── justfile task runner: woc-/wovm-build, the *-test gates, oop-accept, dist, install-accept ├── VERSION single-sourced toolchain version (stamped into woc/wovm; asserted by `just dist`) └── README.md the getting-started front door (also the writeonce.de landing content) ``` `target/` and `.vscode/` are local build and editor state, not part of the project layout. ## Root directories in detail ### `compiler/` — the OCaml `woc` compiler ``` compiler/ ├── dune-project ├── README.md orientation: pipeline map, build/test commands ├── src/ one module per stage: diag, token, lexer, ast, parser, │ types, gcinfer, owner, emit, disasm, dump ├── bin/main.ml the woc executable — check / build-from-manifest / --emit / │ build / version / --update-deps / the --dump-* modes / -D └── test/ golden runner + golden/ fixtures per stage (tokens, ast, owner, owner-err, bc) + fixtures/driver/ CLI-smoke cases ``` The compiler-track plan docs live under [`plan/compiler/`](plan/compiler/architecture.md) in this `docs/` tree, not inside `compiler/` — the repo rule below applies to the compiler like everything else. Doctrine: OCaml stdlib only — no Menhir, no ppx, no opam libraries; handwritten lexer and recursive-descent parser. Build: `just woc-build`; gate: `just woc-test`. Architecture map: [`plan/compiler/architecture.md`](plan/compiler/architecture.md). ### `runtime/` — the C `wovm` VM The register interpreter that loads and runs `.wob` images, plus the arena, inferred GC, and the systems stdlib (`fs`/`time`/`env`/`net`/`proc`/`json`). `runtime/src/main.c` also reads an image embedded in its own binary (`/proc/self/exe`), which is how `woc build` produces a standalone executable. `wo-rt.c` + `bench/` are the phase A–F io_uring event-loop reference that fed the design (see [`plan/exploration/c-runtime/00-plan.md`](plan/exploration/c-runtime/00-plan.md)). Doctrine: C11, libc only, direct syscalls; computed-goto dispatch with `-DWO_ISO_C` fallback; ASan/UBSan gates. Build: `just wovm-build`; gate: `just wovm-test` (both dispatch flavors + `cli_smoke`). ### `database/` — the embedded engine Statically linked into every `wovm` (and every test binary) — one binary, no separate database process. Class-shaped row slabs, an open-addressing id hash, secondary-index multimaps with `@unique` enforcement, foreign-key restrict, and a typed write-ahead log (`len|crc|payload|mark`, ack-after-fsync, torn-tail drop, boot replay). Every class is a table; durability is opt-in via `WO_DATA`. See `database/src/CODE-LOGIC.md`. The query surface that drives it lives in the compiler (`emit.ml`), lowered to engine builtins — no SQL text in the image. ### `tests/`, `scripts/` - `tests/corpus/` — the conformance spine. Four directories carry fixtures: `run/` (60), `compile-fail/` (46), `trap/` (5), `gc/` (2). Five more — `actor/`, `db/`, `lang/`, `sys/`, `sample-logwatcher/` — are reserved slots from the original plan and still **empty**; see [`tests/corpus/README.md`](../tests/corpus/README.md) for which plan each was to be filled by. Exact-outcome matching: byte-equal stdout, exact `WO-E###`, exact trap code. Driven by `scripts/oop-e2e.sh` (`just oop-e2e`). - `scripts/` — the corpus runner (`oop-e2e.sh`) and `single-binary-smoke.sh`; packaging (`mkdist.sh`, `install-accept.sh`); the docs gate (`linkcheck.py`); the benchmark campaign (`db-bench.py`); and one acceptance script per sample — `employee-accept.sh`, `log-watcher-accept.sh`, `web-app-accept.sh`, `site-accept.sh`, `fibers-accept.sh`, `db-actor-accept.sh`, `deps-accept.sh`. ### `docs/` — all documentation ``` docs/ ├── 00-*.md, 01-problem.md, 08-*.md principles / code-review / dependency-graph / │ link-audit / doc-audit / problem / structure ├── stories/ 00-status.md (the board) + board-views.md + │ the canonical iteration arc (language-runtime-database/, │ FLAT — status lives in each story's frontmatter) ├── active-slice-*.md the live slice's one marker doc, deleted when it lands ├── guides/ runbooks: releasing, language-surface, subagents ├── examples/ 13 sample projects, 8 of them wired to a `just` recipe ├── plan/ compiler/ plans, oop-vm/ contracts, exploration/ studies, │ perf-targets.md, discarded.md + learnings.md registers └── superpowers/ specs/ (approved designs) + plans/ (implementation plans) ``` Repo rule: documentation belongs here; code directories keep one orientation README each. ### `.dev/` — developer-local + reference Gitignored per-machine tooling state plus `reference/` study trees: the v1 `wo-*` crates workspace, `colibri`/`llama-cpp` vendored studies, and `linux/`/`go/` source symlinks. Read-only; nothing here is built by the main gates. ## Build & test flow `just woc-build` + `just wovm-build` produce the two binaries; `just oop-accept` runs the full milestone gate (compile-time budget, conformance corpus under ASan, single-binary smoke, both unit gates). Sample acceptance: `just employee` (database), `just log-watcher` (systems stdlib), `just web-app` and `just site` (the framework consumed through `[deps]`), `just fibers` and `just db-actor` (the concurrency arc), `just deps-accept` (the package manager), `just db-bench` / `db-bench-quick` (the benchmark campaign, gated against `bench/baseline.json`). Docs gate: `just linkcheck`. Packaging: `just dist` → `writeonce--linux-amd64.tar.gz`, proven by `just install-accept`; publishing is `.github/workflows/release.yml` on a `v*` tag (see [`guides/releasing.md`](guides/releasing.md)). ## Naming conventions - Binaries: `woc` (OCaml compiler), `wovm` (C VM); a `woc build` / `woc ` output is named by the project's `wo.toml`. - Story iterations: `-.md`, flat in `docs/stories/language-runtime-database/`. **No directory encodes status** (directive 2026-08-26) — each story's `status:` frontmatter key is the only place state is recorded, so a status change is a one-line edit and never moves a file or breaks a link. - Plan/spec files: `YYYY-MM-DD-.md` under `docs/superpowers/{specs,plans}/`; compiler plans under `docs/plan/compiler/`; normative contracts under `docs/plan/oop-vm/`. - A project's dependencies (iteration 15): `wo.toml [deps]` declares exact-rev git deps; they fetch to `.wo-deps//` (gitignored) and pin in `wo.lock` (committed). - Sample projects live under `docs/examples//` with their own `wo.toml` and module `justfile`.