Secrets
How project_secrets flow from the manifest to your sandbox.
The technical contract for secrets. For a walkthrough, see Managing secrets.
Secrets are per-project, encrypted at rest, and injected into every session as plain environment variables. They live in the platform's database (project_secrets table), never inline in your repo.
Encryption: AES-256-GCM with HKDF-derived per-project keys rooted in the platform's master API_KEY_SECRET. Rotating the master key rotates every project's effective key without re-encrypting individual records.
How they flow
-
Declare a secret name in
kortix.toml:[env] required = ["DATABASE_URL"] optional = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "WEBHOOK_SLACK_SECRET"] -
Set the value in the Kortix Secrets Manager (dashboard) — or via
kortix secrets set/kortix env push. -
When a session boots, the platform decrypts every secret on the project and injects them as plain env vars into the sandbox.
-
Your agent reads them like any other env var (
process.env.DATABASE_URL,os.environ['DATABASE_URL'], etc.).
required vs optional
| List | Effect |
|---|---|
required | Advisory. The dashboard surfaces it to nag the user about secrets to set. The session bootstrap does not currently block on missing values. |
optional | Surfaced in the Secrets Manager UI so users can set them; missing is fine. |
Treat required as a contract with the user, not a hard gate. Prefer optional for things with a sensible default-off behavior in your agent code.
Rules
- Names in the Secrets Manager match
^[A-Z_][A-Z0-9_]{0,63}$— env-var-shaped, capped at 64 chars. The manifest parser is looser (^[A-Z_][A-Z0-9_]*$, no length cap), so a name longer than 64 chars is accepted in[env]but can never get a value. Keep names ≤ 64 chars. - The
KORTIX_*prefix is reserved for platform variables; user secrets cannot use it. The Secrets Manager CRUD endpoint rejects it. The manifest parser does not enforce this, so declaringKORTIX_FOOin[env]is accepted but no matching secret can be created. Don't. - Webhook triggers reference signing secrets by name only (
secret_env = "WEBHOOK_FOO_SECRET"). The value is resolved at fire-time — the manifest never sees the plaintext. See Triggers. - Never commit a secret value into the repo. If you do by accident, rotate it via the dashboard and force-push a cleaned history.
Rotation timing
Provider keys enter the sandbox at session-create time. Rotating a value takes effect on the next session — running sessions keep their copy. A key revoked mid-session makes upstream calls fail until the user restarts the session.
Inspecting what's set
The dashboard's Secrets Manager (and kortix secrets ls) shows which secrets are declared in kortix.toml (required or optional) and which have a value set, marking required-but-missing names.