.env file locally, or
your platform’s secret store once you deploy.
That means agent.yaml is safe to commit, and the same package works on your
machine and in production without editing.
On this page:
- Three steps - write the value, declare the name, point at it
- Where a name goes - every key that takes one
- A secret is not a variable - two things that look alike
- What you do not declare - the names the target owns
Three steps
1
Put the value in .env
Next to
agent.yaml, in a file git already ignores:.env
unmute dev reads .env and .env.local from both the current directory
and the package directory. Neither is ever generated with values, and
neither is committed.2
Declare the name in secrets:
agent.yaml
3
Point at the name from where it is used
Never at the value. Each has its own A Python handler reads its own with
*_env field:tools/reschedule_appointment.yaml
os.environ["SALON_API_TOKEN"].build/<target>/.env.example lists exactly the values you have to
supply for that build, ready to copy to .env.
Every key a secrets block takes
One key, at the top level ofagent.yaml.
list of UPPER_SNAKE names
The environment variables the generated project reads. Each entry is a
capital letter, then capitals, digits and underscores; a lower case or
punctuated entry is refused, and so is the same name twice. Left out, the
compiler still infers the names it can see and warns that the inventory is
incomplete.
Where a name goes
Every key a seam takes
Each one holds the name of an environment variable, never a value.UPPER_SNAKE name
In
tools/<name>.yaml. The base URL of an authenticated API. A webhook tool
needs this or base_url, and the code targets read this one.UPPER_SNAKE name
In
tools/<name>.yaml. The MCP server’s address. The code targets dial the
server themselves and need it; an slng package leaves it out.UPPER_SNAKE name
Under
auth: in a webhook: or mcp: block. The bearer token or API key,
and required once auth: is written at all.UPPER_SNAKE name
On a
models: entry in agent.yaml. Points that model at your own gateway
instead of the provider’s.map of route fields to UPPER_SNAKE names
In
connections/<name>.yaml. The account behind a phone route, one key per field the route needs.map of names to UPPER_SNAKE names
In
agent.yaml. Each entry is the desk an escalation reaches, mapped onto
the variable holding its phone number.local: handler is the one case with no key: it reads
os.environ itself, so the name lives in the Python you wrote rather than in
agent.yaml. Declare it in secrets: all the same, so the inventory stays
complete.
A secret is not a variable
They look similar and they are not the same thing.What you do not declare
Some names the target supplies for you:LIVEKIT_URL and its key pair, REDIS_URL
for the phone routes that need it, the public URL and token unmute dev creates
for a local phone run. Leave those out of secrets:.
You may still have to supply some of their values when you deploy. The
generated README.md and compile-report.json list the complete set and say
who supplies each one.
Where to go next
Secrets reference
Every seam, every check, and what the generated files do with the inventory.
Going live
Moving these values into a platform’s secret store.