# Managing secrets How to give your agent the API keys and tokens it needs, stored safely per project. Canonical page: https://kortix.com/docs/guides/managing-secrets **Secrets** are private values — API keys, tokens, connection strings — that belong to a [project](/docs/concepts/projects) 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 legacy `kortix.toml`). Safe to commit — it's only a label like `STRIPE_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: ```yaml 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 all ``` `secrets` 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: ```yaml 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](#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 ` 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 ] [--force]` exports a names-only skeleton `.env` (values are never exported). See the [secrets reference](/docs/reference/secrets).