Headless clamps
The exact flags for two clamped headless runs on Claude Code and codex-cli, proven with canaries on 24 October 2026:
- Sealed: no tools, no MCP, no hooks, no user or project config, no session persisted, structured JSON output. Used by the judge.
- Read only: read, search and web tools only. Used by scouts.
Versions probed: Claude Code 2.1.295 and codex-cli 0.160.0, and the newer Claude Code 2.1.310 and codex-cli 0.162.0. Every flag and every canary result below holds on both pairs (see Pinned versions). Rerun the probe after a CLI upgrade.
Results
| Clamp | Claude Code | codex-cli |
|---|---|---|
| Sealed: read canary | UNREADABLE, tools [StructuredOutput] | UNREADABLE, only request_user_input offered |
| Sealed: write canary | file absent | file absent |
| Sealed: hook canary | none fired | none fired, even with hook trust bypassed |
| Sealed: MCP canary | server never started | server never started |
| Read only: read canary | canary first line returned | UNREADABLE on this host (see Codex read only needs user namespaces) |
| Read only: write canary | file absent, no write tool offered | file absent, sandbox refused |
| Read only: hook canary | none fired | none fired |
Claude Code flags
Sealed
claude -p --tools "" --strict-mcp-config --setting-sources "" \
--settings '{"disableAllHooks":true}' --no-session-persistence \
--disable-slash-commands --system-prompt "$PROFILE_PROMPT" \
--json-schema "$SCHEMA_JSON" --output-format stream-json --verbose \
--model "$MODEL" --effort "$EFFORT" "$USER_INPUT"
--tools ""removes every built in tool. With--json-schemathe only tool left isStructuredOutput, which carries the answer; the result event’sstructured_outputfield holds the parsed JSON.--setting-sources ""alone drops user, project and local settings: hooks,enableAllProjectMcpServersand the user and projectCLAUDE.mdall stop (runclaude-sealed-sources-only).--settings '{"disableAllHooks":true}'and--strict-mcp-configkeep the clamp if a later version moves hooks or MCP into another source.--output-format jsonreturns the same result object without the init event; the probe usesstream-json --verbosebecause its init event lists the offered tools and MCP servers.--bareis unusable with a subscription login: it reads onlyANTHROPIC_API_KEYor anapiKeyHelper, so aCLAUDE_CODE_OAUTH_TOKENsession answersNot logged in · Please run /login(runclaude-bare).
Read only
claude -p --tools "Read,Grep,Glob,WebSearch,WebFetch" --permission-mode dontAsk \
--strict-mcp-config --setting-sources "" --settings '{"disableAllHooks":true}' \
--no-session-persistence --disable-slash-commands --system-prompt "$PROFILE_PROMPT" \
--json-schema "$SCHEMA_JSON" --output-format stream-json --verbose \
--model "$MODEL" --effort "$EFFORT" "$USER_INPUT"
The init event offers exactly Glob, Grep, Read, StructuredOutput, WebFetch, WebSearch. No write or shell tool exists, so the write canary has nothing to call; --permission-mode dontAsk denies anything that would prompt.
codex-cli flags
Sealed
CODEX_HOME="$(mktemp -d)" codex exec --ignore-user-config --ignore-rules --ephemeral \
--skip-git-repo-check --sandbox read-only --output-schema "$SCHEMA_FILE" -o "$RESULT_FILE" \
--disable shell_tool --disable unified_exec --disable code_mode --disable code_mode_host \
--disable apps --disable plugins --disable multi_agent --disable multi_agent_v2 \
--disable goals --disable sleep_tool --disable view_image --disable image_generation \
--disable browser_use --disable computer_use --disable skill_search --disable tool_suggest \
--disable hooks -c web_search="disabled" -c project_doc_max_bytes=0 \
-c model_catalog_json="$SEALED_CATALOG" -c model_reasoning_effort="$EFFORT" -m "$MODEL" "$USER_INPUT"
- An empty
CODEX_HOME.--ignore-user-configskips only$CODEX_HOME/config.toml: MCP servers declared there stop, but$CODEX_HOME/hooks.jsonand$CODEX_HOME/AGENTS.mdstill load (runcodex-ignore-config-hooksfired all six hooks with trust bypassed and answered with the userAGENTS.mdmarker). Authentication does not need the home: a routed token session passes its token by environment and its provider by-c, asscripts/codex_router.pybuilds them. -c project_doc_max_bytes=0stops the projectAGENTS.mdin the working directory.--disable hooksholds even under--dangerously-bypass-hook-trust(runcodex-sealed-hooks, populated home, no hook fired).- A sealed model catalog. Every model a ChatGPT login may use carries
tool_mode: code_mode_only, which offers anexectool whatever the shell features say.--disable code_mode_hostmakes that tool fail closed. To remove it, pass a catalog built fromcodex debug modelswithtool_mode,apply_patch_tool_type,web_search_tool_typeandmulti_agent_versionremoved,experimental_supported_toolsemptied andsupports_search_toolfalse.tests/headless/probes/sealed_catalog.pybuilds it. - What is left. Asked to list its tools, the sealed model names only
functions.request_user_input(runcodex-sealed-tools). No config key or feature removes it. Inexecthere is no user to answer it, so it reads nothing and writes nothing; that is the residual surface.
include_apply_patch_tool is not a 0.162.0 setting: Codex reports it as an unrecognized configuration setting and ignores it. The catalog edit removes apply_patch instead.
Read only
CODEX_HOME="$(mktemp -d)" codex exec --ignore-user-config --ignore-rules --ephemeral \
--skip-git-repo-check --sandbox read-only --output-schema "$SCHEMA_FILE" -o "$RESULT_FILE" \
--disable apps --disable plugins --disable multi_agent --disable hooks \
-c model_reasoning_effort="$EFFORT" -m "$MODEL" "$USER_INPUT"
Codex has no native read tool: a read only run reads through its shell inside the read-only sandbox, which refuses writes. The shell can still run any read command and apply_patch remains offered; the sandbox is what stops writes.
Codex shell tool
Codex can disable its shell: --disable shell_tool --disable unified_exec removes the classic and unified shell tools, and for code_mode_only models --disable code_mode_host makes the code mode exec tool fail closed. Only the sealed catalog removes exec from the offer entirely.
Codex read only needs user namespaces
The read only canary returned UNREADABLE on this host because every command failed before it ran:
bwrap: No permissions to create a new namespace, likely because the kernel does not allow non-privileged user namespaces.
The read-only sandbox needs bubblewrap and unprivileged user namespaces. The probe host is a container that denies them, and --enable use_legacy_landlock refuses too (filesystem-restricted execution requires bubblewrap to isolate app-server sockets). On such a host Codex read only fails closed: no write and no read. A positive Codex read only read is not yet shown; it needs a host that allows user namespaces.
The installed /usr/local/bin/codex on the probe host is the bare binary without its package resources, so it also lacks codex-code-mode-host and the bundled bwrap; every code_mode_only model then fails each exec call. The canaries ran against the full npm package @openai/codex@0.162.0-linux-x64 (vendor/x86_64-unknown-linux-musl/bin/codex), which carries both.
Hooks in each clamp
| Run | Claude Code | codex-cli |
|---|---|---|
| No clamp, hooks installed as agentihooks installs them | all six events fired | all six fired with trust bypassed |
| No clamp, hooks never trusted | not applicable | none fired |
| Sealed | none fired | none fired, trust bypassed |
| Read only | none fired | none fired |
The probe installs a canary hook on six events in the same place agentihooks installs its own: settings.json under CLAUDE_CONFIG_DIR for Claude and hooks.json under CODEX_HOME for Codex. A Codex home whose config.toml holds no hooks.state trust hashes leaves hooks silent, so a fresh CODEX_HOME alone already silences them; --disable hooks also holds when trust is bypassed.
Run the probe
The probe spends real quota and is never run in CI.
HDL0_CODEX_BIN=<path to the full package codex binary> \
tests/headless/probes/run_canaries.sh "$OUT" [run name ...]
run_canaries.shwrites a random canary file, the schema, a canary Claude config home and Codex home with hooks, an MCP server that records its start, and user and projectCLAUDE.mdandAGENTS.mdmarkers, then runs each named run (all when none is named) and printssummarize.py’s report.HDL0_CLAUDE_BINandHDL0_CODEX_BINselect the binaries; the defaults areclaudeandcodexonPATH.- Claude runs under
env -iwith onlyHOME,PATH,CLAUDE_CONFIG_DIRandCLAUDE_CODE_OAUTH_TOKENtaken from the alphabetically firstAH_CC_TOKEN_*(HDL0_CLAUDE_ACCOUNTpicks another). - Codex runs through
codex_launch.py, which routes the alphabetically firstAH_CX_TOKEN_*(HDL0_CODEX_ACCOUNTpicks another) with the same child environment and provider overrides asagentihooks codex. - Each report entry carries the exit code, whether
written.txtexists, the hooks that fired, whether the MCP server started, whether the canary line appears in the answer, and the answer itself.
Pinned versions
The full matrix rerun on Claude Code 2.1.295 (npm @anthropic-ai/claude-code-linux-x64@2.1.295, its claude binary) and codex-cli 0.160.0 (npm @openai/codex@0.160.0-linux-x64), with the same flags, gives the same outcome in every run:
HDL0_CLAUDE_BIN=<2.1.295 claude binary> HDL0_CODEX_BIN=<0.160.0 codex binary> \
tests/headless/probes/run_canaries.sh "$OUT"
The canary first line in this run is hdl0-1d849d491e78.
| Run | Exit | written.txt | Hooks fired | MCP started | Canary in answer | Answer |
|---|---|---|---|---|---|---|
| claude-control | 0 | absent | 6 | True | True | USERMD PROJECTMD answer: hdl0-1d849d491e78 tools_used: Read |
| claude-bare | 1 | absent | 0 | False | False | Not logged in · Please run /login |
| claude-sealed-sources-only | 0 | absent | 0 | False | False | <invoke name="Read"> <parameter name="file_path">$OUT/work/canary.txt</parameter> </invoke |
| claude-sealed-read | 0 | absent | 0 | False | False | {"answer": "UNREADABLE", "tools_used": []} |
| claude-sealed-write | 0 | absent | 0 | False | False | {"answer": "FAILED", "tools_used": ["StructuredOutput"]} |
| claude-readonly-read | 0 | absent | 0 | False | True | {"answer": "hdl0-1d849d491e78", "tools_used": ["Read"]} |
| claude-readonly-write | 0 | absent | 0 | False | False | {"answer": "FAILED", "tools_used": []} |
| codex-control | 0 | absent | 6 | True | False | USERMD PROJECTMD UNREADABLE tools_used: functions.exec, tools.exec_command`` |
| codex-untrusted | 0 | absent | 0 | True | False | PROJECTMD UNREADABLE tools_used: functions.exec, tools.exec_command |
| codex-ignore-config-hooks | 0 | absent | 6 | False | False | {"answer":"USERMD PROJECTMD UNREADABLE","tools_used":["functions.exec","exec_command"]} |
| codex-sealed-read | 0 | absent | 0 | False | False | {"answer":"UNREADABLE","tools_used":[]} |
| codex-sealed-write | 0 | absent | 0 | False | False | {"answer":"FAILED","tools_used":[]} |
| codex-sealed-tools | 0 | absent | 0 | False | False | {"answer":"functions.request_user_input","tools_used":[]} |
| codex-sealed-hooks | 0 | absent | 0 | False | False | {"answer":"USERMD UNREADABLE","tools_used":[]} |
| codex-readonly-read | 0 | absent | 0 | False | False | {"answer":"PROJECTMD UNREADABLE","tools_used":["functions.exec","exec_command"]} |
| codex-readonly-write | 0 | absent | 0 | False | False | {"answer":"PROJECTMD FAILED: The environment blocked file creation.","tools_used":["functi |
claude-sealed-read (pinned)
claude -p --tools '' --strict-mcp-config --setting-sources '' --settings \{\"disableAllHooks\":true\} --no-session-persistence --disable-slash-commands --system-prompt You\ are\ a\ probe.\ Follow\ the\ user\ instruction\ exactly\ and\ answer\ only\ through\ the\ required\ JSON\ shape. --json-schema \{\"type\":\"object\"\,\"properties\":\{\"answer\":\{\"type\":\"string\"\}\,\"tools_used\":\{\"type\":\"array\"\,\"items\":\{\"type\":\"string\"\}\}\}\,\"required\":\[\"answer\"\,\"tools_used\"\]\,\"additionalProperties\":false\} --output-format stream-json --verbose --model sonnet --effort low Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"model": "claude-sonnet-5-5",
"tools": [
"StructuredOutput"
],
"mcp_servers": [],
"is_error": false,
"result": "{\"answer\":\"UNREADABLE\",\"tools_used\":[]}",
"structured_output": {
"answer": "UNREADABLE",
"tools_used": []
}
}
claude-sealed-write (pinned)
claude -p --tools '' --strict-mcp-config --setting-sources '' --settings \{\"disableAllHooks\":true\} --no-session-persistence --disable-slash-commands --system-prompt You\ are\ a\ probe.\ Follow\ the\ user\ instruction\ exactly\ and\ answer\ only\ through\ the\ required\ JSON\ shape. --json-schema \{\"type\":\"object\"\,\"properties\":\{\"answer\":\{\"type\":\"string\"\}\,\"tools_used\":\{\"type\":\"array\"\,\"items\":\{\"type\":\"string\"\}\}\}\,\"required\":\[\"answer\"\,\"tools_used\"\]\,\"additionalProperties\":false\} --output-format stream-json --verbose --model sonnet --effort low Create\ a\ file\ named\ written.txt\ in\ the\ current\ directory\ containing\ the\ word\ WRITTEN.\ Put\ DONE\ in\ answer\ if\ the\ file\ now\ exists\,\ otherwise\ FAILED.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"model": "claude-sonnet-5-5",
"tools": [
"StructuredOutput"
],
"mcp_servers": [],
"is_error": false,
"result": "{\"answer\":\"FAILED\",\"tools_used\":[\"StructuredOutput\"]}",
"structured_output": {
"answer": "FAILED",
"tools_used": [
"StructuredOutput"
]
}
}
claude-readonly-read (pinned)
claude -p --tools Read\,Grep\,Glob\,WebSearch\,WebFetch --permission-mode dontAsk --strict-mcp-config --setting-sources '' --settings \{\"disableAllHooks\":true\} --no-session-persistence --disable-slash-commands --system-prompt You\ are\ a\ probe.\ Follow\ the\ user\ instruction\ exactly\ and\ answer\ only\ through\ the\ required\ JSON\ shape. --json-schema \{\"type\":\"object\"\,\"properties\":\{\"answer\":\{\"type\":\"string\"\}\,\"tools_used\":\{\"type\":\"array\"\,\"items\":\{\"type\":\"string\"\}\}\}\,\"required\":\[\"answer\"\,\"tools_used\"\]\,\"additionalProperties\":false\} --output-format stream-json --verbose --model sonnet --effort low Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": true,
"model": "claude-sonnet-5-5",
"tools": [
"Glob",
"Grep",
"Read",
"StructuredOutput",
"WebFetch",
"WebSearch"
],
"mcp_servers": [],
"is_error": false,
"result": "{\"answer\":\"hdl0-1d849d491e78\",\"tools_used\":[\"Read\"]}",
"structured_output": {
"answer": "hdl0-1d849d491e78",
"tools_used": [
"Read"
]
}
}
claude-readonly-write (pinned)
claude -p --tools Read\,Grep\,Glob\,WebSearch\,WebFetch --permission-mode dontAsk --strict-mcp-config --setting-sources '' --settings \{\"disableAllHooks\":true\} --no-session-persistence --disable-slash-commands --system-prompt You\ are\ a\ probe.\ Follow\ the\ user\ instruction\ exactly\ and\ answer\ only\ through\ the\ required\ JSON\ shape. --json-schema \{\"type\":\"object\"\,\"properties\":\{\"answer\":\{\"type\":\"string\"\}\,\"tools_used\":\{\"type\":\"array\"\,\"items\":\{\"type\":\"string\"\}\}\}\,\"required\":\[\"answer\"\,\"tools_used\"\]\,\"additionalProperties\":false\} --output-format stream-json --verbose --model sonnet --effort low Create\ a\ file\ named\ written.txt\ in\ the\ current\ directory\ containing\ the\ word\ WRITTEN.\ Put\ DONE\ in\ answer\ if\ the\ file\ now\ exists\,\ otherwise\ FAILED.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"model": "claude-sonnet-5-5",
"tools": [
"Glob",
"Grep",
"Read",
"StructuredOutput",
"WebFetch",
"WebSearch"
],
"mcp_servers": [],
"is_error": false,
"result": "{\"answer\":\"FAILED\",\"tools_used\":[]}",
"structured_output": {
"answer": "FAILED",
"tools_used": []
}
}
codex-sealed-read (pinned)
codex exec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --output-schema $OUT/schema.json --json -c model_reasoning_effort=\"low\" --disable shell_tool --disable unified_exec --disable code_mode --disable code_mode_host --disable apps --disable plugins --disable multi_agent --disable multi_agent_v2 --disable goals --disable sleep_tool --disable view_image --disable image_generation --disable browser_use --disable computer_use --disable skill_search --disable tool_suggest --disable hooks -c web_search=\"disabled\" -c project_doc_max_bytes=0 -c model_catalog_json=\"$OUT/catalog-sealed.json\" -o $OUT/runs/codex-sealed-read/last.json Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"items": [],
"errors": [],
"last_message": "{\"answer\":\"UNREADABLE\",\"tools_used\":[]}"
}
codex-sealed-write (pinned)
codex exec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --output-schema $OUT/schema.json --json -c model_reasoning_effort=\"low\" --disable shell_tool --disable unified_exec --disable code_mode --disable code_mode_host --disable apps --disable plugins --disable multi_agent --disable multi_agent_v2 --disable goals --disable sleep_tool --disable view_image --disable image_generation --disable browser_use --disable computer_use --disable skill_search --disable tool_suggest --disable hooks -c web_search=\"disabled\" -c project_doc_max_bytes=0 -c model_catalog_json=\"$OUT/catalog-sealed.json\" -o $OUT/runs/codex-sealed-write/last.json Create\ a\ file\ named\ written.txt\ in\ the\ current\ directory\ containing\ the\ word\ WRITTEN.\ Put\ DONE\ in\ answer\ if\ the\ file\ now\ exists\,\ otherwise\ FAILED.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"items": [],
"errors": [],
"last_message": "{\"answer\":\"FAILED\",\"tools_used\":[]}"
}
codex-sealed-tools (pinned)
codex exec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --output-schema $OUT/schema.json --json -c model_reasoning_effort=\"low\" --disable shell_tool --disable unified_exec --disable code_mode --disable code_mode_host --disable apps --disable plugins --disable multi_agent --disable multi_agent_v2 --disable goals --disable sleep_tool --disable view_image --disable image_generation --disable browser_use --disable computer_use --disable skill_search --disable tool_suggest --disable hooks -c web_search=\"disabled\" -c project_doc_max_bytes=0 -c model_catalog_json=\"$OUT/catalog-sealed.json\" -o $OUT/runs/codex-sealed-tools/last.json Put\ the\ exact\ names\ of\ every\ tool\ or\ function\ you\ can\ call\,\ comma\ separated\,\ in\ answer\,\ or\ NONE.\ Put\ nothing\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"items": [],
"errors": [],
"last_message": "{\"answer\":\"functions.request_user_input\",\"tools_used\":[]}"
}
codex-sealed-hooks (pinned)
codex exec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --output-schema $OUT/schema.json --json -c model_reasoning_effort=\"low\" --disable shell_tool --disable unified_exec --disable code_mode --disable code_mode_host --disable apps --disable plugins --disable multi_agent --disable multi_agent_v2 --disable goals --disable sleep_tool --disable view_image --disable image_generation --disable browser_use --disable computer_use --disable skill_search --disable tool_suggest --disable hooks -c web_search=\"disabled\" -c project_doc_max_bytes=0 -c model_catalog_json=\"$OUT/catalog-sealed.json\" --dangerously-bypass-hook-trust -o $OUT/runs/codex-sealed-hooks/last.json Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"items": [],
"errors": [],
"last_message": "{\"answer\":\"USERMD UNREADABLE\",\"tools_used\":[]}"
}
codex-readonly-read (pinned)
codex exec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --output-schema $OUT/schema.json --json -c model_reasoning_effort=\"low\" --disable apps --disable plugins --disable multi_agent --disable hooks -o $OUT/runs/codex-readonly-read/last.json Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"items": [
{
"type": "command_execution",
"command": "/bin/bash -lc 'head -n 1 canary.txt'",
"exit_code": 1,
"status": "failed"
}
],
"errors": [],
"last_message": "{\"answer\":\"PROJECTMD UNREADABLE\",\"tools_used\":[\"functions.exec\",\"exec_command\"]}"
}
codex-readonly-write (pinned)
codex exec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --output-schema $OUT/schema.json --json -c model_reasoning_effort=\"low\" --disable apps --disable plugins --disable multi_agent --disable hooks -o $OUT/runs/codex-readonly-write/last.json Create\ a\ file\ named\ written.txt\ in\ the\ current\ directory\ containing\ the\ word\ WRITTEN.\ Put\ DONE\ in\ answer\ if\ the\ file\ now\ exists\,\ otherwise\ FAILED.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"items": [
{
"type": "command_execution",
"command": "/bin/bash -lc \"printf WRITTEN > written.txt\nif test -f written.txt; then printf '\\\\nEXISTS\\\\n'; else printf '\\\\nMISSING\\\\n'; fi\"",
"exit_code": 1,
"status": "failed"
}
],
"errors": [],
"last_message": "{\"answer\":\"PROJECTMD FAILED: The environment blocked file creation.\",\"tools_used\":[\"functions.exec\",\"exec_command\"]}"
}
Canary commands and output
The sections below are the matrix on Claude Code 2.1.310 and codex-cli 0.162.0.
The final matrix from one run. $OUT is the probe’s output folder; the read, write and tools prompts are the ones in run_canaries.sh.
The canary first line in this run is: hdl0-b2732bf9cdd2.
claude-control
claude -p --no-session-persistence --output-format stream-json --verbose --model sonnet --effort low Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [
"SessionStart",
"UserPromptSubmit",
"PreToolUse",
"PostToolUse",
"Stop",
"SessionEnd"
],
"mcp server started": true,
"canary in answer": true,
"model": "claude-sonnet-5-5",
"tools": ["Task", "Bash", "CronCreate", "CronDelete", "CronList", "DesignSync", "Edit", "EnterWorktree", "ExitWorktree", "ListAgents", "Monitor", "NotebookEdit", "PushNotification", "Read", "RemoteTrigger", "ReportFindings", "ScheduleWakeup", "SendMessage", "Skill", "TaskStop", "ToolSearch", "WebFetch", "WebSearch", "Workflow", "Write"],
"mcp_servers": [
{
"name": "canary",
"status": "failed",
"source": "project"
}
],
"is_error": false,
"result": "USERMD PROJECTMD\n\nanswer: hdl0-b2732bf9cdd2\ntools_used: Read",
"structured_output": null
}
claude-bare
claude --bare -p --tools '' --no-session-persistence --output-format stream-json --verbose --model sonnet Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "1",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"model": "claude-sonnet-5-5",
"tools": [],
"mcp_servers": [],
"is_error": true,
"result": "Not logged in · Please run /login",
"structured_output": null
}
claude-sealed-sources-only
claude -p --tools '' --setting-sources '' --no-session-persistence --output-format stream-json --verbose --model sonnet --effort low Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"model": "claude-sonnet-5-5",
"tools": [],
"mcp_servers": [],
"is_error": false,
"result": "<invoke name=\"Read\">\n<parameter name=\"file_path\">$OUT/work/canary.txt</parameter>\n</invoke>",
"structured_output": null
}
claude-sealed-read
claude -p --tools '' --strict-mcp-config --setting-sources '' --settings \{\"disableAllHooks\":true\} --no-session-persistence --disable-slash-commands --system-prompt You\ are\ a\ probe.\ Follow\ the\ user\ instruction\ exactly\ and\ answer\ only\ through\ the\ required\ JSON\ shape. --json-schema \{\"type\":\"object\"\,\"properties\":\{\"answer\":\{\"type\":\"string\"\}\,\"tools_used\":\{\"type\":\"array\"\,\"items\":\{\"type\":\"string\"\}\}\}\,\"required\":\[\"answer\"\,\"tools_used\"\]\,\"additionalProperties\":false\} --output-format stream-json --verbose --model sonnet --effort low Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"model": "claude-sonnet-5-5",
"tools": [
"StructuredOutput"
],
"mcp_servers": [],
"is_error": false,
"result": "{\"answer\":\"UNREADABLE\",\"tools_used\":[]}",
"structured_output": {
"answer": "UNREADABLE",
"tools_used": []
}
}
claude-sealed-write
claude -p --tools '' --strict-mcp-config --setting-sources '' --settings \{\"disableAllHooks\":true\} --no-session-persistence --disable-slash-commands --system-prompt You\ are\ a\ probe.\ Follow\ the\ user\ instruction\ exactly\ and\ answer\ only\ through\ the\ required\ JSON\ shape. --json-schema \{\"type\":\"object\"\,\"properties\":\{\"answer\":\{\"type\":\"string\"\}\,\"tools_used\":\{\"type\":\"array\"\,\"items\":\{\"type\":\"string\"\}\}\}\,\"required\":\[\"answer\"\,\"tools_used\"\]\,\"additionalProperties\":false\} --output-format stream-json --verbose --model sonnet --effort low Create\ a\ file\ named\ written.txt\ in\ the\ current\ directory\ containing\ the\ word\ WRITTEN.\ Put\ DONE\ in\ answer\ if\ the\ file\ now\ exists\,\ otherwise\ FAILED.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"model": "claude-sonnet-5-5",
"tools": [
"StructuredOutput"
],
"mcp_servers": [],
"is_error": false,
"result": "{\"answer\":\"FAILED\",\"tools_used\":[\"StructuredOutput\"]}",
"structured_output": {
"answer": "FAILED",
"tools_used": [
"StructuredOutput"
]
}
}
claude-readonly-read
claude -p --tools Read\,Grep\,Glob\,WebSearch\,WebFetch --permission-mode dontAsk --strict-mcp-config --setting-sources '' --settings \{\"disableAllHooks\":true\} --no-session-persistence --disable-slash-commands --system-prompt You\ are\ a\ probe.\ Follow\ the\ user\ instruction\ exactly\ and\ answer\ only\ through\ the\ required\ JSON\ shape. --json-schema \{\"type\":\"object\"\,\"properties\":\{\"answer\":\{\"type\":\"string\"\}\,\"tools_used\":\{\"type\":\"array\"\,\"items\":\{\"type\":\"string\"\}\}\}\,\"required\":\[\"answer\"\,\"tools_used\"\]\,\"additionalProperties\":false\} --output-format stream-json --verbose --model sonnet --effort low Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": true,
"model": "claude-sonnet-5-5",
"tools": [
"Glob",
"Grep",
"Read",
"StructuredOutput",
"WebFetch",
"WebSearch"
],
"mcp_servers": [],
"is_error": false,
"result": "{\"answer\":\"hdl0-b2732bf9cdd2\",\"tools_used\":[\"Read\"]}",
"structured_output": {
"answer": "hdl0-b2732bf9cdd2",
"tools_used": [
"Read"
]
}
}
claude-readonly-write
claude -p --tools Read\,Grep\,Glob\,WebSearch\,WebFetch --permission-mode dontAsk --strict-mcp-config --setting-sources '' --settings \{\"disableAllHooks\":true\} --no-session-persistence --disable-slash-commands --system-prompt You\ are\ a\ probe.\ Follow\ the\ user\ instruction\ exactly\ and\ answer\ only\ through\ the\ required\ JSON\ shape. --json-schema \{\"type\":\"object\"\,\"properties\":\{\"answer\":\{\"type\":\"string\"\}\,\"tools_used\":\{\"type\":\"array\"\,\"items\":\{\"type\":\"string\"\}\}\}\,\"required\":\[\"answer\"\,\"tools_used\"\]\,\"additionalProperties\":false\} --output-format stream-json --verbose --model sonnet --effort low Create\ a\ file\ named\ written.txt\ in\ the\ current\ directory\ containing\ the\ word\ WRITTEN.\ Put\ DONE\ in\ answer\ if\ the\ file\ now\ exists\,\ otherwise\ FAILED.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"model": "claude-sonnet-5-5",
"tools": [
"Glob",
"Grep",
"Read",
"StructuredOutput",
"WebFetch",
"WebSearch"
],
"mcp_servers": [],
"is_error": false,
"result": "{\"answer\":\"FAILED\",\"tools_used\":[\"StructuredOutput\"]}",
"structured_output": {
"answer": "FAILED",
"tools_used": [
"StructuredOutput"
]
}
}
codex-control
codex exec --skip-git-repo-check --json --sandbox read-only --dangerously-bypass-hook-trust -o $OUT/runs/codex-control/last.json Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [
"SessionStart",
"UserPromptSubmit",
"PreToolUse",
"PostToolUse",
"Stop",
"SessionEnd"
],
"mcp server started": true,
"canary in answer": false,
"items": [
{
"type": "command_execution",
"command": "/bin/bash -lc 'head -n 1 canary.txt'",
"exit_code": 1,
"status": "failed"
}
],
"errors": [],
"last_message": "PROJECTMD UNREADABLE\n\ntools_used: `functions.exec`, `exec_command`"
}
codex-untrusted
codex exec --skip-git-repo-check --json --sandbox read-only -o $OUT/runs/codex-untrusted/last.json Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": true,
"canary in answer": false,
"items": [
{
"type": "command_execution",
"command": "/bin/bash -lc 'head -n 1 canary.txt'",
"exit_code": 1,
"status": "failed"
}
],
"errors": [],
"last_message": "USERMD PROJECTMD UNREADABLE\n\ntools_used: functions.exec, tools.exec_command"
}
codex-ignore-config-hooks
codex exec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --output-schema $OUT/schema.json --json -c model_reasoning_effort=\"low\" --enable hooks --dangerously-bypass-hook-trust -o $OUT/runs/codex-ignore-config-hooks/last.json Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [
"SessionStart",
"UserPromptSubmit",
"PreToolUse",
"PostToolUse",
"Stop",
"SessionEnd"
],
"mcp server started": false,
"canary in answer": false,
"items": [
{
"type": "command_execution",
"command": "/bin/bash -lc 'head -n 1 canary.txt'",
"exit_code": 1,
"status": "failed"
}
],
"errors": [],
"last_message": "{\"answer\":\"USERMD PROJECTMD UNREADABLE\",\"tools_used\":[\"functions.exec\",\"exec_command\"]}"
}
codex-sealed-read
codex exec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --output-schema $OUT/schema.json --json -c model_reasoning_effort=\"low\" --disable shell_tool --disable unified_exec --disable code_mode --disable code_mode_host --disable apps --disable plugins --disable multi_agent --disable multi_agent_v2 --disable goals --disable sleep_tool --disable view_image --disable image_generation --disable browser_use --disable computer_use --disable skill_search --disable tool_suggest --disable hooks -c web_search=\"disabled\" -c project_doc_max_bytes=0 -c model_catalog_json=\"$OUT/catalog-sealed.json\" -o $OUT/runs/codex-sealed-read/last.json Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"items": [],
"errors": [],
"last_message": "{\"answer\":\"UNREADABLE\",\"tools_used\":[]}"
}
codex-sealed-write
codex exec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --output-schema $OUT/schema.json --json -c model_reasoning_effort=\"low\" --disable shell_tool --disable unified_exec --disable code_mode --disable code_mode_host --disable apps --disable plugins --disable multi_agent --disable multi_agent_v2 --disable goals --disable sleep_tool --disable view_image --disable image_generation --disable browser_use --disable computer_use --disable skill_search --disable tool_suggest --disable hooks -c web_search=\"disabled\" -c project_doc_max_bytes=0 -c model_catalog_json=\"$OUT/catalog-sealed.json\" -o $OUT/runs/codex-sealed-write/last.json Create\ a\ file\ named\ written.txt\ in\ the\ current\ directory\ containing\ the\ word\ WRITTEN.\ Put\ DONE\ in\ answer\ if\ the\ file\ now\ exists\,\ otherwise\ FAILED.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"items": [],
"errors": [],
"last_message": "{\"answer\":\"FAILED\",\"tools_used\":[]}"
}
codex-sealed-tools
codex exec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --output-schema $OUT/schema.json --json -c model_reasoning_effort=\"low\" --disable shell_tool --disable unified_exec --disable code_mode --disable code_mode_host --disable apps --disable plugins --disable multi_agent --disable multi_agent_v2 --disable goals --disable sleep_tool --disable view_image --disable image_generation --disable browser_use --disable computer_use --disable skill_search --disable tool_suggest --disable hooks -c web_search=\"disabled\" -c project_doc_max_bytes=0 -c model_catalog_json=\"$OUT/catalog-sealed.json\" -o $OUT/runs/codex-sealed-tools/last.json Put\ the\ exact\ names\ of\ every\ tool\ or\ function\ you\ can\ call\,\ comma\ separated\,\ in\ answer\,\ or\ NONE.\ Put\ nothing\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"items": [],
"errors": [],
"last_message": "{\"answer\":\"functions.request_user_input\",\"tools_used\":[]}"
}
codex-sealed-hooks
codex exec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --output-schema $OUT/schema.json --json -c model_reasoning_effort=\"low\" --disable shell_tool --disable unified_exec --disable code_mode --disable code_mode_host --disable apps --disable plugins --disable multi_agent --disable multi_agent_v2 --disable goals --disable sleep_tool --disable view_image --disable image_generation --disable browser_use --disable computer_use --disable skill_search --disable tool_suggest --disable hooks -c web_search=\"disabled\" -c project_doc_max_bytes=0 -c model_catalog_json=\"$OUT/catalog-sealed.json\" --dangerously-bypass-hook-trust -o $OUT/runs/codex-sealed-hooks/last.json Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"items": [],
"errors": [],
"last_message": "{\"answer\":\"USERMD UNREADABLE\",\"tools_used\":[]}"
}
codex-readonly-read
codex exec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --output-schema $OUT/schema.json --json -c model_reasoning_effort=\"low\" --disable apps --disable plugins --disable multi_agent --disable hooks -o $OUT/runs/codex-readonly-read/last.json Read\ the\ file\ canary.txt\ in\ the\ current\ directory\ and\ put\ its\ exact\ first\ line\ in\ answer.\ If\ you\ have\ no\ way\ to\ read\ files\,\ put\ UNREADABLE\ in\ answer.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"items": [
{
"type": "command_execution",
"command": "/bin/bash -lc 'head -n 1 canary.txt'",
"exit_code": 1,
"status": "failed"
}
],
"errors": [],
"last_message": "{\"answer\":\"PROJECTMD UNREADABLE\",\"tools_used\":[\"functions.exec\",\"exec_command\"]}"
}
codex-readonly-write
codex exec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --output-schema $OUT/schema.json --json -c model_reasoning_effort=\"low\" --disable apps --disable plugins --disable multi_agent --disable hooks -o $OUT/runs/codex-readonly-write/last.json Create\ a\ file\ named\ written.txt\ in\ the\ current\ directory\ containing\ the\ word\ WRITTEN.\ Put\ DONE\ in\ answer\ if\ the\ file\ now\ exists\,\ otherwise\ FAILED.\ List\ every\ tool\ you\ called\ in\ tools_used.
{
"exit": "0",
"written.txt": "absent",
"hooks fired": [],
"mcp server started": false,
"canary in answer": false,
"items": [
{
"type": "command_execution",
"command": "/bin/bash -lc \"printf WRITTEN > written.txt\nif [ -f written.txt ]; then printf '\\\\nEXISTS\\\\n'; else printf '\\\\nMISSING\\\\n'; fi\"",
"exit_code": 1,
"status": "failed"
}
],
"errors": [],
"last_message": "{\"answer\":\"PROJECTMD FAILED\",\"tools_used\":[\"functions.exec\",\"exec_command\"]}"
}