Skip to content

THI-463: Rail: a sonar strip and a Next queue in the agent's words (design A) - #59

Merged
tdody merged 26 commits into
mainfrom
thibaultdody/thi-463-rail-a-sonar-strip-and-a-next-queue-in
Nov 12, 2026
Merged

tdody merged 26 commits into
mainfrom
thibaultdody/thi-463-rail-a-sonar-strip-and-a-next-queue-in

Conversation

@tdody

@tdody tdody commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

This builds design A ("Sonar strip"), one of three rail redesigns mocked up side by side with today's rail: the options. The other two were B ("Sorted in place") and C ("Focus / All").

It fixes most of what the 2026-11-09 rail critique (23/40) found: broken agents were invisible, the attention rows dropped what the agent said, colour and motion reported nothing new, and branch headers doubled the rail's height.

What changes

  • Sonar strip, pinned to the top of the rail. One line per track, one blip per pane. A blip's shape says the state as well as its colour, so it reads without colour too:

    State Blip
    asks orange filled circle, pulsing
    broken red square
    done green ring, dimmer after an hour
    working amber three-quarter sweep
    idle small grey dot
    shell short bar

    Clicking a blip opens its pane. Clicking a track's name shows only that track in the tree; this replaces the filter chips.

  • A Next queue replaces NEEDS YOU, READY and RUNNING. It lists panes that ask (longest wait first), then broken ones, then finished ones.

    • Broken means an API error, or failing CI on an open PR, unless the agent is already working on it. A failing PR gets one card, however many panes show it, the same way Clawd counts it.
    • Each card shows what the agent said, its track (not the tmux session) and the reason it's there.
      • A permission request shows its command in mono.
      • An ask shows the newest notify message.
      • A finished pane shows the first sentence of its reply, as the done banner does.
    • Three cards show; the rest fold into "+N".
    • One done card per pane, with its newest message. Broken outranks done for a single pane: a finished pane on a red PR, or with an API error, shows its broken card until CI clears or you open it (opening it marks the done news seen).
    • A failing PR's one card opens a finished pane first, then the linked one, then the first in window order. Other panes on that PR keep their own done cards.
    • × marks a done card seen without opening it, or dismisses an event's card.
  • ⌘J opens the next pane that wants you, from anywhere, including the terminal. Repeated presses walk the queue in order, skip the pane already on screen, and start over once every card has been opened.

  • PINNED stays, without its green tint. Its rows show the blip, name and track.

  • ACTIVITY rows read " · " (every row used to read " · shell"), in token colours, with no hover background.

  • A quieter tree:

    • A branch gets a header only when two or more panes in a multi-branch track share it. A pane alone on its branch shows the branch, in mono, on its selected card.
    • Each row has an age column: how long it has waited for you, or how long since its last turn finished. A waiting pane's age turns amber after 10 minutes and red after an hour.
    • Only asking panes pulse. Done no longer pulses, and nothing pulses under prefers-reduced-motion.
    • ↻ shows only when memory, not age, triggers it. The detail header still shows both.
    • Context shows on a compact row only once it's in the warning band. A raw token count now reads "653k ctx".
    • The PR chip, with its CI glyph, moves to the row's first line.
    • "+" (new tab) moves into the track header.
  • One answer to "what wants you", so the rail, ⌘J and Clawd agree:

    • alertFeed owns the Next queue (buildNext), and ⌘J walks that same list.
    • Clawd's bell, API, CI and done duties are Next's entries. Clawd no longer flags a pane the rail shows as working, asking or a shell, or counts a finished pane on a red PR as done as well.
    • A blip asks, and its row ages, exactly when Next lists the pane as asking.
    • Why a pane is broken (brokenCause) and its blip's words (blipReason) are each written once.
    • The done and needs-input banner wording is shared with the Next cards.
    • A banner's Mark seen now also dismisses that pane's notify(done) events, so they can't come back in its place.
  • Accessibility:

    • Blips and cards are buttons with names that include the state.
    • The hover actions show when the row has keyboard focus, with a focus outline.
    • Section headers are 10px labels again. A rule-ordering bug had set them in 13px.
    • Keyboard focus in the rail holds the strip and Next as hover does; after × focus moves to the next card; a control focused while Shift+Tabbing up scrolls into view below the sticky strip.
    • The hover actions fade in left of a row's PR chip and age, so the chip stays clickable.
  • Cleanup:

    • DESIGN.md describes the strip, Next cards, blip shapes and the asks-only pulse.
    • Removed now-dead code: the attention-row tints and dots, filter chips, the wt-meta strip, NewTabRow, WorktreeMeta, maxSeverity, the branch-order pref and its server field.

Testing

  • npm test: 1474 pass. New cases cover:

    • paneBlip, buildNext, nextToOpen, isCiFailing
    • the Next card's words (nextWords)
    • the clustering rule in mergeLiveAndPrefs
    • markReadySeen / dismissEvents
    • isNextKey
    • render checks for the strip, cards and clusters
  • bin/check is clean (3 Biome warnings that are already on main). Full uv run pytest -q: 2189 pass.

  • Checked on a dev instance (:17375) against the live panes:

    • the strip stays pinned while the tree scrolls
    • the track scope works
    • ⌘J from inside the terminal opened the first card (CI failing)
    • no console errors
  • An independent review found eight issues; all are fixed in the third commit.

    • A card click didn't release the layout freeze.
    • ⌘J bounced back to the top of the queue.
    • Each pane on a failing PR got its own card.
    • × on a done card let its event card come back.
    • An asking card showed the oldest question, not the newest.
    • A track scope could strand the tree when its track emptied.
    • Asks and working blips had the same shape.
    • A role=button card hid its × from screen readers.
  • A second, multi-agent review (24 findings: 10 medium, 14 low, none blocking) is addressed in the last 23 commits, one per finding or shared cause, with regression tests. Two were description-only (fixed above) and one was refuted. Further visible changes from it:

    • The sonar strip freezes with Next while the pointer or focus is in the rail; "updates paused" sits in Next's title row, in fg-2 (5.4:1).
    • ⌘J releases the freeze, so the card it opened doesn't linger.
    • A filtered track view clears once its track has no panes.
    • A track's tab order follows its card (a shared branch's tabs together), so dragging inside a branch cluster no longer moves the cluster.
    • An asking pane no longer expands into a card; only the selected pane lifts. The narrator line is prefixed "API error", "CI failing" or "done". Track and branch status dots, the expanded footer's time and the sec:needs / sec:ready / sec:running collapse prefs are gone.
    • The is_claude fallback is removed (no server has sent it since July).

Assumptions to challenge

  • Failing CI counts on any PR a pane shows, including one picked up from the branch rather than linked, as Clawd's CI duty already does. A pane on a PR you're only reviewing will sit in Next until CI goes green; broken cards have no ×.
  • THI-440 (the API-error flag sticking after a text-only reply) looks fixed by THI-455: error-then-only-text now expects False. Next relies on that flag.
  • Done panes stay in Next until seen, however old, as READY did. Their blip dims after an hour. This overrides THI-456's "a done pane pulses for about an hour".
  • Pre-existing: .impeccable/design.json still describes the old attention headers. /impeccable document regenerates it.

Not in this PR

  • THI-458's roving-tabindex tree (↑/↓ between rows).
  • THI-431's bare-key shortcuts (j/k, a, r, ?).

Covers most of THI-456, THI-457, THI-459 and THI-460.

🤖 Generated with Claude Code

tdody and others added 26 commits November 9, 2026 14:23
…DS YOU/READY/RUNNING; broken panes join it, branches cluster only when shared, only asks pulse, ⌘J opens the next (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pulse (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ened, one card per failing PR, the newest question shows, × dismisses a pane's events together, working blips sweep (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the fallback in paneBlip, the Next card, PaneRow and moveAccountTarget goes (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ason) are each said once, so the strip, the row and the Next card can't word a pane differently; an unanswered question reads 'asked you something' on its card too (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ards and ⌘J) and ⌘J's walk, and opening or dismissing an entry from anywhere releases the layout freeze, so ⌘J no longer leaves the card it opened on screen; waitingPanes carries the newest question (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… as asking (one waitingPanes answer), so a soft question you've opened stops pulsing in the strip and tree and shows as broken if its PR is red (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…(buildNext), so Clawd no longer flags a pane the rail shows as working, asking or a shell, nor calls a pane on a red PR finished (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ne that speaks for it, a finished one first, then the linked one, and only that pane is taken, so a sibling's done news keeps its card instead of vanishing until CI is green (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, carrying the newest message, so a pane that finished twice and went back to work shows one done card and Clawd counts finished panes, not events (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, and 'updates paused' sits in Next's title row, so neither a new track nor the hint moves the cards under the pointer (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…il, from 2.3:1) (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ter does, and × hands focus to the card that takes its place (or Next's title), so a keyboard user no longer drops to <body> (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ontrol focused while Shift+Tabbing up the tree is no longer hidden under the strip (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…instead of over them, so a compact row's PR opens on click and its age stays in view (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…esn't narrow again without warning when that track gets a new pane (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…branch's tabs together, so dragging a pane inside a branch cluster no longer moves the whole cluster below an unrelated pane (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ail stops re-deriving railTree's no-branch bucket behind a guard that can't fire; markReadySeen's comment names the done card, not READY (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nNextEntry, and tests pin which cards get one and what it dismisses (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…renders (its stripe class and titled age), since the Next card carries the same classes (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…names (broken, asks, done), not on the legend that always shows every blip, and the no-need_human check runs with a need_human event present (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd, and its age from the needs-input stamp, 'now' or the last turn (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds you says so with its stripe, blip and Next card), so the unselected expanded-card look goes (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed READY section (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ads them now that the blip and Clawd go through Next (THI-463)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tdody
tdody merged commit 51dcb0f into main Nov 12, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant