Skip to content

fix(codex): guide the RC session and give it a usable machine name - #161

Open
defangdevs wants to merge 1 commit into
masterfrom
fix/codex-session-onboarding
Open

fix(codex): guide the RC session and give it a usable machine name#161
defangdevs wants to merge 1 commit into
masterfrom
fix/codex-session-onboarding

Conversation

@defangdevs

Copy link
Copy Markdown
Owner

Fixes the first three items of #159.

Before

A codex session with remoteControl = true (the default) showed this, then nothing, forever:

{"status":"started","backend":"pid","pid":814306,...,"appServerVersion":"0.146.0"}

Not a TUI, so typing does nothing. No indication that Remote Control cannot enroll until someone signs in — while README.md:43 told the quickstart user to complete sign-in in that exact tab. Pairing failed with remote control pairing is unavailable until enrollment completes, which never mentions login, and codex login --device-auth — the only flow that works on a headless box — appeared nowhere in this repo.

After

The pane is a status screen: what it is, the machine name, and whichever step is outstanding with the exact command to run. Sign-in happens in another tab, so the existing health loop polls for the transition and confirms when it lands. Daemon-start JSON goes to the log rather than being the pane's first impression, and both failure paths now name what failed and point at app-server.stderr.log instead of dumping into a silent post-mortem shell.

The machine name

Codex takes it from gethostname(2), so the apps showed the internal cloud fqdn. There is no override — HOSTNAME does not occur in the binary, every candidate -c key is rejected by --strict-config, and disassembly shows the gethostname crate result fed straight to the serverName notification. networking.hostName cannot hold a dotted public name either (nixos/modules/tasks/network-interfaces.nix:564 types it strMatching with no dots).

So the wrapper re-execs inside a private UTS namespace whose hostname is hostLabel — the same public address Claude sessions already use. The user namespace is unprivileged: --keep-caps grants CAP_SYS_ADMIN inside the new namespace only, uid unchanged, conferring nothing outside. unshare execs in place, so the wrapper keeps its pid and its trap-based daemon teardown, and the daemon inherits the namespace after detaching.

Verification

All on this aarch64 box:

  • nix-instantiate --parse on both .nix and .nix.in; assemble-module.py --check confirms the generated file is in sync.

  • Generated wrapper extracted and bash -n clean.

  • UTS re-exec in the exact committed form: uname -n is the public name inside, unchanged outside.

  • End to endserverName read back via codex app-server on stdio with a throwaway CODEX_HOME:

    serverName
    baseline ip-10-42-1-247.eu-central-1.compute.internal
    inside namespace 3.79.168.78.sslip.io

Not verified: the VM tests, which are x86_64-linux-only and need KVM — CI has to cover those. A codex session without skipPermissions (codex landlock/seccomp under a nested user namespace) is also untested.

Note

Changing the reported name mints a new server_id and replaces the remote_control_enrollments row, so an already-paired box needs re-pairing once. Taken as acceptable pre-1.0 rather than designed around.

Not in this PR (still open on #159)

  • The RC-codex singleton bug: two RC codex sessions kill each other's daemon.
  • initialPrompt silently discarded on RC codex sessions.
  • aws/lightsail-template.yaml:552's stale "Codex has no Remote Control channel" — left alone to avoid conflicting with fix(lightsail): derive Remote Control name from the public host #156, which is already editing that block.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PsqGhkpjsb4kKAdVz25xKN

A codex session with remoteControl = true showed one line of daemon-start
JSON and then nothing, forever. It is not a TUI, so typing did nothing,
and nothing said that Remote Control cannot enroll until someone signs
in — while README told the quickstart user to complete sign-in in that
very tab. Pairing then failed with "remote control pairing is
unavailable until enrollment completes", which never mentions login, and
the flow that actually works headless (`codex login --device-auth`)
appeared nowhere in this repo.

Replace the blank pane with a status screen: what the pane is, the
machine name, and whichever of sign-in / pairing is outstanding, with
the exact commands. Sign-in happens in another tab, so the health loop
polls for the transition and confirms when it lands. Daemon-start JSON
goes to the log instead of being the first impression, and both failure
paths now say what failed and point at app-server.stderr.log rather than
dumping into an unexplained post-mortem shell.

Also fix the name the Codex apps show. It came from gethostname(2) — the
internal cloud fqdn — and codex offers no override: HOSTNAME does not
occur in the binary, every candidate -c key is rejected by
--strict-config, and disassembly shows the gethostname crate result fed
straight to the serverName notification. networking.hostName cannot hold
a dotted public name either (NixOS types it strMatching without dots).
So the wrapper re-execs in a private UTS namespace whose hostname is
hostLabel — the same public address claude sessions already use. The
user namespace is unprivileged (--keep-caps grants CAP_SYS_ADMIN inside
the namespace only, uid unchanged), and unshare execs in place, so the
wrapper keeps its pid and its trap-based daemon teardown.

Verified on an aarch64 box: serverName goes from
ip-10-42-1-247.eu-central-1.compute.internal to 3.79.168.78.sslip.io,
read back via `codex app-server` on stdio with a throwaway CODEX_HOME.

Refs #159.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PsqGhkpjsb4kKAdVz25xKN
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.

2 participants