Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2350059
app-server: Add transport for remote control
euroelessar Feb 28, 2026
a8d299f
always https except localhost
euroelessar Mar 27, 2026
5537c4c
lock to chatgpt.com
euroelessar Mar 27, 2026
db806e3
fix test
euroelessar Mar 27, 2026
558b357
allow ips
euroelessar Mar 27, 2026
bca7d04
simplify, cover all loopback ips
euroelessar Mar 27, 2026
f2623f2
maybe fix windows?
euroelessar Mar 27, 2026
457fabc
rm run_remote_control_websocket_loop
euroelessar Mar 27, 2026
0f1f511
maybe fix windows?
euroelessar Mar 27, 2026
e716db6
cr
euroelessar Mar 28, 2026
044fe18
Merge branch 'main' of github.com:openai/codex into codex/websocket-r…
euroelessar Mar 31, 2026
de684bd
Merge branch 'main' of github.com:openai/codex into codex/websocket-r…
euroelessar Mar 31, 2026
93672f0
share auth manager init code
euroelessar Apr 1, 2026
2230a7c
Merge branch 'main' of github.com:openai/codex into codex/websocket-r…
euroelessar Apr 4, 2026
cb3931b
add logging & add regular pings
euroelessar Apr 4, 2026
5b53648
fix cleanup on acking
euroelessar Apr 4, 2026
9bc01bc
simplify cleanup of outbound buffer
euroelessar Apr 4, 2026
32706e4
fix test
euroelessar Apr 4, 2026
fe2732c
fix migrations due to bad merge
euroelessar Apr 4, 2026
623af9a
Merge branch 'main' of github.com:openai/codex into codex/websocket-r…
euroelessar Apr 6, 2026
194e34f
cr for db
euroelessar Apr 6, 2026
cb51056
Merge branch 'main' of github.com:openai/codex into codex/websocket-r…
euroelessar Apr 6, 2026
bd65cce
Merge branch 'main' of github.com:openai/codex into codex/websocket-r…
euroelessar Apr 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions codex-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions codex-rs/app-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@ codex-state = { workspace = true }
codex-tools = { workspace = true }
codex-utils-absolute-path = { workspace = true }
codex-utils-json-to-toml = { workspace = true }
codex-utils-rustls-provider = { workspace = true }
chrono = { workspace = true }
clap = { workspace = true, features = ["derive"] }
constant_time_eq = { workspace = true }
futures = { workspace = true }
gethostname = { workspace = true }
hmac = { workspace = true }
jsonwebtoken = { workspace = true }
owo-colors = { workspace = true, features = ["supports-colors"] }
Expand All @@ -81,6 +83,7 @@ tokio-util = { workspace = true }
tokio-tungstenite = { workspace = true }
tracing = { workspace = true, features = ["log"] }
tracing-subscriber = { workspace = true, features = ["env-filter", "fmt", "json"] }
url = { workspace = true }
uuid = { workspace = true, features = ["serde", "v7"] }

[dev-dependencies]
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Supported transports:

- stdio (`--listen stdio://`, default): newline-delimited JSON (JSONL)
- websocket (`--listen ws://IP:PORT`): one JSON-RPC message per websocket text frame (**experimental / unsupported**)
- off (`--listen off`): do not expose a local transport

When running with `--listen ws://IP:PORT`, the same listener also serves basic HTTP health probes:

Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/src/app_server_tracing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ fn transport_name(transport: AppServerTransport) -> &'static str {
match transport {
AppServerTransport::Stdio => "stdio",
AppServerTransport::WebSocket { .. } => "websocket",
AppServerTransport::Off => "off",
}
}

Expand Down
49 changes: 42 additions & 7 deletions codex-rs/app-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use codex_core::config::ConfigBuilder;
use codex_core::config_loader::CloudRequirementsLoader;
use codex_core::config_loader::ConfigLayerStackOrdering;
use codex_core::config_loader::LoaderOverrides;
use codex_features::Feature;
use codex_login::AuthManager;
use codex_utils_cli::CliConfigOverrides;
use std::collections::HashMap;
use std::collections::HashSet;
Expand All @@ -28,6 +30,7 @@ use crate::transport::OutboundConnectionState;
use crate::transport::TransportEvent;
use crate::transport::auth::policy_from_settings;
use crate::transport::route_outgoing_envelope;
use crate::transport::start_remote_control;
use crate::transport::start_stdio_connection;
use crate::transport::start_websocket_acceptor;
use codex_analytics::AppServerRpcTransport;
Expand All @@ -42,10 +45,10 @@ use codex_core::config_loader::ConfigLoadError;
use codex_core::config_loader::TextRange as CoreTextRange;
use codex_exec_server::EnvironmentManager;
use codex_feedback::CodexFeedback;
use codex_login::AuthManager;
use codex_protocol::protocol::SessionSource;
use codex_state::log_db;
use tokio::sync::mpsc;
use tokio::sync::oneshot;
use tokio::task::JoinHandle;
use tokio_util::sync::CancellationToken;
use toml::Value as TomlValue;
Expand Down Expand Up @@ -499,13 +502,13 @@ pub async fn run_main_with_transport(

let feedback_layer = feedback.logger_layer();
let feedback_metadata_layer = feedback.metadata_layer();
let log_db = codex_state::StateRuntime::init(
let state_db = codex_state::StateRuntime::init(
config.sqlite_home.clone(),
config.model_provider_id.clone(),
)
.await
.ok()
.map(log_db::start);
.ok();
let log_db = state_db.clone().map(log_db::start);
let log_db_layer = log_db
.clone()
.map(|layer| layer.with_filter(Targets::new().with_default(Level::TRACE)));
Expand All @@ -532,11 +535,18 @@ pub async fn run_main_with_transport(
let single_client_mode = matches!(&transport, AppServerTransport::Stdio);
let shutdown_when_no_connections = single_client_mode;
let graceful_signal_restart_enabled = !single_client_mode;
let mut app_server_client_name_rx = None;

match transport {
AppServerTransport::Stdio => {
start_stdio_connection(transport_event_tx.clone(), &mut transport_accept_handles)
.await?;
let (stdio_client_name_tx, stdio_client_name_rx) = oneshot::channel::<String>();
app_server_client_name_rx = Some(stdio_client_name_rx);
start_stdio_connection(
transport_event_tx.clone(),
&mut transport_accept_handles,
stdio_client_name_tx,
)
.await?;
}
AppServerTransport::WebSocket { bind_address } => {
let accept_handle = start_websocket_acceptor(
Expand All @@ -548,6 +558,29 @@ pub async fn run_main_with_transport(
.await?;
transport_accept_handles.push(accept_handle);
}
AppServerTransport::Off => {}
}

let auth_manager =
AuthManager::shared_from_config(&config, /*enable_codex_api_key_env*/ false);

if config.features.enabled(Feature::RemoteControl) {
let accept_handle = start_remote_control(
config.chatgpt_base_url.clone(),
state_db.clone(),
auth_manager.clone(),
transport_event_tx.clone(),
transport_shutdown_token.clone(),
app_server_client_name_rx,
)
.await?;
transport_accept_handles.push(accept_handle);
}
if transport_accept_handles.is_empty() {
return Err(std::io::Error::new(
ErrorKind::InvalidInput,
"no transport configured; use --listen or enable remote control",
));
}

let outbound_handle = tokio::spawn(async move {
Expand Down Expand Up @@ -852,7 +885,9 @@ pub async fn run_main_with_transport(
fn analytics_rpc_transport(transport: AppServerTransport) -> AppServerRpcTransport {
match transport {
AppServerTransport::Stdio => AppServerRpcTransport::Stdio,
AppServerTransport::WebSocket { .. } => AppServerRpcTransport::Websocket,
AppServerTransport::WebSocket { .. } | AppServerTransport::Off => {
AppServerRpcTransport::Websocket
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion codex-rs/app-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const MANAGED_CONFIG_PATH_ENV_VAR: &str = "CODEX_APP_SERVER_MANAGED_CONFIG_PATH"
#[derive(Debug, Parser)]
struct AppServerArgs {
/// Transport endpoint URL. Supported values: `stdio://` (default),
/// `ws://IP:PORT`.
/// `ws://IP:PORT`, `off`.
#[arg(
long = "listen",
value_name = "URL",
Expand Down
Loading
Loading