3.8 KiB
SIDEBAR.md — the session card contract
One rule for how a session is rendered as a card in the sidebar, so the web sidebar (#107) and the TUI sidebar (#108) describe a session the same way. Read this before changing either. Both clients implement exactly what is written here; if it needs to change, change it here first.
A card has line 1 always and line 2 only when line 2 has something to say.
Line 1 — name + actions
- Left: the session name —
metadata.nameif present, else the command line (same fallback both clients already use). - Right: two actions anchored to the top-right corner: spawn similar
(
⧉) and kill (✕). In the TUI these are keyboard affordances shown on the highlighted row; in the web they are buttons. The glyphs are shared so muscle memory transfers. - Actions reserve their fixed width; the name truncates with
…before it can ever reach them. Overlap between the name and the actions is a defect — that overlap is what started this milestone.
Line 1 carries no badges. The ⚠ blocked work badge (#83) and the exited
badge move off this row into line 2.
Line 2 — meta line (adaptive)
Rendered only when at least one of these holds:
- The session has been held in its current activity state longer than
30 seconds (
activity_sincefrom #102). A freshly-active session stays one line. - Its worktree holds blocked work:
blocked_workisSomeand not clear (InTheWay::is_clear()), rendered informatInTheWay's phrasing on web and as⚠ <summary>on the TUI. - It has exited:
status == Dead. - An agent-reported state (#105) of
Erroris in force (see Precedence).
Otherwise line 2 is absent — never an empty placeholder row.
When present, line 2 reads left to right:
<duration> [<state badge>] [<blocked work> | exited]
Colour per activity state
The state word is never spelled out — the colour carries it.
| Activity state | Web token | ratatui colour |
|---|---|---|
Active |
--live |
Color::Green |
Idle |
--muted |
Color::DarkGray |
AwaitingInput |
--warn |
Color::Yellow |
Error |
--danger |
Color::Red |
Web tokens resolve per theme automatically (styles.css defines dark, light,
and prefers-color-scheme variants for each). The TUI uses the plain ratatui
named colours above; do not introduce RGB values or a new palette module for
this.
The duration text inherits its state's colour; the blocked-work and exited
fragments use the muted colour (--faint / default style), since the ⚠ glyph
already signals severity.
Duration format
Time spent in the current activity state, sourced from activity_since
(#102) — not time since spawn, and not time since last PTY output
(last_activity_at). Both clients compute it identically:
< 60s→ whole seconds, floored:30s< 60m→ whole minutes, floored:4m≥ 60m→ whole hours, floored:2h
No days unit, no seconds inside minutes, no rounding up. Floor everywhere so the counter never shows a duration the state hasn't actually reached yet. Clock granularity: re-render at least once every 30s while visible so the cutover points land within one tick.
Precedence
An agent-reported ActivityState (#105) overrides the daemon's inference for
the TTL the report carries; when the TTL expires, inference resumes. Clients
never blend the two: whichever source is in force supplies both the colour and
the clock for activity_since.
If a client receives an ActivityState variant it does not know, it must not
fail rendering: treat it as Idle (neutral/dim, line-2 rules apply as usual)
until the daemon sends a variant it does know. Rust clients deserialize
activity leniently for the same reason.