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 the snapshot registered by the calling connection itself, never one named by the request, 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 every connection, but the daemon keeps the snapshot only where it is trusted: an operator-level principal on a local connection (the Unix socket or the Windows named pipe), which is the local IDE flow described above. On a WSS connection the snapshot describes the client’s host rather than the daemon’s, and a roster principal with a permission profile must not choose what runs as the daemon account, so in both cases the daemon drops the snapshot at initialize, logs that it did, and the session’s shell subprocesses see only Layer 1. Use shell_env_passthrough on the risk profile to supply specific variables from the daemon’s own environment there.

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 B attaches a session Client A created while that session is still liveRefused unless both clients forward exactly the same environment; per-terminal variables such as TERM_SESSION_ID usually differ, so start a new session instead
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: the registry hands the session 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.