Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Environment variable pass-through

The daemon runs as a background process and typically has a stripped-down environment. Your terminal has the full environment set up by your shell profile. There are two ways env vars reach shell subprocesses spawned by the agent.

zerocode forwarding (automatic)

When zerocode connects it captures its own process environment and sends it to the daemon as part of the initialize handshake. The daemon stores that snapshot in TuiRegistry keyed by zerocode’s unique tui_id. When you open a new chat session (session/new), the daemon looks up zerocode’s snapshot and clones it into the agent’s ShellTool. That clone is then overlaid on top of the safe-env baseline for every shell subprocess the agent spawns:

cmd.env_clear()
  → Layer 1: SAFE_ENV_VARS + shell_env_passthrough (from daemon process)
  → Layer 2: zerocode's env snapshot (wins on conflict)

zerocode vars win on conflict: your PATH, HOME, and credential sockets take precedence over whatever the daemon inherited. No configuration required.

This is why SSH_AUTH_SOCK works when you run zerocode from a terminal that has an ssh-agent running, even if the daemon was started as a service with no agent:

sh

# Terminal has SSH_AUTH_SOCK set by ssh-agent or a hardware token (YubiKey, etc.)
echo $SSH_AUTH_SOCK
# /run/user/1000/gnupg/S.gpg-agent.ssh

# Daemon was started as a systemd service, with no SSH_AUTH_SOCK in its env.
# zerocode forwards its env at connect time, so any shell command the agent
# runs (git push, ssh, gpg-sign) gets SSH_AUTH_SOCK from your terminal.

zerocode sends its full environment. On a shared or remote daemon where that’s a concern, use WSS with a dedicated user account.

Multiple connected clients: no cross-session clobbering

Each zerocode instance gets a unique tui_id (tui_ + 8 random hex chars). The registry is a HashMap<tui_id → TuiEntry>, and entries are completely independent:

TuiRegistry
├── "tui_a1b2c3d4"  →  { env: { PATH: "/home/alice/…", VIRTUAL_ENV: "…" } }
├── "tui_beef0042"  →  { env: { PATH: "/home/bob/…"  } }
└── "tui_cafe1234"  →  { env: { PATH: "/opt/pyenv/…" } }

When zerocode tui_a1b2c3d4 opens a session, only its env snapshot is cloned and used. The other clients’ envs are never touched. Concretely:

ScenarioResult
Two clients open from different shells with different PATHsEach session gets its own PATH; neither affects the other
Client A has VIRTUAL_ENV set; Client B does notOnly sessions from Client A see VIRTUAL_ENV
Client A disconnects while Client B’s session is runningClient B is unaffected; env was cloned at session creation
Client A reconnects with the same tui_idOld entry is removed, new entry with fresh env is registered; already-running sessions keep their original clone

The last point matters: get_env returns a clone, not a reference. Once a session is created it owns its env snapshot. Reconnects or disconnects of the originating client have no effect on running sessions.

Risk profile passthrough (explicit allowlist)

shell_env_passthrough on a risk profile controls which variables from the daemon’s own process environment are passed to shell subprocesses. This is useful when you want specific vars available regardless of whether zerocode is connected, for example on a headless server where the daemon itself has the vars set.

Subagents cannot expand this list beyond what the parent policy allows: adding a var not present on the parent’s list is rejected as a policy escalation.