Store a secret
This guide stores, replaces and lists your tenant's secrets with
kindgi secrets, without a value going through your shell's history or a
command line.
Tools' declared secrets, HTTP tools' credentials, model providers' keys and MCP endpoints' credentials are all secrets of your tenant. Each is looked up by name in an environment.
Before you start
Section titled “Before you start”- A runtime, such as
kindgi dev, with Kindgi 0.1's CLI. openssl, to make a key for the examples.
Set one
Section titled “Set one”A secret belongs to an environment and a scope. Set it, and type the value when it asks:
pnpm exec kindgi secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenantuv run kindgi secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenant./kindgiw secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenant./kindgiw secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenantValue:Re-enter to confirm:It prompts twice, without echoing, then prints the secret's name, scope,
environment and version as JSON, and
Set RECEIPT_SIGNING_KEY at tenant in local.
RECEIPT_SIGNING_KEYis the secret's name, as a tool declares it. A new name uses only ASCII letters, digits,.,-and_, starts with a letter, digit or_, doesn't end with.or have two.in a row, and is at most 255 characters long;setrefuses one that doesn't (secret-name-invalid). With your own secret manager, a secret already stored under a name outside the rule can't be set, read or rotated either. Underkindgi dev, the rule is narrower.--envis the environment the secret belongs to. A runtime resolves secrets in the environment it serves, whichKINDGI_ENVnames.kindgi devserveslocal.--scopeis where it lives:tenant,org:<orgId>orproject:<projectId>. It's required.
In a script, pipe the value in with --from-stdin. Or read it from a file
only you can read, with --from-file=<path>: a file others can read is
refused. Here openssl rand -hex 32 | tr -d '\n' makes a 64-character key,
without a newline:
openssl rand -hex 32 | tr -d '\n' | pnpm exec kindgi secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenant --from-stdinopenssl rand -hex 32 | tr -d '\n' | uv run kindgi secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenant --from-stdinopenssl rand -hex 32 | tr -d '\n' | ./kindgiw secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenant --from-stdinopenssl rand -hex 32 | tr -d '\n' | ./kindgiw secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenant --from-stdin… Set RECEIPT_SIGNING_KEY at tenant in local.The secret is available to the next call. Nothing restarts.
Replace one
Section titled “Replace one”set refuses a name that exists:
Version conflict: RECEIPT_SIGNING_KEY already exists (version 1). To store a new version, retry with --write-mode=add-version.Write a new value with --write-mode=add-version:
openssl rand -hex 32 | tr -d '\n' | pnpm exec kindgi secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenant --from-stdin --write-mode=add-versionopenssl rand -hex 32 | tr -d '\n' | uv run kindgi secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenant --from-stdin --write-mode=add-versionopenssl rand -hex 32 | tr -d '\n' | ./kindgiw secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenant --from-stdin --write-mode=add-versionopenssl rand -hex 32 | tr -d '\n' | ./kindgiw secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenant --from-stdin --write-mode=add-versionIt prints the JSON, with the new versionId, and the same
Set RECEIPT_SIGNING_KEY at tenant in local. line.
--if-version=<n> makes the write conditional: it fails if someone changed
the secret since version n.
List them
Section titled “List them”list and get show names and versions, never values. Get one by its
name, environment and scope:
pnpm exec kindgi secrets get RECEIPT_SIGNING_KEY --env=local --scope=tenantuv run kindgi secrets get RECEIPT_SIGNING_KEY --env=local --scope=tenant./kindgiw secrets get RECEIPT_SIGNING_KEY --env=local --scope=tenant./kindgiw secrets get RECEIPT_SIGNING_KEY --env=local --scope=tenant{ "name": "RECEIPT_SIGNING_KEY", "scope": { "kind": "tenant", "tenantId": "bb22c936-5111-429a-bfce-09650af85492" }, "envName": "local", "currentVersion": 1, "createdAt": "1970-01-01T00:00:00.000Z", "updatedAt": "1970-01-01T00:00:00.000Z"}kindgi secrets list --env=local --scope=tenant lists the environment's
secrets by name, 25 to a page (--limit takes up to 100). While more
remain, the page has a nextCursor: pass it as --cursor for the next
page. --include-revoked lists revoked secrets too, with their
revokedAt and revokeReason. Paging and --include-revoked need a
runtime of 0.1.8 or later.
A tenant admin lists the environments with GET /v1/environments: each env
name that holds an env value or a secret, at any scope, once, in byte order.
A revoked secret doesn't count.
Under kindgi dev
Section titled “Under kindgi dev”kindgi dev's secrets store is the pack's env files: your app's, and
Kindgi's own. Keep local values in env files describes
them. So the store behaves like them:
setwrites the value to Kindgi's own.kindgi/secrets.env, readable only by you, which your app doesn't load. With--app, it writes your app's own env file instead, for a value your app reads too.- Every name in the env files is a secret of
local, andlistshows them all. Their timestamps are the epoch, as inget's answer. - Its environments are
localand each.env.<name>file, each once it holds a name.GET /v1/environmentslists those. - A name has one value: replacing it with
add-versionoverwrites it, and its version stays 1. - The files are the same for every scope, so
--scopedoesn't separate anything here. - It refuses what an env file can't hold as given: a name that isn't
capital letters, digits and underscores, starts with a digit, or is
KINDGI_*(secret-name-invalid; akindgi.name getsreserved-name-prefix, as in every store), and a value no env-file quoting can hold so that it reads back unchanged (secret-value-invalid). Each message says why. Store such a value encoded (base64, say). - There's nothing to rotate or revoke. Those commands say so:
Error [secret-operation-unsupported]: Dev secrets live in your env files (.env, .env.local, .kindgi/secrets.env) and have no versions to rotate. Edit the value there, or run `kindgi secrets set RECEIPT_SIGNING_KEY --write-mode=add-version`.Error [secret-operation-unsupported]: Dev secrets live in your env files (.env, .env.local, .kindgi/secrets.env) and have no revocation. Remove HTTPBIN_TOKEN from those files.Versions, scopes, rotation and revocation are what a deployment's secrets
store adds. That store is Postgres, with KINDGI_SECRETS_BACKEND=postgres,
or your own secret manager. The
environment variable reference
has the setting. Every flag is in the
kindgi secrets reference.