Coding agents
penv detects coding agent sessions, seals and masks your values, and never prints a value to one without your approval. It cannot stop a process running as you.
An agent runs as you and can read anything you can read. penv treats its session as a separate actor: values are sealed and masked, and a reveal needs your approval. Setup and the full reveal flow: keep agents out of .env.
Threat model
| penv stops | penv does not stop |
|---|---|
The agent reading .env or .env.* through a harness that enforces the rules penv guard writes | A process running as you reading values directly |
A @hosts key reaching the agent's command as anything but a placeholder (sealed runs) | A sealed command calling any endpoint of an allowed host that the key permits |
Values of four or more characters appearing in child output captured by the agent (penv run masks them) | A harness that does not enforce a rule penv wrote |
A value printing without your approval (penv reveal exits 4, or the hook refuses it) | Anything inside the child process that received an unsealed value |
A .env written to disk from an agent session (penv pull exits 2) |
Agent detection
Detection is a ladder tried in order, because vendors set colliding variables. The first rung that matches wins.
| Order | Signal |
|---|---|
| 1 | A vendor's own marker, such as CLAUDECODE, CODEX_THREAD_ID or CURSOR_AGENT |
| 2 | Shared conventions: AI_AGENT, then AGENT against a known list |
| 3 | The /opt/.devin path |
| 4 | The parent process chain, matched against known executables |
Every variable, in order: environment variables. A session that is not a terminal and whose GIT_EDITOR cannot prompt turns masking on without naming an agent. --agent declares an agent session by hand.
Detection reads variables any process can set or unset, so it only changes defaults.
Sealed runs
# @type=string(startsWith=sk_live_, minLength=32) @hosts=api.stripe.com
STRIPE_SECRET_KEY=Under an agent, penv run is always sealed; you opt in with penv run --sealed.
| Part | Behavior |
|---|---|
| The command | Holds a placeholder shaped by the key's type, never the value |
Requests to a @hosts host | A proxy inside penv run puts the value into the request line and headers. Bodies keep the placeholder |
| Responses | A value echoed back, raw or encoded, returns as the placeholder |
Computed @hosts | @hosts=url($DATABASE_URL, host) seals to the hosts pinned under [hosts]; a differing host refuses the run (@hosts). We receive the expression as hostsExpr and store it; your machine computes and enforces the hosts |
postgres://, redis:// URLs | Go through local proxies that log in with the real value. Postgres TLS follows the URL's sslmode; verify-ca checks the host name too, as verify-full does |
Controls
| Control | Mechanism |
|---|---|
| Guards | penv guard writes each harness's own config: deny rules for .env and .env.*, a hook that runs penv hook, or both, as the harness allows |
| Sealing | @hosts keys become placeholders; always on under an agent |
| Masking | On by default in every penv run: penv scrubs every value not marked public, and its base64, hex, percent-encoded and JSON-escaped forms, from child output, and a preload masks inside Node, Bun, Deno and Python. --no-mask and --no-preload are ignored under an agent. Variables: environment variables |
| Reveal approval | You approve in the console within 10 minutes; the value prints once. Under a harness that runs penv hook, the hook lets penv reveal through to your approval from 1.0.0-beta.4; 1.0.0-beta.3 refuses it there, so no approval is created |
| Attribution | A request from an agent session carries the harness name and, where the harness sets one, its session id; we stamp both on the audit entry |
Next: encryption in the cloud.
Local mode and cloud mode
Your schema header and a credential decide the mode. Local files layer over cloud values, and a sealed local copy lets warm runs skip the round trip to us.
Encryption in the cloud
We seal every value with AES-256-GCM under your workspace's data key, wrapped by a key in a key management service. We can decrypt to serve your machines.