18 KiB
Agent Dashboard
The Agent Dashboard is a centralised, agent-native overview of every top-level session you have in flight — your local sessions and forks — grouped by state, with peek, attach, and dispatch from one screen. Subagents are not listed here: they run under their parent session, which already shows when work is in flight.
Opening the dashboard
Three entry points, all opening the same view:
grok dashboard— launches the TUI directly into the dashboard./dashboard(aliases/agents-dashboard,/sessions) — open from inside an active session.- Ctrl+\ — same as the slash command, two keystrokes. Configurable
in
~/.grok/config.tomlunder[keybindings]like every other shortcut.
What you see
Grok Build · Dashboard — 4 agents · 2 awaiting
▌● reviewer · audit token flow Awaiting your input 2m
● implementer · fix login bug Running: cargo test 12m
⋅ refactor · feat/login Responding… 24m
○ housekeeping idle 1h
● implementer · add login tests 8 tools · 1.2k tok 14m
╭─────────────────────────────────────────────────────────────────╮
│ ❯ Dispatch a new agent │
╰─ dispatch ──────────────────────────────────────────────────────╯
↑/↓ select (peek) · Enter open · Ctrl+R rename · Ctrl+T pin · Ctrl+X stop · ? help · Esc new
Each row is a top-level agent (subagents aren't shown — they run under
their parent). Rows are sorted by state (Needs input → Working → Idle →
Inactive → Completed → Failed) so same-state rows sit adjacent, or by
working directory (toggle with Ctrl+G). Inactive holds roster-only
sessions — idle/dormant sessions owned by other pager processes that
haven't been loaded in this one — so Idle stays focused on the
sessions you're actively cycling between. Because it's background noise,
Inactive starts collapsed (expand it with → / click — see below).
To keep the Idle group scannable, only the most recent idle agents
stay visible — the 8 freshest, plus any active within the last hour. The
rest fold into a "N more" row (marked with a + / - toggle) at the
bottom of the group; select it and press Enter / → (or click it) to
reveal them all, and ← to re-fold. The Idle header always shows the true total. Folding is
suspended while a filter or search is active (so every match shows).
The state icon matches Grok Build's sibling views (
tasks_pane):
⋅/:/⸬/⁙— animated spinner for Working rows.●— filled circle for Needs input, Completed, Failed, Blocked. Colour communicates the state (yellow / green / red / amber).○— hollow circle for Idle and Inactive rows.
A row stays in Working while it has live background work even if its
turn has finished — a running background task, a monitor, or an active
scheduled /loop. The activity line says what's running (e.g.
watching · 1 monitor · 2 loops), since each can wake the agent for a
new turn.
There are no inline group headers — the sort order keeps same-state rows adjacent and the per-row dot+colour communicates which group each row belongs to (matching other session lists).
The dispatch input shares the same PromptWidget chrome as the
agent view's prompt (rounded box, ❯ prefix, accent border, info
line). Pressing Ctrl+/ flips it into search mode: the ❯
prefix becomes a yellow Search: and whatever you type live-filters
the row list instead of being dispatched.
Keybindings
| Key | Action |
|---|---|
↑ / ↓, j / k |
Navigate rows AND section titles (selecting a row opens its peek panel) |
→ / ← (on a section title) |
Expand / collapse the section (shows / hides its rows); l / h in vim mode |
Enter (on a section title) |
Toggle the section collapsed / expanded |
Enter (empty reply) |
Open the selected agent's conversation full-screen (details view) |
Ctrl+S |
Send the peek reply AND open the agent (or dispatch + attach a new session) |
Shift+Enter / Alt+Enter |
Insert a newline in the reply / dispatch input (multiline compose) |
1–9 |
Answer a pending permission / ask question (when the peek shows options) |
Enter (typed reply) |
Send / queue the reply to the selected agent |
/ |
Types a literal / into the prompt |
Ctrl+/ |
Toggle search mode (live-filter the rows) |
Ctrl+R |
Rename selected row |
Ctrl+T |
Pin / unpin |
Ctrl+G |
Toggle grouping (state ↔ directory) |
Ctrl+X |
Stop / kill (two presses within 2s to close a session) |
Shift+↑ / Shift+↓ |
Reorder pinned rows |
Esc |
Step back one level: cancel search → close peek (clear reply draft, then unselect) → clear filter → unfocus the dispatch input (so ↑/↓, j/k navigate the list) → unselect row (→ [+ New Agent]) → exit dashboard. Esc never clears your typed dispatch draft — use Ctrl+U / Ctrl+C for that |
Ctrl+\ |
Return to the dashboard from the details view, or exit dashboard |
Ctrl+. (alt: ?) |
Open the keyboard shortcuts cheatsheet. Footer advertises ? when Ctrl+. cannot be delivered. Bare ? opens help when list-focused or the draft is empty (otherwise types); Ctrl+X remains stop |
When grouping by state, each group has a section title (e.g. Working,
Idle) with a ▸/▾ disclosure marker. Section titles are part of the
up/down navigation: select one and press → to expand it (showing its rows)
or ← to collapse it — l / h do the same when vim mode is on.
Clicking a section title toggles it, and hovering
brightens its text. Collapse state is remembered while the dashboard stays open.
The Inactive section starts collapsed by default each time the pager
starts; expanding it sticks until you quit.
Opening a row shows the agent's conversation in the details view:
a single top header row (the agent name on the left, {i}/{n} [‹][›] [Dashboard] cycle/close affordances on the right) sits above the conversation,
which renders full-width — no bordered modal frame — so the prompt
position and overall padding match the dashboard list view. All key
presses route to the attached agent; Esc / Ctrl+\\ (or the [Dashboard]
affordance) return to the dashboard, the [‹] / [›] chips cycle to
the previous / next agent, and the agent's shortcuts bar shows a
Ctrl+\\: back to dashboard hint. Quick gotcha — Esc only returns to
the dashboard; typing /exit inside the agent actually closes the
underlying session (returning to the dashboard with a "Session closed"
toast).
Ctrl+X in the details view is state-dependent. While a turn is
running it cancels the turn — the same behaviour as Ctrl+C,
including the keep-subagents prompt — and never touches the session
itself, so mashing it to stop a turn can't close anything. In any
other state — idle, a slash command in flight (commands can't
be cancelled yet), or a cancel still pending — Ctrl+X arms a
confirmation: the shortcuts bar flips to "press Ctrl+x again to
close this session", and a second press within 2 seconds closes the
session and returns you to the dashboard. Pressing any other key
cancels the confirmation, and a turn that starts inside the window
downgrades the confirmed press to a cancel instead of closing.
(On terminals where Ctrl+X doubles as the shortcuts-cheatsheet
binding, the cheatsheet stays reachable via Ctrl+. inside the
details view.)
For the full behavioural specification (including the registry-lookup rules and the mouse-event intercept matrix) see plan §3.10 "Keybindings (v1)" — the user guide here is intentionally short and cross-references the plan as the source of truth.
All shortcuts are registered under When::DashboardFocused and can be
rebound via ~/.grok/config.toml.
Dispatch input
The bottom textarea always spawns a NEW session — it is never a
reply target. A selected row is the overview's navigation cursor, not a
reply destination; to talk to an existing agent, open it (navigate +
Enter, or click) and reply inside its own view.
Enter handler:
- Free text → creates a new top-level session, seeded with the prompt.
Text is never reinterpreted as a filter — a prompt may start with
/,s:,a:, or#and still dispatches verbatim (filtering is the explicitCtrl+/search mode). A leading/runs a pager-global slash command. - Empty input → opens the selected row (
Attach), or creates a new agent when the[+ New Agent]button is focused.
Press Ctrl+S after typing a prompt to dispatch AND attach
(jump into the new session); plain Enter stays on the dashboard so
you can dispatch several sessions in a row. Shift+Enter / Alt+Enter
insert a newline for a multi-line prompt — the box grows in height
as you add lines (up to a cap, after which it scrolls), so the whole
draft stays visible.
The dispatch input accepts any non-empty prompt; an empty / whitespace-only prompt is ignored. Prompts above 64 KiB are rejected with a toast.
Focus: input bar ↔ overview list (Tab)
The dashboard has two focus areas — the dispatch input bar (typing)
and the overview list (navigating). Tab toggles between them; the
inactive input dims its border and hides its caret.
On open, focus defaults to the overview list when at least one agent
exists (so ↑/↓ / vim j/k navigate immediately). With no
agents, focus stays on the dispatch input so you can type a first
prompt right away. Either way, the [+ New Agent] button is the cursor
target (no agent row is pre-selected).
- Input focused: type to compose a new-session prompt.
↑/↓navigate the row list when the prompt is empty (a convenience), otherwise move the caret.Escunfocuses the input → overview list (your typed draft is kept) so you can navigate straight away. - Overview focused:
↑/↓— and, in vim mode,j/k— move between agent rows.Enteropens the highlighted agent (on[+ New Agent], it sends a typed draft, else creates a new session).Escstays on the list and steps back — clearing an active filter, then unselecting the row (→[+ New Agent]), then exiting the dashboard.Tabori(vim) — or any other printable key — return to the input.
Peek panel
The peek panel is shown by default whenever an agent row is
selected — it replaces the new-session dispatch box. With no row
selected (the [+ New Agent] button focused, or after Esc), the
dispatch box returns for starting a new session. So selecting a row is
how you talk to an existing agent; deselecting is how you start a new
one.
The panel shows, top to bottom, a header (the last response type —
Thinking / Thought / Response / Edit / Read / Bash / … — on
the left, time on the far right), the most recent response
(word-wrapped to fit, up to ~3 rows), and a live ❯ reply input. A
… marker appears on the last row only when there's more than fits.
The selected agent's model and, when it's in always-approve (yolo)
mode, an always-approve flag are shown on the panel's bottom
border (bottom-right) — the same config-badge slot the new-session
dispatch box uses. This holds in the question / approval modes too, so
the model and approval mode are always in view while you answer. (The
dashboard list rows no longer repeat the model or an always-approve badge,
keeping the list compact.)
Shift+Tab cycles the peeked agent's mode (Normal → Plan →
Always-approve → Normal) — the same cycle as Shift+Tab inside that agent's
chat view, applied to the live agent (the badge updates to match).
This differs from the new-session dispatch box, where Shift+Tab only
stages the mode for the next agent.
Unlike the dispatch box (which only ever spawns new sessions), the peek's reply talks to the selected agent:
- Type into
❯ reply, thenEnterto send. An idle agent starts the turn immediately; a busy agent queues the message so it sends after the current turn finishes (the same queue/drain behaviour as the agent view's own prompt).Ctrl+Sreplies AND opens the agent's detail view;Shift+Enter/Alt+Enterinsert a newline (multiline compose) and the reply grows in height to fit the draft (up to a cap, then it scrolls). - With an empty reply,
Enteropens the agent. ↑/↓move the caret within the reply once it has content (so you can edit a multi-line draft). While the reply is empty (or unfocused viaTab),↑/↓instead switch the selected agent — the panel follows the selection cursor and refreshes live, and the switch clears any half-typed draft so a reply can't land on the wrong agent. (Tabto the row list to navigate agents while a draft is in the reply.)Escunselects: it first clears a typed reply, then deselects the row and focuses the[+ New Agent]button (bringing back the new-session input).Tabtoggles focus between the reply input and the row list: an unfocused reply dims its border and hides the caret; a printable key re-focuses it and starts composing.- The reply is a full prompt editor (the same component as the
dispatch box and the agent prompt): pasting multi-line text folds
into a
[Pasted: N lines]chip with the same preview overlay and expand affordances as the agent prompt (Enter/ double-click / paste-again), mouse click / drag place the caret and select text, and the usual editing chords work (word navigation,Ctrl+A/Ctrl+E,Alt+Backspace,Ctrl+W/Ctrl+U/Ctrl+K, undo, Shift+arrow selection,Ctrl+Shift+Vinline paste). Typing@opens the file-context picker rooted at the peeked agent's working directory (so@pathresolves against the agent you're replying to); its dropdown floats above the panel and↑/↓/Tab/Enter/Escdrive it while it's open. Dashboard chords (Ctrl+Xstop,Ctrl+Tpin,Shift+↑/↓reorder, …) still win over the editor while the panel is open. - When a permission / ask-tool question is pending, the
❯ replyrow is hidden and the options are listed instead:↑/↓move the highlighted option (marked with▸) andEnteranswers it.1–9still answer an option directly. (While answering, the arrows pick options rather than switching agents.) - The free-text row accepts an inline typed answer (just like the
chat panel): the permission "No" / reject option ("No, reject
(type to add feedback)") and the ask-tool "Other" row ("Other
(type your own answer)"). Type on it and
Entersends the rejection + message / the free-text answer. - This also covers the agent's Ask tool (
AskUserQuestion): its options + the "Other" row show in the peek, answered the same way. Multi-question forms are walked one question at a time — a(i/N)marker shows progress and each answer advances to the next, submitting on the last. (Forms with a multi-select question are left to the agent's own view — open the agent to answer those.)
The panel only renders when the terminal is tall enough; on very short terminals the dispatch box shows even with a row selected.
Search / filter (Ctrl+/)
Filtering lives behind an explicit search mode so normal typing
always dispatches. Press Ctrl+/ to toggle it: the prompt prefix
flips from ❯ to a yellow Search: and every keystroke live-filters
the row list.
Inside search mode:
Enter— confirm: keep the filter applied and return to the dispatch prompt (rows stay filtered;Esclater clears them).EscorCtrl+/— cancel: clear the filter and exit search.↑/↓— navigate the filtered rows.
The query supports the same prefixes as before (they are only honoured inside search mode now):
a:<name>— filter by agent label (case-insensitive substring, matches persona / role).s:<state>— filter by row state. Acceptsworking,idle,completed,failed,needs-input,blockedand synonyms (busy/running/done/etc.).#<text>— substring match on#<text>(matches the literal#in labels; reserved for future PR filtering).- anything else — plain substring match over label + working dir.
Persistence
Per-user dashboard preferences live under [dashboard] in
~/.grok/config.toml:
[dashboard]
enabled = true
grouping = "state" # or "directory"
pinned = ["top:<session_id>", "sub:<parent_session_id>:<child_session_id>"]
reorder = ["top:<session_id>"]
Pinned/reorder entries are keyed by session id, not by the
per-process AgentId(usize), so they survive restarts and don't
attach to whatever agent happens to share the old slot number.
Set GROK_AGENT_DASHBOARD=0 to force-disable the feature for a single
pager invocation; the slash command and CLI subcommand will print a
friendly toast.
Phase 4 (out of scope for v1)
The current dashboard lists only agents owned by this pager
process. The plan's Phase 4 ("supervisor / grok --bg") would list
sessions that survive pager exit — that's a separate roadmap and not
shipped yet.