Synopsis
-- is passed through to the child process verbatim. capy run has 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.
Plaintext values live only in the child process’s memory and are never written to disk.
Two modes
capy run auto-detects which mode to run in based on what’s in process.env:
Local mode (default)
WhenSECRETS_BLOB and PROJECT_KEY are not 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 bothSECRETS_BLOB and PROJECT_KEY are set in process.env, capy run:
- Parses
SECRETS_BLOBlocally - 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
PROJECT_KEYwith 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, no local key state on disk, no interactive auth.
If only one of
SECRETS_BLOB / PROJECT_KEY is set, capy run exits with an error rather than silently falling back to local mode. Makes platform misconfiguration loud instead of silent.Behavior
In both modes,capy run:
- Forwards
SIGINT,SIGTERM, andSIGHUPto the child. - Exits with the child’s exit code.
- Deployed mode: variables already set in the environment win over every value decrypted from
SECRETS_BLOB. Platform-level overrides stay sovereign. - 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:
SECRETS_BLOB and PROJECT_KEY (from capy deploy) are 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 Deploying → Vercel for the full walkthrough.
See also
- Running your app - the full runtime story
- Deploying - how
SECRETS_BLOBandPROJECT_KEYreach your platform