acp-ws-bridge 0.3.3

WebSocket bridge between GitHub Copilot CLI (ACP) and remote clients
acp-ws-bridge-0.3.3 is not a library.

acp-ws-bridge

CI Coverage Crates.io License: MIT

WebSocket-to-stdio bridge for relaying Agent Client Protocol (ACP) JSON-RPC messages between a remote client (e.g., iOS app) and GitHub Copilot CLI.

┌─────────────────┐        stdio         ┌─────────────────────┐       WebSocket        ┌─────────────────┐
│  GitHub Copilot │◄──────────────────►  │   acp-ws-bridge     │◄──────────────────────►│   Remote Client │
│  CLI (Host)     │   JSON-RPC/NDJSON    │   (Rust Server)     │   JSON-RPC/NDJSON      │   (iOS App)     │
└─────────────────┘                      └─────────────────────┘                        └─────────────────┘

Features

  • Transparent relay — passes all ACP JSON-RPC messages without modification
  • WebSocket + optional TLS — secure remote connections
  • REST API — session history, stats, Copilot CLI usage metrics and capabilities
  • Copilot CLI version detection — detects CLI version at startup, exposes via API
  • Ping/pong keepalive — detects dead connections
  • Session management — tracks active sessions with --resume support

Compatibility

Copilot CLI Version Status
1.0.x (GA) ✅ Fully supported
0.0.418 – 0.0.423 ✅ Fully supported
< 0.0.418 (pre-GA) ⚠️ Basic relay works; some features may be missing

New ACP protocol methods (exitPlanMode.request, MCP elicitations, reasoning effort config) are transparently relayed without bridge changes.

Quick Start

# Build
cargo build --release

# Run (starts Copilot CLI via stdio, listens on WebSocket port 8765)
cargo run -- --ws-port 8765

# With TLS (enables wss:// for WebSocket and HTTPS for REST API)
cargo run -- --ws-port 8765 --tls-cert cert.pem --tls-key key.pem

# Generate cert.pem/key.pem with mkcert (after `mkcert -install`)
mkcert -key-file key.pem \
  -cert-file cert.pem \
  localhost 127.0.0.1 ::1

# With custom API port
cargo run -- --ws-port 8765 --api-port 8766

# With an exact ACP command override (alias: --command)
cargo run -- --acp-command "copilot --acp --stdio --allow-all"

# With a custom Copilot data directory
cargo run -- --ws-port 8765 --copilot-dir /srv/copilot-home

Install

# Install from crates.io
cargo install acp-ws-bridge

Prebuilt release binaries are published on GitHub Releases for:

  • x86_64-unknown-linux-gnu
  • x86_64-apple-darwin
  • aarch64-apple-darwin
  • x86_64-pc-windows-msvc

Configuration

Flag Default Description
--ws-port 8765 WebSocket listen port
--api-port 8766 REST API listen port
--tls-cert TLS certificate path (enables wss:// and HTTPS)
--tls-key TLS private key path
--generate-cert Generate self-signed certificate and exit
--cert-hostnames localhost,127.0.0.1 Hostnames for self-signed certificate
--copilot-path copilot Path to Copilot CLI executable when using the default spawned command
--copilot-args Extra args appended to the default spawned Copilot CLI command
--acp-command, --command Exact Copilot ACP command override, parsed without shell execution
--copilot-mode stdio Copilot transport mode (stdio or tcp)
--copilot-host 127.0.0.1 Copilot CLI host in TCP mode
--copilot-port 3000 Copilot CLI port in TCP mode
--spawn-copilot true Disable this to connect to an already-running Copilot CLI instance
--copilot-dir ~/.copilot Copilot data directory for session history, session-state, and stats cache files

When --tls-cert and --tls-key are provided, both the WebSocket server (wss://) and the REST API (HTTPS) use the same TLS configuration.

If --acp-command / --command is set, it takes precedence over --copilot-path and --copilot-args. The provided command is treated as an exact override, so it must already include the ACP transport flags you want the spawned process to use, and in TCP mode it must match the configured --copilot-port.

REST API

The REST API runs on a separate port (default: --ws-port + 1).

Endpoint Description
GET /health Health check with bridge version, Copilot CLI version, uptime
GET /api/sessions List active WebSocket sessions
GET /api/sessions/:id Get session details
DELETE /api/sessions/:id Delete a session
GET /api/sessions/:id/commands Get cached ACP commands for a session
GET /api/stats Aggregate session statistics
GET /api/copilot/info Copilot CLI version, path, mode, GA status, feature capabilities
GET /api/copilot/usage Copilot CLI usage statistics (model usage, tool executions)
GET /api/history/sessions Historical sessions from the configured Copilot data directory
GET /api/history/sessions/:id/turns Session conversation turns
GET /api/history/stats Aggregate historical statistics

Project Docs

Generate TLS Cert/Key

If you installed acp-ws-bridge from crates.io or GitHub Releases and just need cert.pem / key.pem for local TLS, mkcert is the simplest option on macOS and Linux.

macOS

brew install mkcert
brew install nss
mkcert -install

nss is only needed if you want Firefox and other NSS-based clients to trust the local CA.

Linux

Install mkcert from your distro package manager or the upstream release, plus the NSS tools package if you want Firefox and other NSS-based clients to trust the local CA.

# Debian / Ubuntu
sudo apt install mkcert libnss3-tools

# Fedora
sudo dnf install mkcert nss-tools

# Arch Linux
sudo pacman -S mkcert nss

# One-time local CA install
mkcert -install

Generate a certificate and key for every hostname or IP your clients will use:

mkcert -key-file key.pem \
  -cert-file cert.pem \
  localhost 127.0.0.1 ::1 192.168.0.100 bridge-host.example.com

Replace 192.168.0.100 and bridge-host.example.com with the LAN IP and DNS name clients actually use.

If a client connects from another device, that device must also trust the mkcert root CA. Use mkcert -CAROOT to locate the CA files if you need to import them on another machine or device.

Once the files exist, start the installed binary with:

acp-ws-bridge --ws-port 8765 --tls-cert cert.pem --tls-key key.pem

The bridge loads these PEM files directly and should not need macOS keychain identity access for the server certificate.

Run in background with:

acp-ws-bridge  --ws-port 8700 --acp-command "copilot --acp --stdio" --tls-cert cert.pem --tls-key key.pem  --log-level debug >~/logs/acp-ws-8700.log 2>&1 &

Tailscale Serve (Reverse Proxy)

If the machine running the bridge is on a Tailscale tailnet, you can skip certificate management entirely and let Tailscale provide automatic HTTPS/WSS with a valid Let's Encrypt certificate.

Run the bridge without --tls-* flags (plain HTTP/WS):

acp-ws-bridge --ws-port 8765

Then use tailscale serve to expose both ports over HTTPS:

# Reverse-proxy HTTPS → local WebSocket port (wss:// for clients)
tailscale serve --bg https / http://localhost:8765

# Reverse-proxy HTTPS on /api → local REST API port
tailscale serve --bg https /api http://localhost:8766

Clients on the tailnet connect to:

wss://<machine-name>.<tailnet-name>.ts.net/
https://<machine-name>.<tailnet-name>.ts.net/api/health

Tailscale handles TLS termination, certificate renewal, and access control — no mkcert, no self-signed certs, no keychain prompts.

To stop serving:

tailscale serve off

See tailscale serve docs for more options.

Release Process

Releases are tag-driven and deterministic:

  1. Bump version in Cargo.toml (manual semver).
  2. Merge to main.
  3. Create and push a matching tag: vX.Y.Z.

The release workflow verifies the tag matches Cargo.toml, runs strict checks (fmt, clippy -D warnings, test, package dry-run), publishes to crates.io using the CARGO_REGISTRY_TOKEN GitHub secret, and uploads platform binaries to GitHub Releases.

Contributing and Support

  • Please read CONTRIBUTING.md before opening a pull request.
  • Use the GitHub bug report and feature request templates for public issues.
  • Report vulnerabilities privately according to SECURITY.md.
  • Community interactions in this repository follow CODE_OF_CONDUCT.md.

Roadmap

Near-term repository improvements are focused on OSS maintainability:

  • keep contributor-facing docs current as the bridge evolves
  • improve quality visibility through the dedicated coverage workflow
  • evaluate future release automation and additional examples only after the contributor baseline is stable

License

MIT