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.Why there is no SDK
Section titled “Why there is no SDK”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.
The three commands
Section titled “The three commands”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.
What happens on run
Section titled “What happens on run”- 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.
- Resolve the project and environment; pull and decrypt the payload locally.
- Build the child’s environment: inherit the real one, then overlay Cendarum’s managed keys on top.
- Spawn the child with that environment.
- Drop Cendarum’s own copy of the values immediately.
- Pass stdin, stdout, and stderr through untouched; forward signals.
- 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.
Configuration
Section titled “Configuration”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.