Skip to content

feat(desktop): codex attach-rung resolver (L4a) - #568

Merged
physercoe merged 2 commits into
mainfrom
feat-vision-l4a-codex-attach-v2
Aug 16, 2026
Merged

feat(desktop): codex attach-rung resolver (L4a)#568
physercoe merged 2 commits into
mainfrom
feat-vision-l4a-codex-attach-v2

Conversation

@physercoe

Copy link
Copy Markdown
Owner

Replaces #567, which was based on the F4 branch and therefore got zero CI — this repo's workflows are pull_request: branches: [main], so a stacked PR is never verified. Now based on main (which has both #565 and #566).

L4's plan line specified a WebSocket attach to a codex app-server daemon, authenticated with a bearer scheme, with stdio spawn-per-session as "the fallback rung only".

Measured against the installed codex-cli 0.147.0, all three parts are wrong. This lands the corrected decision as a pure, tested resolver before any driver is written against it — building the WebSocket client the plan describes would have been a dead end.

What codex actually ships

  1. The shared-daemon transport is a Unix domain socket, not a WebSocket, and there is no bearer scheme. codex app-server daemon start brings the daemon up; codex app-server proxy --sock <path> pipes stdio to its control socket at <CODEX_HOME>/app-server-control/app-server-control.sock. The --code-mode-host <WS_URL> flag that does exist is a different feature (where code mode runs), not the session transport. So the attach rung needs no WebSocket client and no token — it's the same JSON-RPC-over-stdio we already speak, pointed at another process.

  2. "Spawn it detached if absent" isn't available. daemon start refuses unless codex was installed by the official installer script, wanting the managed binary at <CODEX_HOME>/packages/standalone/current/codex:

    managed standalone Codex install not found … This command requires the standalone install managed by the Codex installer, because the daemon starts and updates app-server from that fixed path.

    An npm / homebrew / distro codex — including this machine's /usr/lib/node_modules/@openai/codex — has no daemon rung at all.

  3. The rung order inverts. Per-session stdio isn't a fallback; for the common install it's the only rung. The daemon is an opportunistic upgrade when the managed install is present.

Also measured: the control socket is subject to the platform SUN_LEN cap (~104–108 bytes). A deeply relocated CODEX_HOME fails at connect time with path must be shorter than SUN_LEN — a message nobody would attribute to path length — so the resolver disqualifies the daemon rung up front and returns a reason saying why. CODEX_HOME relocation is honoured for both the socket and the managed-binary probe, the same way #566 honours CLAUDE_CONFIG_DIR.

(Incidentally: the CLI here is 0.147.0, not the 0.133.0 E3 was written against — it moved under us mid-plan.)

Scope

The install probe is an input, so the whole decision table is unit-testable with no codex on the box. Every rung returns a reason sentence: a user whose session isn't shared with their TUI should be able to find out why without reading code.

7 tests, 5 mutations checked, all killed. Electron suite 635 pass / 0 fail, tsc clean, doc lints green.

L4b is still to do — the app-server JSON-RPC driver over whichever argv this returns, delta throttling, R1 approval cards, turn/interrupt, config seeding.

Ubuntu and others added 2 commits August 16, 2026 11:35
L4's plan line specified a WebSocket attach to a `codex app-server`
daemon, authenticated with a bearer scheme, with stdio spawn-per-session
as "the fallback rung only". Measured against the installed codex-cli
0.147.0, all three parts are wrong, so this lands the corrected decision
as a pure, tested resolver before any driver is written against it.

  - The shared-daemon transport is a UNIX DOMAIN SOCKET, not a
    WebSocket, and there is no bearer scheme: `codex app-server daemon
    start` brings the daemon up, `codex app-server proxy --sock <path>`
    pipes stdio to its control socket at
    <CODEX_HOME>/app-server-control/app-server-control.sock. The
    `--code-mode-host <WS_URL>` flag is a different feature (where code
    mode runs), not the session transport. The attach rung therefore
    needs no WebSocket client and no token — it is the same
    JSON-RPC-over-stdio we already speak, pointed at another process.

  - "Spawn it detached if absent" is not available. `daemon start`
    refuses unless codex was installed by the official installer script,
    wanting the managed binary at
    <CODEX_HOME>/packages/standalone/current/codex. An npm / homebrew /
    distro codex — including this machine's — has no daemon rung at all.

  - So the rung order inverts: per-session stdio is not a fallback, it
    is the only rung for the common install, and the daemon is an
    opportunistic upgrade.

Also measured: the control socket is subject to the platform SUN_LEN cap
(~104-108 bytes). A deeply relocated CODEX_HOME fails at connect time
with "path must be shorter than SUN_LEN", which nobody would attribute
to path length — so the resolver disqualifies the daemon rung up front
and returns a reason saying so. CODEX_HOME relocation is honoured for
both the socket and the managed-binary probe, the same way F4 honours
CLAUDE_CONFIG_DIR.

The probe (does the managed binary exist?) is an input, so the whole
decision table is unit-testable with no codex on the box. 7 tests, 5
mutations checked, all killed. Electron suite 634 pass / 0 fail, tsc and
doc lints green.

L4b — the app-server JSON-RPC driver over whichever argv this returns,
delta throttling, R1 approval cards, turn/interrupt, config seeding —
is still to do.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The dev machine was moved from the npm codex to the installer-managed
standalone, which makes the daemon rung reachable here for the first
time. Exercising it confirms both paths the L4a resolver computes,
exactly: `daemon start` reports managedCodexPath =
<CODEX_HOME>/packages/standalone/current/codex and socketPath =
<CODEX_HOME>/app-server-control/app-server-control.sock. The socket is
created srw------- — filesystem permissions are the auth, the positive
form of "there is no bearer scheme".

Records two things L4b must not inherit as assumptions:

  - The proxy's DATA path is unproven. `codex app-server proxy --sock`
    connects and exits 0 with no stdout and no stderr for the same
    initialize handshake that works over a plain `codex app-server`
    child, stdin held open. Candidates: the daemon may need
    `enable-remote-control` (undocumented in its help, and the sibling
    `bootstrap` frames it as SSH-driven, so it is a security-posture
    call for the director, not a default), or the control socket may
    want a framing the bare JSON-RPC line does not supply. The resolver
    decides WHICH ARGV, never THAT IT SUCCEEDS.

  - Discoverability regressed: the standalone codex lives at
    ~/.local/bin/codex with its PATH entry in .bashrc, which a
    GUI-launched Electron app never sources — less discoverable than the
    /usr/bin/codex package was. L4b should resolve the binary the way
    kimiweb.ts already does for kimi, not trust PATH.

Doc-only; no version bump.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@physercoe
physercoe merged commit b9fc30c into main Aug 16, 2026
8 checks passed
@physercoe
physercoe deleted the feat-vision-l4a-codex-attach-v2 branch August 16, 2026 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant