chat-saiden
Web terminal for BT on the MARAUDER mesh. chat.saiden.dev lands a browser-native
xterm.js session on claude CLI (bt7274 cart) running on junkpile, gated by
Cloudflare Access with Google OAuth.
Architecture
User browser
│ HTTPS
▼
chat.saiden.dev ──┐ Cloudflare edge
│ │
│ CF Access │ Google IdP challenge
│ (whitelist) │ → reject if not on list
│ │
▼ │
Cloudflare Tunnel │ Zero-trust ingress
│ │
▼
junkpile:7681 │ ttyd (localhost-only, no public bind)
│ │
▼
claude (bt7274) │ marauder MCP gives BT identity + memory + tools
Properties
- No frontend code. ttyd ships xterm.js + WS + theming. Custom Saiden palette via CLI flags.
- No auth code. CF Access does Google OAuth + whitelist enforcement before the request ever reaches the tunnel.
- ttyd binds
127.0.0.1only — the public path is exclusively through the Tunnel + Access. - Real BT. Not an API impersonation. Full marauder MCP toolkit available in-session.
Components
| Path | Purpose |
|---|---|
junkpile/ttyd-wrapper.sh |
Launches claude with bt7274 cart, with Saiden banner |
junkpile/ttyd-chat.service |
systemd unit for ttyd (localhost-only bind, Saiden palette) |
junkpile/cloudflared-chat-saiden.service |
systemd unit for tunnel (token-mode, reads /etc/cloudflared/chat-saiden.env) |
cloudflare/dashboard-setup.md |
Step-by-step: create tunnel + public hostname + Access app + Google IdP + whitelist |
install.sh |
Junkpile-side installer (ttyd + units + token env stub) |
deploy.md |
End-to-end deploy walkthrough |
Tunnel mode: token-based, matches existing junkpile pattern
(cloudflared-mesh, cloudflared-tensors-art). Tunnel ingress lives in the CF
dashboard, not in a local config file. Token sits in
/etc/cloudflared/chat-saiden.env (mode 0640, root:chi).
Threat model (read before deploying)
ttyd-over-claude exposes shell-equivalent power on junkpile. The defense is the CF Access whitelist. Treat the whitelist as the security boundary:
- Never open the Access policy to "any Google account" or "any domain".
- Always keep
cloudflared-chat-saidenandttyd-chatlocalhost-bound. - If the whitelist is ever modified,
auth_verifythe change with the Pilot first.
Status
- ttyd installed on junkpile (1.7.7_11)
- ttyd wrapper installed →
~/.local/bin/ttyd-wrapper.sh - systemd units installed (
ttyd-chat,cloudflared-chat-saiden) - Tunnel created in CF dashboard → token in
/etc/cloudflared/chat-saiden.env - Public hostname
chat.saiden.dev → http://localhost:7681 - CF Access app + Google IdP + whitelist configured
- WebSocket support enabled on Access app
sudo systemctl enable --now ttyd-chat cloudflared-chat-saiden- First successful login as adam.ladachowski@gmail.com
- Whitelist denial verified from second Google account