There's no integration to write.
cendarum run decrypts an environment on your machine and hands the values to your program through the spawn syscall itself. No SDK, no config file, nothing written to disk.
$ cendarum run --env dev -- npm run dev Email: you@example.com Master password: Secret Key (SK1-…): > my-api@0.1.0 dev > vite VITE v7.0.4 ready in 412 ms Local: http://localhost:5173/ why it works everywhere
Injection happens below the language.
Process creation hands the new process an environment block — a list of KEY=VALUE pairs. That's an operating-system concept, not a library, and every runtime reads from the same one.
| 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 |
There is exactly one injection path to build, and it serves every language at once — which is why we will never write a per-ecosystem adapter. Child processes inherit the block, so injecting at the top of a tree flows all the way down.
prove it
Nothing leaks into your shell.
The second command is the interesting one. Same variable, no cendarum run, empty line.
$ cendarum run --env dev -- sh -c 'echo $DB_PASSWORD' s3cr3t-smoke-value $ sh -c 'echo $DB_PASSWORD' the rules
Two decisions worth knowing about.
The vault wins
Your real environment is inherited — PATH, HOME, everything — and Cendarum's managed keys are overlaid on top. For the keys it manages, the vault is the source of truth.
This is also why an existing dotenv call in your app stays harmless: those libraries default to "an existing environment variable wins", so they find our value and leave it alone.
$ API_URL=ambient cendarum run --env dev -- printenv API_URL https://api.example.test Loader variables are skipped
Some names don't configure your program — they configure the machinery that starts it. A stored value for one of those could hijack every process launched under cendarum run, which matters because a teammate with a write grant can edit your environment.
So they're skipped, with a warning naming the key, and --only is the explicit per-key override.
$ cendarum run --env dev -- printenv LD_PRELOAD cendarum: 'LD_PRELOAD' excluded (loader denylist); pass --only LD_PRELOAD
to inject deliberately the other two commands
One to get in. One we'd rather you didn't need.
cendarum import
Your existing .env, encrypted, in one command. Comments, quotes, and export prefixes tolerated. Two lines setting the same key is an error naming both line numbers — never a silent last-one-wins.
cendarum export
Writes plaintext to disk, for the rare tool that reads only a file. It warns on every invocation, there is no flag to silence it, and it refuses to write inside a git working tree without --force.
a use case people keep asking about
Let an AI agent make real API calls.
You want Claude Code or aider to actually hit the API — a real request, a real error you can debug. So it needs a real key. Paste it into the chat and the model refuses, correctly: a credential in a transcript is a credential sent to a provider.
$ cendarum run --env dev --only STRIPE_SECRET_KEY -- claude Email: you@example.com Master password: Secret Key (SK1-…): the agent now has one key, by name Referenced, not pasted
The agent inherits the environment, so it refers to the key by name. What lands in the transcript is $STRIPE_SECRET_KEY — not the value. Nothing to refuse, because nothing was pasted.
One key, not your whole environment
--only narrows what gets injected. An agent session is a long-running process doing things you did not approve one by one; it does not also need your database URL.
It is not a boundary against the agent — it runs in your environment, and curl -v prints the header. The docs say so plainly, along with what to do if it leaks. Read the whole pattern, limits included.
The honest limitation.
Injection has one exposure, and it's inherent rather than incidental.