Skip to content
Get early access

The CLI

cendarum — zero-knowledge secrets for local dev
USAGE:
cendarum run [--project <name|id>] --env <name|id> [--only KEY,KEY]
[--email <email>] [--shell] -- <cmd> [args...]
cendarum import [--project <name|id>] --env <name|id> [--email <email>]
[--file <path>|-]
cendarum export [--project <name|id>] --env <name|id> [--email <email>]
[--format dotenv|json] [--out <path>] [--force]
ENVIRONMENT:
CENDARUM_API_BASE API base URL (default https://api.cendarum.com)
CENDARUM_EMAIL account email (else --email, else prompted)
CENDARUM_DATA_DIR override the vault data dir (testing/isolated profiles)
`run` injects the decrypted environment into <cmd>'s process environment —
nothing is written to disk. Everything after `--` is executed verbatim.

Environment-variable injection works below every language, so there is exactly one mechanism to build and it serves every runtime at once.

Process creation — execve on Unix, CreateProcess on Windows — hands the new process an environment block: a list of KEY=VALUE pairs. That block is an operating-system concept, not a language feature. Every runtime reads from the same one:

Language Reads the same block via
Node process.env.X
Python os.environ["X"]
Go os.Getenv("X")
Ruby ENV["X"]
Rust std::env::var("X")
Java System.getenv("X")
PHP getenv("X")
shell / Make $X

Child processes inherit the block, so injecting at the top of a process tree flows down for free: npm spawns node, which spawns your bundler, and all of them see the same values.

This is also why every tool in this space converges on env injection rather than per-language SDKs. We write no per-ecosystem adapter, ever.

cendarum run is the everyday one. It decrypts an environment on your machine and spawns your command with those values in its process environment. Nothing touches disk.

cendarum import is the on-ramp: a .env file becomes an encrypted environment.

cendarum export writes plaintext to disk. It is a deliberate, warned escape hatch for the rare tool that reads only a file — not a convenience, and never a default path.

One use worth calling out separately: AI coding agents. cendarum run --env dev -- claude lets a terminal agent make real API calls while the key stays out of the conversation — the model writes $STRIPE_SECRET_KEY and your shell resolves it. No pasting a credential into a chat, so nothing for the model to refuse.

  1. Ensure an unlocked vault, prompting for your master password and Secret Key if needed. Unlocking is separate from API authentication — the bearer token authorises the ciphertext download, and decrypts nothing.
  2. Resolve the project and environment; pull and decrypt the payload locally.
  3. Build the child’s environment: inherit the real one, then overlay Cendarum’s managed keys on top.
  4. Spawn the child with that environment.
  5. Drop Cendarum’s own copy of the values immediately.
  6. Pass stdin, stdout, and stderr through untouched; forward signals.
  7. Exit with the child’s exit code.

Step 5 is worth noticing: your dev server can run for eight hours, but Cendarum does not need to stay unlocked or keep the values around. It hands them over at spawn and lets go.

One consequence, stated plainly: run is a snapshot taken at spawn time. Rotating a key, revoking a grant, or locking your vault does not reach into a process that is already running. Restart it.

CENDARUM_API_BASE, CENDARUM_EMAIL, and CENDARUM_DATA_DIR are the whole surface — see the reference.

There is deliberately no environment variable for your master password. A process’s environment is readable by anything running as the same user, which is precisely the exposure the product exists to reduce; providing that variable would undo the point of the tool. It is typed, or it is not supplied.