A member's tmux server keeps the version it started with until their last
pane closes, but the dashboard asked it with TMUX_BIN, the newest tmux: a
3.8 client on a 3.6 server spun it at 100% CPU (three members needed a
manual kill on 2026-10-15).
- /opt/agenthub/libexec/tmux-member (install-system, in sudoers): runs a
member's tmux call with the binary of THEIR running server
(/proc/<pid>/exe, found from the socket in /proc/net/unix), else
TMUX_BIN. It runs as the member and execs only a process they own.
sudoArgv uses it once installed (linux-accounts readConf), TMUX_BIN
until then.
- Users → Members' tmux (GET /api/users/tmux): each member server's version
beside the installed one, sessions, agents working. An admin restarts one
(POST /api/users/:id/tmux-restart) or every idle outdated one
(POST /api/users/tmux-restart-idle), with their password again, audited
per member; a server that will not stop answers 409 ETMUXSTUCK naming
its pid for root.
- server-s3-system.test.js: `delete` is a provision action since Delete
user, so the "unknown action" case now uses `purge`.
Operators: run `sudo agenthub server install-system` once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Artifacts (/artifacts): claude.ai pages sessions publish (captured from the
Artifact tool's hook), pinned workspace files, skills and plugins, each
kept as a snapshot; shared ones appear in a Hub and a skill or plugin
installs into the viewer's own account (server/lib/artifacts.js,
/api/artifacts, docs/plans/artifacts/).
- Workspace extra folders: clone one or more related repos beside the
workspace and add them in one step (POST /api/lanes/:id/sources/clone).
- A pane that ended by itself while tmux kept running is no longer offered
for resume (tmux.serverStartedAt in reconcileOrphans).
- Changes panel: a folder that is not a git repo opens on Files, and its
files open from there.
- Plus the parallel sessions' work in this tree: File Explorer button in the
panel header, user delete, RSA SSH keys, chat/terminal and pet fixes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- File Explorer (Files in the sidebar, /files; also from a workspace's Files
tab, portalled so no panel clips it), laid out like GNOME Files: places
(Home, workspaces, Trash), Back/Forward/Up, path bar, search, icon grid with
image thumbnails or list, labelled New/Upload, selection action bar, hidden
files behind Ctrl+H, right-click menus and the usual keys.
Make, rename, move, copy (within a workspace, between workspaces, home ↔
workspace), delete into a per-account trash restorable for 7 days, streamed
upload of files and whole folders (≤ 500 MB a batch, Replace / Keep both /
Skip on a taken name), download a file or a zip of anything.
server/lib/file-explorer.js, /api/lanes/:id/fs/*, /api/homes/:who/fs/*.
- The user's home: every dot entry at its top stays hidden and refused
(also via a symlink, download, zip or as a copy source); an admin may view
other users' homes read-only, audited.
- write-as learns move/copy (re-run `sudo agenthub server install-system`).
- Hardening: a write to a workspace re-checks its owner by the live role;
S3 keeps its server.conf if the file stops reading and a tmux call never
falls back to the host's server; the AI Proxy gateway marks what it relays
and the dashboard refuses it; a NUL in a pane's argv/env is refused.
- OpenAPI for the new routes (server/openapi-extra/files.js); docs (API,
SERVER-MODE, CLAUDE.md) updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
UI
- No animation runs forever: Sagi moods, the custom pet sprite, status dots
(pulse-dot, pulse-slow, ping) and the chat shimmer play a few cycles and
rest. An infinite animation kept the browser drawing 60 frames a second.
- useSagiBrain: frames that only move lastActivityAt by <1 s keep the old
state; the 1 s tick re-renders only when the mood changes.
- ConversationView and MessageList are memoized and PaneChat passes stable
callbacks: typing in the chat box no longer re-renders the conversation.
- The chat's 700 ms menu poll reads plain text first and scans the terminal
cell by cell (reusing one cell) only when a row could be a menu cursor row.
Server
- GET /sessions/:id/transcript?after=N skips lines <= N before JSON.parse.
- GET /sessions/:id/outline is cached until the session's events change.
- broadcastLane uses the cached tmux.liveSessions(); tmux.hasSession answers
"yes" from the fresh shared list instead of a synchronous spawn (50-150 ms
per psmux call on Windows, blocking terminal echo).
- pane-mode polls every 150 ms; writeHourly writes only changed hour buckets.
- /api/metrics: agenthub_event_loop_delay_seconds{quantile}.
Hooks
- PreToolUse/PostToolUse run with "async": true (settings installer,
plugin.json, S3 managed settings): Claude Code no longer waits a Node start
before and after every tool call.
Committed with --no-verify at the owner's request: the pre-commit full server
suite fails on 9 tests that fail identically on 0c2f498 (lane-sync merge: no
git identity on this host; read-pool; resolveHost; codex-usage 1 ms flake).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Users page: one Edit user form (display name, email, role, active, a new or
generated password, workspaces given or taken back, sign out everywhere),
validated as a whole before anything is written (PATCH /api/users/:id,
GET /api/users/:id); users.display_name/email added migration-safe.
- Settings → Account for every signed-in user: profile, own password (the
current one required, this login kept), sign out other devices
(/api/me/account, /api/me/password, /api/me/sign-out-others; login cookie
only, never a pane token).
- Display names wherever a person is named (sidebar, workspace owner groups,
Users page and audit log); owner_display_name / reader_display additive.
- Users page: admins add and remove Claude/Codex pool accounts.
- Folder browser: an admin with their own Linux account opens in their home;
the "Server folder" tick opens the host's (never remembered).
- AI Proxy: "Config 9router" beside Add profile when 9router is installed,
opened on the dashboard's own host (GET /api/ai-proxies/9router).
- Terminal: a tmux selection reaches the clipboard over plain HTTP too
(writeClipboard's textarea fallback, focus handed back).
- Chat: a file the session touched outside the workspace previews
(GET /api/sessions/:id/file).
- install-system: `!requiretty` only when visudo accepts it (sudo-rs on
Ubuntu 25.10+ rejects the setting).
- openapi.yaml regenerated; docs (API, SERVER-MODE, LANES) updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Server mode can now run each account as its own Linux user (ah-<name>)
when `agenthub server install-system` has set S3 up. The dashboard
reaches a member only through sudo -u / write-as / pane-launch, reads a
member's files only through owner- and type-checked opens, and hooks
are authenticated by peer uid. Local mode and server mode without S3
are unchanged.
EXPERIMENTAL: tested with fake sudo and fake accounts only. It has not
yet been verified on a real install with real member accounts, sudo or
a real Codex login. Do not offer it to real users yet.
- S3 core: provisioning, per-member tmux servers, the proxy key
gateway, shared tools in /opt, dropped capabilities for children
(P0–P5)
- P4: plan and quota per member home
- P6: ~/.claude.json seed; opt-in plugin baseline installed as the
member; managed-settings spike script (not run)
- P7: Codex account pool (`agenthub accounts add --tool codex`)
- Roles merged with main's admin / analyst / developer: analysts write
only their own rows, under S3 as well
- Per-account prefs: one implementation (Chat UI + onboarding)
- Security reviews F1–F49 (five rounds), each fix with a regression
test: symlink/TOCTOU-safe member reads, no host writes in a member
home, credentials and the data dir never served, owner and folder
account must agree, pane tokens bound to the pane's uid, bounded
sudo/tmux/git calls and member reads (no hang or crash from a member),
async route rejections answer 500 instead of exiting
- Docs: docs/SERVER-MODE.md (S3 model, accepted ceilings, operator
runbook), docs/plans/server-mode/S3-PLAN.md, CLAUDE.md S3 rules
Tests: server 2838/2841 (3 need 127.0.0.1:3000, held on this box);
client 1162/1162; tsc clean; headers check passes.
Co-Authored-By: Claude <noreply@anthropic.com>