Write your own blueprint
Authoring a blueprint: the decisions that are yours to make, the rules the format holds you to, and the loop that gets a document right.
A blueprint is a Markdown file you write by hand. There is no compiler to install and no project to scaffold: a text editor and a project you can plan against are the whole toolchain.
Start by reading one. The documents in Examples are the reference for what a good one looks like, and the shortest of them is small enough to paste into the authoring screen as a starting point. The grammar itself — every key, every brick kind, every diagnostic code — is on Reference.
This page is about the decisions the grammar leaves to you.
#Choose the namespace parameter first
Exactly one of your parameters carries namespace: true, and every name your document
creates has to embed it. That one rule is what lets a project install your blueprint
twice without a collision, and what lets an uninstall tell your tables from the project's.
Choose it before you write anything else, because it reaches every name in the document and it cannot be changed afterwards: its value is recorded on the install, and planning with a different one produces a separate estate rather than an update.
Watch for the identities a prefix cannot reach. Some resources are not addressed by a name
you write in full — a navigation entry is addressed by its label, which is also what a user
reads — and wherever that is true the identity is still yours to make unique. So it carries
both: a parameter for the installer's own words, and the namespace parameter beside it
("${params.nav_label} (${params.prefix})"). Validation holds a nav item's label to that
rule exactly as it holds a collection's name to it.
#Ask for what you cannot know
Parameters are the questions your document asks at install time. Give each one a prompt written for the person installing, not for you, and a sensible default where there is one.
A parameter typed secret is different in kind: its value never appears in the document,
never reaches a plan, and is never written to the ledger. It may not carry a default —
a default is a stored credential — and it may not appear in seeded data.
#Group bricks into assemblies, and say what declining one costs
An assembly is a set of bricks the installer accepts or declines as one choice, and it is the unit the consent screen counts. There is no declining an individual brick, so the grouping you write is exactly the set of choices an installer gets.
Mark as required the ones without which the document means nothing, and for each optional one, say in the prose what is lost by declining it — in terms of rows and columns, not adjectives. "Decline it and see" is not a choice anybody can make.
#Order by dependency, not by position
A brick names what it needs on its own fence rather than relying on where it sits in the file. A cycle in those dependencies is refused when the document is validated rather than discovered halfway through an install, which is the failure that is genuinely expensive.
#Say accessPreset: private out loud
A collection brick has to state its access preset explicitly, and omitting it is not the same as saying private: the create endpoint would fall back to the project's default access setting, so the same document would install different permissions on different instances and the consent screen could not say which. The format refuses the brick rather than pick for you.
Then reach for grants only for what a row scope cannot express. A scope is one stored rule per collection with a single write switch; individual actions, field lists, filters and presets are grants. Both need a tick from the installer, and grants need one every time.
#Seeding rows
Seeded rows need a natural key — a column you choose, such as a slug — because a record's id is the server's and is not knowable when you write the document. Only the columns your rows declare are ever compared, so a default the create fills in never reads as a later difference. Keep each brick's rows uniform and modest in number; the exact limits and what is refused are on Reference.
#Write the prose for the person approving
The paragraphs between the bricks are not commentary. Each brick's prose is what is shown beside its tick on the consent screen, and it is the only thing a non-author reads before saying yes. Write it as "what this gives you and what it costs", and keep it next to the brick it belongs to.
#The loop
- Write, then validate. Validation reads no project state, so run it as often as you like. Every diagnostic carries a stable code; branch on the code, not the message.
- Plan it against a real project. Validation says the document is readable; a plan says what it would do to somebody's project. This is where naming collisions, missing permissions and unreachable resources show up.
- Install it, then plan it again. The second plan must be
NOOPthroughout. Anything else means the document says something different from what it created — which is the failure that teaches people to stop reading plans. - Uninstall, then plan once more. Everything should come back
ADOPT. Reinstall and you are back where you started.
Steps 3 and 4 are the exit bar the shipped examples are held to, and running them once on your own document will find more than any amount of re-reading it.
#Shipping it
A blueprint travels as its own text, or inside a zip archive carrying exactly one document and nothing else — the archive is transport, and unpacking it yields the same install, the same plan and the same hash as posting the text would. See Reference.
Whatever you ship it in, ship the README beside it: what it builds, which assemblies are optional and what declining one loses, what an update and an uninstall do to it, and what you wanted it to do and could not. That last section is the one readers thank you for.