Summary
When a provider agent (e.g. claude_code) is executed inside a container — via a PATH-shadow shim that does podman exec <task-container> claude "$@" on the host, so CAO/herdr run on the host and the agent process lives in the container — CAO cannot complete terminal initialization. The agent binary itself runs fine and completes real turns, but three assumptions in the provider/herdr layer break for wrapped (containerized/remote) execution. I got a full turn to complete only by manually driving the startup dialogs and delivering the task; CAO's own auto-init/auto-delivery never succeeds.
This is a "run agents in isolated containers" use case (one container + worktree per task) on a shared host; the shim is what makes CAO's host-side provider detection resolve (shutil.which("claude") → shim). Filing so the wrapped-execution path can be supported (or documented).
Environment
- CAO:
git main (also repro on v2.2.0), --terminal herdr
- herdr: 0.7.x, host-side, session
cao
- Agent: Claude Code 2.1.204, launched inside a rootless-podman container via
podman exec -it -e IS_SANDBOX=1 -w /home/.../arcadia at-<task> claude "$@"
- Host: Linux, rootless podman 3.4.4
Blockers (in order hit)
1. Host-written --append-system-prompt-file / --mcp-config are inaccessible to a containerized agent
claude_code._build_claude_command() writes the profile system prompt and MCP config to host temp files under ~/.aws/cli-agent-orchestrator/tmp/<id>.prompt / .mcp.json and passes those host paths to the claude command. When claude runs in a container, that path does not exist there:
claude --dangerously-skip-permissions --append-system-prompt-file /home/<user>/.aws/cli-agent-orchestrator/tmp/<id>.prompt --mcp-config .../<id>.mcp.json --strict-mcp-config
Error: Append system prompt file not found: /home/<user>/.aws/cli-agent-orchestrator/tmp/<id>.prompt
claude exits immediately → herdr never registers an agent → init times out.
Workaround (integration side): bind-mount ~/.aws/cli-agent-orchestrator/tmp into the container at the same path. Works, but couples the container to CAO's host layout. A CAO-side option to pass the system prompt/MCP config inline (already shlex-escaped), or to make the temp dir configurable, would remove the host-filesystem coupling for wrapped execution.
2. Startup trust / bypass-permissions dialogs are not auto-accepted for slow-starting agents
After (1) is worked around, claude starts but shows two interactive dialogs: the workspace-trust dialog ("Yes, I trust this folder") and the --dangerously-skip-permissions bypass confirmation ("Yes, I accept"). _handle_startup_prompts() is meant to answer both (its TRUST_PROMPT_PATTERN / BYPASS_PROMPT_PATTERN do match the current wording), but it runs once for startup_prompt_handler_timeout (~20 s) before wait_until_status, and a containerized claude renders those dialogs after that window (cold-ish node start + gateway connect). Result: Startup prompt handler timed out, dialogs left unanswered, then Claude Code initialization timed out after 60s.
Manually sending Enter (trust) then Down+Enter (bypass) via herdr pane send-keys cleared both and claude reached its REPL normally. Suggestion: keep answering trust/bypass prompts during the wait_until_status wait (not only in a fixed pre-window), so agents that start slower than the handler timeout are still handled.
3. get_native_status maps herdr agent_status="unknown" → ERROR, blocking init/inbox for wrapped agents
HerdrBackend.get_native_status() maps herdr agent_status="unknown" to TerminalStatus.ERROR ("pane exists but no agent registered yet"). For a containerized agent the pane's foreground process is podman exec …; herdr's native agent detection never registers the nested claude, so agent_status stays "unknown" permanently → CAO reports ERROR → wait_until_status({IDLE, COMPLETED}) never succeeds → init fails and inbox auto-delivery is blocked. Even with blockers (1) and (2) resolved and claude's REPL fully up (verified: banner + bypass permissions on + a real turn), agent_status remained "unknown".
"unknown" at startup is arguably transient rather than a terminal error; mapping it to ERROR (instead of e.g. a not-yet-ready state, or falling through) turns "herdr can't classify this pane" into a hard init failure. This is the core blocker for any agent herdr can't natively introspect (containerized / remote / wrapped).
Repro sketch
- Put a wrapper named
claude on the CAO host PATH that execs podman exec -it -e IS_SANDBOX=1 -w <container-workdir> <container> claude "$@".
cao launch --agents <profile-with-system-prompt> --provider claude_code --headless --yolo --working-directory <dir> "<task>".
- Observe:
Append system prompt file not found in the pane (herdr pane read), then—after bind-mounting the temp dir—Startup prompt handler timed out → Claude Code initialization timed out after 60s; herdr pane get shows agent_status: "unknown" throughout.
What already works
The agent and turn themselves are fine: driving the two dialogs and delivering the task by hand via herdr pane send-text/send-keys produced a correct, completed turn (tool use + file write) inside the container. Only CAO's automatic init/status/delivery is blocked by the three items above.
Happy to provide full logs or test a patch.
Summary
When a provider agent (e.g.
claude_code) is executed inside a container — via aPATH-shadow shim that doespodman exec <task-container> claude "$@"on the host, so CAO/herdr run on the host and the agent process lives in the container — CAO cannot complete terminal initialization. The agent binary itself runs fine and completes real turns, but three assumptions in the provider/herdr layer break for wrapped (containerized/remote) execution. I got a full turn to complete only by manually driving the startup dialogs and delivering the task; CAO's own auto-init/auto-delivery never succeeds.This is a "run agents in isolated containers" use case (one container + worktree per task) on a shared host; the shim is what makes CAO's host-side provider detection resolve (
shutil.which("claude")→ shim). Filing so the wrapped-execution path can be supported (or documented).Environment
git main(also repro onv2.2.0),--terminal herdrcaopodman exec -it -e IS_SANDBOX=1 -w /home/.../arcadia at-<task> claude "$@"Blockers (in order hit)
1. Host-written
--append-system-prompt-file/--mcp-configare inaccessible to a containerized agentclaude_code._build_claude_command()writes the profile system prompt and MCP config to host temp files under~/.aws/cli-agent-orchestrator/tmp/<id>.prompt/.mcp.jsonand passes those host paths to theclaudecommand. Whenclauderuns in a container, that path does not exist there:claudeexits immediately → herdr never registers an agent → init times out.Workaround (integration side): bind-mount
~/.aws/cli-agent-orchestrator/tmpinto the container at the same path. Works, but couples the container to CAO's host layout. A CAO-side option to pass the system prompt/MCP config inline (already shlex-escaped), or to make the temp dir configurable, would remove the host-filesystem coupling for wrapped execution.2. Startup trust / bypass-permissions dialogs are not auto-accepted for slow-starting agents
After (1) is worked around,
claudestarts but shows two interactive dialogs: the workspace-trust dialog ("Yes, I trust this folder") and the--dangerously-skip-permissionsbypass confirmation ("Yes, I accept")._handle_startup_prompts()is meant to answer both (itsTRUST_PROMPT_PATTERN/BYPASS_PROMPT_PATTERNdo match the current wording), but it runs once forstartup_prompt_handler_timeout(~20 s) beforewait_until_status, and a containerizedclauderenders those dialogs after that window (cold-ish node start + gateway connect). Result:Startup prompt handler timed out, dialogs left unanswered, thenClaude Code initialization timed out after 60s.Manually sending
Enter(trust) thenDown+Enter(bypass) viaherdr pane send-keyscleared both andclaudereached its REPL normally. Suggestion: keep answering trust/bypass prompts during thewait_until_statuswait (not only in a fixed pre-window), so agents that start slower than the handler timeout are still handled.3.
get_native_statusmaps herdragent_status="unknown"→ERROR, blocking init/inbox for wrapped agentsHerdrBackend.get_native_status()maps herdragent_status="unknown"toTerminalStatus.ERROR("pane exists but no agent registered yet"). For a containerized agent the pane's foreground process ispodman exec …; herdr's native agent detection never registers the nestedclaude, soagent_statusstays"unknown"permanently → CAO reportsERROR→wait_until_status({IDLE, COMPLETED})never succeeds → init fails and inbox auto-delivery is blocked. Even with blockers (1) and (2) resolved andclaude's REPL fully up (verified: banner +bypass permissions on+ a real turn),agent_statusremained"unknown"."unknown"at startup is arguably transient rather than a terminal error; mapping it toERROR(instead of e.g. a not-yet-ready state, or falling through) turns "herdr can't classify this pane" into a hard init failure. This is the core blocker for any agent herdr can't natively introspect (containerized / remote / wrapped).Repro sketch
claudeon the CAO hostPATHthat execspodman exec -it -e IS_SANDBOX=1 -w <container-workdir> <container> claude "$@".cao launch --agents <profile-with-system-prompt> --provider claude_code --headless --yolo --working-directory <dir> "<task>".Append system prompt file not foundin the pane (herdrpane read), then—after bind-mounting the temp dir—Startup prompt handler timed out→Claude Code initialization timed out after 60s;herdr pane getshowsagent_status: "unknown"throughout.What already works
The agent and turn themselves are fine: driving the two dialogs and delivering the task by hand via
herdr pane send-text/send-keysproduced a correct, completed turn (tool use + file write) inside the container. Only CAO's automatic init/status/delivery is blocked by the three items above.Happy to provide full logs or test a patch.