Variables and secrets
Reusable tokens substituted into your tools at call time, including secrets that stay encrypted in the vault and never reach the model.
A variable is a named value you write once and reuse anywhere a tool
makes an HTTP request. You reference it with a {{token}}, and the runtime
swaps in the real value when the agent makes the call.
Variables keep configuration out of your prompt and tool definitions, let you
change a value in one place instead of editing every tool that uses it, and give
you a safe home for credentials that must never leak.
There are two reasons to reach for a variable:
- Reuse. If three tools all call the same booking system, put the base URL
in
{{booking_url}}once. Move to a new endpoint and you edit one value, not three tools. - Safety. An API key or token belongs in a secret variable, where it is stored encrypted and only the call-time runtime can read it. The key never sits in plain text inside a tool, and it never reaches the language model.
Variables are scoped to the agent, not to a version. They are configuration, not content, so changing one does not require a new draft of your prompt or tools.
Plain and secret
Every variable is one of two kinds, set when you create it.
- Plain. A visible value. Anyone with workspace access can read and edit it. Use plain variables for non-sensitive configuration: a base URL, an account ID, a region code.
- Secret. An encrypted value. Stored in Supabase Vault, shown as bullets after you save it, and never displayed again. Use secrets for API keys, tokens, and anything that must not leak.
A variable's kind is fixed once it is created. If you picked the wrong one, delete the variable and add a new one with the kind you want.
Add, edit, and delete
The Variables section lives under your agent, in the editor's left rail. Each variable has three fields:
- Name. Lowercase snake_case, starting with a letter, 64 characters or
fewer (for example
booking_urlorcalendar_api_key). This is the name you put inside the{{token}}. - Reference. A read-only, click-to-copy display of the
{{token}}you paste into a tool. For a variable namedbooking_urlit reads{{booking_url}}. - Value. The plain text for a plain variable, or the secret you paste for a secret variable.
To add one, use the plus control above the list or the "Add variable" row at the bottom, fill in the fields, and save. To edit a plain variable, select it, change the value, and save. To remove one, open its menu and choose Delete.
Deleting a variable does not clean up the tools that reference it. Any tool
still using {{the_deleted_name}} keeps the literal placeholder in its request,
which sends a broken URL and fails the call. Update or remove those tools first.
How secret storage works
Secrets are built so the value goes in and is never readable again, by anyone or anything except the call-time runtime.
- Encrypted at rest. A secret's value is stored in Supabase Vault. The variable row holds only a pointer to the encrypted entry, not the value itself.
- Write-only in the UI. Once you save a secret, the editor shows that it exists but never re-displays the value. When you edit a secret, the value field starts empty. Type a new value to rotate it, or leave the field blank to keep the current value unchanged. Saving a blank value is a no-op, not an erase.
- Read only by the runtime. When a call starts, the runtime fetches the
decrypted secret values server-side, with elevated access, purely to fill in
the
{{token}}references in your tools. Nothing in the browser ever sees the decrypted bytes.
Secrets never reach the model
The language model that runs your agent never receives a secret's value. Secrets are decrypted at call time only to be substituted into a tool's URL or headers, which the model does not author. The model writes the tool's request body, but the substituted secret lives in the URL and headers, out of its reach. A secret cannot be leaked through a transcript, an answer to the caller, or the Builder Chat.
Using tokens in tools
You write a {{token}} anywhere in a webhook tool's request: the URL, a header
value, a param, or the body. At call time the runtime substitutes the value. A
typical pattern is a base URL plus an auth header:
GET {{booking_url}}/slots?date={{$today_iso}}
Authorization: Bearer {{calendar_api_key}}Here {{booking_url}} and {{calendar_api_key}} are variables you set, and the
runtime fills them in before the request goes out.
Resolution order
When the runtime meets a {{token}} it resolves the name in this order:
- Your per-agent variable. If you have set a variable with that name, its value wins. This is the normal case.
- A platform-managed value. A small set of shared platform names resolve from a runtime setting instead of a per-agent variable. These are managed for you, hidden from the Variables list, and you will not normally create or see them.
- Leave the token in place and warn. If nothing matches, the runtime leaves
the literal
{{token}}in the request rather than sending an empty value. The request then fails fast (typically a 404) instead of silently calling the wrong endpoint, and a warning is logged. An empty substitution would be the worse outcome, so the placeholder stays put as a loud signal that a variable is missing.
To stop a missing variable reaching a live call, the publish check refuses to
publish a version whose tools reference a {{token}} that has no matching
variable. If you see the placeholder appear at call time, it usually means a
typo in the token name or a variable that was edited away from the published
version.
Renaming safely
Renaming a variable is atomic: the runtime renames the variable and rewrites
every {{token}} reference to it in one step. When you rename booking_url to
crm_base_url, the new name is applied across the agent's draft prompt and draft
tool URLs and headers together, so a reference can never be left pointing at a
name that no longer exists. The editor confirms how many references it updated.
Published versions are locked. A published version is an immutable snapshot, so if a published version still references the old name, the rename is rejected and you are asked to create a draft first, then rename. Drafts can churn freely; published snapshots stay intact.
The Builder Chat secret dialog
The Builder Chat (the AI editor that helps you build your agent) can wire tools that need authentication, but it never handles secret values directly. When a change needs a credential, it calls for a secret variable and the editor opens a passive password dialog. You type the value there, and it goes straight from your browser to the vault. The value never passes through the chat text, and the model never sees it.
So if you ask the Builder Chat to connect a tool that needs an API key, expect it to open a secure input for the key rather than asking you to paste it into the conversation. If you do paste a credential into the chat, it will redirect you to the secure dialog instead of storing what you typed.
Good practice
- Put every endpoint base URL and credential behind a variable instead of hard-coding it into a tool.
- Use plain variables for values that are safe to read, and secrets for anything you would not paste into a public channel.
- Name tokens for what they are (
{{crm_base_url}},{{calendar_api_key}}) so a teammate reading a tool can tell at a glance what gets substituted. - When you retire a variable, update or delete the tools that reference it in the
same change, so no
{{token}}is left dangling.
If you prefer to manage variables from outside the app, the same operations are available through the API and tooling described in Claude Code setup. For the bigger picture of how tools, prompts, and variables fit together, see Tools and Agents.