Summary
When codex exec-server runs in --remote mode, the two outbound calls to the environment registry / rendezvous travel without a User-Agent header:
POST {base_url}/cloud/environment/{environment_id}/register — uses reqwest::Client::new() (codex-rs/exec-server/src/remote.rs:41 on rust-v0.133.0), which does not set a default UA.
connect_async(rendezvous_url) — uses tokio-tungstenite's default handshake, which does not set one either.
This is the only outbound path in codex that omits the UA. Every other outbound HTTP call already routes through codex_login::default_client::get_codex_user_agent() — see codex-rs/backend-client/src/client.rs:174 (ClientBuilder::user_agent(...)) and codex-rs/app-server/src/request_processors/initialize_processor.rs:140 (process-global UA suffix set during initialize).
Why it matters
For server-side observability — release-health stats, version-distribution telemetry, debugging connection issues — the upstream registry can't tell which codex version / OS / architecture is connecting from headers alone. The only identifying signal is whatever the auth token's claims carry.
Proposal
Mirror backend-client's pattern in exec-server:
- Replace
reqwest::Client::new() with reqwest::Client::builder().user_agent(get_codex_user_agent()).build().
- Wrap the rendezvous URL in an
http::Request with a User-Agent header and pass that to connect_async.
No protocol changes, no server-side change required (unknown headers are ignored). Resulting UA shape matches what backend-client already sends:
codex_cli_rs/<ver> (<os> <os_ver>; <arch>) tungstenite-rs/<ver>
Happy to send a PR — branch is ready locally if there's interest. Wanted to surface as an issue first to confirm the team would accept this kind of change before opening one.
Summary
When
codex exec-serverruns in--remotemode, the two outbound calls to the environment registry / rendezvous travel without aUser-Agentheader:POST {base_url}/cloud/environment/{environment_id}/register— usesreqwest::Client::new()(codex-rs/exec-server/src/remote.rs:41onrust-v0.133.0), which does not set a default UA.connect_async(rendezvous_url)— uses tokio-tungstenite's default handshake, which does not set one either.This is the only outbound path in
codexthat omits the UA. Every other outbound HTTP call already routes throughcodex_login::default_client::get_codex_user_agent()— seecodex-rs/backend-client/src/client.rs:174(ClientBuilder::user_agent(...)) andcodex-rs/app-server/src/request_processors/initialize_processor.rs:140(process-global UA suffix set duringinitialize).Why it matters
For server-side observability — release-health stats, version-distribution telemetry, debugging connection issues — the upstream registry can't tell which codex version / OS / architecture is connecting from headers alone. The only identifying signal is whatever the auth token's claims carry.
Proposal
Mirror
backend-client's pattern inexec-server:reqwest::Client::new()withreqwest::Client::builder().user_agent(get_codex_user_agent()).build().http::Requestwith aUser-Agentheader and pass that toconnect_async.No protocol changes, no server-side change required (unknown headers are ignored). Resulting UA shape matches what
backend-clientalready sends:Happy to send a PR — branch is ready locally if there's interest. Wanted to surface as an issue first to confirm the team would accept this kind of change before opening one.