Managing secrets
How to give your agent the API keys and tokens it needs, stored safely per project.
Secrets are private values — API keys, tokens, connection strings — that belong to a project and are made available to your agent during a session. They're stored encrypted, never written into your project's files, and provided to each session as it starts.
How a secret works
A secret has two parts in different places:
- The name is declared in your manifest (
kortix.yaml, or legacykortix.toml). Safe to commit — it's only a label likeSTRIPE_API_KEY. - The value is set separately on the project's Environment variables page. Encrypted, never in your repo.
Anyone reading your project can see which secrets it expects, but no one can read the values out of the code.
Under the hood, a stored secret is actually { identifier, key, value }. The identifier is the stable handle you (and your manifest's agent grants) refer to; the key is the env-var name the agent sees, like STRIPE_API_KEY. For most projects the identifier and the key are the same string, so this distinction is invisible — it only matters if you keep more than one value under the same key (e.g. per-environment variants), since identifiers are unique per project but keys aren't.
Which agents receive it
Setting a secret on a project doesn't hand it to every agent automatically. Each agent block in your manifest has its own secrets grant (named env in legacy kortix_version: 1 manifests — same mechanism, renamed in v2) that lists which secret identifiers it's allowed to receive as sandbox environment variables:
agents:
reviewer:
secrets: [STRIPE_API_KEY] # only this identifier
ops:
secrets: all # every project secret — the default when omitted
sandboxed-demo:
secrets: none # no secrets at allsecrets defaults to all when omitted, so most agents don't need to set it. But it's the sole authorization gate on agent secret access — a session running a scoped-down agent will not see a secret just because it's declared in env: { required, optional } and set on the project.
Add a secret
Declare the name in the manifest
In kortix.yaml, add the name under env. List it as required if the agent can't work without it, or optional if it's nice to have:
env:
required: [DATABASE_URL]
optional: [STRIPE_API_KEY, WEBHOOK_SLACK_SECRET](Legacy kortix.toml uses the same shape as a [env] table with TOML arrays.)
Set the value
Open the project's Environment variables page and enter the value for that name. It's encrypted as soon as you save.
Start a session
The next session receives every secret its running agent is granted (all by default — see Which agents receive it), read like any environment variable.
Required vs optional
- Required — flagged on the Environment variables page when missing. Use for values the agent genuinely can't work without.
- Optional — shows up so you can fill it in, with no warning if empty.
required is a contract with your team about what a project needs, not a lock. Keep the list to the values that truly matter.
Rotating a secret
Set the new value on the Environment variables page. Kortix hot-pushes it to every sandbox with an active session for that project — you don't need to end and restart a session for it to pick up the change. The sandbox's live environment refreshes immediately, and if the secret affects the model/gateway configuration, the agent process itself is restarted so it picks up the new credential too.
Under the hood
Secrets are encrypted at rest with AES-256-GCM and injected as plain environment variables into the sandbox at session boot (and hot-pushed to already-running sandboxes on rotation). Names must be env-var-shaped, and the KORTIX_* prefix is reserved for platform values. From the CLI: kortix secrets set NAME=VALUE upserts a value, kortix secrets ls lists what's declared and set, kortix secrets unset NAME removes one, kortix secrets request NAME --scope runtime|connector --expires <min> mints a short-lived link so someone else can enter a value without you ever seeing it, kortix env push --from .env bulk-uploads a dotenv file, and kortix env pull [--out <path>] [--force] exports a names-only skeleton .env (values are never exported). See the secrets reference.