esper-relay keeps
codex app-serverrunning on a machine you trust and gives you a mobile-friendly remote control surface over Tailscale. You get your Codex sessions on your phone, without exposing the host directly to the public internet.
Thread view, prompt composer, and session controls on a phone-sized screen.
- Remote Codex access: resume threads, send prompts, and handle approvals from your phone.
- Private by default: keep remote access inside your tailnet instead of opening public ports.
- Host-side supervision: let
esper-relaykeepcodex app-serverrunning instead of managing it manually. - Mobile-first UI: use a touch-friendly web interface instead of remoting into a full desktop.
- Better file links: referenced host files open through the relay instead of dead local filesystem URLs.
cargo install esper-relayIf you want a prebuilt archive instead, use GitHub Releases.
- Codex CLI installed and authenticated so
codex app-serverworks on the host machine. - Tailscale installed on the host if you want remote access from your phone.
- Tailscale installed on your phone if you want to use the tailnet URL there.
- Rust and Cargo available for
cargo install.
esper-relay --daemonThen open http://127.0.0.1:3000.
Create ~/.config/esper-relay/config.toml:
bind_addr = "127.0.0.1:3500"
ready_timeout_ms = 60000
[tailnet]
enabled = true
hostname = "esper-relay"
listener_mode = "https"
listen_addr = ":443"
advertise_tags = ["tag:esper-relay"]
oauth_client_secret = "tskey-client-REPLACE_ME"Then start the relay:
esper-relay --daemonThis gives you:
- local access on your configured
bind_addr - tailnet-only
https://<hostname>.<tailnet>.ts.net/access once MagicDNS and tailnet HTTPS are enabled
esper-relay --stopWhen tailnet.oauth_ephemeral = true, a clean stop logs the ephemeral node out immediately instead of waiting for delayed tailnet cleanup.
- Run
esper-relayon the machine where Codex lives. - Open the web UI locally or through your tailnet.
- Resume a thread or start a new one from your phone.
- Send prompts, approve actions, and keep the session moving without sitting at the host machine.
~/.config/esper-relay/config.tomlis loaded automatically when it exists.bind_addrcontrols the local web UI address.app_server_cmddefaults tocodex app-server.tailnet.listener_mode = "https"replaces the raw tailnet listener with tailnet-only HTTPS on:443.tailnet.advertise_tagsis required when you usetailnet.oauth_client_secret.tailnet.oauth_ephemeraldefaults totrue; set it tofalseif you want persistent OAuth-derived authkeys instead.
Full environment variable reference
ESPER_RELAY_BIND(default:127.0.0.1:3000)ESPER_RELAY_APP_SERVER_CMD(default:codex app-server)ESPER_RELAY_READY_TIMEOUT_MS(default:8000)ESPER_RELAY_RESTART_BASE_DELAY_MS(default:500)ESPER_RELAY_RESTART_MAX_DELAY_MS(default:8000)ESPER_RELAY_EVENT_BUFFER(default:256)ESPER_RELAY_TRUSTED_LAN(default:true)ESPER_RELAY_TAILNET_LISTENER_MODE(default:tcp, valid values:tcp,https)ESPER_RELAY_TAILNET_OAUTH_EPHEMERAL(default:true, only applies totailnet.oauth_client_secret)
Stable and prerelease archives are published on GitHub Releases for:
x86_64-unknown-linux-gnuaarch64-unknown-linux-gnux86_64-pc-windows-gnuaarch64-apple-darwin
git clone https://github.com/beisel-it/esper-relay.git
cd esper-relay
make runmake runmake fmtmake fmt-checkmake clippymake testmake ci-localmake fetch-codex-sourcesmake fetch-themes
POST /api/sessionsGET /api/themesGET /api/files/content?path=/absolute/path[&line=n][&column=n]GET /api/sessions/latestGET /api/sessions/{session_id}GET /api/sessions/{session_id}/timelineGET /api/sessions/{session_id}/events(WebSocket)POST /api/sessions/{session_id}/turnsPOST /api/sessions/{session_id}/interruptPOST /api/sessions/{session_id}/approvals/{approval_id}POST /api/sessions/{session_id}/server-requests/{request_id}/respondGET /api/threads?limit=50POST /api/threads/{thread_id}/resume
Approval and tool-input prompts surface the related turn/item context from the app-server payload, and explicit Codex file-reference links are rewritten through the relay so remote users can request host files safely through GET /api/files/content.
GET /healthGET /readyGET /metrics
.
βββ .github/workflows/
βββ crates/esper-relay/
βββ docs/
βββ scripts/
βββ vendor/
- Canonical captures:
docs/sources/codex/ - Latest snapshot metadata:
docs/sources/codex/manifest.json - Primary protocol reference:
docs/sources/codex/snapshots/.../remote/app-server.md
- Release and publishing details: docs/releasing.md
release-plzmanages release PRs, tagging, and crates.io publish.- Stable binaries are published from
v*tags, and prerelease binaries are published from pushes tomain.



