# Fix a blueprint problem

Every blueprint message you may see, what it means and what to do, with common questions and a glossary.

Find the message you see on this page: press Ctrl+F (Cmd+F on a Mac) and type a few of its words. Each message has what it means and what to do. The console and the command line show the same messages, because BuildBase makes them in one place. Messages that only the command line or an AI agent shows are in [their own section](#messages-from-the-command-line-and-ai-agents).

## How to read a message

In the console, problems with the file are listed in the card **Problems in the file**, each with an **Error** or **Warning** badge, then a path, then the message. The command line prints the same three parts:

```bash
npx buildbase blueprint validate
```

{/* message: cli */}

```text
error /webhooks/crm/url: Must be a full web address, like https://example.com.
```

- An **error** stops the file from being planned or applied. A **warning** does not: read it, and decide.
- The **path** says where in the file the problem is. `/webhooks/crm/url` means: in `webhooks`, in the entry `crm`, the field `url`. A number in a path is a place in a list, counting from 0, so `/app/currencies/0` is the first currency. A path of `/` alone means the whole file.
- For an unknown field, the path is the object that holds it, not the field itself.

Notes in a plan appear under the change they are about. Problems during apply appear under the step that failed.

## Problems in the file

These come from **Check file**, `validate` and the start of every plan. Nothing in your organization has changed when you see them.

### The file is not valid JSON

{/* message: os */}

```text
This is not valid JSON: Expected ',' or '}' after property value in JSON at position 19 (line 3 column 3). Look for a missing comma, quote or bracket near there.
```

The file could not be read as JSON at all. The middle of the message comes from the JSON reader, so its words can differ. It names the line and column (the character in that line) where the reader got stuck. The console also shows `Not valid JSON yet:` under the editor while you type.

1. Go to that line and column. The mistake is there or right before it.
2. Look for a missing comma between two entries, a comma after the last entry, a missing quote, or a bracket that is not closed. This file has no comma at the end of line 2, so the reader gets stuck at the start of line 3:

   {/* json: invalid blueprint */}

   ```json
   {
     "version": 1
     "app": { "name": "Acme" }
   }
   ```

3. Add the comma after `"version": 1`, and check the file again.

### The file is not one object

{/* message: os */}

```text
A blueprint must be one JSON object: it starts with { and ends with }.
```

The file is valid JSON, but it is a list or a single value instead of an object. Make sure the first character of the file is `{` and the last is `}`.

### A key appears twice

{/* message: os */}

```text
"pro" appears twice in the same object; the second one would silently replace the first.
```

The same name is used twice inside one object, so the second entry would hide the first. This often happens after a copy and paste:

{/* json: invalid blueprint */}

```json
{
  "version": 1,
  "billing": {
    "plans": {
      "pro": { "name": "Pro" },
      "pro": { "name": "Pro yearly" }
    }
  }
}
```

Give each entry its own key, such as `pro` and `pro-yearly`, or delete the one you do not want.

### The version is missing or wrong

{/* message: os */}

```text
Missing "version". Add it: it is required here.
Must be 1.
```

Every blueprint starts with `"version": 1`. Add that line after the opening `{`, or change the number to `1`.

### A field name is not known

{/* message: os */}

```text
Unknown field "nmae". Did you mean "name"?
Unknown field "colour". The fields allowed here are "name", "domain", "currencies", "workflowLimits", "notifications".
```

The object at the path has no field with that name. Field names are exact: capital letters and spelling must match.

{/* json: invalid blueprint */}

```json
{
  "app": { "nmae": "Acme" }
}
```

1. If the message says `Did you mean`, use that name.
2. Otherwise, pick one of the fields it lists, or look the object up in the [file reference](/blueprints/reference).
3. A whole section can be misspelt too, such as `biling` for `billing`.

### A required field is missing

{/* message: os */}

```text
Missing "url". Add it: it is required here.
```

The entry at the path needs that field. Add it. The [file reference](/blueprints/reference) marks each required field.

### A value is the wrong kind

{/* message: os */}

```text
Must be text in quotes, like "hello".
Must be a number, like 10.
Must be a whole number, like 10.
Must be true or false (no quotes).
Must be an object in curly brackets { }.
Must be a list in square brackets [ ].
```

The value at the path is the wrong kind of value. For example, `"enabled": "true"` is text, because of the quotes, but the field wants `true` or `false` without quotes. Change the value to the kind the message names.

### A value is not in the right form

{/* message: os */}

```text
Must be a full web address, like https://example.com.
Must be an email address, like name@example.com.
Must be a domain name, like app.example.com.
Not in the expected form. Stripe publishable key (pk_test_... or pk_live_...).
```

The value has the right kind but the wrong shape. A web address starts with `https://`. A domain name has no `https://` and no `/`. When the field has its own rule, such as a Stripe key that starts with `pk_test_` or `pk_live_`, the message adds the first sentence of the field's description. The [file reference](/blueprints/reference) describes each field.

### A value is not one of the choices

{/* message: os */}

```text
Did you mean "platform"? Must be one of: "personal", "platform".
```

The field accepts only certain values, and the message lists them. Copy one exactly. When the list is long, it ends with how many values there are, and the [file reference](/blueprints/reference) lists them all, such as every webhook event.

### A value is too short, too long or out of range

{/* message: os */}

```text
Cannot be empty.
Must be at least 2 characters long.
Needs at least 1 item.
Can have at most 10 items.
Must be 0 or more.
Must be 100 or less.
Lists the same value twice (items 1 and 2). Remove one.
```

The value breaks a limit, and the message says which. For a list, an item number counts from 1.

### A key is not allowed

{/* message: os */}

```text
"Pro Plan" cannot be used as a key here. Each key is the plan slug (cannot change after creation).
```

A key is the name of an entry in a map, such as `pro` in `billing.plans.pro`. Many keys are slugs: lowercase letters, digits, `-` and `_`, without spaces. Rename the key, for example to `pro-plan`. The message says what a key here should be.

### A name is not defined in the file

{/* message: os */}

```text
"google" is not defined in auth.methods. Add it there, or fix the name.
"email.senders.main" is not defined in this file. Add main under email.senders, or fix the name.
```

One entry names another by its key, and that key is not in the file. In the first message, an auth client lists the method `google`, but `auth.methods` has no `google`.

1. Check the spelling of the name, at the path the message gives.
2. If the spelling is right, add the entry where the message says.

### A secret is written in the file

{/* message: os */}

```text
This field holds a secret, so its value never goes in the file. Write "${env:NAME}" here, and give the value when you plan or apply.
This looks like a Stripe secret key, a real secret. Never write a secret in the file: write "${env:NAME}" here, and give the value when you plan or apply.
```

The file holds a real secret, such as a key. A blueprint is meant to be shared, so secrets never go in it. The first message is about a field that is always secret. The second is about a value that looks like a known kind of key, in any field.

{/* json: invalid blueprint */}

```json
{
  "billing": {
    "stripe": {
      "publishableKey": "pk_test_51Hxxxxxxxxxxxxxxxx",
      "secretKey": "sk_test_xxxxxxxxxxxxxxxxxxxxxxxx"
    }
  }
}
```

1. Replace the value with a name in this form, such as `${env:STRIPE_SECRET_KEY}`:

   ```json
   {
     "billing": {
       "stripe": {
         "publishableKey": "pk_test_51Hxxxxxxxxxxxxxxxx",
         "secretKey": "${env:STRIPE_SECRET_KEY}"
       }
     }
   }
   ```

2. Give the value when you plan or apply: in the console's **Values for `${env:...}`** field, or as an environment variable on the [command line](/blueprints/cli#values-for-env-name).
3. If the file with the real key was shared or committed to Git, treat the key as known to others: make a new key in that service and delete the old one.

### A name has no value

{/* message: os */}

```text
APP_URL has no value. Set the environment variable APP_URL (in the console, fill in its field), then try again.
```

The file uses `${env:APP_URL}` in a field that is not a secret, such as a web address, and no value was given. Such a value is needed to check the file. A second message about the same field, such as `Must be a full web address`, goes away once the value is set.

- In the console, type the value in the field named `APP_URL` under **Values for `${env:...}`**.
- On the command line, set it in the terminal, or add `APP_URL=...` to the file you pass with `--env-file`.

### Rules of a section

Some sections have rules of their own. A few that people meet often:

{/* message: os */}

```text
The publishable key is a live key and the secret key a test key. Both must come from the same mode of one Stripe account.
Not a Stripe secret key: it starts with sk_test_, sk_live_, rk_test_ or rk_live_.
Freemium onboarding needs a freemium plan: set billing.plans.pro.freemium to true, or pick another plan.
A credit package needs a price in at least one currency.
roles must keep the built-in role "admin".
admin cannot be the default role.
Must start with https://hooks.slack.com/.
Text messages cannot be the only second step. Allow totp too.
```

Each message says what to change. The [file reference](/blueprints/reference) explains the field it is about. Stripe keys come in a test pair and a live pair: use both keys from the same pair.

## Notes in a plan

These appear under a change in the plan. The plan itself worked: each note says what BuildBase cannot do for that one change, or what you need to do.

### More than one thing matches

{/* message: os */}

```text
More than one existing webhook endpoint matches "crm". Rename one of them in the console, or delete the duplicate, then plan again.
```

The badge is **Conflict**. Your organization has two or more things that fit this entry, so BuildBase does not guess which one you mean, and leaves all of them alone. Rename or delete the extra one in the console, then plan again.

### The key cannot read this part

{/* message: os */}

```text
The API key used here cannot read this part of the organization, so it cannot be compared. Use an owner or admin key.
```

The badge is **Cannot check**. The key's role cannot see this part of the console. Use a key with the owner or admin role: see [making an API key](/blueprints/overview#before-you-start).

### A secret has no value

{/* message: os */}

```text
Give a value for STRIPE_SECRET_KEY to create this: set the environment variable, or fill in its field in the console.
Not compared: secretKey (STRIPE_SECRET_KEY is not set). Give this value to compare it.
```

The first note is on a **Blocked** change: the thing does not exist yet, and it cannot be created without its secret. The second is on something that exists: BuildBase keeps the secret already saved, and does not compare it. Give the value if you want to set or change the secret. Otherwise, leave it empty.

### Removed from the file, but not deleted

{/* message: os */}

```text
Created by this blueprint and removed from the file. List "webhooks" in policy.prune and apply with prune to delete it.
Webhook endpoint cannot be deleted through the blueprint; remove it in the console.
```

You removed an entry, and the thing it made is still in your organization. Nothing is deleted unless you allow it in two places: see [prune](/blueprints/file-format#prune-deleting-what-the-file-no-longer-lists). The second note means this kind can never be deleted by a blueprint: delete it in the console if you want it gone.

### A step only you can take

{/* message: os */}

```text
After it is added, publish the DNS records apply lists for mail.acme.example, then verify it in Messaging > Sender accounts > Domains.
Connect the Gmail account in the console: Messaging > Sender accounts, then connect the Google account. It needs a browser sign-in, so a blueprint cannot do it.
Currencies cannot be removed, so eur stays. Add it to app.currencies to silence this.
```

The badge is **You do this step**. Apply skips these, and the note says what to do. Adding DNS records and connecting Gmail are explained in [what a blueprint cannot do](/blueprints/file-format#what-a-blueprint-cannot-do).

### What was sold cannot change that way

{/* message: os */}

```text
Add-on "extra" is published, so its shape stays "recurring": buyers hold grants written from it, and every version of an add-on shares it. Sell "lifetime" as a new add-on under another key, and take this one off sale (archive it in the console, or list "billing.offers" in policy.prune and remove it from the file).
A coupon named "Launch 20%" exists (co_123) with other terms (percentOff 25, the file says 20). A coupon's terms never change. Give this one another name to make a new coupon, or write the existing terms.
Promotion code LAUNCH20 exists with other maxRedemptions, and a code's restrictions never change. Use a new code, and switch this one off (active: false).
```

The badge is **Blocked**, and nothing is written. People already bought this, or hold it, so the change would alter what they have. The note says what to do instead: usually a new add-on, coupon or code under another key or name. See [versioned billing](/blueprints/file-format#versioned-billing).

### A move waits for confirmation

{/* message: os */}

```text
12 holders of v3: a move waits for confirmation in the console after this publish (https://console.buildbase.app/dashboard/admin/subscriptions/plans/<id>/moves). versionMoves is "gains" (30 days of notice before a loss); the blueprint never starts, confirms or cancels a move.
Holders not counted (this credential may not read them): a move this publish makes waits for confirmation in the console (https://console.buildbase.app/dashboard/admin/subscriptions/offers). versionMoves is "all" (30 days of notice before a loss); the blueprint never starts, confirms or cancels a move.
```

`versionMoves` is on, so publishing the new version makes a move for the people who hold the version it replaces. Apply publishes, and nobody moves until an admin opens the move in the console, checks its preview and confirms it. When the holders could not be counted, the move still waits in the same way. See [version moves](/blueprints/file-format#version-moves).

### The plan was not made

{/* message: os */}

```text
The blueprint has problems, so nothing was compared. Fix the errors above, then plan again.
```

The file has errors, listed above this line. Fix each one, as this page explains, then plan again.

### Nothing to change

{/* message: os */}

```text
No changes. The organization matches the blueprint.
Nothing to apply: this organization already matches the file.
```

Your organization already looks the way the file describes. There is nothing to apply.

## Problems when you apply

### The plan changed before apply

{/* message: os */}

```text
This organization or the file changed after that plan was made, so nothing was applied. Plan again, review the new plan, then apply it.
Nothing was applied.
```

Between your plan and your apply, someone changed your organization, or the file or its values changed. BuildBase refuses, so that only a plan you have read is applied. Nothing changed.

1. Plan again: press **Plan changes**, or run `plan`.
2. Read the new plan.
3. Apply it.

### Apply stopped

{/* message: os */}

```text
Apply stopped
Recheck: still different afterwards:
```

One step failed. Apply stops there: the steps before it are **Done** and stay done, and the steps after it are **Not run**. The failed step shows the message of the console screen that would have made that change, as if you had clicked it yourself. The number before it, on the command line, says what kind of refusal it was:

| Number | What it usually means                              |
| ------ | -------------------------------------------------- |
| `400`  | The value was refused. The message names the field |
| `402`  | Your BuildBase plan does not include this feature  |
| `403`  | The key's role may not make this change            |
| `409`  | Something with that name or address already exists |

1. Read the failed step's message and fix the file, or the setting in the console.
2. Plan again. The plan shows only what is still left to do.
3. Apply again.

### Another apply is running

{/* message: os */}

```text
A blueprint is already being applied to this organization. Wait for it to finish, then plan again.
```

Only one apply runs for each organization at a time, so two runs never create the same thing twice. Wait until it finishes, then plan again: the first apply may have changed what your plan should be.

### A value shown once

{/* message: os */}

```text
Store the client secret from this apply result: it is not shown again (rotate it in the console if lost).
Store the signing secret from this apply result: it is not shown again (rotate it in the console if lost).
```

The apply made a value that is shown only this once. In the console it is in the **Copy these now** dialog. On the command line it is in `.buildbase/blueprint-outputs.json`. Store it in your password manager or secret store. If it is lost, make a new one in the console: you cannot see the old one again.

## Messages in the console

### A request did not go through

{/* message: os */}

```text
Could not check the blueprint
Could not plan the blueprint
Could not apply the blueprint
Could not get the current setup
Could not download the schema
Could not read the file
```

The request did not reach BuildBase, or BuildBase refused it. The line under the title gives the reason. Check your connection and try again. If the reason is a refusal, check that your role is owner or admin.

### The file has problems

{/* message: os */}

```text
The file has problems
3 to fix, listed below.
```

**Check file** or **Plan changes** found errors. They are listed in **Problems in the file**, and the sections above explain each one.

### Apply is turned off

{/* message: os */}

```text
Apply turns on after you plan the file and the plan has changes.
Only an owner or admin can plan and apply a blueprint.
```

**Apply** works only on the plan you made last, and only when that plan has changes. Changing the file, a value or the delete switch clears the plan, so plan again after each change. If you see the second message, ask the owner or an admin of your organization to plan and apply, or to give you the admin role.

### The copy button did not work

{/* message: os */}

```text
Could not copy
Select the text and copy it yourself.
```

Your browser did not allow the copy. Select the whole value in its field, copy it with Ctrl+C (Cmd+C on a Mac), and paste it into your secret store.

## Messages from the command line and AI agents

These come from the command line or the AI agent server, which are part of the SDK, so their words can change with a new SDK release. The command line starts each one with `buildbase:`.

### A variable is not set

{/* message: cli */}

```text
buildbase: BUILDBASE_API_TOKEN is not set. Set it to an API key of this organization, the whole <orgId>:<secret> value. Create one in the BuildBase console under Settings, API keys, with the owner or admin role.
buildbase: BUILDBASE_SERVER_URL is not set, so there is no server to talk to. Set it to the BuildBase API address, for example https://api.console.buildbase.app, or pass --server-url <url>.
BUILDBASE_API_TOKEN is not set in this MCP server's environment.
```

Set both variables in the same terminal window before you run the command: see [set the two variables safely](/blueprints/cli#set-the-two-variables-safely). For an AI agent, the message goes on to show where to add them: put them in the server's `env`, as on the [AI agents page](/blueprints/ai-agents).

### An AI agent's value was not read

{/* message: cli */}

```text
Not read, so not sent: STRIPE_SECRET_KEY. This MCP server reads a variable from its own environment only when BUILDBASE_BLUEPRINT_ENV lists its name, and never a BUILDBASE_* one, because the agent writes the blueprint. To use one, add its name to BUILDBASE_BLUEPRINT_ENV where this server is configured (claude mcp add buildbase -e BUILDBASE_BLUEPRINT_ENV=NAME,OTHER ...), or put NAME=value in an envFile inside this folder.
```

The blueprint names a `${env:NAME}` that the MCP server did not read, so a plan shows it as not set. Setting the variable is not enough: list its name in `BUILDBASE_BLUEPRINT_ENV` too, beside the value in the server's `env` (comma separated for several), and restart the server. See [the AI agents page](/blueprints/ai-agents#set-it-up-in-another-mcp-client).

### The server cannot be reached

{/* message: cli */}

```text
buildbase: Could not reach the BuildBase server at https://api.console.buildbase.app: nothing answered at that address (connection refused). Check BUILDBASE_SERVER_URL and that the server is running.
buildbase: The server has no blueprint API at that address (HTTP 404, not found). Check that BUILDBASE_SERVER_URL is the BuildBase API address (for example https://api.console.buildbase.app), not the console or a website. A server from before blueprints answers the same way.
```

The address in `BUILDBASE_SERVER_URL` is wrong, or nothing answers there. The end of the first message says why, such as `the host name was not found`. Use the API address, which on BuildBase's cloud starts with `https://api.`, not the address of the console. A self-hosted server needs a version with the blueprint routes.

### The key was refused

{/* message: cli */}

```text
buildbase: The server did not accept the API token (HTTP 401, not signed in). Either the key is wrong or no longer active, or its role is not owner or admin, which blueprints need. Check that BUILDBASE_API_TOKEN holds the whole key, <orgId>:<secret>. Create one in the BuildBase console under Settings, API keys, with the owner or admin role.
buildbase: The API token is not allowed to do this (HTTP 403, forbidden). Blueprints need an API key with the owner or admin role. Create one in the BuildBase console under Settings, API keys, with the owner or admin role.
```

1. Check that you pasted the whole key: the organization ID, a colon and the secret.
2. In the console, open **Settings**, then **API keys**, and check that the key is active and has the owner or admin role.
3. If in doubt, make a new key and set `BUILDBASE_API_TOKEN` again.

### A file cannot be read

{/* message: cli */}

```text
buildbase: cannot read buildbase.blueprint.json: there is no such file. Create it, name another file (buildbase blueprint plan <file>), or run "buildbase blueprint export --out buildbase.blueprint.json" to start from the organization as it is now.
buildbase: Cannot read the --env-file file .env.staging: there is no such file. Check the path, or leave --env-file out to use only the environment.
node: .env.staging: not found
```

The file is not in the folder the terminal is in, or its name is spelt differently. Move to the folder that holds the file, or give its full path. The last message comes from Node.js 20 and 22, which read `--env-file` themselves and stop, with exit code `9`, before the command starts. It means the same thing: check the name of the `--env-file` file.

### Apply did not run

{/* message: cli */}

```text
buildbase: nothing was applied. apply asks you to type "yes" first, and there is no terminal here to ask in. Check the plan above, then run the same command with --yes.
buildbase: nothing was applied (the answer was not "yes").
```

The first message: apply runs where nobody can type `yes`, such as CI. Read the plan it printed, then add `--yes` if you want it to apply without asking. The second message: the answer was not `yes`, so nothing changed.

### Apply stopped at a failed step

{/* message: cli */}

```text
buildbase: the apply stopped at a step that failed (marked FAIL above). The steps before it were applied. Fix the cause, then run plan to see what is left.
```

See [apply stopped](#apply-stopped): the line marked `FAIL` above it gives the reason.

### The outputs file is in the way, or could not be written

{/* message: cli */}

```text
buildbase: .buildbase/blueprint-outputs.json already exists and is not a blueprint outputs file, so nothing was applied (saving the values an apply shows only once would overwrite it). Move that file, or choose another with --outputs.
buildbase: The changes were applied, but the values shown only once (for webhooks.crm) could not be saved to .buildbase/blueprint-outputs.json: permission denied. They cannot be shown again: create new ones in the BuildBase console (rotate the webhook signing secret, client secret or API key).
```

The first message: nothing changed. Move the other file, or name another outputs file with `--outputs`. The second: the changes were made, but the values shown only once are lost. Make new ones in the console, such as a new webhook signing secret, then fix the folder's permissions before the next apply.

### A file would be replaced

{/* message: cli */}

```text
buildbase: buildbase.blueprint.json already exists, so nothing was written. Pass --force to replace it, or choose another file with --out.
```

`export` or `schema` would write over a file that exists. Choose another name with `--out`, or add `--force` to replace it.

### The command was not understood

{/* message: cli */}

```text
buildbase: Unknown blueprint command "deploy". Use one of: validate, plan, apply, export, schema, mcp.
buildbase: Unknown option: --dry-run
buildbase: --server-url must be a full address that starts with https:// or http://, for example https://api.console.buildbase.app.
buildbase: Unknown command: blueprint plan
```

Check the spelling against the [list of commands](/blueprints/cli#commands) and [options](/blueprints/cli#options). These end with exit code `1`. `Unknown command: blueprint` means the SDK you ran is older than the `blueprint` commands, and that one ends with exit code `2`.

### An AI agent tried to apply without a plan

{/* message: cli */}

```text
blueprint_apply needs the planHash that blueprint_plan returned for this file. Run blueprint_plan, show the plan to the user, and once they agree, call blueprint_apply with that planHash. Nothing was applied.
```

The agent called `blueprint_apply` without the `planHash` of a plan. Nothing changed. Ask it to plan first and show you the plan: see [why apply needs the plan hash](/blueprints/ai-agents#why-apply-needs-the-plan-hash).

## Frequently asked questions

### Does a blueprint delete what I leave out?

No. Anything the file does not mention stays as it is. A thing is deleted only when the file lists its kind in `policy.prune` and you also turn prune on. See [prune](/blueprints/file-format#prune-deleting-what-the-file-no-longer-lists).

### What happens if I apply the same file twice?

The second plan finds nothing to change and says so. Applying is safe to repeat.

### Can I undo an apply?

There is no undo button. Before you apply, press **Download current setup** to keep a copy. Applying that copy later sets the fields it lists back to their old values. Things the newer apply created stay, unless you prune them, and new plan versions stay in each plan's history.

### What happens to people who already pay when I change a price?

They keep the plan version they bought. The new price applies to new subscribers. An add-on works the same way, and so does a credit package once someone holds it. With `versionMoves` on, a new version can move them, but only after an admin confirms the move in the console. See [versioned billing](/blueprints/file-format#versioned-billing).

### Does BuildBase keep the values I type for `${env:NAME}`?

The values are sent with that one request. BuildBase uses them to make the changes, and keeps what the console would keep for the same setting, such as a saved Stripe key, plus a fingerprint of each secret so a later plan can tell whether it changed. It never sends a value back in a plan or a result.

### I lost a shown-once value. Can I see it again?

No. Make a new one in the console, such as a new webhook signing secret or a new API key, and update the program that used the old one.

### Can I use one file for a test organization and the live one?

Yes. Use `${env:NAME}` for what differs, such as your app's address or your Stripe keys, and give each organization its own values when you plan and apply.

### Does it work with a self-hosted BuildBase?

Yes, when your server is a version with the blueprint routes. Set `BUILDBASE_SERVER_URL` to your own server.

## Words used in these pages

### API key

A long password that lets a program act for your organization. It is your organization ID, a colon and a secret. Make one under **Settings**, **API keys**.

### Apply

Make the changes a plan lists, then compare again to confirm the organization matches the file.

### Blueprint

One JSON file, usually `buildbase.blueprint.json`, that describes how your organization is set up.

### CI

Continuous integration: a service that runs commands for you on a schedule or when code changes, such as GitHub Actions.

### Environment variable

A named value that a terminal or a service passes to the programs it starts, such as `APP_URL`. A blueprint names one as `${env:APP_URL}`.

### Export

Write how your organization is set up now as a blueprint. Secrets are left out and named instead.

### JSON

JavaScript Object Notation: a plain text format of names and values in curly brackets, with lists in square brackets.

### MCP

Model Context Protocol: an open standard that lets an AI assistant call tools on your computer.

### Organization

Your account in the BuildBase console, with everything set up in it: sign-in, billing, email and the rest.

### Owner or admin

The two highest roles in an organization. Only they may plan, apply and export a blueprint. See your role under **Settings**, **Users**.

### Path

Where a problem is in the file, such as `/billing/plans/pro`: each part after a `/` is one step into the file.

### Plan

A list of every change apply would make. Making a plan changes nothing.

### Plan hash

A short code that stands for one plan. Apply compares it with a plan made at that moment, and refuses if they differ.

### Prune

Delete what the file no longer lists. Off unless the file allows it in `policy.prune` and you also turn it on.

### Publish

Make a new version of a plan, pricing group, collection or workflow live. `policy.publish` decides whether apply does it.

### Schema

The description of every field a blueprint may hold, which code editors and AI agents use to check the file.

### Secret

A value that must stay private, such as a password or a key. A blueprint never holds one: it holds `${env:NAME}` instead.

### Shown-once value

A value BuildBase makes and shows only once, right after the apply that creates it, such as a webhook signing secret, a new API key or an auth client secret.

### Validate

Check the file on its own, without your organization. It changes nothing.

### Version

A saved state of a plan, pricing group, collection or workflow. A change makes a new version, and the old ones stay, so subscribers keep what they bought.
