# Gridwillow > A text language for software architecture. You write one `.bp` file naming a > system's services, stores, queues and the data that moves between them; the > Rust compiler renders it as an interactive isometric blueprint — one > self-contained HTML file, with a hover card on every block and an inspector > behind each one. Think Mermaid, for infrastructure, in three dimensions. Gridwillow is built to be written by a coding agent pointed at a repository. Two rules carry the design: every construct is one line beginning with a keyword, and indentation is decorative — so a mis-indented generated file still parses exactly the same. Every connection must name something concrete that crosses it (a table, a route, a function, a type) or the checker rejects it. That rule is what stops a generated architecture diagram from becoming boxes joined by vibes. If you are going to read one file, read /llms-full.txt: it is every document below, concatenated, and it is enough to write a blueprint that compiles. ## Start here - [The .bp language](https://gridwillow.com/docs/language.md): The complete language reference — the two rules, the whole syntax on one screen, the eight-shape table, the six connection kinds, every attribute by scope, prose blocks and inline markup, and what the checker treats as an error versus a warning. Read this one first. - [Writing a blueprint](https://gridwillow.com/docs/writing-a-blueprint.md): The procedure to follow against a real codebase: survey before writing anything, choose 15–40 subsystem blocks, trace only the connections you can name, then let `bp check` grade the result. - [Writing the prose](https://gridwillow.com/docs/prose.md): How to write `is`, `why` and `carry` so the hover cards are worth opening. The default register of generated documentation is the wrong one here, and this page is about correcting it. - [Keeping a blueprint true](https://gridwillow.com/docs/keeping-it-true.md): The procedure for re-checking an existing blueprint against the code it claims to describe — moved paths, deleted functions, new tables — and rewriting only what actually drifted. ## Grammar and examples - [/docs/grammar.ebnf](https://gridwillow.com/docs/grammar.ebnf): The formal grammar, in EBNF. The normative answer when the prose reference and your parser disagree. - [/docs/blueprint-ir.schema.json](https://gridwillow.com/docs/blueprint-ir.schema.json): JSON Schema for the compiled intermediate form the renderer consumes. You never write this by hand; `bp build` emits it. - [/examples/payments.bp](https://gridwillow.com/examples/payments.bp): A complete, checked blueprint of a payments platform — 16 blocks, 19 connections, groups, tabs and terms. The worked example, and the file rendered on the front page. - [/examples/self.bp](https://gridwillow.com/examples/self.bp): Gridwillow’s own architecture as a blueprint — the compiler, the renderer and the app, drawn in their own language. ## Using it ``` cargo install --path crates/gridwillow-cli # the `bp` binary, from a clone bp check infra.bp # every problem at once, with line and column bp build infra.bp -o infra.json # the compiled IR bp fmt infra.bp --write # canonical formatting, in place bp export infra.bp -o infra.html # one self-contained HTML file ``` `--force` builds or exports anyway when there are errors. The desktop app (`cd app && cargo tauri dev`) redraws on every save. The compiler is the grader. `bp check` splits its findings in two: errors block a build (a connection to a block that does not exist, a dangling `[[…|id]]`, a duplicate id, a value out of range), and warnings never do but each names a way the drawing is worse to read (fewer than 15 or more than 40 blocks, a block nothing connects to, a vague `carry` like "data", a one-sentence `why`). Write, run `bp check`, fix what it reports, repeat. ## Optional - [Source, issues and releases](https://github.com/ethereumdegen/gridwillow): the repository. MIT licensed; the compiler is Rust, the renderer is three.js, and there are no runtime dependencies. - [Agent skills](https://github.com/ethereumdegen/gridwillow/tree/main/skills): `SKILL.md` files in the format Claude Code and OMP both discover. `./skills/install.sh claude` symlinks them into `~/.claude/skills/`; the same two documents are served here as /docs/writing-a-blueprint.md and /docs/keeping-it-true.md. - [A rendered blueprint](https://gridwillow.com/payments.blueprint.html): the compiled output of examples/payments.bp. About a megabyte of generated three.js scene — worth opening in a browser, not worth fetching as text. ============================================================================== # About this file Everything linked above, concatenated, in reading order: the language reference, the procedure for writing a blueprint from a codebase, the prose guide, the procedure for keeping one true, the formal grammar, and a complete worked example. Sections are separated by a line of "=". Two of these documents ship as agent skills in the repository, so they cite sibling files by relative path — `reference/language.md` is the language reference and `reference/voice.md` is the prose guide. Both are already in this file; there is nothing further to fetch. ============================================================================== # The .bp language (source: https://gridwillow.com/docs/language.md) A `.bp` file describes a software system — its servers, databases, queues and the data that moves between them — and a fixed renderer draws it as an animated isometric engineering plan you can hover and click through. Think Mermaid, for infrastructure, in three dimensions. `spec/blueprint.ebnf` is the formal grammar. `spec/blueprint-ir.schema.json` is the compiled form the renderer consumes. This file is the one to read. --- ## Two rules carry the whole design **Line-oriented.** Every construct is one line beginning with a keyword. Indentation is decorative and means nothing. A file that is mis-indented — the most common way a generated file goes wrong — still parses exactly the same. **Context-scoped.** A declaration opens a scope; the attribute lines after it attach to that scope until the next declaration. Attribute keywords are checked against the open scope, so a misplaced line is a precise error instead of data that silently vanishes. The one exception to the first rule is the block scalar, `>` and `|`, where indentation delimits the block. Prose has to span lines somehow, and this follows YAML's convention so it reads the way you expect. ## The whole language, on one screen ``` # comments are whole-line only blueprint payments-platform title The Payment Path tagline what happens between a card tap and a settled ledger row branch main stamp v4.2.0 stat Services = 11 · 3 languages stat Peak = 4,200 req/s group edge "The edge" note everything before the request is ours lb ingress "Load balancer" x1.2 is terminates TLS and picks a healthy checkout instance why > Two of them, one per zone, sharing a floating address. Health checks are shallow on purpose — a deep check took the whole pool down in March when the ledger was slow. src infra/nginx/ uses nginx num Zones = 2 group core "Core" svc checkout "Checkout" x1.5 is turns a cart into an authorised payment why Owns the state machine. Every transition is written before the call that causes it, so a crash mid-flight is recoverable. src services/checkout/ db orders "Orders" x1.4 is the ledger — every authorisation, capture and refund why > Postgres, single writer, replicas for reads. It is the only store in the system that is allowed to be the source of truth. fact Engine = Postgres 16 fact Region = us-east-1 fact Backups = PITR, 7 days list Tables = orders, order_items, captures, refunds list Indexes = orders_customer_idx, orders_created_at_idx link Runbook = https://wiki/runbooks/orders-db env DATABASE_URL PGBOUNCER_HOST topic settlements "Settlements" !planned is the queue the ledger writes to and settlement reads from why Not built yet. Settlement polls the table directly today, which is the reason the nightly job takes nineteen minutes. # ------------------------------------------------------------------ # connections # ------------------------------------------------------------------ ingress -call-> checkout "a tap" carry POST /v1/checkout {cart_id, payment_method} why The only inbound path. A 5xx here is the one alert that pages. vol 0.9 checkout -write-> orders "the authorisation" carry INSERT INTO orders (id, cart_id, state, amount_cents) why > Written before the processor is called, never after. If the process dies between the two, a reconciliation job finds the orphan by state. vol 0.8 # ------------------------------------------------------------------ # narrative # ------------------------------------------------------------------ tab what "What it does" h The Payment Path p > A card tap arrives at [[the load balancer|ingress]] and leaves as a row in [[the ledger|orders]]. Everything between is one {{state machine}}. note Hover a block for what it is. Click one for everything about it. code | curl -XPOST https://api/v1/checkout -d @cart.json term "state machine" = a set of named states and the legal moves between them ``` ## The shape table `kind` decides the geometry. There are eight shapes and that is the whole visual vocabulary — learn them once and every blueprint anyone writes is readable. What varies is the *word* you use: many domain words alias onto each shape, so you can call a thing what it actually is. | shape | drawn as | reads as | write it as | |---|---|---|---| | entrypoint | tall narrow prism | a way in | `entry` `lb` `ingress` `gateway` `cli` `endpoint` | | service | cube, vertical hatch | a thing that does work | `svc` `server` `api` `app` `worker` `lambda` `module` | | store | wide laminated slab | a place data rests | `store` `db` `postgres` `mysql` `sqlite` `cache` `redis` `bucket` `s3` `blob` `volume` `index` `table` | | queue | ribbed stack of plates | a place work waits | `queue` `topic` `stream` `channel` `buffer` `bus` `kafka` `pubsub` `mailbox` | | model | cube with a dot | a call to a model | `model` `llm` `inference` `agent` | | library | low flat plate | shared code or contract | `lib` `pkg` `crate` `schema` `config` `contract` | | external | ghost box, no fill | not yours | `ext` `saas` `vendor` `client` `browser` `mobile` `user` `cdn` | | job | small cube on a stem | runs on its own clock | `job` `cron` `timer` `scheduler` `batch` `task` | Pick the shape a reader recognises, not the one that is most technically precise. Redis used only as a job queue is a `topic`, not a `cache`. **Modifiers**, in any order after the label: - `x1.4` — visual weight, 0.5 to 2.0. Raise it for the two or three blocks that dominate. If everything is heavy, nothing is. - `@4,-2` — manual grid position. Reach for it after you have seen the render, never while writing. - `!dormant` — faded, for code that exists but is not switched on. `!planned` — a ghost outline, for what is coming. Default is active. ## The line table | kind | drawn as | use it for | |---|---|---| | `-data->` | solid hairline | a value moves from one place to another | | `-call->` | solid with arrowhead | A invokes B and waits | | `-event->` | dashed | fire-and-forget, pub/sub, webhooks | | `-read->` | fine dotted | A reads state B owns | | `-write->` | double solid, arrowhead | A mutates state B owns | | `-spawn->` | sparse dotted | A creates or launches B | Write `<-call->` for bidirectional; it changes the hover card's arrow, not the line. `vol` (0 to 1) sets packet density and speed — the only way the drawing shows where the hot path is, so spend it. A connection's id is derived as `from__to`; override it with `as` only when you need to. ## Attributes by scope | scope | keywords | |---|---| | `blueprint` | `title` `tagline` `branch` `stamp` | | top level | `stat