Tower dashboard
A tower session with a TUI shows a monitoring widget above its editor. It is read-only: it never takes focus, never prompts, and is shown only while the session holds the tower role (a tower that yields, a headless tower, and main agents never show it). Its first lines say what the pane is, the channel main agents reach each other through with call_tower, and give the straw net GUI’s link while a GUI server answers (otherwise that /boss gui opens it).
╭─ ? Alpha ─────────────────────────────────────────────────────────────╮│ Control tower: main agents talk here (call_tower). ││ GUI http://127.0.0.1:52662/<token>/ ││ ││ this net ││ ├─ tab api-main ││ │ ├─ ○ api-main main ││ │ │ └─ ⠸ [sub] psb-sleeper subagent bash ││ │ └─ ○ docs-member member ││ └─ tab other ││ └─ ? ops-main main waiting on a question ││ other towers ││ ✓ Beta tower │╰──────────────────────────────────────────────────────────────────────────╯Details
-
This net, in detail: the sessions that joined in this workspace, by tab (main agent first, then members), each with the subagents it launched, and this workspace’s sub workspaces. Sessions that did not join are not listed, and neither is anything in other workspaces.
-
Other towers: the head tower first when it exists (
head tower, with its state), then one line per workspace that has a live tower (workspace and status). No workspace tower carries the head tag. -
Each row carries the role mark Herdr’s sidebar shows (see Sidebar net view), in Nerd Font glyphs one column wide: the radio tower (U+F043B) for a tower and in the title, the glyph of its kind for a main agent or a launched subagent that has one (see
sb_markbelow), Font Awesome’s star (U+F005) for a main with no known kind, person (U+F007) for a member, and[sub]for a subagent with none. A tab and a sub workspace have none. Their colors are pi theme roles, so they follow the active theme: the towerwarning, a main kind’s glyph (and the star)accent, the personsuccess, all bold, and a subagent kind’s glyph and[sub]dim. The kind column keeps the role’s word. -
One glyph and theme color per state: a spinner in the accent color for working,
?warning for waiting on a question,◈in the bold title color for commanding (an idle session whose subagent works or waits),○dim for idle,✓success for done,✗error. Colors come from the active pi theme. The title mark shows the most urgent state of the net. -
The spinner runs at 1 fps, and only while something is working and the tower’s tab is on screen (the active tab of Herdr’s focused workspace): every frame redraws the tower’s whole TUI, and at 8 fps each idle tower burned 5–13% CPU for as long as anything in the net worked. The data is re-read when Herdr reports a change: the dashboard subscribes to Herdr’s
pane.*(created, closed, updated, moved, exited, agent detected),tab.*(created, closed, renamed, moved, focused) andworkspace.*(created, updated, metadata updated, renamed, moved, reordered, closed, focused) events, and a burst of them is one read 0.5 s after the first. An intercom presence, join, or leave event re-reads at once.No two reads are closer than 0.5 s, and a request that comes inside that gap, or while a read runs, is read when it ends instead of being dropped. A poll every 30 s is the safety net: it catches an event that was missed, and what no event tells (a subagent’s activity file, which holds the tool it is running), and a reconnection of the event stream re-reads after the same 0.5 s, so a missed event never leaves the screen wrong for longer than that. Shutdown, or losing the tower role, removes the widget, the subscription and every timer.
Where the data comes from: pi-intercom listSessions() (status idle, thinking, tool:<name>, and the Herdr location of each session), Herdr’s pane list (sb_role token, Herdr’s agent status where blocked means waiting on a question, and the pi session file) and workspace list (workspace status, tower token, linked-worktree fields), which one session.snapshot request answers together (the snapshot’s panes and workspaces are what herdr pane list and herdr workspace list print). Subagents are linked to their parent through pi-herdr-agents’ own layout: the parent’s session file names its artifacts directory, subagent-activity/<child id>.json there records each child’s activity, and the child’s pane session file contains the child id.
So a subagent is grouped under the session that launched it wherever it runs, and it never counts as a net member of the workspace or tab it sits in. The pane of each child is found by one pass over the panes (their session file names are indexed by child id), the two directories are listed again only when their timestamp changes (a directory changed in the last two seconds is always listed), and a launch script is read again only when it changes.
How Herdr is read
Section titled “How Herdr is read”The listings (pane list, workspace list, tab list --workspace) are requests on Herdr’s socket (pane.list, workspace.list, tab.list), not spawned herdr commands; the reply is the same as the CLI’s, so every reader is the same. Every write (report-metadata, tab create, agent start, closing, and the rest) still runs the CLI. A listing that fails rejects with Herdr’s own error, and nothing falls back to the CLI. A request that only reads (the listings, pane.current, pane.get, pane.read, pane.process_info, pane.layout, session.snapshot) and times out or whose connection closes before an answer is asked once more after 250 ms; a request that changes something is sent once. The dashboard and the browser view read the panes and workspaces together from one session.snapshot. The browser view’s poll (every 2 s while a page listens) stays a poll: its net also holds what only the session files and intercom know (what a unit waits on, its queue, its dialogs), which no Herdr event tells.