Running coding agents without exposing your API keys
Kiwi's credential model is built so that customer secrets are only ever in plaintext inside the one process that needs them — the daemon running the task — and never in the sandbox, never in the Control Plane's memory in BYOC, and never on disk unencrypted.
Two keypairs per daemon
On boot, a daemon generates two keypairs (pkg/crypto):
- X25519 — for credential sealing. Customer credentials are encrypted to the daemon's X25519 public key, so only that daemon can open them.
- Ed25519 — for heartbeat signing. The daemon signs its polls so the Control Plane can verify the request comes from the registered daemon.
How a credential travels
Customer credentials (an Anthropic, OpenAI or Gemini key, a git token) are stored by the Control Plane sealed to a specific daemon's X25519 public key — using a NaCl anonymous sealed box (an ephemeral sender keypair per seal, so there is no sender identity). At rest, that sealed blob is additionally encrypted by the configured key manager: a static key for dev/BYOC, or Cloud KMS envelope encryption for managed.
When a daemon leases work, it receives the sealed credentials in the poll response and opens them in memory with its X25519 private key. They are used to call the LLM provider and to open the PR — and are never written into the sandbox or persisted in plaintext.
BYOC vs managed — and the zero-knowledge caveat
The same sealing model runs in both deployment modes; what differs is who operates the machine that holds the private key.
| Managed | BYOC | |
|---|---|---|
| Who runs the daemon | Kiwi | You, in your own cloud |
| Where credentials are unsealed | Kiwi-operated host | Your VPC |
| Can the Control Plane operator decrypt? | Yes — Kiwi holds the private key | No — the key never leaves your cloud |
| Zero-knowledge? | No | Yes |
:::warning Managed is not zero-knowledge In BYOC, the daemon runs in your cloud and the Control Plane never sees plaintext credentials — that is a genuine zero-knowledge property. In managed mode, Kiwi operates the daemon and holds its private key, so Kiwi can decrypt. Do not treat managed mode as zero-knowledge. Zero-knowledge is a BYOC-only claim. :::
Defense in depth around the sandbox
The credential model is reinforced by the execution seam:
- The Architect and Implementer run in the daemon, so model-generated code never sees the LLM key.
- The sandbox is split in two, which makes the claim stronger than "the sandbox has no network": model-generated code never has network access, and the phase that does never holds a secret. Dependencies install with a network and an empty environment; verification has the credentials and no route off the machine.
- On the shared Free tier, the host additionally blocks the cloud metadata endpoint, so no container can read the VM's service-account token.
- Free-tier daemons each have their own keypair, so the per-org sealing boundary holds even when many daemons are packed onto a shared host.
What ran is on the record
Credential handling is a claim about what Kiwi does not do, which is the hardest kind to check. Every job therefore produces a verified execution record: a signed, hash-chained account of which model ran, on which provider, in which sandbox and network mode, and what each step of the loop did. In BYOC the daemon's signing key never leaves your cloud, so the execution half of the record is attested by something Kiwi does not hold.
Operational hardening
- In
productionmode,KIWI_ENCRYPTION_KEY,KIWI_SERVER_TOKEN, andKIWI_CORS_ALLOWED_ORIGINSmust be set explicitly. - For managed deployments, set
KIWI_KMS_KEYto use Cloud KMS envelope encryption instead of a static key. - Set
KIWI_VER_SIGNING_KEYto counter-sign execution records; without it they persist asunsignedrather than being signed by a throwaway key. - Daemons register with single-use join tokens; after registration the persisted identity key is sufficient.