Synopsis
-- separator is optional. Capy passes the child command and its arguments through unchanged, including the child’s own flags. capy run has no Capy-specific options and no help of its own, so capy run --help forwards --help to the child rather than printing Capy’s help. With no command at all it prints Usage: capy run -- <command> [args...] and exits 1.
Description
capy run decrypts your project’s secrets in memory and spawns the given command with them set as environment variables. Your app reads env vars the normal way for its runtime - process.env, os.environ, ENV["KEY"], std::env::var, whatever.
This is Capy’s single runtime mechanism - works for any language, any framework, local dev through production, no per-language SDK to install.
Capy decrypts values in memory and passes them to the child process. It does not write decrypted values to disk; your application can still choose to do so.
Two modes
capy run auto-detects which mode to run in based on what’s in process.env:
Local mode (default)
When neither complete deployed runtime pair is set,capy run:
- Reads
.envfrom the current working directory. - If nothing in
.envis encrypted, spawns the child right there - no key, nokeep.lock, no network. - Otherwise reads
keep.lockin that same directory to learn which org and project it belongs to. - Resolves your project key. On a cloud or BYOC profile that means authenticating silently against your existing session (refreshing the access token if it has expired) and resolving the key through the Capy service. On a local-only profile it happens entirely offline from your local key, with a passphrase prompt if the session is locked.
- Decrypts each
capy:…snippet in.envand spawns the child with the decrypted values set in its environment.
capy once in the directory to sync; capy run works from then on.
On a cloud or BYOC profile, local mode needs the Capy service reachable and your session valid on every run. There is no offline key cache and no
CAPY_KEY override. That is deliberate: it means every decryption is authorized and audit-logged at the moment it happens, so removing someone’s access takes effect on their very next capy run rather than whenever a cached key happens to expire.The practical consequence for unattended machines: if the session is no longer valid, capy run exits with capy run: not authenticated. Run capy to sign in. and your process does not start. On a server you restart automatically, plan for that — or use deployed mode, which authenticates with a deploy token instead of a human session.A local-only profile is the exception: it resolves the project key offline from your passphrase-protected local key, so no service is contacted and capy run keeps working after capy lock (it just prompts for the passphrase).Deployed mode
When either complete runtime pair is set inprocess.env, capy run enters deployed mode:
SECRETS_BLOBandPROJECT_KEYare emitted by the token-and-instructions flow._SECRETS_BLOBand_PROJECT_KEYare also supported; when both complete pairs are present, Capy uses the underscore-prefixed pair.
- Parses the selected secrets blob locally - extracts the deploy ID, the service-held outer blob, and the encrypted env map.
- Posts the outer blob to
POST /deploy/{deployId}/decrypton the Capy service. The service verifies the deploy token isn’t revoked and returns a derived service key. - Combines the selected project key with the service key to derive the decrypt key, then AES-GCM-decrypts the env map.
- Spawns the child with those values set in its environment.
capy deploy. No local .env file, local key state, or interactive auth is required.
Each runtime pair must be complete. If only one value from either pair is set,
capy run exits instead of falling back to local mode. When both pairs are complete, the underscore-prefixed pair is used.Behavior
In both modes,capy run:
- Forwards
SIGINT,SIGTERM, andSIGHUPto the child. - Exits with the child’s exit code.
- Deployed mode with
SECRETS_BLOB/PROJECT_KEY: variables already set in the environment win over decrypted values. Platform-level overrides stay sovereign. - Deployed mode with
_SECRETS_BLOB/_PROJECT_KEY: decrypted values win over same-named values already in the environment. This lets a platform retain an older plaintext variable while the new runtime pair takes effect. - Local mode: plaintext keys in
.envfollow the same rule - the parent environment wins. Encryptedcapy:…values do not: they’re re-applied after the merge, so a project secret always overrides a same-named variable inherited from your shell.
Examples
In containers
capy run can serve as the Docker entrypoint:
capy deploy is present in the container’s environment at runtime.
Next.js on Vercel
In deployed mode,capy run also writes .capy/next-env.js before spawning the child. That file maps each decrypted variable name to its process.env reference. In next.config.js, guard the require since the file exists only in deployed builds (not in local dev):
next.config.js. See Build-time inlining for the walkthrough.
See also
- Running your app - the full runtime story
- Deploying - how
SECRETS_BLOBandPROJECT_KEYreach your platform