A self-hosted browser console for running Codex and OMX sessions across tmux worktrees.
Live output · Persistent prompt queues · Worktree context · Desktop and mobile
Remote Agent Console turns the Codex sessions already running in tmux into one focused, authenticated workspace. Watch several agents, move between worktrees, queue follow-up prompts, retain project notes, and inspect branch or pull-request state without losing the terminal-native workflow underneath.
Important
This is a single trusted operator console. It can send input to terminals and execute worktree commands as the host account. Bind it to loopback and publish it only through an authenticated HTTPS proxy or tunnel.
| Area | Capabilities |
|---|---|
| Agent overview | Discover Codex/OMX descendants in tmux, see working/ready/action-required state, unread activity, and launch configured or scratch agents. |
| Live output | Stream the active pane, page through history, open detected links, copy selected output, answer guided questions, and temporarily switch to an interactive terminal. |
| Prompt workflow | Use per-worktree prompt history, arrow-key recall, saved drafts, attachments, skill/slash-command autocomplete, press-and-hold voice dictation, and persistent queued prompt management. |
| Worktree context | Show branch and full Git status, changed filenames, pull-request checks and review issues, GitHub Actions, project links, and trusted stack commands. |
| Conversations and notes | Name, list and resume each agent's own Conversations from the console, and keep autosaved Markdown notes with reusable file attachments beside output. Both are shared automatically across a Project's worktrees. |
| Guided review | Generate an AI-narrated tour of active Working or All PR implementation changes, visit or skip each logical step, and send consolidated feedback to the agent. |
| Operations | Install as a browser app, enable notifications, review stale runtime cleanup targets, and deploy with Docker Compose plus an optional Cloudflare Tunnel. |
| Conversational control | Connect ChatGPT through scoped remote MCP or use the built-in OpenAI Realtime voice dialog to inspect and direct the same agents. |
Open the branch-status flyout, choose Working or All PR, then select Review. The console captures a fresh Git snapshot and generates a narrated tour that explains how related implementation changes fit together. Tests and documentation are excluded by default and can be included with the tour toggles, which regenerates the snapshot.
The tour is explanatory rather than an automated code review: it does not produce findings, verdicts, or patches. Visit or skip every logical step, add feedback where useful, then optionally send one editable consolidated change request to the active agent. Generation runs as a bounded, cancellable job and the tour requires regeneration if the underlying changes move.
Prompts submitted while an agent is busy are stored per worktree. The clock attached to Queue opens an oldest-first list where prompts can be reordered, edited, or cancelled before they are dispatched.
Notes are persistent, autosaved, and rendered as Markdown. On wider screens they share the output area; on narrow screens the layout adapts vertically.
flowchart LR
B[Authenticated browser] <-- HTTPS / WebSocket --> S[Remote Agent Console]
S <-- tmux socket --> T[Host tmux server]
T --> A1[Codex / OMX agent]
T --> A2[Codex / OMX agent]
S --> G[Git + GitHub CLI]
S --> D[(Local JSON state)]
The server discovers tmux panes, verifies that their process trees belong to
Codex/OMX, and streams each pane's raw output to the browser over one tmux
control-mode client per session (see docs/adr/0008). Prompts and terminal input
are sent only to the pane selected through a freshly validated agent target.
Persistent state—console-named conversations, notes, prompt history, queues,
device names, and optional push subscriptions—stays in local JSON files.
Each agent CLI the console understands is described by one Adapter: a module
that says how to recognise its processes, read its state, compose a launch,
submit a prompt, and find its conversations, while the console performs every
side effect through its single tmux and /proc layer. Each agent CLI is
configured once under adapters; the console composes
each launch as [program, …adapter.launch(input).args, …operator args] with the
operator's environment and runs it through the operator's interactive shell. An
entry may also carry setup/teardown lifecycle commands, run before each
launch (aborting it on failure) and best-effort after each console-driven
stop, plus updates commands that move version checks and explicit upgrades
into Global settings. See
ADR 0002 for why adapters
describe and the console acts; the docs/adr/ directory records the
other architecture decisions.
- Linux with
/proc - Node.js 22+ and pnpm
- tmux
- An installed and authenticated Codex CLI
- A C/C++ build toolchain for the native
argon2dependency when running outside Docker - An HTTPS reverse proxy or tunnel for access beyond the local machine
Docker Compose is the recommended deployment because it packages Node, Codex, tmux, and the native build/runtime dependencies. It starts in an isolated scratch-only mode; connecting to a host tmux server and adding a public tunnel are separate opt-in steps.
git clone https://github.com/anstosa/remoteagents.git
cd remoteagents
pnpm install
cp .env.example .env
cp config/remote-agent-console.example.json ~/remote-agent-console.jsonGenerate the two required secrets:
node -e "require('argon2').hash('choose-a-long-password',{type:require('argon2').argon2id}).then(console.log)"
node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"Set RAC_PASSWORD_HASH, RAC_SESSION_SECRET, and RAC_CONFIG in .env, then
validate the scratch-only starter configuration:
pnpm config:check ~/remote-agent-console.jsonpnpm build
pnpm startOpen http://127.0.0.1:8787. Loopback HTTP is accepted only for local use;
every non-loopback deployment still requires canonical HTTPS.
Copy the scratch-only configuration into the ignored Compose location, then start the console:
cp config/remote-agent-console.example.json config/remote-agent-console.docker.json
pnpm config:check --compose config/remote-agent-console.docker.json
docker compose up -d --build
docker compose psThe default stack runs only the console and manages its own container-local
tmux sessions. Enable the optional Cloudflare sidecar with
docker compose --profile tunnel up -d --build.
After startup, use Global settings → Add account to connect one or more ChatGPT accounts through device-code login and select the active Codex login. Failed account queries offer Re-login without changing the active account. Use Rename beside any saved account or API key to change its display name without switching credentials. API-key rows show spending for today and this week when optional OpenAI billing access is configured; missing billing data is shown as unavailable, never as zero.
Connecting Docker to existing host tmux sessions requires host-specific bind
mounts, worktree paths, and runtime settings. Follow the
Docker Compose guide for that optional bridge and for tunnel
setup. Keep host values in ignored .env, compose.override.yaml, and
config/ files.
To run directly as the host user, use the portable user-unit installer in the systemd deployment guide. Native execution connects to the user's tmux socket and Codex configuration without Docker bind mounts.
The projects array may be empty or omitted for scratch-only use. Each Project
is a git repository with a stable ID, canonical path, and label; its Worktrees
are discovered from git worktree list. Optional fields expose project links,
stack actions, new-task flows, and customized prompt actions, plus a
commands.setup that prepares each freshly created Worktree (for example
pnpm install) before its agent launches. Agents launch by
Adapter kind — codex, omx, claude, and later pi and opencode —
configured once under adapters; Codex and OMX are separate kinds, so a
deployment can run plain Codex in some worktrees and OMX in others.
{
"listen": { "host": "127.0.0.1", "port": 8787 },
"name": "My server",
"publicOrigin": "https://agents.example.com",
"remoteServers": [
{ "url": "https://other-agents.example.com" }
],
"adapters": {
"codex": {
"program": "/usr/local/bin/codex",
"args": ["-c", "check_for_update_on_startup=false"],
"updates": {
"current": "/usr/local/bin/codex --version | awk '{print $2}'",
"latest": "npm view @openai/codex version",
"run": "/usr/local/bin/codex update"
}
},
"omx": {
"program": "/absolute/path/to/omx",
"args": ["-c", "check_for_update_on_startup=false"],
"env": { "OMX_AUTO_UPDATE": "0" },
"updates": {
"current": "/absolute/path/to/omx version | sed -n '1s/^oh-my-codex v//p'",
"latest": "npm view oh-my-codex version",
"run": "/absolute/path/to/omx update --stable"
}
}
},
"projects": [
{
"id": "my-project",
"label": "My project",
"path": "/absolute/path/to/project",
"newTask": "detach && new {taskId}",
"push": { "label": "Finish and PR", "prompt": "$finish" }
}
]
}name identifies the current Remote Agents server. Remote entries contain only
their canonical URL; each server publishes its own name and icon through the
authenticated peer-status API. The login, control, and output screens show one
direct navigation button for each server.
Upgrading from an older worktrees[] configuration is automatic: start the
console once and it migrates the config and its .data stores to Projects,
leaving *.pre-projects.bak backups. Preview the plan with
pnpm config:check "$RAC_CONFIG", or migrate a read-only config in place with
pnpm config:migrate "$RAC_CONFIG". See
Migrating from worktrees[].
See the setup reference for the full security boundary, Projects and Worktrees, browser capabilities, and operational checks.
| Control | Action |
|---|---|
Enter |
Queue the current prompt |
Shift+Enter / Ctrl+Enter / ⌘+Enter |
Insert a newline |
↑ / ↓ |
Recall older/newer prompt history when the cursor is on the first line |
Ctrl+S / ⌘+S |
Save the current prompt as a draft |
Tab |
Insert a tab in the prompt; in terminal mode, send Tab to the pane |
$ or / |
Open skill or slash-command completion |
Ctrl+C with selected output |
Copy the selection; without a selection in terminal mode, interrupt the process |
pnpm install
pnpm dev
pnpm lint
pnpm typecheck
pnpm test
pnpm buildBrowser behavior is covered with Playwright specs under apps/web/e2e.
README screenshots are deterministic and use synthetic data:
pnpm --filter @rac/web screenshots:readmeSee CONTRIBUTING.md before changing discovery, authentication, tmux input, or worktree command boundaries.
apps/server/ Fastify API, tmux discovery/input, persistence, and integrations
apps/web/ React/Vite browser UI and Playwright coverage
config/ Example application and Cloudflare Tunnel configuration
docs/ Deployment guides and README screenshots
compose.yaml Local production stack
- Setup, configuration, and browser capabilities
- Docker Compose deployment
- systemd deployment
- Using an existing Cloudflare Tunnel
- ChatGPT, MCP, Realtime voice, and federation
- Security policy and deployment expectations
- Contributing and validation
Remote Agent Console is intentionally not a general-purpose web terminal or a multi-user collaboration service. It is a focused remote control surface for one operator's Codex/OMX worktrees. Authentication, strict Host/Origin checks, short-lived WebSocket tickets, bounded caches, and target revalidation reduce risk, but the console still inherits the privileges of the host account that runs it.



