acp-ws-bridge 0.3.3

WebSocket bridge between GitHub Copilot CLI (ACP) and remote clients
# Deployment

This document covers practical deployment guidance for running `acp-ws-bridge` as a long-lived service.

## What the service exposes

By default the bridge starts:

- a WebSocket listener on `--ws-port` (default `8765`)
- a REST API on `--api-port` (default `ws-port + 1`, usually `8766`)

The REST API is intended for local operational visibility, not as a public replacement for the WebSocket endpoint.

## Prerequisites

- GitHub Copilot CLI installed on the host
- Copilot CLI already authenticated for the runtime user
- access to the runtime user's Copilot data directory for history/usage features (`~/.copilot` by default)
- TLS certificate and key if you plan to expose the bridge over untrusted networks

## Install options

### crates.io

```bash
cargo install acp-ws-bridge
```

### GitHub Releases

Download a prebuilt archive for your platform from the project's Releases page and place the binary on the host's `PATH`.

## Choosing a transport mode

### Default: stdio mode

Use stdio mode unless you have a specific reason to share a Copilot CLI instance.

```bash
acp-ws-bridge --ws-port 8765 --api-port 8766
```

If you want to override the spawned Copilot command exactly, use:

```bash
acp-ws-bridge \
  --ws-port 8765 \
  --acp-command "copilot --acp --stdio --allow-all-tools"
```

### TCP mode

Use TCP mode when you want the bridge to connect to or auto-spawn a Copilot CLI instance listening on a port.

```bash
acp-ws-bridge \
  --ws-port 8765 \
  --api-port 8766 \
  --copilot-mode tcp \
  --copilot-port 3000
```

With an exact TCP command override, you are responsible for including the ACP/TCP flags and matching the configured port:

```bash
acp-ws-bridge \
  --copilot-mode tcp \
  --copilot-port 3000 \
  --command "copilot --acp --port 3000 --allow-all-tools"
```

## Custom Copilot data directory

Use `--copilot-dir` when Copilot session data lives somewhere other than `~/.copilot`:

```bash
acp-ws-bridge \
  --ws-port 8765 \
  --copilot-dir /srv/copilot-data
```

This affects:

- `session-store.db` history lookups
- `session-state/**/events.jsonl` usage scanning
- the bridge stats-cache database location

## TLS

To enable `wss://` and HTTPS for the REST API, provide both a certificate and key:

```bash
acp-ws-bridge \
  --ws-port 8765 \
  --api-port 8766 \
  --tls-cert /path/to/cert.pem \
  --tls-key /path/to/key.pem
```

For local testing with an installed binary on macOS or Linux, generate `cert.pem` and `key.pem` with `mkcert` after running `mkcert -install`:

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

If clients connect from another device, include the externally used hostname or IP in the `mkcert` command, and make sure that client trusts the `mkcert` root CA too.

Then start the bridge with:

```bash
acp-ws-bridge --ws-port 8765 --api-port 8766 --tls-cert cert.pem --tls-key key.pem
```

## Tailscale Serve (Reverse Proxy)

If the host is on a [Tailscale](https://tailscale.com) tailnet, you can let Tailscale handle TLS instead of managing certificates yourself.

Run the bridge in plain mode (no `--tls-*` flags):

```bash
acp-ws-bridge --ws-port 8765 --api-port 8766
```

Then expose both ports over HTTPS with `tailscale serve`:

```bash
tailscale serve --bg https / http://localhost:8765
tailscale serve --bg https /api http://localhost:8766
```

Clients on the tailnet connect using the machine's Tailscale FQDN:

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

Tailscale provisions a valid Let's Encrypt certificate automatically — no `mkcert`, no self-signed certs, no CA trust setup on client devices.

To stop serving:

```bash
tailscale serve off
```

See [`tailscale serve` docs](https://tailscale.com/kb/1242/tailscale-serve) for more options.

## Example systemd unit

```ini
[Unit]
Description=acp-ws-bridge
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=bridge
WorkingDirectory=/opt/acp-ws-bridge
Environment=RUST_LOG=acp_ws_bridge=info
ExecStart=/usr/local/bin/acp-ws-bridge --ws-port 8765 --api-port 8766 --copilot-path /usr/local/bin/copilot
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
```

Adjust paths, user, ports, TLS flags, `--copilot-dir`, and any custom command override to match your environment.

## Operational checks

### Health endpoint

```bash
curl http://127.0.0.1:8766/health
```

This should return bridge version, Copilot CLI version, and uptime.

### Session visibility

```bash
curl http://127.0.0.1:8766/api/sessions
curl http://127.0.0.1:8766/api/stats
```

### Logs

Use `RUST_LOG` or `--log-level` for runtime visibility.

Example:

```bash
RUST_LOG=acp_ws_bridge=debug acp-ws-bridge --ws-port 8765
```

## Troubleshooting

### Copilot CLI fails to spawn

- confirm the configured `--copilot-path` exists
- if using `--acp-command` / `--command`, confirm the full override command is valid and already includes the ACP flags you expect
- confirm the runtime user can run `copilot --version`
- confirm the runtime user is already authenticated with Copilot CLI

### REST API is unavailable

- check whether `--api-port` conflicts with another service
- remember the bridge can continue running even if the REST API fails to bind

### No history or usage data appears

- confirm the configured Copilot data directory is populated
- confirm `session-store.db` exists in that directory for history endpoints
- confirm session-state event files exist for cached usage metrics

### TLS handshake issues

- verify the certificate matches the hostname clients use
- confirm both `--tls-cert` and `--tls-key` are provided
- test locally with the generated cert before exposing the service publicly