Harness Notes

Environment detection

Updated 2026-10-27

On this page

How a script, hook or CLI can tell it was started by each harness, and which session started it. Children inherit these variables, so treat them as hints that an agent is involved, not as proof that no person is watching.

Detecting the harness

QuestionCodex CLIchecked at 0.164.0Claude Codechecked at 2.1.310Cursor Agentchecked at 2026.10.12-d47ca18OpenCodechecked at 2.1.4pichecked at 1.4.0
The variable to check

CODEX_THREAD_ID holds the current thread's ID (a UUID). Commands the model runs also get CODEX_CI=1. Check either to know you're inside Codex.

CODEX_CI doesn't mean a hosted CI job; Codex sets it on its own command runs.

CLAUDECODE=1. Since v2.1.172 commands Claude Code itself starts also get CLAUDE_CODE_CHILD_SESSION=1. It also sets AI_AGENT: claude-code_2-1-310_agent in commands its tools run, and claude-code_2-1-310_harness everywhere else it starts (unless another agent already set AI_AGENT).

AI_AGENT isn't in the environment reference, and the value carries the version, so match the claude-code_ prefix.

CURSOR_AGENT. Cursor suggests checking it in ~/.zshrc or ~/.bashrc to skip heavy prompts and themes; the CLI sets it to 1.

OPENCODE=1 and AGENT=1, plus AI_AGENT=opencode unless AI_AGENT is already set.

Because an existing AI_AGENT is kept, OpenCode running inside another agent passes the outer agent's name through.

AI_AGENT=pi (since 0.84.0) and PI_CODING_AGENT=true (since 0.67.1).

Which processes get it

Every command the model runs through its shell tool, including commands sent to a remote executor, and every command you run yourself with !.

Child processes inherit it, so anything those commands start sees it too.

CLAUDECODE: Bash and PowerShell tool commands, tmux sessions, hooks, status line commands and stdio MCP servers. CLAUDE_CODE_CHILD_SESSION: Bash, PowerShell and Monitor tool commands, hooks and status line commands, but not MCP servers.

Partly

Commands the agent runs in its terminal. Hooks and MCP servers aren't documented.

Partly

Commands the agent runs with its shell tool. Terminals OpenCode opens get only OPENCODE_TERMINAL=1, which agent commands also carry.

Everything Pi starts. Pi sets both on its own process at startup, so every child inherits them. Not set when Pi is embedded through the SDK.

Which session started the command

CODEX_THREAD_ID is the thread ID; the SDK resumes it with codex.resumeThread(process.env.CODEX_THREAD_ID). Each command also gets CODEX_TOOL_CALL_ID, the call that started it.

Codex says these labels are for correlation, not authorization: shell startup files and child processes can change or remove them.

CLAUDE_CODE_SESSION_ID in tool commands, hooks and stdio MCP servers; it matches the hooks' session_id and changes on /clear (an MCP server keeps the ID it started with). Cloud sessions add CLAUDE_CODE_REMOTE_SESSION_ID, and Remote Control adds CLAUDE_CODE_BRIDGE_SESSION_ID (v2.1.199+).

Partly

Undocumented, but agent commands in 2026.10.12 get CURSOR_CONVERSATION_ID, CURSOR_REQUEST_ID and AGENT_TRANSCRIPTS (the project's transcript folder).

OPENCODE_SESSION_ID in agent shell commands.

PI_SESSION_ID, PI_SESSION_FILE (the session's JSONL file, unset for ephemeral sessions), PI_PROVIDER, PI_MODEL and PI_REASONING_LEVEL in the agent's bash and powershell commands.

Relying on it

QuestionCodex CLIchecked at 0.164.0Claude Codechecked at 2.1.310Cursor Agentchecked at 2026.10.12-d47ca18OpenCodechecked at 2.1.4pichecked at 1.4.0
Telling the agent's commands from yours

Partly

Use CODEX_CI. Your own ! commands get CODEX_THREAD_ID but not CODEX_CI, which is only set on commands the model runs.

Use CLAUDE_CODE_CHILD_SESSION. The IDE extensions also set CLAUDECODE in their integrated terminals, so a person typing there looks like Claude Code; CLAUDE_CODE_CHILD_SESSION is only set when Claude Code launches the process.

Not documented

Not documented. Cursor doesn't say whether a person's own terminal in the editor also gets CURSOR_AGENT.

Partly

Use OPENCODE or AGENT: OpenCode's terminals don't get them. Don't use OPENCODE_TERMINAL, which both get.

Partly

Use PI_SESSION_ID. The two markers are inherited by everything, including your own ! and !! commands, but the session variables are only given to the agent's bash and powershell tools.

Signs that nobody will answer a prompt

Commands the model runs get CODEX_CI=1, TERM=dumb, NO_COLOR=1, COLORTERM empty, UTF-8 locale and cat as PAGER, GIT_PAGER and GH_PAGER.

Partly

Undocumented, but commands get CLAUDE_CODE_SESSION_ATTENDED: 1 in an interactive session, 0 in background and daemon sessions. Bash tool commands also get GIT_EDITOR=true, so git never opens an editor.

Commands also get CLAUDE_PID (the Claude Code process) and CLAUDE_EFFORT (the current effort level).

Not documented

Not documented. Cursor doesn't say whether agent commands get a dumb terminal, pager overrides or a CI flag.

Partly

Agent commands run with standard input closed, so a prompt reads end-of-file. TERM is xterm-256color, not a dumb terminal.

Not documented

Not documented. Pi's environment reference lists no terminal, pager or CI settings for agent commands.

Removing or overriding it

Not supported

No. shell_environment_policy (inherit, exclude, include_only, set) is applied first and CODEX_THREAD_ID is added afterwards, so no setting removes or replaces it. The CODEX_CI defaults are also applied after your policy.

Not documented

Not documented. The reference describes a scrub that strips credentials from subprocesses, not a way to remove these markers.

Not documented

Not documented. Cursor doesn't say whether CURSOR_AGENT can be removed or changed.

Partly

A plugin's shell create.before hook can edit the environment, but the shell tool sets OPENCODE, AGENT and OPENCODE_SESSION_ID after the hooks run, so only AI_AGENT can be changed that way.

A custom shell tool's spawnHook can rewrite the environment, and exposeSessionEnvironment: false drops the session variables (and strips inherited ones). The two process markers can't be turned off.

Notes and sources

Codex CLI, 5 sources
The variable to check, 2
Which processes get it, 3
Which session started the command, 2
Telling the agent's commands from yours, 2
Signs that nobody will answer a prompt, 1
Removing or overriding it, 2
Claude Code, 3 sources
The variable to check, 3
Which processes get it, 1
Which session started the command, 1
Telling the agent's commands from yours, 1
Signs that nobody will answer a prompt, 3
Removing or overriding it, 1
Cursor Agent, 2 sources
The variable to check, 2
Which processes get it, 2
Which session started the command, 2
Telling the agent's commands from yours, 1
Signs that nobody will answer a prompt, 1
Removing or overriding it, 1
OpenCode, 4 sources
The variable to check, 2
Which processes get it, 3
Which session started the command, 1
Telling the agent's commands from yours, 2
Signs that nobody will answer a prompt, 1
Removing or overriding it, 2
pi, 5 sources
The variable to check, 4
Which processes get it, 2
Which session started the command, 1
Telling the agent's commands from yours, 2
Signs that nobody will answer a prompt, 1
Removing or overriding it, 1