Skip to content

UX phase 3 — make the agent loop visible#14

Merged
plosson merged 5 commits into
mainfrom
ux-phase-3
Jul 15, 2026
Merged

UX phase 3 — make the agent loop visible#14
plosson merged 5 commits into
mainfrom
ux-phase-3

Conversation

@plosson

@plosson plosson commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Phase 3 of the UX rework (docs/plans/ux-rework/phase-3-agent-loop.md). Makes the human⇄agent loop tangible: act on suggestions where the text is, see what agents did, move anywhere with ⌘K, and get pulled back when you're needed. Builds on phases 1–2 (PRs #11#13).

What's in it

3.1 Inline suggestion popovers. Clicking a suggestion mark (or ghost insert widget) opens an anchored popover at the text — author chip, kind, −old/+new preview, Accept / Reject / Withdraw — reusing the shared accept/reject/delete helpers (no model changes). Positioned via view.coordsAtPos with a scroll-into-view + measure so it works in long documents; follows the anchor on scroll/resize, closes on outside click / Escape / scrolling away. The right rail becomes explicit bulk review ("Review N suggestions") with Accept all / Reject all behind a danger confirm; Accept all re-resolves ranges between applications (anchor order, skips orphans) and reports the outcome in a toast. The concurrent double-accept trade-off from the PR #9 review is documented in code.

3.2 Agent activity feed. A per-project, ephemeral in-memory ring buffer (src/server/activity.ts, ~500 events, resets on restart, never persisted) at GET /api/projects/:p/activity. Events come from signals already flowing through a room — join/leave, composing↔idle, suggestions, comments, and version saves/restores — via observers wired in Room.open that die with the room; events with no resolvable actor are dropped. Rendered as an Activity block on the Agents page and a compact last-3 strip on Home project cards.

3.3 ⌘K command palette (src/client/palette.ts). Keyboard-first overlay (⌘K/Ctrl+K or the sidebar Search item): jump to any document across projects, full-text-search the current project (≥3 chars, "In text"), and run actions (New document/project, Connect an agent, Settings, Toggle mode, Copy MCP config). Replaces the per-project sidebar search input.

3.4 Attention. The inbox polls on a 60s interval and on focus, keeping the sidebar badge and the tab title ((2) mdio) in sync; a newly-arrived unhandled @mention pops a clickable toast that deep-links to the thread. (Non-goals noted in code: web push, sounds, per-thread read state.)

3.5 Polish. History and Versions merged into one two-tab drawer (single History & versions ⋯-menu entry); composing agent avatar pulses; empty-inbox teaching copy; ? keyboard-shortcuts dialog.

Tests

All of bun test is green (171 tests across server, MCP, model, CLI, and the Playwright e2e suite). New coverage: popover accept + bulk Accept-all e2e, activity API test (join/writing/suggested/commented/resolved in order, saved-version, left, 404), palette e2e including keyboard nav, attention toast/title e2e, and the merged drawer. Visual flows were screenshot-verified with Playwright.

Docs

CHANGELOG.md (Unreleased) and CLAUDE.md updated — the activity endpoint is documented as ephemeral, and the src/server/api.ts header route table lists it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Gnrgu8jdLx12jkWY1B8vb3

plosson and others added 5 commits July 15, 2026 20:22
Click a suggestion mark (or ghost insert widget) to open an anchored popover
at the text — author chip, kind, −old/+new preview, Accept/Reject, and Withdraw
when it's yours — reusing the shared accept/reject/delete helpers (no model
changes). Positioned via view.coordsAtPos with a scroll-into-view + measure so
it works in long documents; follows the anchor on scroll/resize and closes on
outside click / Escape / scrolling out of view.

The right rail becomes explicit bulk review ("Review N suggestions") with
Accept all / Reject all behind a danger confirm. Accept all re-resolves ranges
between applications (anchor order, skipping orphans) and reports the outcome
in a toast. The concurrent double-accept limitation from the PR #9 review is
documented in a code comment.

Ghost insert widgets now carry their suggestion id so clicks resolve the same
way delete/replace marks do. e2e: popover accept flow + bulk Accept-all.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gnrgu8jdLx12jkWY1B8vb3
Per-project in-memory ring buffer (ActivityLog, ~500 events) exposed at
GET /api/projects/:p/activity — deliberately ephemeral (resets on restart,
never persisted; unknown project 404s). Events are emitted from the signals
already flowing through a room, wired in Room.open after hydration so they die
with the room and pre-existing suggestions/comments don't replay:

- awareness join/leave and composing↔idle transitions (writing/finished),
- suggestions map observer (suggested / accepted / rejected via resolvedBy),
- comments map observer (commented / replied; resolved attributed to the
  socket that applied it → its awareness identity),
- snapshot save/restore, driven from the api.ts handlers via Room.recordVersion.

Events with no resolvable actor are dropped rather than guessed. Client: an
Activity block on the Agents page (polled with peers, doc-linked, newest first)
and a compact last-3 strip on Home project cards, sharing an activityLabel()
phrasing helper. e2e: Agents-page feed renders alice's activity. API test:
join/writing/suggested/commented/resolved in order, saved-version, left, 404.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gnrgu8jdLx12jkWY1B8vb3
A keyboard-first overlay (src/client/palette.ts) opened with ⌘K/Ctrl+K and via
a new sidebar Search item. Sources are ranked: documents across all projects
(title + path, fetched once per open and cached), full-text hits in the current
project for queries ≥3 chars (debounced, "In text" section), and actions (New
document, New project, Connect an agent, Settings, Toggle mode, Copy MCP
config). Arrow keys move the selection, Enter runs it, Escape/backdrop close.

The per-project sidebar search input is removed — the palette absorbs it — and
its now-dead search styles/handlers are deleted. e2e replaces the old sidebar
search test with a keyboard-driven palette test (⌘K, arrow nav, doc jump,
in-text section, action).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gnrgu8jdLx12jkWY1B8vb3
refreshInboxBadge now polls the cross-project inbox on a 60s interval and on
focus, keeps the sidebar Inbox badge and the document title (`(2) mdio`) in
sync, and toasts a newly-arrived unhandled mention while the app is open (the
first poll only primes the seen-set so existing mentions don't nag). The toast
is clickable and deep-links to the thread; toast() grew an onClick option and
clickable toasts opt back into pointer events over the click-through tray.
Explicit non-goals (web push, sounds, per-thread read-state) are noted in code.

e2e: tab title/badge reflect the pending count and a fresh @mention pops a
deep-linking toast.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gnrgu8jdLx12jkWY1B8vb3
…ts, docs

- History and Versions merge into one two-tab drawer behind a single
  "History & versions" ⋯-menu entry; history.ts/versions.ts now fill their tab
  pane while the drawer owns visibility, tabs, title, and close.
- A composing agent's presence avatar pulses subtly (reduced-motion aware).
- Empty inbox teaches the core loop ("Nothing needs you — mention @agent…").
- A `?` keyboard-shortcuts dialog (ignored while typing), listing the palette,
  mode toggle, and comment affordances.
- Docs: CHANGELOG Unreleased gains the phase-3 summary; CLAUDE.md documents the
  ephemeral activity endpoint and its observers.

e2e updated to drive the merged drawer (History tab + Versions tab).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gnrgu8jdLx12jkWY1B8vb3
@plosson
plosson merged commit 99a8079 into main Jul 15, 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