diff --git a/CLAUDE.md b/CLAUDE.md index 200996b..bba3919 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -138,6 +138,9 @@ read them à la carte. - **"What does the dashboard look like?"** → [`docs/web-ui.md`](docs/web-ui.md). +- **"How does the per-agent terminal classify + colour + events?"** → [`docs/terminal-rendering.md`](docs/terminal-rendering.md) + (taxonomy + known inconsistencies + a proposed coherence pass). - **"How does claude get its prompt and what tools does it have?"** → [`docs/turn-loop.md`](docs/turn-loop.md). - **"How do config changes flow from manager to operator to diff --git a/docs/terminal-rendering.md b/docs/terminal-rendering.md new file mode 100644 index 0000000..77d124c --- /dev/null +++ b/docs/terminal-rendering.md @@ -0,0 +1,104 @@ +# Per-agent terminal: row taxonomy + inconsistencies + +Snapshot of how the per-agent web UI's live pane renders each +event kind today, written up so the next coherence pass has a +reference to work from. Source of truth lives in +`hive-ag3nt/assets/app.js` (`renderStream`, +`fmtToolUse`, `renderRichToolUse`, `renderToolResult`, +`renderTaskEvent`) + `hive-fr0nt/assets/terminal.css` (the +shared `.live .` styling). + +## Row taxonomy + +| CSS class | Prefix glyph | Color | Triggered by | Source | +|---|---|---|---|---| +| `.turn-start` | `◆ TURN ← ` | amber, bold, top-margin, amber left rule | `LiveEvent::TurnStart` | harness wake | +| `.turn-body` | (inline under turn-start) | fg dimmed 85% | same | the wake-prompt body | +| `.turn-end-ok` | `✓ turn ok` | green, green left rule | `LiveEvent::TurnEnd { ok: true }` | harness | +| `.turn-end-fail` | `✗ turn fail — note` | red, red left rule | `LiveEvent::TurnEnd { ok: false }` | harness | +| `.text` | none | fg/white, indented | claude `assistant.content[].text` | stream-json | +| `.thinking` | `·` or `· thinking …` | muted, italic | claude `assistant.content[].thinking` | stream-json | +| `.tool-use` | `→ Name args…` | cyan | `assistant.content[].tool_use` | stream-json | +| `.tool-use` `
` | `→ Name path · +N` | cyan, body is diff | rich tool_use (Write/Edit) | renderRichToolUse | +| `.tool-use` `
` | `→ send → to · headline` | cyan, body is text | mcp__hyperhive__send | renderRichToolUse | +| `.tool-result` | `← ` | muted | short `user.content[].tool_result` (≤120c) | stream-json | +| `.tool-result-block` `
` | `▸ ← Nl · headline` | muted, body is text | long `tool_result` (>120c) | stream-json | +| `.tool-use` | `⌁ task started · [type]` | cyan | claude Task-tool subagent event | renderTaskEvent | +| `.turn-end-ok` / `.turn-end-fail` / `.tool-result` | `⌁ task ✓/✗/◌ · · → ` | green / red / muted | claude Task-tool result | renderTaskEvent | +| `.note` | `· ` | muted | `LiveEvent::Note` (harness chatter, /cancel /compact /new-session, stderr lines, etc.) | harness | +| **`.sys`** | `· {json…}` | **muted** | **anything `renderStream` doesn't recognise** | catch-all | +| `.result` | (defined, never emitted today) | green | — | — | +| Banner shimmer | mauve | turn in flight (ref-counted) | `setBannerActive` | + +## Where the inconsistencies live + +1. **Glyph vocabulary drifts**: + - tool_use uses `→` + - tool_result uses `←` + - thinking uses `·` + - notes use `·` + - turn-end ok/fail use `✓ / ✗` + - turn-start uses `◆` + - task events use `⌁` + - The `·` glyph is overloaded across thinking, notes, sys. + +2. **What gets a `
` block vs a flat row** is per-tool + ad-hoc: Write/Edit always expand, send always expands, every + other tool_use is flat regardless of input size. + `tool_result` is flat if ≤120 chars otherwise `
`. + +3. **Stderr handling**: claude's stderr lines come through as + `LiveEvent::Note` with `text: "stderr: "` — they + render as muted `· stderr: …`, identical styling to harness + notes about /compact / /model. No red-tinted "this is an + error" affordance for stderr. + +4. **Catch-all `.sys` rows** are visually identical to `.note` + rows — both muted, both `·` prefix. They look like normal + notes despite usually being "an event renderStream couldn't + classify". Unmatched stream shapes (rate limit warnings under + odd type/subtype combos, future claude additions, etc.) + silently fall through. + +5. **`.tool-use` ranges from one-liner (`Read foo.md`) to + multi-page collapsed diff** — same color, same prefix glyph, + very different visual weight. A small marker on the collapsed + `
` summary would help (the `▸` is present in + `.tool-result-block` summaries but absent in tool-use + `
` summaries). + +6. **Cancel/compact/new-session notes** are styled the same as + autonomous harness chatter; nothing flags them as "operator + initiated." + +## Suggested coherence pass + +Pick one scheme and audit all renderers to match. A concrete +proposal: + +- **`→` cyan**: outbound action (tool_use, send) +- **`←` muted**: inbound result (tool_result) +- **`◆` amber**: turn framing (turn_start) +- **`✓ / ✗`**: success / failure, green / red (turn_end, + task_notification) +- **`⌁` mauve**: subagent / background event (task_*) +- **`·` muted**: ambient note, italic for thinking +- **`!` orange**: caught error (stderr lines, .sys catch-all + that landed something the renderer didn't recognise) + +Plus: every tool_use `
` summary gets `▸` so collapsed +content is visually announced. Operator-initiated notes get a +distinct prefix (`op·` or similar) so they're easier to spot in +the scrollback. + +The `.sys` catch-all should escalate visually — a louder +"unrecognised event" rendering surfaces silently-dropped event +shapes for future fix-up rather than hiding them in the muted +note stream. + +## Dashboard side (not covered here) + +The main dashboard's message-flow pane is a different beast: +broker messages render as `.msgrow` grid lines (ts / arrow / +from / → / to / body) with separate styling. The current file +focuses only on the per-agent terminal.