Kairokuplaybook
Orchestration

Secrets

The keys a dispatched run needs, set in the app and delivered per run.

A dispatched run stands up the project's own stack and runs its suite, so it needs the project's own keys. Those are set in Kairoku — Settings → Developers → Secrets at organization scope, the project's Settings tab at project scope — and delivered to the machine in the claim for one run.

What goes here, and what does not

Belongs in SecretsDoes not
The keys the project's app needs to run its tests: an Exa key, a Stripe test key, a Resend key, a hosted test database URLThe coding CLIs' logins — claude and codex
Anything a .env file on a developer's laptop would hold for the test profileYour Kairoku personal access token, or a daemon token

The distinction is not a preference. A coding CLI's login is a browser flow completed by a person on the machine itself; it is not a value anyone pastes, and there is nothing here that could deliver it. See Runner setup for the two sign-ins that stay human-only, and the manifest for the machine-local env store, which is where a value that belongs to one machine rather than to the project goes.

Scopes and profiles

Two scopes and one profile column:

  • Organization secrets are set once in Settings and available to every project the organization owns.
  • Project secrets are set on that project and override an organization value of the same name.
  • Profile is the run environment a value belongs to — test by default, and the profile you choose in Advanced settings is the one delivered.

A name is unique within (owner, scope, project, profile), so DATABASE_URL at profile test and DATABASE_URL at another profile are two different rows. Saving over an existing name writes a new version rather than editing in place.

Names must look like environment variable names — capital letter first, then capitals, digits and underscores.

The table

NameScopeProfileSet byLast deliveredModified
EXA_API_KEYorgtestyou3 minutes ago2 days agoReplace · Delete

Nothing renders a value, ever. There is no reveal, no copy-to-clipboard and no show toggle — and that is a property of the server rather than a decision about the UI: the query behind the table never selects the ciphertext, so there is no read path a button could be wired to. The value field on the form is write-only and is cleared on save.

To change a value you paste a new one. To find out what a value is, look where you got it from.

References to a vault

A value that starts with op:// or that looks like an AWS Secrets Manager ARN is stored as a reference rather than as a secret, and shown as one in the table. It is delivered to the daemon unresolved, and the daemon resolves it at the start of the run — the 1Password CLI for an op:// path, the AWS CLI for an ARN. A machine with no resolver for a reference it was handed fails the run naming the secret, never the value.

This is the way to keep a value in a vault you already trust and let Kairoku carry only the pointer. Resolution happens on the machine, so the machine needs the vault's own CLI signed in: kairoku doctor lists which resolvers it found under secret resolvers, and warns when it found neither. Those two are the whole set — a reference in any other scheme fails the run naming the key.

Delivery

Secrets travel in the claim — the moment a machine picks up a queued dispatch — as env.secrets, with organization values overlaid by project values for the dispatch's profile. Three things follow from that:

  • They are decrypted only inside the claim handler, and never written to a log there or on the machine. On the machine they stay in memory: nothing under ~/.kairoku ever holds a delivered value.
  • Every delivered value joins the machine's masking set, so it cannot appear in an event line, a captured stream, or the curated log the Floor prints.
  • Each claim writes one activity row — how many secrets went to which machine for which run. Never a name and a value together.

The table's Last delivered column is written from the same path, so a secret that has never been used says so.

The honest limit

Secret values are encrypted at rest with a single application key (AES-256-GCM under the API's SECRETS_KEY) — exactly what protects the stored forge tokens. That is the whole of it:

  • There is no envelope encryption and no KMS in front of it. Adding one would mean re-wrapping every stored forge token, and would not change who can read the values.
  • There is no end-to-end encryption. Kairoku decrypts to deliver, which means a Kairoku deployment can read what it holds. Anyone with the application key and the database can read these values.
  • A secret is only as scoped as its owner: an organization secret is available to every project that organization owns, and to every machine that claims one of their dispatches.

Set values here that you would be comfortable having on the agent machine — a test key, a sandbox key, a throwaway database. For anything else, store a reference and keep the value in your vault.

On this page