Files
Kigi-CLI/crates/codegen/kigi-tui/docs/user-guide/23-dashboard.md
T
ZacharyZhang-NY 6f31415ed6 §9 acceptance: grep-zero sweep — every internal x.ai/grok identifier renamed
The PRD's first acceptance gate now holds: grep -RinE '\bx\.ai\b|grok'
crates/ --include='*.rs' → 0 matches (exempt: NOTICE and third-party
license archives, README provenance, and the required 'Based on Grok
Build Open Source' attribution, now sourced from version_attribution.txt).

Wire-visible renames (both sides in this repo, changed in lockstep):
- Auth method id 'grok.com' → 'kimi-code' (AuthMethodKind::KimiCode).
- Every x.ai/* and _x.ai/* ACP ext method and meta key → kigi/* /
  _kigi/* (~200 names; grokShell → kigiShell). Session-file replay keeps
  a read-side alias for the legacy '_x.ai/session/update' method so
  existing updates.jsonl histories load; writes emit only the new name
  (both directions test-pinned).
- Agent types grok-build* → kigi* with a documented legacy-prefix alias
  at resolution time so persisted sessions keep resolving.
- ToolNamespace/BuiltinAgentName GrokBuild* → Kigi* (wire snake_case
  kigi/kigi_concise/kigi_hashline; schema regenerated); grok_build
  implementation dirs renamed to kigi*.
- x-grok-* headers → x-kigi-*, __GROK_* sentinels → __KIGI_*, themes
  grokday/groknight → kigiday/kiginight (old persisted values fall back
  to the default theme), web_fetch allowlist xAI hosts → kimi.com +
  moonshot platforms, changelog CDN → this repo, grok-build changelog
  archives deleted.
- BYOK default endpoint removed: [endpoints] api_base_url is now truly
  optional with NO default — consumers fail fast with the flag name when
  unset (no silent x.ai egress). Mock harnesses inject it explicitly.
- System-prompt identity fixed: 'released by xAI' → 'an unofficial
  community CLI for Kimi' (template + regenerated encrypted form).

Also repaired pre-existing grok-era test debt found by the sweep: the
stale trace_classify default-model pin, the grok-pager UA label test,
pty-harness stale-binary reuse and non-hermetic moonshot routing (a PTY
test could previously reach the real api.moonshot.cn), and the outdated
oauth fixture scope key.

Gates: §9 grep 0; fmt clean; workspace check/clippy 0/0 (-D warnings);
FULL cargo test --workspace: 234 suites, 21,961 passed, 0 failed;
deny advisories ok.
2026-07-18 02:48:46 -04:00

17 KiB
Raw Blame History

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:

  • kigi 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 ~/.kigi/config.toml under [keybindings] like every other shortcut.

What you see

 Kigi · 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 Kigi'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 ~/.kigi/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 explicit Ctrl+/ 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. Esc unfocuses 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. Enter opens the highlighted agent (on [+ New Agent], it sends a typed draft, else creates a new session). Esc stays on the list and steps back — clearing an active filter, then unselecting the row (→ [+ New Agent]), then exiting the dashboard. Tab or i (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, then Enter to 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+S replies AND opens the agent's detail view; Shift+Enter / Alt+Enter insert 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, Enter opens 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 via Tab), ↑/↓ 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. (Tab to the row list to navigate agents while a draft is in the reply.)
  • Esc unselects: it first clears a typed reply, then deselects the row and focuses the [+ New Agent] button (bringing back the new-session input).
  • Tab toggles 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+V inline paste). Typing @ opens the file-context picker rooted at the peeked agent's working directory (so @path resolves against the agent you're replying to); its dropdown floats above the panel and ↑/↓/Tab/Enter/Esc drive it while it's open. Dashboard chords (Ctrl+X stop, Ctrl+T pin, Shift+↑/↓ reorder, …) still win over the editor while the panel is open.
  • When a permission / ask-tool question is pending, the ❯ reply row is hidden and the options are listed instead: ↑/↓ move the highlighted option (marked with ▸) and Enter answers it. 1–9 still 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 Enter sends 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; Esc later clears them).
  • Esc or Ctrl+/ — 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. Accepts working, idle, completed, failed, needs-input, blocked and 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 ~/.kigi/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 KIGI_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 / kigi --bg") would list sessions that survive pager exit — that's a separate roadmap and not shipped yet.