The variables penv reads
Every variable the penv binary and its installers read, what each one changes, and exactly what a child process started by penv run gets.
penv has no config file. Everything you can set outside a flag is here, and every row was read out of the source that uses it.
Every variable, and what it changes
| Variable | What it changes | Who usually sets it |
|---|---|---|
PENV_ENV | The environment a command reads, when --env says nothing. Local mode accepts only development. | You, or your shell |
PENV_TOKEN | A pck_ machine credential. It comes before the operating system keychain and every other credential source. | Your pipeline or your server |
PENV_URL | The address the binary talks to instead of https://penv.cloud. https anywhere, and plain http only for 127.0.0.1, localhost and [::1]. | Nobody, in normal use |
NO_COLOR | Any non-empty value turns color off. | You, or your terminal |
CLICOLOR | 0 turns color off. Any other value changes nothing. | You, or your terminal |
AWS_ACCESS_KEY_ID | With the secret key, offers this machine's own AWS identity as a credential. | The AWS runtime |
AWS_SECRET_ACCESS_KEY | The other half of that pair. Both must be present. | The AWS runtime |
AWS_SESSION_TOKEN | Carried into the signed request when a role supplied one. | The AWS runtime |
AWS_REGION | The STS region penv signs against. | The AWS runtime |
AWS_DEFAULT_REGION | The same, read when AWS_REGION is unset. Neither means us-east-1. | The AWS runtime |
ACTIONS_ID_TOKEN_REQUEST_URL | With the request token, tells penv to mint a GitHub Actions token for your workspace. | GitHub Actions |
ACTIONS_ID_TOKEN_REQUEST_TOKEN | The other half of that pair. Both must be present. | GitHub Actions |
CI_JOB_JWT_V2 | A platform token penv exchanges as it stands. | GitLab CI |
ID_TOKEN | The same, read when CI_JOB_JWT_V2 is unset. | GitLab CI |
PENV_OIDC_TOKEN | The same, for any other platform or a token you minted yourself. | You |
AGENT | amp names Amp outright. Any other name on penv's list is a weaker match. | Your coding agent |
COPILOT_CLI | Set and not 0 or false names Copilot. | Copilot CLI |
CLAUDE_CODE_CHILD_SESSION | Set and not 0 or false names Claude Code. | Claude Code |
CLAUDECODE | Set and not 0 or false names Claude Code. | Claude Code |
CODEX_THREAD_ID | Present names Codex, and is the session id stamped on cloud requests. | Codex |
CODEX_SESSION_ID | Present names Codex, and is the session id when the thread id is unset. | Codex |
GEMINI_CLI | Set and not 0 or false names Gemini. | Gemini CLI |
CURSOR_SANDBOX | Present names Cursor. | Cursor |
CURSOR_AGENT | Present names Cursor. | Cursor |
CLINE_ACTIVE | Set and not 0 or false names Cline. | Cline |
ROO_ACTIVE | Set and not 0 or false names Roo. | Roo |
ROO_CLI_RUNTIME | Set and not 0 or false names Roo. | Roo |
OR_APP_NAME | Aider, in any case, names Aider. | Aider |
PS1 | A prompt holding ###PS1JSON### names OpenHands. | OpenHands |
AI_AGENT | A shared convention. penv parses both name_version_mode and name@version. | Several agents |
CLAUDE_CODE_SESSION_ID | The session id stamped on every cloud request under Claude Code. | Claude Code |
CURSOR_TRACE_ID | The same, under Cursor. | Cursor |
AMP_CURRENT_THREAD_ID | The same, under Amp. | Amp |
AGENT_THREAD_ID | The same, under Amp, when AMP_CURRENT_THREAD_ID is unset. | Amp |
COPILOT_AGENT_SESSION_ID | The same, under Copilot. | Copilot CLI |
GIT_EDITOR | An editor that cannot prompt anybody, such as true or cat, turns masking on when stdout is not a terminal too. No agent is named. | Your tooling |
PATH | Where penv looks for the command you gave penv run, and for a language target's toolchain. | Your shell |
PATHEXT | Which suffixes count as runnable on Windows, so tsc finds tsc.cmd. | Windows |
HOME | The ~/.penv half of the target and guard lookup, and the cache directory on macOS and Linux. | Your shell |
USERPROFILE | The same ~/.penv lookup on Windows, read when HOME is unset. | Windows |
LOCALAPPDATA | Where the encrypted cache lives on Windows. | Windows |
XDG_CACHE_HOME | Where the encrypted cache lives on Linux. Without it penv uses $HOME/.cache. | Your desktop |
COMPUTERNAME | The machine name shown on a reveal approval page. | Windows |
HOSTNAME | The same, read when COMPUTERNAME is unset. | Your shell |
HOST | The same, read after those two. Without all three penv reads /etc/hostname, then calls itself the penv CLI. | Your shell |
PENV_VERSION | Pins a release tag such as v1.2.3. Installers only. | You |
PENV_INSTALL_DIR | Where the binary lands. Installers only. | You |
PENV_RELEASE_BASE | The address a release is read from. Installers only. The binary carries the one address. | The installer tests |
PENV_TARGET | Install for another machine's target triple. install.sh only. | You |
PENV_ALLOW_ROOT | 1 installs as root. install.sh refuses by default. | You |
PENV_ALLOW_ELEVATED | 1 installs from an elevated shell. install.ps1 refuses by default. | You |
PENV_ADD_TO_PATH | 1 writes your user PATH, which is the only way to ask when you pipe install.ps1 through iex. | You |
SHELL | Which PATH line install.sh prints for you to paste. It edits no startup file. | Your shell |
TMPDIR | Where install.sh makes the scratch directory it reads the release into. Without it, /tmp. | Your shell |
PROCESSOR_ARCHITECTURE | The processor install.ps1 builds a target triple from, read only when the machine's own registry value is missing. | Windows |
PROCESSOR_ARCHITEW6432 | The same, and it wins over PROCESSOR_ARCHITECTURE, because an x64 shell on an ARM64 machine says AMD64. | Windows |
Two more variables exist in the penv repository and nothing that ships reads either one.
PENV_SIGNING_KEY is the release workflow's secret, read by a signing tool that is never published.
PENV_BLESS rewrites the snapshots the test suite compares against, and only the tests read it.
Detection is a ladder and the first row that matches wins, which is why two agents setting colliding variables still resolve to one name. The order and what changes under an agent are on coding agents.
Masking has a second way on that names nobody. When stdout is not a terminal and GIT_EDITOR is set
to something that cannot prompt, penv records the session as non-interactive and turns masking on.
That is the only thing it changes. penv reveal and penv pull still work the way they do for a
person, and the credential keeps a person's lifetime.
Setting an agent variable by hand does not give you an agent's protections, and unsetting one does
not take them away in any way that matters. Detection changes defaults and adds friction. Use
--agent when you want the agent treatment on purpose, and read penv guard for
what actually holds a harness back.
What a child process gets
penv run starts one child and hands it three things.
- Everything penv itself was started with. The child inherits penv's own environment as it stands.
- Every key the schema resolved, from
.envin local mode or from the cloud in cloud mode. A key left empty in the file takes the default written on its schema line. PENV_ENV, set to the environment this run actually read, so your program can see which one it got.
Values reach that child and nothing else. penv writes no value into its own environment, and in
cloud mode penv run writes no value to disk. The one file it keeps is an encrypted cache whose key
lives in the operating system keychain.
What a child process does not get
- A value for a key the cloud mints on request. Those keys are skipped, and penv says how many.
- A value for a key that has none.
penv runrefuses at exit 3 before it starts anything when a required key is missing. - Its output back unread. When masking is on, penv pipes the child's stdout and stderr and scrubs every sensitive value out of them first.
penv removes nothing from the environment it inherits. A PENV_TOKEN in your shell reaches the
child too, along with everything else your shell holds. Give a pipeline its credential on the step
that needs it rather than on the whole job.
Next: error codes.