| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Terminals that survive the closed tab, the dropped VPN and a restart of the service — because they are real tmux sessions.
Start a Claude agent · close the window · open it again — same session, still running.
Start a shell or a Claude Code agent on your server, close the tab, walk away, come back on your phone — it is still there, still running, still where you left it. Every session is a tmux session, so nothing dies with your browser. No account, no cloud, no build step: one Node process and a handful of static files.
Long-running agents do not fit the SSH-in-a-tab model. You start a Claude Code run, it works for twenty minutes, and meanwhile your laptop sleeps, the VPN blips, or you simply want to check on it from the couch. With a plain ssh that run is gone.
AgentDeck puts a thin browser layer on top of tmux instead. The browser is only a viewer: sessions live on the host, keep running when nothing is attached, and reattach instantly from any device on your network. Restarting the service does not kill them either.
AgentDeck has no login of its own. The only gate is an IP allowlist (ALLOW_PREFIXES). Anyone who reaches it from an allowed address can open a root shell on your host — which is to say, do anything.
This is deliberate: the tool exists to hand you a root shell quickly. Treat the network as the security boundary and it is a fine trade. Treat it carelessly and it is a remote-root hole.
# 1) Dependencies
apt update && apt install -y nodejs npm tmux build-essential python3 git
# Node must be >= 18 — the version in older Debian/Ubuntu repos is not.
node -v || true
# If that prints < v18, install a current Node instead, e.g.:
# curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt install -y nodejs
# 2) Get the code
git clone https://github.com/DuarteSantos8/agentdeck.git /opt/agentdeck
cd /opt/agentdeck
# 3) Install (compiles node-pty natively)
npm install --omit=dev
# 4) Configure — at minimum, narrow the allowlist
cp .env.example .env
$EDITOR .env
# 5) Try it
node server.js
# → "AgentDeck on :7700" → http://<host-ip>:7700cp agentdeck.service /etc/systemd/system/agentdeck.service
$EDITOR /etc/systemd/system/agentdeck.service # adjust WorkingDirectory; the .env next to
# server.js is picked up automatically
systemctl daemon-reload
systemctl enable --now agentdeckThe unit runs with KillMode=process on purpose: when you restart the service, only the Node process is replaced. Your tmux agents survive and the fresh process reattaches to them.
Everything is environment variables — see .env.example. A .env file next to server.js is read on start; anything already set in the real environment (Environment= or EnvironmentFile= in the systemd unit) wins over it.
| Variable | Default | What it does |
|---|---|---|
| PORT | 7700 | TCP port of the web server. |
| ALLOW_PREFIXES | all RFC-1918 ranges | Comma-separated IP prefixes allowed to connect, e.g. 192.168.1.,10.8.0.. localhost is always allowed. |
| UPLOAD_DIR | /root/uploads | Root of the file manager. Created on start. |
| DATA_DIR | ./data | Where shared metadata (agent names, colours, folders) is stored. |
| TMUX_SOCKET | agentconsole | tmux socket name (tmux -L <socket>). |
| MAX_UPLOAD_BYTES | 2147483648 (2 GB) | Upload size limit. |
browser ──WebSocket──> node ──PTY──> tmux attach ──> agent-1 (bash, claude, …) xterm.js socket: $TMUX_SOCKET
| Keys | Action |
|---|---|
| Ctrl+Shift+K / ⌘K | Command palette — every session and every action |
| Ctrl+Shift+1…9 | Jump to session 1…9 |
| Esc | Close the palette, a menu or a dialog |
| Drag with the mouse | Select — copied to the clipboard on release |
| Ctrl+Shift+C / Cmd+C | Copy the selection |
| Ctrl+V, right-click, middle-click | Paste (text or image) |
| Ctrl+Shift+V | Native browser paste (works over plain http too) |
| Ctrl+C | Always SIGINT — never hijacked for copying |
Ctrl+K is deliberately left alone: it kills the line in every shell. That is why the palette sits on Ctrl+Shift+K everywhere except macOS, where ⌘K is free.
The title bar gains ⧉ (copy) and ⇪ (paste) buttons, a long press on the terminal opens the paste dialog — camera and gallery included — and a key bar appears above the dock with the keys a software keyboard does not have:
| Key | |
|---|---|
| esc ⇥ ⇧⇥ | Escape, Tab and Shift+Tab — ⇧⇥ is what cycles the permission mode in Claude Code |
| ctrl | Sticky: tap it, then the key it applies to |
| ← ↓ ↑ → | Arrows, with Ctrl held if ctrl is lit |
| ^C ^D | Interrupt and end-of-input |
server.js Entry point — HTTP server + WebSocket, ~15 lines
src/config.js Environment configuration and constants
src/allowlist.js The IP allowlist, as a function and as middleware
src/app.js Express app assembly
src/tmux.js Every tmux call the app makes (list, create, kill, capture)
src/attach.js WebSocket ↔ PTY ↔ "tmux attach", with the keepalive
src/meta-store.js Shared agent metadata, sanitised and written atomically
src/uploads.js Path guards and the streaming upload
src/routes/ sessions.js · meta.js · files.js
public/index.html Shell of the page
public/style.css The whole interface, derived from one accent colour
public/js/main.js Bootstrap: toolbar, polling, global paste, viewport insets
public/js/deck.js Window manager — open, focus, drag, snap, geometry, restore
public/js/terminal.js xterm.js + WebSocket + copy/paste, mouse and touch handling
public/js/taskbar.js Session chips, groups, chip menu, hover preview
public/js/palette.js Command palette: fuzzy search over sessions and actions
public/js/keybar.js The on-screen Esc/Tab/Ctrl/arrow keys for phones
public/js/file-manager.js The file browser
public/js/store.js Agent metadata with server sync
public/js/settings.js Accent colour maths, fonts, effects
public/js/ui.js Ask/confirm sheets and the popover menu
public/js/modal.js One dialog primitive: stacking, focus trap, Escape
public/js/icons.js The inline SVG icon set
public/js/dialogs/ paste.js · copy.js · help.js · settings.js
public/js/{api,bus,clipboard,dom,toast,uploads}.js
Small shared pieces
agentdeck.service systemd unit template
The frontend is plain ES modules loaded straight by the browser — no bundler, no transpiler, no npm run build. Edit a file, reload the page.
Issues and pull requests are welcome — see CONTRIBUTING.md. The project is deliberately small and dependency-light; changes that keep it that way have the easiest path in.
MIT — see LICENSE.
| Back | FazBrowse Home | New Git URL |