agents (reloadlife/agents) is a remote control plane for AI coding CLIs (Claude Code, Grok, Codex, OpenCode, Cursor Agent). It can:
- Start interactive agent sessions in
tmux - Bridge a full remote PTY over WebSocket to your laptop
- Optionally archive session pane snapshots (recording — default off)
- Optionally run headless “print” jobs
That is powerful. Treat the API token like a root shell on the machine that runs agentsd.
| Line | Support |
|---|---|
| v0.8.x (current, latest intent v0.8.11+) | Security fixes land on main and ship in the next patch/minor tag |
Older (v0.7.x and below) |
No dedicated backports; upgrade to v0.8.x |
| Asset | Risk if stolen |
|---|---|
AGENTSD_TOKEN / extra tokens |
Create/kill sessions, attach PTY, run print jobs, manage server SSH public identities, login/switch/logout gh accounts (private keys / tokens never returned by the API) |
| PTY WebSocket | Interactive control of the agent TUI (and tools it can run) |
Embedded web shell (/, /assets/*) |
Public static SPA only — no secrets in HTML/JS bundle; all control is via /v1/* + token |
| Session recordings | Full terminal scrollback (secrets typed into agents, API keys, code) if sessions.recording = true |
| Workspace allowlist escape | Read/write outside intended repos |
All /v1/* routes require a valid bearer (including WebSocket PTY).
| Method | How |
|---|---|
| HTTP header | Authorization: Bearer <token> |
| Query (WebSocket-friendly) | ?token=<token> on /v1/sessions/{id}/pty (and any /v1/* if needed) |
Public by design:
GET /healthz- Non-
/v1paths (embedded web UI static shell at/,/assets/*, SPA routes)
The SPA stores the token in localStorage and sends the header on REST and ?token= on the PTY WebSocket. Prefer localhost + Tailscale / tunnel, not a raw public bind.
Primary token comes from auth.bearer_env (default AGENTSD_TOKEN) and is labeled default.
Additional tokens map label → env var name (not the raw secret):
[auth]
bearer_env = "AGENTSD_TOKEN"
extra_tokens = { ops = "AGENTS_TOKEN_OPS", guest = "AGENTS_TOKEN_GUEST" }
# trusted_header = "Tailscale-User-Login"
# require_bearer = trueexport AGENTSD_TOKEN="$(openssl rand -hex 32)"
export AGENTS_TOKEN_OPS="$(openssl rand -hex 32)"Any matching token authenticates. The label is the audit actor (optionally combined with a trusted identity header). Labels are for logging / ops distinction only — they do not provide multi-tenant isolation.
[auth]
trusted_header = "Tailscale-User-Login" # or Cf-Access-Authenticated-User-Email
require_bearer = true # default: header only enriches actor
# require_bearer = false # allow header-only auth behind a trusted proxyrequire_bearer |
Behavior |
|---|---|
true (default) |
Valid bearer still required; if trusted_header is present it is appended to the actor label for audit |
false |
A non-empty trusted header alone may authenticate (proxy:<value>). Only use behind a reverse proxy that strips client-supplied copies of that header |
Never set require_bearer = false on a bind reachable without that proxy.
- Generate with
openssl rand -hex 32(≥32 hex chars; short tokens log a soft warning at startup) - Store env files mode
600(~/.config/agentsd/envor/etc/agentsd/env) - Never commit tokens; rotate if leaked
- Prefer separate
extra_tokensfor different clients (laptop vs CI) so you can rotate one without the other
- Default off. Enable only with
[sessions] recording = true - Archives pane snapshots under
{jobs_dir}/recordings/(mode600files,700dirs) - Readable by anyone with a valid API token (
GET /v1/recordings, history search) - No automatic retention purge — delete on disk or via host backups policy
- Full details: docs/RECORDING.md
- Bind carefully
- Prefer
listen = "127.0.0.1:8787"+ Tailscale / SSH tunnel / Cloudflare Tunnel + Access - Avoid
0.0.0.0on untrusted networks
- Prefer
- Token
- Long random values; mode
600env files; multi-token viaextra_tokenswhen useful
- Long random values; mode
- Workspace allowlist
- Keep
[allow].pathstight - Do not set
paths = ["."]on multi-user hosts unless intentional
- Keep
- Auth on every control path
- All
/v1/*require bearer (or trusted-header-only when deliberately configured) - Only
/healthzand the static web shell are public
- All
- Recording
- Leave off unless you need archives; treat archives as sensitive
- Print jobs (
claude -p, etc.)- Opt-in only; may burn API credits and run non-interactive agent code
- Run as non-root when possible
- Prefer
deploy/agentsd.user.serviceunder your own account - Units use
KillMode=processso restart does not kill agent tmux sessions
- Prefer
- Playwright / headed browsers
- Prefer localhost Playwright server; see docs/PLAYWRIGHT.md
Operational single-admin checklist and lab host pattern: docs/SECURITY-OPS.md.
Please open a private security advisory on GitHub or email the maintainer via the GitHub profile for reloadlife. Do not file public issues with exploit details until a fix is available.