#22873·orca

[Bug]: Codex 0.157 shared app-server daemon runs hooks with the first worker's env — concurrent workers are misattributed, and releasing one kills the others

Author: fukutomyCreated Sep 25, 2026Updated Sep 29, 2026

Operating system

macOS (coordinator). Workers run on an SSH host: a Linux arm64 Docker Sandbox, reached through the Orca relay.

Orca version

1.4.211

Details

Summary

Codex 0.157.0 turned on daemon_auto_start by default (openai/codex#47179). The TUI now attaches to a shared codex app-server --managed-daemon, and lifecycle hooks run inside that daemon. The daemon is spawned as a child of whichever codex TUI started first, so it carries that pane's environment (ORCA_PANE_KEY, ORCA_AGENT_LAUNCH_TOKEN, hook endpoint). With two or more concurrent supervised codex workers on the same host:

  1. The second worker's hook events are sent under the first worker's identity. Orca then attributes them to the wrong Dispatch.
  2. Releasing the first worker closes its terminal, the daemon exits with it, and the second worker's session dies mid-task. It never sends worker_done.

The readiness timeout in #22825 has to be worked around first ([tui] fullscreen_transcript = false); otherwise no codex 0.157 worker gets far enough to show this.

Environment

  • Orca 1.4.211, orca orchestration worker-start --agent codex onto an SSH host
  • codex-cli 0.157.0 with default daemon_auto_start (true), plus [tui] fullscreen_transcript = false

Reproduction

  1. Start worker A with a short read-only task. Start worker B, in the same Run, while A is still live, with a task that runs sleep 90 first.
  2. Record the ancestors of the hook processes on the worker host. We added a temporary line to the codex hook script that logs the parent chain's command lines, and nothing else.
  3. Compare orca orchestration worker-read --dispatch <A|B> --json for the two workers.
  4. After A sends worker_done, run worker-release for A, then read B's screen with orca terminal read --screen.

Observed

  • Hooks for both A and B run under the same process tree: bash (A's Orca pane) → node codex → codex TUI (A) → codex app-server --managed-daemon.
  • B: provider: null, fallbackReason: session_not_reported, liveness unverifiable / missing_status, even though B is working.
  • A, already settled: stage.activity: working, and its liveness observedAt equals B's PreToolUse time. B's events land on A.
  • After releasing A, the daemon process is gone. B shows:
    ■ Connection lost. Attempting to reconnect…
    ■ Automatic reconnect could not restore this session. …
    ■ app-server session could not be restored
    • Reconnect failed — check the endpoint, then relaunch
    B never sends worker_done. We had to worker-stop it.
  • Strictly sequential use hides the problem: releasing a worker kills its daemon, and the next worker starts a fresh one under its own pane.

Expected

Each supervised worker's hook events are attributed to its own Dispatch, and releasing one worker does not affect other live workers.

Workaround (verified)

On the worker host, in ~/.codex/config.toml:

toml
[features]
daemon_auto_start = false

With this set and no daemon running, two concurrent workers each ran hooks under their own TUI process. Both showed provider: codex and liveness live. Releasing B did not affect A, which completed and sent worker_done.

Caveat, from reading codex source and not verified: a TUI may still attach to an already-running daemon socket even with the feature off. So a daemon started by hand (codex app-server daemon start, codex agents) would bring the problem back.

Possible fixes

  • Launch supervised codex workers with --no-daemon. Codex's own help says this runs "without the background server".
  • Or stop relying on the hook process's inherited environment for pane attribution when codex runs through the shared daemon.