Remote Agent Guide
The remote agent is a Python daemon that runs on remote machines to provide AI coding tool access via the Open ACE platform.
Architecture
┌──────────┐ HTTP Polling ┌──────────────┐
│ Agent │ ◄──────────────► │ Flask API │
│ (daemon) │ 1s interval │ │
└────┬─────┘ └──────────────┘
│
├── subprocess ──► CLI Tool (claude/qwen/codex/openclaw)
│
└── WebSocket ──► Terminal Server (PTY / piped subprocess)
│
Browser (xterm.js)
Installation
Linux / macOS
curl -fsSL https://<server>/api/remote/agent/install.sh | bash -s -- \
--server https://your-server.com \
--token <agent-token> \
--name my-machine
Options:
--server— Open ACE server URL (required)--token— Agent registration token (required)--name— Machine display name--install-cli— Default CLI tool (default: qwen-code-cli)--dir— Installation directory (default:~/.open-ace-agent)--ca-bundle PATH— PEM CA bundle for a private or self-signed server--insecure-skip-tls-verify— Explicitly disable TLS verification (dangerous)
When the installer endpoint itself uses a private CA, bootstrap curl with the same bundle and pass it through to the installer:
curl --cacert /path/to/ca.pem -fsSL https://<server>/api/remote/agent/install.sh | \
bash -s -- --server https://<server> --token <agent-token> --ca-bundle /path/to/ca.pem
Windows
.\install.ps1 -ServerUrl https://your-server.com -RegistrationToken <agent-token>
For a private CA, add -CaBundlePath C:\path\to\ca.pem. The emergency
-InsecureSkipTlsVerify switch is intentionally explicit and should only be
used for short-lived testing.
Requirements
- Python 3.8+
- websocket-client, requests, websockets (auto-installed)
Starting and Managing the Agent
After installation, you can use the start scripts to manage the agent process:
Linux / macOS
# Start the agent (skips if already running)
bash ~/.open-ace-agent/start-agent.sh
# Check agent status
bash ~/.open-ace-agent/start-agent.sh --status
# Stop the agent
bash ~/.open-ace-agent/start-agent.sh --stop
# Configure auto-start on boot (requires sudo to create systemd service)
bash ~/.open-ace-agent/start-agent.sh --auto-start
Auto-start details:
- Systems with systemd (Ubuntu 16.04+, CentOS 7+, RHEL 7+): Creates a systemd service that starts on boot and restarts on crash
- Environments without systemd (e.g., WSL2): Uses crontab
@rebootfor auto-start
Windows
# Start the agent (skips if already running)
powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.open-ace-agent\start-agent.ps1"
# Check agent status
powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.open-ace-agent\start-agent.ps1" -Status
# Stop the agent
powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.open-ace-agent\start-agent.ps1" -Stop
# Configure auto-start on login (Windows Task Scheduler)
powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.open-ace-agent\start-agent.ps1" -InstallAutoStart
Auto-start details:
- Uses Windows Task Scheduler to start automatically on login
- Task name:
OpenACEAgent - Can be managed in Task Scheduler
Shortcut (Windows)
Windows users can also use the batch wrapper:
%USERPROFILE%\.open-ace-agent\start-agent.cmd
Configuration
Config file: ~/.open-ace-agent/config.json
| Setting | Default | Description |
|---|---|---|
| server_url | http://localhost:19888 | Open ACE server |
| heartbeat_interval | 60s | Heartbeat frequency |
| reconnect_base_delay | 1s | Initial reconnect delay |
| reconnect_max_delay | 60s | Max reconnect delay (exponential backoff) |
| output_buffer_size | 4096 | Terminal output buffer |
| max_sessions | 5 | Concurrent sessions |
| log_level | INFO | Logging level |
| skip_ssl_verify | false | Skip TLS verification; non-local HTTPS also requires an explicit CLI acknowledgement |
| allow_insecure_tls | false | Administrator policy gate for the explicit insecure switch |
| ca_bundle_path | null | PEM CA bundle for private/self-signed certificates |
Environment variable overrides: OPENACE_SERVER_URL, OPENACE_AGENT_TOKEN, OPENACE_MACHINE_ID, OPENACE_HEARTBEAT_INTERVAL, OPENACE_MAX_SESSIONS, OPENACE_LOG_LEVEL, OPENACE_SKIP_SSL_VERIFY, OPENACE_ALLOW_INSECURE_TLS, OPENACE_CA_BUNDLE_PATH
TLS policy and migration
New installations verify server certificates by default. For an internal CA,
install with --ca-bundle /path/to/ca.pem (or -CaBundlePath on Windows), or
set ca_bundle_path in config.json. The same CA is used by agent HTTP calls,
terminal relay WebSockets, openace login/menu/shell, installer downloads, and
registration.
For a non-local HTTPS server, a legacy configuration containing
"skip_ssl_verify": true no longer starts silently. Prefer replacing it with a
CA bundle. If verification must be disabled temporarily, start the daemon with
python agent.py --insecure-skip-tls-verify; the installer equivalents persist
both skip_ssl_verify=true and the administrator approval
allow_insecure_tls=true, then add the explicit service argument. Manual use
requires the same two-step approval: policy plus CLI flag. Administrators can
disable the escape hatch by leaving allow_insecure_tls=false. This mode prints
a prominent warning and exposes credentials and commands to man-in-the-middle
attacks.
Use python agent.py --ca-bundle /path/to/ca.pem for a one-run CA override, and
openace login|menu|shell --ca-bundle /path/to/ca.pem for a CLI override. Run
openace config-check to inspect the persisted TLS configuration.
Supported CLI Tools
| Tool | Executable | NPM Package | Config Location |
|---|---|---|---|
| Claude Code | claude | @anthropic-ai/claude-code | ~/.claude/ |
| Qwen Code | qwen | @qwen-code/qwen-code | ~/.qwen/ |
| Codex | codex | @openai/codex | ~/.codex/config.toml |
| OpenClaw | openclaw | N/A | — |
| ZCode | zcode | N/A (bundled with the ZCode desktop app) | ~/.zcode/ |
Each tool has a dedicated adapter in cli_adapters/ that handles start arguments, environment variables, permission modes, and session resume.
openace CLI
The openace command-line tool is installed alongside the agent:
| Command | Description |
|---|---|
openace login [--token TOKEN] [--ca-bundle PATH] | Authenticate to server |
openace logout | Remove stored credentials |
openace status | Show server URL, machine ID, login state |
openace menu [--ca-bundle PATH] | Start interactive AI tool selector |
openace shell [--ca-bundle PATH] | Start shell with proxy credentials |
openace config-check | Validate the persisted TLS configuration |
Terminal Server
The terminal server provides WebSocket-based terminal access:
- Terminal process model — Uses a persistent PTY on Linux/macOS and a persistent piped subprocess on Windows
- Authentication — HMAC token via query parameters
- Reconnection — Terminal process persists across WebSocket disconnects; 64KB output history for screen restore
- Resize — JSON control messages
{"type":"resize","cols":N,"rows":N} - Environment — Auto-injects
ANTHROPIC_API_KEY/OPENAI_API_KEYfrom proxy tokens
On Windows, openace menu uses a numbered text menu instead of the Unix arrow-key raw-terminal UI so the same workflow remains available in PowerShell/cmd and browser terminals.
Known limitations of the Windows pipe mode
On Linux/macOS the terminal server spawns the shell on a real PTY. On Windows it uses a piped subprocess instead (stdin/stdout are anonymous pipes, not a pseudo-terminal). Because there is no tty attached to stdin, the Windows pipe mode has these limitations — this is expected behavior, not a regression:
- No interactive tty semantics on stdin — there is no echo, no line editing, no Tab completion, and no prompt redraw. Input is forwarded to the shell as raw bytes once the client submits it (typically on Enter).
- Raw-byte CJK / wide-char input — multi-byte input is sent as raw bytes into a non-tty stdin, so IME composition and wide-char readline handling are not available the way they are on a Unix PTY.
- Resize does not take effect — there is no tty to apply a window-size
change to, so
{"type":"resize",...}only records the requested size and the shell keeps wrapping output at the original width. The server logs a one-time notice on the first resize. Writing an ANSI size sequence is deliberately avoided: stdin is a pipe, so those bytes would be consumed as shell input and pollute the session. Real resize support requires ConPTY (pywinpty/winpty or the Win32 API) and is tracked as future work. - Persistence and history still work — the piped shell still persists across WebSocket reconnects, and the 64KB output history is replayed for screen restore on reconnection.
Process-tree cleanup (Windows)
To make shutdown reliable, the Windows terminal server binds the shell process
tree to a Win32 Job Object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE. When the
server exits (normal shutdown, hard-kill, or crash), the kernel reaps the whole
tree — including grandchildren holding the stdout write-end — which is what lets
the output relay stop cleanly. The soft-kill path (kill_pty) closes the Job
handle first, falling back to taskkill /T /F only when no Job is bound.
Narrow residual (accepted): if Job creation and taskkill /T both fail, the
shell tree may be orphaned (it then needs manual cleanup; the agent's
proc.kill() targets the terminal server, not the orphaned shell), and the
output relay may stay pinned until the process is force-killed. An
agent-initiated stop_terminal is reaped by the agent's proc.kill() watchdog;
agent shutdown intentionally leaves terminal servers running, so a natural-exit
under this dual-failure may wedge a terminal server until that terminal is
restarted.
Session Sync
The agent scans session history directories every 30s and syncs to the server:
| Tool | Directory |
|---|---|
| Claude Code | ~/.claude/projects/ (JSONL) |
| Qwen Code | ~/.qwen/projects/ (JSONL) |
| Codex | ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl |
Sync state is tracked in ~/.open-ace-agent/session_sync_state.json.
Codex CLI Specifics
- Config format: TOML (
~/.codex/config.toml), not JSON - Permission modes:
plan→--ask-for-approval untrusted,auto→--dangerously-bypass-approvals-and-sandbox - Non-interactive mode:
codex exec --json --sandbox read-only - Session files: JSONL with event types
session_meta,turn_context,response_item - Content blocks:
input_text,output_text,reasoning,function_call
Daemon Commands
The agent handles these commands from the server:
| Command | Description |
|---|---|
start_session | Start a new CLI session |
send_message | Send user message to active session |
stop_session | Terminate CLI session |
pause_session | SIGSTOP the CLI process |
resume_session | SIGCONT the CLI process |
permission_response | Forward user's permission decision |
update_permission_mode | Change session permission mode |
update_model | Switch AI model |
start_terminal | Launch WebSocket terminal server |
stop_terminal | Shutdown terminal server |
Troubleshooting
Agent won't connect:
- Check
OPENACE_SERVER_URLis reachable - Verify agent token is valid
- Check
~/.open-ace-agent/agent.log
CLI tool not found:
- Ensure the tool is installed globally (
which claude/which qwen/which codex) - Check PATH includes npm global bin directory
Terminal not connecting:
- Verify WebSocket port is not blocked by firewall
- Check terminal server process is running (
ps aux | grep terminal_server) - Review HMAC token in
~/.open-ace-agent/.terminal_sessions/
Session sync not working:
- Check
~/.open-ace-agent/session_sync_state.jsonis writable - Verify session directories exist and contain JSONL files