Keep a LikeC4 architecture model that describes the code as it is, the way as-built drawings describe a building as constructed rather than as designed.
asbuilt survey reads a code base and writes the .c4 model: crates as
containers, modules as components, module-to-module references as
relations labeled with the item names they reference, and the metadata
that ties every element to a path in the tree. Nothing in the model is
hand-written and nothing in the code is annotated. asbuilt check surveys
again and fails when the committed model no longer matches, so it runs as
a pre-commit hook and as a CI step. Validation, export and rendering are
LikeC4's; asbuilt shells out to a pinned npx likec4 for those and
reimplements none of it.
The core is language-agnostic, with one front-end per language. The Rust
front-end (asbuilt-rust) ships first. It is implemented in Rust so it
installs as one static binary that a pre-commit hook in any repo can
call, and so later front-ends can use Rust-native parsers without a Node
or Python runtime present.
The landing site is at https://padamson.github.io/asbuilt/, versioned
per release, and every snapshot carries this repo's own architecture
documentation under architecture/: asbuilt docs over the model that
asbuilt survey wrote for this very code base, with the views LikeC4
rendered. The site is built, driven with playwright-rs, and deployed by
.github/workflows/pages.yml (docs/versioned-site.md).
Status
0.2.0. The model, the Rust front-end, survey, check, the LikeC4
wrappers and docs, now with a viewer (a readable scale, zoom and pan,
nodes that link to their pages, edges that open the relations behind
them), are in use on this repo and on
playwright-rust. Before
1.0 a minor version may change the model's shape or the CLI, and
CHANGELOG.md names every such change; 0.2.0 changes every model with
a bin, tests or examples.
Installation
To try what is on main before it is released, cargo install --git https://github.com/padamson/asbuilt asbuilt.
survey and check need only cargo. validate, export json,
render and docs shell out to npx likec4 (Node) at the release
the badge above names, and
render and docs also need Graphviz dot; docs --no-render
reuses SVGs already rendered and needs neither.
Usage
Every subcommand takes an optional root (the current directory by
default) and --config <path>. Exit codes: 0 done or current, 1 drift or
an invalid model, 2 anything else, with the file or id in the message.
What the model says
One container per crate, one component per module nested as in the code,
a tests, an examples and a bin element per crate that has them
(each a kind of its own, so [theme] colors them apart), and one
relation per pair of modules with the referenced item names as the label
and the strongest evidence as the kind (implements, constructs,
calls, names, uses). Descriptions come from the first paragraph of
each module's //! doc. Paths resolve through pub use chains and glob
re-exports to the defining module; an edge from a module to its own
ancestor or descendant is never recorded. A macro's body counts when it
parses as Rust (assert_eq!, vec!, fuzz_target!); method calls on
values are not resolved.
Configuration
Optional asbuilt.toml at the root:
[]
= "docs/architecture/model.c4"
[]
= "playwright-rust"
= "https://github.com/padamson/playwright-rust/blob/main/"
= "../" # a link back to the hosting site on every page
[]
= "#f0a884" # the diagrams in your palette, per element kind
[]
= ["crates/site-e2e/Cargo.toml"] # crates in the repo but outside the workspace
= true
= true
[[]] # what the code cannot state
= "node_driver"
= "process"
= "Playwright driver"
= "Node.js process"
[[]]
= "playwright_rs.server.playwright_server"
= "spawns"
= "stdio"
A from that names no generated element fails the survey, so a typo is
an error rather than a missing edge. [docs] title and source_url
name the documentation tree and turn its paths into links;
home_url, home_title and stylesheet fit it into a host site.
docs replaces only the files an earlier run wrote, and refuses to
overwrite tree files it did not write unless --force. [theme]
colors each element kind in the rendered diagrams, with a light and a
dark color the docs pages switch between; a visitor can pick System,
Light or Dark in the header, and [docs] color_scheme and
scheme_toggle set the default or leave the control out. Every
diagram sits in a frame at a readable scale with Fit, 1:1, Wide and
Fullscreen controls, zooms with the wheel and Ctrl or ⌘ (or a pinch)
and pans by drag; [docs] viewer = false (or --no-viewer) leaves
the viewer and its script out. Curated views go in
a sibling .c4 file that references generated ids; asbuilt validate
catches a stale one. Rendered SVGs and the docs tree are build output:
commit model.c4 and the curated views, and ignore the rest.
Keeping it honest
# .pre-commit-config.yaml (pre-commit or prek)
repos:
- repo: https://github.com/padamson/asbuilt
rev: v0.2.0
hooks:
- id: asbuilt-check
The hook runs the asbuilt on the PATH, so install the release rev
names. It runs when a .rs file, a Cargo.toml, asbuilt.toml or
anything under docs/architecture/ changes; a model kept elsewhere
([output] path) sets files: on the hook to include its directory.
Run the same command as a CI step on every platform.
Brand
The asbuilt mark (a telescope sighting over a graduated arc) and the
AS/BUILT wordmark live in brand/, with the fonts they need
and a VERSION a copy records. A site that links to asbuilt can copy
the directory whole; its README says how each piece is used.
Agent skill
Works with Claude Code,
Codex, Cursor, and any
other compatible agent. The install copies
the skill into your repo and records its source in skills-lock.json.
Development
See CLAUDE.md for development commands.
Prerequisites
- Rust toolchain (MSRV: 1.88)
- prek for pre-commit hooks:
cargo install prek && prek install - Node (for
npx likec4) and Graphvizdot, only for the tests and commands that validate or render a model
Build and test
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.