Skip to content

[bug] codex-multi-auth-codex app-server cannot run on the shadow CODEX_HOME #659

Description

@possibilities

Summary

codex-multi-auth-codex app-server takes the shadow-CODEX_HOME transport, and a resident server cannot live there. On any machine that has previously run an app-server it does not start at all; where it does start, every attached client drives threads against a frozen copy of the thread index.

This is the same class of defect as #647, which was fixed for resume/fork in #648 by routing them to the canonical-home app helper. app-server was left on the shadow path.

Environment

codex-cli            0.147.0
codex-multi-auth     2.8.3
node                 v24.16.0
macOS                26.5.2

Account-pool output from codex-multi-auth status / report --json is omitted deliberately — it carries account emails, and nothing in this report depends on it. Reproduces with any single managed account and runtime rotation on (the default).

Reproduction 1 — the server refuses to start

Codex requires <CODEX_HOME>/app-server-control to be a directory, and the check is lstat-strict. Codex itself creates that directory the first time an app-server runs, so most real homes have one. The shadow mirror links directories rather than copying them, so the shadow home gets a symlink at that path.

$ ls -ld ~/.codex/app-server-control
drwx------  3 user  staff  96 ... /Users/user/.codex/app-server-control

$ codex-multi-auth-codex --account <id> app-server --listen unix:///path/to/a.sock
Error: socket directory path exists and is not a directory: \
  /Users/user/.codex/multi-auth/runtime-shadow-homes/codex-multi-auth-runtime-home-XXXXXX/app-server-control

Exit 1, no server. Removing ~/.codex/app-server-control makes it start again, which confirms the mirror's symlink is the trigger.

Unrelated but easy to trip over while testing: Codex applies the same lstat-strict check to the listen socket's parent directory, so --listen unix:///tmp/x.sock fails on macOS because /tmp is a symlink to /private/tmp. Use real paths.

Reproduction 2 — a server that does start serves a frozen thread index

The runtime-rotation shadow mirror snapshots state_N.sqlite rather than linking it. For resume that was #647: the requested thread was absent and the TUI hung. For an app-server the same divergence is held for the life of the process and handed to every client that attaches, and any thread the server creates is written into a copy that is discarded on exit.

$ ls -l ~/.codex/state_5.sqlite
-rw-r--r--  1 user  staff  6799360 ... /Users/user/.codex/state_5.sqlite

$ ls -l <shadow home>/state_5.sqlite     # while the server runs
-rw-r--r--  1 user  staff  6799360 ...   # a copy, not a link; discarded at exit

Expected

app-server runs against the canonical CODEX_HOME, like the interactive TUI and resume/fork already do, receiving the rotation provider through -c overrides.

Why it matters

An app-server is the programmatic entry point: clients attach to it and drive whole sessions through it, and the account bound to the server process is the one those sessions bill. Runtime rotation is on by default, so on 0.147.0 the wrapper's app-server path is effectively unusable.

Fix

Happy to send the patch — it is one predicate plus two details, and it follows #648's shape. PR to follow.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions