anyagent-bridge 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/.env.example +81 -0
  2. package/LICENSE +21 -0
  3. package/README.md +289 -0
  4. package/bin/anyagent-bridge.js +127 -0
  5. package/client/index.html +525 -0
  6. package/config.example.json +69 -0
  7. package/docs/INSTALL.md +138 -0
  8. package/docs/ROADMAP.md +168 -0
  9. package/docs/SECURITY.md +85 -0
  10. package/docs/WALKTHROUGH.md +82 -0
  11. package/docs/screenshots/.gitkeep +3 -0
  12. package/docs/screenshots/01-startup-banner.png +0 -0
  13. package/docs/screenshots/02-terminal-view.png +0 -0
  14. package/docs/screenshots/03-agent-running.png +0 -0
  15. package/docs/screenshots/04-mobile.png +0 -0
  16. package/package.json +57 -0
  17. package/server/auth/index.js +20 -0
  18. package/server/auth/manager.js +448 -0
  19. package/server/auth/oauth.js +154 -0
  20. package/server/auth/providers/github.js +59 -0
  21. package/server/auth/providers/google.js +44 -0
  22. package/server/auth/sessions.js +160 -0
  23. package/server/auth/store.js +135 -0
  24. package/server/auth/totp.js +140 -0
  25. package/server/index.js +1779 -0
  26. package/server/safety/audit.js +139 -0
  27. package/server/safety/clientip.js +73 -0
  28. package/server/safety/index.js +17 -0
  29. package/server/safety/manager.js +507 -0
  30. package/server/safety/redact.js +153 -0
  31. package/server/safety/sandbox.js +130 -0
  32. package/server/tunnel/adapters/cloudflare-quick.js +40 -0
  33. package/server/tunnel/adapters/cloudflared-named.js +49 -0
  34. package/server/tunnel/adapters/devtunnel.js +54 -0
  35. package/server/tunnel/adapters/tailscale.js +42 -0
  36. package/server/tunnel/base-adapter.js +185 -0
  37. package/server/tunnel/detect.js +65 -0
  38. package/server/tunnel/index.js +15 -0
  39. package/server/tunnel/manager.js +321 -0
  40. package/server/tunnel/registry.js +31 -0
  41. package/test/stage4-boot.js +98 -0
  42. package/test/stage4-smoke.js +267 -0
@@ -0,0 +1,138 @@
1
+ # Installation
2
+
3
+ anyagent-bridge runs on **macOS, Windows, and Linux**. Pick one of the three
4
+ install paths below. For what the bridge is and how to use it once running, see
5
+ the top-level [README](../README.md); for the security model, read
6
+ [SECURITY.md](SECURITY.md) before exposing it to anything but localhost.
7
+
8
+ ## Requirements
9
+
10
+ - **Node.js ≥ 18** (`node -v`). The bridge uses only Node's built-ins plus a few
11
+ small npm packages; the one native dependency is `node-pty`.
12
+ - **A C/C++ toolchain** so `node-pty` can build (only for the npx / from-source
13
+ paths — the Docker image builds it for you):
14
+ - **macOS** — Xcode Command Line Tools: `xcode-select --install`.
15
+ - **Linux** — `build-essential` + `python3` (Debian/Ubuntu:
16
+ `sudo apt-get install -y build-essential python3`).
17
+ - **Windows** — Visual Studio Build Tools (C++ workload) + Python 3. The
18
+ simplest route is to install Node via the official installer with the
19
+ "Tools for Native Modules" checkbox ticked.
20
+ - **The agent CLI(s) you want to drive** — e.g. `claude` (Claude Code) or
21
+ `codex` — installed and working in your own terminal. The bridge launches
22
+ whatever you register; it does not bundle any agent.
23
+ - **Optional:** Docker (only for the container path or for Stage 4 sandboxing),
24
+ and a tunnel CLI (`devtunnel`, `cloudflared`, or `tailscale`) for remote access.
25
+
26
+ ---
27
+
28
+ ## Path A — `npx` (fastest way to try it)
29
+
30
+ ```bash
31
+ npx anyagent-bridge
32
+ ```
33
+
34
+ This downloads and runs the bridge in one step, then prints an access URL with a
35
+ token. Open it in your browser. Useful flags:
36
+
37
+ ```bash
38
+ npx anyagent-bridge --port 8080 # listen on a different port
39
+ npx anyagent-bridge --host 0.0.0.0 # expose on your LAN (token is the only gate)
40
+ npx anyagent-bridge --tunnel devtunnel # also open a remote tunnel
41
+ npx anyagent-bridge --help # all flags
42
+ ```
43
+
44
+ **State location caveat.** Run this way, the generated token and runtime state
45
+ live inside the package's install directory under npm's cache, not in your
46
+ current folder. That is fine for a quick try, but for daily or persistent use
47
+ prefer **Path B (from source)** or **Path C (Docker)**, where you control where
48
+ state lives.
49
+
50
+ ---
51
+
52
+ ## Path B — From source (recommended for regular use)
53
+
54
+ ```bash
55
+ git clone https://github.com/elon-choo/anyagent-bridge.git
56
+ cd anyagent-bridge
57
+ npm ci # installs deps and builds node-pty
58
+ cp config.example.json config.json
59
+ npm start
60
+ ```
61
+
62
+ Edit `config.json` to register your agents, projects, and (optionally) auth or
63
+ tunnel settings — every field is documented inline in `config.example.json` and
64
+ in the README. Environment overrides go in a `.env` file (copy `.env.example`).
65
+
66
+ On first boot the server generates an access token and saves it to
67
+ `.data/auth.json`; the startup banner prints the full URL with the token. Re-runs
68
+ reuse the saved token.
69
+
70
+ To keep it running in the background, use your platform's process manager
71
+ (`pm2 start npm --name anyagent-bridge -- start`, a `systemd` unit, a `launchd`
72
+ agent, or Windows Task Scheduler).
73
+
74
+ ---
75
+
76
+ ## Path C — Docker / docker-compose (isolated, reproducible)
77
+
78
+ ```bash
79
+ git clone https://github.com/elon-choo/anyagent-bridge.git
80
+ cd anyagent-bridge
81
+ docker compose up -d --build
82
+ docker compose logs bridge # the startup banner prints your access token
83
+ ```
84
+
85
+ Then open <http://127.0.0.1:3001> and paste the token. The compose file:
86
+
87
+ - Publishes the port on **127.0.0.1 only** (localhost). The bridge binds
88
+ `0.0.0.0` *inside* the container; the `ports:` mapping is what controls host
89
+ exposure — keep it on `127.0.0.1` unless you front it with an authenticated
90
+ tunnel/proxy.
91
+ - Persists the access token and audit log (both under `.data`) in a named volume
92
+ (`bridge-data`), so they survive `docker compose down && up`. (The session list
93
+ in `sessions.json` lives outside `.data` and is not in the volume.)
94
+
95
+ **Reading the token without the logs:** pin your own instead —
96
+ set `BRIDGE_AUTH_TOKEN` in the `environment:` block of `docker-compose.yml`.
97
+
98
+ **Agents inside the container.** The image ships the bridge plus a `bash` shell,
99
+ **not** the agent CLIs. To launch `claude`/`codex` from within the container you
100
+ must either:
101
+
102
+ 1. derive your own image (`FROM anyagent-bridge:local`, then install the agent
103
+ CLI and bake in or mount its credentials), or
104
+ 2. run the bridge on the host (Path A/B) where your agents already live, and use
105
+ Docker only for Stage 4's per-session sandbox (which runs each session in a
106
+ *separate*, operator-supplied agent image).
107
+
108
+ Plain shell access and the file API work in the container as-is.
109
+
110
+ ---
111
+
112
+ ## Updating
113
+
114
+ - **npx** — always fetches the latest published version; nothing to update.
115
+ - **From source** — `git pull && npm ci`.
116
+ - **Docker** — `git pull && docker compose up -d --build`.
117
+
118
+ ## Uninstalling
119
+
120
+ - **From source** — delete the cloned folder; it holds `.data/` (including your
121
+ token) and there is no Docker volume to clean up.
122
+ - **Docker** — `docker compose down -v` (the `-v` also deletes the `bridge-data`
123
+ volume and its token), then delete the cloned folder.
124
+ - **npx** — `npm cache clean --force` removes the cached package.
125
+
126
+ ## Troubleshooting
127
+
128
+ - **`node-pty` build fails** — you are missing the toolchain above. Install it,
129
+ then `npm ci` again. On Windows, reopen the terminal after installing the
130
+ Build Tools so the new `PATH` is picked up.
131
+ - **Port already in use (`EADDRINUSE`)** — pick another port with `--port` /
132
+ `PORT=` / `config.json`.
133
+ - **The agent dropdown is empty or "command not found"** — the agent CLI is not
134
+ on the `PATH` of the process running the bridge. Verify it works in the same
135
+ shell, or set an absolute `command` in `config.json`.
136
+ - **Remote access not connecting** — see the README's "Remote access" section;
137
+ confirm the tunnel CLI is installed and logged in, and set
138
+ `auth.oauth.callbackBaseUrl` to your public URL when using OAuth behind a tunnel.
@@ -0,0 +1,168 @@
1
+ # Roadmap
2
+
3
+ anyagent-bridge ships in stages. Stage 1 is a self-contained, useful tool on its own;
4
+ each later stage adds a layer for safer remote access without breaking the core. The
5
+ codebase deliberately leaves clean extension points (seams) for these stages.
6
+
7
+ ## Stage 1 — Portable core ✅ (current)
8
+
9
+ The "it works" core, with nothing macOS- or person-specific:
10
+
11
+ - `TerminalSession` class with PTY spawn/respawn (automatic re-creation + backoff).
12
+ - Multi-viewer broadcast over a WebSocket protocol.
13
+ - Scrollback buffer (10,000 lines), heartbeat, and dead-connection detection.
14
+ - Session persistence (`sessions.json`).
15
+ - Universal agent profiles — register **any** command; launch via `startAgent`, drive via `sendAgent`/raw `input`.
16
+ - File-management API (browse/read/write/rename/move/delete/upload/download) behind a path whitelist.
17
+ - Crash guards (`uncaughtException`, `unhandledRejection`, `SIGINT`, `SIGTERM`).
18
+ - Token auth with constant-time comparison and a rate-limiting structure.
19
+ - Cross-platform shell selection and plain `fs.*` file access (no platform-specific brokers).
20
+
21
+ ## Stage 2 — Free tunnel adapters ✅
22
+
23
+ Zero-/low-config remote access without paying for anything, via pluggable
24
+ adapters spawned as external CLIs (no new npm dependencies). Disabled by default;
25
+ when off, missing, or misconfigured the server runs exactly like Stage 1
26
+ (localhost-only) and never crashes.
27
+
28
+ - **Microsoft Dev Tunnels** (default) — one-time `devtunnel user login`; the URL rotates per run unless you pre-create a tunnel (`tunnelId`).
29
+ - **Cloudflare Quick Tunnel** (`cloudflare-quick`) — no account; ephemeral `*.trycloudflare.com` URL; testing-grade (≈200 req cap, no SSE).
30
+ - **Tailscale** (`tailscale`) — needs `tailscale up` + Funnel enabled in the tailnet ACL; stable `*.ts.net` URL; may need sudo.
31
+ - **cloudflared named tunnel** (`cloudflared-named`) — needs a Cloudflare account + zone, a pre-created tunnel and DNS route; stable custom hostname.
32
+
33
+ Config: the `tunnel` block in `config.json` (default `enabled:false`,
34
+ `provider:"devtunnel"`). Env overrides: `BRIDGE_TUNNEL_ENABLED`,
35
+ `BRIDGE_TUNNEL_PROVIDER`, `BRIDGE_TUNNEL_HOSTNAME`. Control at runtime:
36
+ `GET|POST /api/tunnel/{status,start,stop,restart}`. Add a 5th provider by
37
+ dropping an adapter under `server/tunnel/adapters/` and registering it in
38
+ `server/tunnel/registry.js`.
39
+
40
+ ## Stage 3 — Authentication & sessions ✅
41
+
42
+ Login on top of Stage 1's static token, all opt-in. With OAuth off, no TOTP
43
+ enrolled, and `requireLogin` false, the bridge behaves exactly like Stage 2 (the
44
+ static token works everywhere). Zero new npm dependencies — built on Node's
45
+ `crypto` and the global `fetch`. Lives in `server/auth/`.
46
+
47
+ - **Signed sessions** — HMAC-SHA256 tokens, expiring and revocable, tracked by id
48
+ and persisted (`.data/auth-sessions.json`). Primary browser transport is an
49
+ httpOnly `aab_session` cookie (the WS upgrade and fetches carry it automatically);
50
+ `X-Session-Token` / `Authorization: Bearer` / `?session=` work for API clients.
51
+ - **TOTP 2FA** (RFC 6238) — enroll from the UI (`/api/auth/totp/setup` → `confirm`),
52
+ scan the `otpauth://` QR, get one-time recovery codes. A replay guard tracks the
53
+ last accepted step counter. Operator-only.
54
+ - **OAuth** — Google (auth-code + PKCE S256) and GitHub (auth-code + state). CSRF
55
+ `state` is single-use and TTL-bounded. Identity is checked against a per-provider
56
+ allowlist (`allowedEmails` / `allowedLogins`); an empty allowlist fails closed
57
+ unless `claimFirstUser` is on (first successful login claims the bridge, TOFU).
58
+ - **The one rule** — the static token is a *direct* credential UNLESS `requireLogin`
59
+ is set OR a TOTP secret is confirmed; then it becomes *login-only* (must be
60
+ exchanged, with the 2FA code, for a session). This is what makes 2FA real.
61
+
62
+ Config: the `auth` block in `config.json` (or `BRIDGE_*` env overrides — keep
63
+ OAuth client secrets in env). Routes: `POST /api/auth/login`, `/logout`,
64
+ `GET /api/auth/config|me|sessions`, `DELETE /api/auth/sessions/:id`,
65
+ `GET /api/auth/oauth/:provider/{start,callback}`, `/api/auth/totp/{status,setup,confirm,disable}`.
66
+
67
+ Defense-in-depth added here: a CSRF Origin check on cookie-authenticated writes
68
+ (bearer/token clients are exempt — they are not CSRF-able), an expanded file-API
69
+ denylist for secret-bearing dotfiles, and a bounded OAuth pending-state map.
70
+
71
+ Known residuals (deferred to Stage 4 hardening): `getClientIP` trusts
72
+ `X-Forwarded-For` unconditionally — behind an untrusted proxy the per-IP login
73
+ rate limit is evadable (the global cap still applies); set `callbackBaseUrl` when
74
+ OAuth is exposed so the redirect URI is not derived from request headers.
75
+
76
+ ## Stage 4 — Sandboxing & safety ✅
77
+
78
+ Four opt-in safety layers in one subsystem, `server/safety/` (entry `index.js` exports
79
+ `createSafetyManager`; `manager.js` orchestrates; `sandbox.js` / `audit.js` / `redact.js`
80
+ / `clientip.js` are pure leaves). All default **off** — with `safety.enabled` false the
81
+ server is byte-identical to Stage 3 (proven by `test/stage4-boot.js`). Zero new npm
82
+ dependencies: the Docker layer spawns the `docker` CLI (reusing `tunnel/detect`),
83
+ everything else is Node core. `server/index.js` is touched only at marked seams;
84
+ `auth._isOperator` is reused for the operator gate (auth internals untouched).
85
+
86
+ - **Docker isolation** — the whole session PTY runs `docker run` (the agent launches
87
+ inside the container, so `startAgent`/`sendToAgent` are unchanged). Only sessions
88
+ with a bounded **project dir** are sandboxed (never bind-mounts `$HOME`); the project
89
+ mounts at `/workspace`. Operator-supplied `image` (must contain the agent CLI).
90
+ `-it` for an in-container TTY; default limits (`--memory`/`--cpus`/`--pids-limit`/
91
+ `--security-opt no-new-privileges`); opt-in hardening (`--read-only`/`--cap-drop ALL`/
92
+ `--user`, the last Linux-only). Secrets reach the container as `-e NAME` (values off
93
+ the process table); the docker client env is a minimal allowlist (never the full
94
+ `process.env`); `BRIDGE_*`/token are denied even if listed. `network` defaults to
95
+ `bridge`. `onDockerMissing` = `host` (fall back, default) | `refuse`. Repeated fast
96
+ container exits auto-degrade to a host shell (no respawn storm). **Graceful, never
97
+ crashes.**
98
+ - **Kill-switch** — `POST /api/safety/kill/:id` (SIGKILL pty + `docker rm -f`),
99
+ `POST /api/safety/panic` (kill all + sweep `aab-<installId>-sess-*` strays + optional
100
+ tunnel stop + optional **lock**), `POST /api/safety/unlock`. The lock gates only new
101
+ agent launches (never the shell — no remote soft-brick) and persists across restart.
102
+ Operator-only on REST and WebSocket (`{type:"panic"|"kill"}`). Graceful `destroy()`
103
+ also reaps its container (no leak); a per-install container-name nonce so panic never
104
+ kills another install's containers.
105
+ - **Audit logging** — append-only JSONL under `.data/audit/` via one `res.on('finish')`
106
+ middleware (REST mutations) + WS seams (`agent.start`/`agent.send`); raw keystrokes
107
+ are intentionally not logged. Date + size rotation, retention prune by strict regex,
108
+ synchronous ordered append, `flushSync` on exit. Every field is redacted before write.
109
+ - **Secret redaction** — the audit log is **always** scrubbed (AWS/OpenAI/GitHub/Slack/
110
+ Google keys, JWT, PEM blocks, plus the bridge's own token + session secret by exact
111
+ match). Live PTY-stream redaction is opt-in (`redaction.liveStream`, default off so the
112
+ stream stays byte-identical) with a boundary hold-back for split tokens/PEM/ANSI and a
113
+ bounded `maxHoldBytes` (overflow masks the partial rather than leaking it).
114
+
115
+ **Stage 3 residual closed:** `trustProxy` (default off, opt-in) makes the client IP for
116
+ rate limiting + audit come from the direct socket peer instead of a spoofable
117
+ `X-Forwarded-For`; `true`/`N` trust the nearest / Nth proxy hop. (The OAuth
118
+ `redirect_uri`-from-Host residual remains a documented boot warning — hardening it would
119
+ require changing the shipped Stage-3 auth route, so it is deferred.)
120
+
121
+ Config: the `safety` block in `config.json` (`BRIDGE_SAFETY_ENABLED`, `BRIDGE_SANDBOX_*`,
122
+ `BRIDGE_AUDIT_ENABLED`, `BRIDGE_REDACT_LIVE`, `BRIDGE_TRUST_PROXY` env overrides).
123
+ Verified: `test/stage4-smoke.js` (32 unit) + `test/stage4-boot.js` (9 integrated,
124
+ byte-identical-off + safety-on + audit recording), **plus a live run against a real
125
+ Docker daemon (colima, 2026-06-26):** the real `spawnSpecFor` argv launches a sandbox
126
+ container (the project bind-mounted at `/workspace`, `--network none`, memory/cpu/pid
127
+ limits, `--security-opt no-new-privileges`, secrets passed by name), the session shell
128
+ runs *inside* it (`uname` → Linux), and `panic` kills + sweeps every
129
+ `aab-<installId>-sess-*` container with no leak while the lock gates new agent launches.
130
+
131
+ ## Stage 5 — Packaging & distribution ✅
132
+
133
+ One-command installs plus the docs to run the bridge safely on any of the three
134
+ platforms. Zero new runtime dependencies and **no changes to the Stage 1–4 server** —
135
+ the launcher only sets environment variables the server already reads.
136
+
137
+ - **npx** — `bin/anyagent-bridge.js` (declared in `package.json`'s `bin`) boots the
138
+ server in-process and maps friendly flags (`--port` / `--host` / `--token` /
139
+ `--tunnel [provider]` / `--no-tunnel`) onto the existing `PORT` / `HOST` /
140
+ `BRIDGE_*` env vars. Because dotenv does not override an already-set variable, the
141
+ precedence is CLI flag > `.env` > `config.json`, and `npx anyagent-bridge` stays
142
+ equivalent to `node server/index.js`. Unknown flags and bad values fail with exit 1.
143
+ - **Docker** — a multi-stage `Dockerfile` builds `node-pty` in a toolchain stage and
144
+ ships a slim non-root runtime (`tini` as PID 1, a Node-only `/health` healthcheck,
145
+ `HOST=0.0.0.0` so the published port reaches it). `docker-compose.yml` publishes on
146
+ `127.0.0.1` only and persists the token / sessions / audit log in the `bridge-data`
147
+ named volume (read the token from `docker compose logs`). `.dockerignore` keeps host
148
+ state and secrets out of the build context. The image carries the bridge + a `bash`
149
+ shell but **not** the agent CLIs — documented, with two ways to add an agent.
150
+ - **Publishing hygiene** — a `files` allowlist in `package.json` publishes only the app
151
+ (`bin`/`server`/`client`/`docs`/`test` + `config.example.json` + `.env.example`); a
152
+ `npm pack --dry-run` confirms `config.json`, `.data/`, `.env`, and `sessions.json` are
153
+ never in the tarball (38 files, no secrets).
154
+ - **Docs** — `docs/INSTALL.md` (npx · from source · Docker, per-OS toolchain notes,
155
+ updating / uninstalling / troubleshooting), `docs/SECURITY.md` (threat model, safe
156
+ defaults, what to enable before exposing it, disclaimers), and `docs/WALKTHROUGH.md`
157
+ (end-to-end tour + screenshot capture guide). README gains a Quick start.
158
+
159
+ Verified offline: `node bin/anyagent-bridge.js --version/--help`, error paths exit 1, a
160
+ real boot through the launcher with `/health` returning **HTTP 200** and the banner
161
+ reflecting the `--port`/`--token` flags, `npm pack --dry-run` (file set above), and the
162
+ Stage 4 suites still green (`npm test` → 32 + 9 pass). **Verified live (Docker via colima,
163
+ 2026-06-26):** `docker compose up --build` builds the multi-stage image, the container
164
+ runs **healthy**, `/health` returns 200 on the localhost-published port, it runs
165
+ **non-root** (`uid 1000`), `node-pty` loads and spawns a real PTY inside the container,
166
+ and the named volume persists the access token across `down && up` (the banner's token
167
+ source flips `generated`→`file`). Screenshot PNGs remain deferred to a live capture
168
+ (`docs/WALKTHROUGH.md` ships the text walkthrough + capture steps).
@@ -0,0 +1,85 @@
1
+ # Security model & disclaimers
2
+
3
+ Read this before you expose anyagent-bridge to anything beyond your own machine.
4
+
5
+ ## What you are running
6
+
7
+ anyagent-bridge gives a web browser **a real terminal and file access on the
8
+ machine it runs on**. Anyone who can reach the server *and* holds a valid token
9
+ or session can run commands, read and write files (within the configured path
10
+ whitelist), and drive your AI coding agents — with the same privileges as the
11
+ user running the bridge. Treat the access token like an SSH key.
12
+
13
+ ## Safe by default
14
+
15
+ Out of the box the bridge is conservative:
16
+
17
+ - **Binds to `127.0.0.1`** (localhost only). Nothing on your network can reach it
18
+ until you explicitly set `host`/`HOST` to `0.0.0.0` or publish it.
19
+ - **No tunnel.** Remote access (Stage 2) is opt-in and off by default.
20
+ - **Token required.** A 32-byte random token is generated on first boot and
21
+ saved to `.data/auth.json` with `0600` permissions. There is never a blank or
22
+ default token. Token comparison is constant-time.
23
+ - **Path whitelist.** The file API is restricted to configured `allowedPaths`
24
+ (your home directory by default), and a denylist blocks secret-bearing dotfiles
25
+ (`.env`, `.npmrc`, SSH keys, cloud-credential files, …).
26
+
27
+ ## Before you expose it (tunnel or `0.0.0.0`)
28
+
29
+ The token alone is a single shared secret. When the bridge is reachable beyond
30
+ localhost, layer on the opt-in protections:
31
+
32
+ - **Turn on authentication (Stage 3).** Set `requireLogin` so the static token
33
+ becomes login-only, enroll **TOTP 2FA**, and/or require **Google/GitHub OAuth**
34
+ with an email/login allowlist. With 2FA or `requireLogin` on, a leaked token is
35
+ no longer enough by itself.
36
+ - **Use a tunnel that has its own auth.** Microsoft Dev Tunnels can require a
37
+ sign-in; a Cloudflare/Tailscale path can sit behind their access controls.
38
+ Don't put a raw `0.0.0.0` bind directly on the public internet.
39
+ - **Pin `auth.oauth.callbackBaseUrl`** to your public URL when OAuth is on behind
40
+ a tunnel, so the redirect URI is not derived from (spoofable) request headers.
41
+ - **Set `trustProxy`** (Stage 4) only when you actually sit behind a known proxy,
42
+ so per-client rate limiting and the audit log record the real client IP instead
43
+ of a spoofable `X-Forwarded-For`. Leave it off otherwise.
44
+ - **Sandbox the sessions (Stage 4).** Run each session inside a Docker container
45
+ (`safety.sandbox`) so the agent touches only a mounted project directory, with
46
+ memory/CPU/pid limits and `no-new-privileges`. Use `--network none` for an
47
+ offline agent, `readOnlyRootfs`/`dropAllCaps` to harden further.
48
+ - **Enable the audit log (Stage 4).** Append-only JSONL of REST mutations and
49
+ agent commands, with secrets redacted. Pair it with the kill-switch
50
+ (`POST /api/safety/panic`) for an emergency stop that kills sessions and locks
51
+ new agent launches.
52
+
53
+ ## Handling secrets
54
+
55
+ - **Keep OAuth client secrets in environment variables**, not in `config.json`
56
+ (which can be written back to disk at runtime). `config.json` is gitignored.
57
+ - The published npm package and the Docker image **exclude** `config.json`,
58
+ `.data/`, `.env`, and `sessions.json` — your token and secrets are never baked
59
+ into a distributable artifact.
60
+ - Audit logs are always secret-redacted; live PTY-stream redaction is available
61
+ opt-in (`redaction.liveStream`).
62
+
63
+ ## Known limitations
64
+
65
+ - Stage 1 ships **no TLS** of its own. Terminate TLS at your tunnel/reverse proxy
66
+ (Dev Tunnels, Cloudflare, etc.) — never send a token over plain `http://` across
67
+ an untrusted network.
68
+ - Docker sandboxing is **defense-in-depth, not a security boundary you should bet
69
+ a hostile multi-tenant workload on**. Do not mount the Docker socket into a
70
+ sandboxed session (that is host-equivalent access), and do not bind-mount `$HOME`.
71
+ - The bridge is meant for **a single operator controlling their own machine**, not
72
+ as a multi-user SaaS. It is not a substitute for a VPN or a zero-trust gateway
73
+ in a sensitive environment.
74
+
75
+ ## Reporting a vulnerability
76
+
77
+ Please report security issues **privately** — open a GitHub Security Advisory on
78
+ the repository (Security → Report a vulnerability) rather than a public issue, so
79
+ a fix can ship before details are public.
80
+
81
+ ## Disclaimer
82
+
83
+ anyagent-bridge is provided **as-is, under the MIT License, with no warranty**.
84
+ You are responsible for how and where you expose it. Running it on a machine with
85
+ access to sensitive data or networks is at your own risk.
@@ -0,0 +1,82 @@
1
+ # Walkthrough
2
+
3
+ A guided tour of using anyagent-bridge end to end. The screenshots below live in
4
+ [`docs/screenshots/`](screenshots/); to regenerate them yourself, see the
5
+ [capture instructions](#capturing-screenshots).
6
+
7
+ ## 1. Start the bridge
8
+
9
+ ```bash
10
+ npx anyagent-bridge # or: npm start / docker compose up -d --build
11
+ ```
12
+
13
+ The startup banner prints the access URL and token:
14
+
15
+ ```
16
+ ===============================================================
17
+ AnyAgent Bridge — server running
18
+ ===============================================================
19
+ URL: http://127.0.0.1:3001?token=ab12…ef
20
+ WebSocket: ws://127.0.0.1:3001/ws
21
+ Host: 127.0.0.1
22
+ Shell: /bin/zsh
23
+ Agents: claude, codex
24
+ ...
25
+ Access token (generated): ab12…ef
26
+ ===============================================================
27
+ ```
28
+
29
+ ![Startup banner with the access URL and token](screenshots/01-startup-banner.png)
30
+
31
+ ## 2. Open the browser UI
32
+
33
+ Open the printed URL (the `?token=…` logs you in automatically), or visit
34
+ <http://127.0.0.1:3001> and paste the token. You land on the terminal view: a full
35
+ xterm.js terminal wired to a live shell on your machine, plus a toolbar with the
36
+ agent launcher, a file browser, and (if configured) project and tunnel controls.
37
+
38
+ ![The main terminal view — a live shell in the browser](screenshots/02-terminal-view.png)
39
+
40
+ ## 3. Launch an AI agent
41
+
42
+ Pick an agent (e.g. **Claude Code**) from the dropdown and start it. The bridge
43
+ spawns the agent's CLI inside the session's PTY, so you interact with it exactly
44
+ as you would in your own terminal — streamed live to the browser. Type prompts,
45
+ send keys, and watch output in real time. Detaching the browser keeps the session
46
+ alive; reconnecting reattaches with full scrollback.
47
+
48
+ ![Claude Code running inside a bridge session](screenshots/03-agent-running.png)
49
+
50
+ ## 4. Browse and edit files
51
+
52
+ Use the file panel to browse, open, edit, upload, and download files within the
53
+ configured path whitelist. Image uploads are supported (handy for pasting a
54
+ screenshot to an agent).
55
+
56
+ ## 5. Go remote (optional)
57
+
58
+ To reach the bridge from your phone or another machine, enable a tunnel — either
59
+ at startup (`--tunnel devtunnel`) or at runtime via the tunnel controls
60
+ (`POST /api/tunnel/start`). The banner and the UI show the public URL once it is
61
+ ready. Before exposing anything, read [SECURITY.md](SECURITY.md) and turn on
62
+ login / 2FA / OAuth.
63
+
64
+ ![The bridge UI at a phone-sized viewport](screenshots/04-mobile.png)
65
+
66
+ ---
67
+
68
+ ## Capturing screenshots
69
+
70
+ The images above were captured locally against a running bridge. To regenerate
71
+ them yourself:
72
+
73
+ 1. Start the bridge and note the token: `npm start`.
74
+ 2. Open the printed URL in a browser (desktop and a phone/responsive view for the
75
+ mobile shot).
76
+ 3. Capture each state listed above and save it under `docs/screenshots/` with the
77
+ matching filename (`01-startup-banner.png`, `02-terminal-view.png`, …).
78
+ 4. PNG, ~1400px wide, is plenty. Crop out anything sensitive — **the token in the
79
+ URL bar and any real file contents** — before committing.
80
+
81
+ Because the token grants full access, never publish a screenshot that shows a
82
+ live token, private file paths, or agent credentials.
@@ -0,0 +1,3 @@
1
+ # Screenshot assets for the walkthrough go here.
2
+ # See ../WALKTHROUGH.md → "Capturing screenshots" for the expected filenames and
3
+ # how to capture them. Redact any access token / private paths before committing.
Binary file
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "anyagent-bridge",
3
+ "version": "0.5.0",
4
+ "description": "Control your local terminal and any CLI AI coding agent from a browser, anywhere.",
5
+ "license": "MIT",
6
+ "author": "elon-choo",
7
+ "homepage": "https://github.com/elon-choo/anyagent-bridge#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/elon-choo/anyagent-bridge.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/elon-choo/anyagent-bridge/issues"
14
+ },
15
+ "main": "server/index.js",
16
+ "bin": {
17
+ "anyagent-bridge": "bin/anyagent-bridge.js"
18
+ },
19
+ "engines": {
20
+ "node": ">=18"
21
+ },
22
+ "files": [
23
+ "bin/",
24
+ "server/",
25
+ "client/",
26
+ "docs/",
27
+ "test/",
28
+ "config.example.json",
29
+ ".env.example",
30
+ "README.md",
31
+ "LICENSE"
32
+ ],
33
+ "keywords": [
34
+ "claude-code",
35
+ "codex",
36
+ "ai-agent",
37
+ "terminal",
38
+ "pty",
39
+ "websocket",
40
+ "remote",
41
+ "bridge",
42
+ "self-hosted",
43
+ "developer-tools"
44
+ ],
45
+ "scripts": {
46
+ "start": "node server/index.js",
47
+ "test": "node test/stage4-smoke.js && node test/stage4-boot.js"
48
+ },
49
+ "dependencies": {
50
+ "cors": "^2.8.5",
51
+ "dotenv": "^16.4.5",
52
+ "express": "^4.21.2",
53
+ "multer": "^1.4.5-lts.1",
54
+ "node-pty": "^1.0.0",
55
+ "ws": "^8.18.0"
56
+ }
57
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * AnyAgent Bridge — auth subsystem entry (Stage 3)
3
+ *
4
+ * The only module server/index.js imports for authentication. Creates an
5
+ * AuthManager and exposes the OAuth provider list for diagnostics. Sits on top
6
+ * of the Stage 1 static token; disabled features leave Stage 2 behavior intact.
7
+ */
8
+
9
+ const AuthManager = require('./manager');
10
+ const { PROVIDERS } = require('./oauth');
11
+
12
+ function createAuthManager(authConfig, deps) {
13
+ return new AuthManager(authConfig, deps);
14
+ }
15
+
16
+ function listOAuthProviders() {
17
+ return Object.keys(PROVIDERS);
18
+ }
19
+
20
+ module.exports = { createAuthManager, listOAuthProviders };