Skip to main content

Environment variables

Your workload runs with two sets of environment variables: yours, and the ones the platform sets for you.

Your own variables

Set them in the console's environment editor, or with the API:

curl -X PATCH https://api.example.com/v1/agents/my-agent/env \
-H "Authorization: Bearer $CAI_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"LOG_LEVEL":"debug","FEATURE_FLAGS":"a,b"}'

These are stored in plain text and readable by anyone who can read the workload.

:::caution Not for credentials Put secrets in the Secrets Manager and bind them, or fetch them at call time with crusoe.secret(). A password in a plain environment variable is visible on the workload's page and in its spec. :::

What the platform sets for you

Your workload also starts with variables the platform fills in — where the model endpoint is, where your vector database and memory store live, which project this is, and the credentials for each.

The console shows all of them, so there is nothing to guess at. Each one is marked either default — you can change this or set by the platform.

The four you can change

VariableWhat it is
CHAT_MODELThe chat model your agent uses
EMBED_MODELThe embedding model
MODEL_BASE_URLWhere chat completions are served from
EMBED_BASE_URLWhere embeddings are served from

Set any of these and your value wins. Leave them alone and you get the platform's, which is what almost everyone wants.

They work the same way in every framework — LangGraph, CrewAI and ADK all read these names — so pointing an agent at a different model is one setting, not a code change.

# Use a different chat model for this agent only
curl -X PATCH https://api.example.com/v1/agents/my-agent/env \
-H "Authorization: Bearer $CAI_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"CHAT_MODEL":"my-other-model"}'

To go back to the platform's value, remove the variable. Setting it to an empty string is not the same thing — that gives your workload an empty model name.

:::tip Bring your own endpoint MODEL_BASE_URL and EMBED_BASE_URL point at the platform's hosted inference. Change them and your agent calls somewhere else — your own vLLM, another provider — while everything else about the workload stays the same.

If that endpoint needs a key, bind it as a secret. MODEL_API_KEY is managed by the platform and cannot be overwritten. :::

The ones you cannot change

Everything else is set by the platform and refused if you try. The console shows each one with the reason, and the reason says what to do instead. For example:

  • MODEL_API_KEYa credential the platform manages — set your own model key on the project, or bind a Secret under a different name
  • VALKEY_ADDR, QDRANT_URL — these say where your project's data lives. A workload that could repoint them could address another project's data.
  • AGENT_NAME, CAI_PROJECT_ID — these say which workload and which tenant this is.

These are refused rather than silently ignored, so a mistake here is a clear error at the time you make it, not a confusing failure later.

Secrets, and keeping them current

A binding says "the value of secret X arrives as environment variable Y". Creating the binding records the rule; applying it delivers the value.

That two-step matters when a secret is rotated. Values are delivered to your workload when you apply, and a running instance keeps what it was given. So after you rotate a secret, the workload is still using the old value until you apply again.

The console shows this: a binding whose delivered version is behind the secret's current version is marked, with an Apply button next to it. Nothing about it is silent any more.

If you would rather not think about it, fetch the secret at call time with crusoe.secret() instead of binding it — that reads the current value on every call and needs no apply after a rotation. See Secrets in agents.