Skip to content

Pop-out windows: Slack-style thread windows at parity with the main view - #2896

Draft
jawspeak wants to merge 75 commits into
block:mainfrom
jawspeak:design/popout-window
Draft

jawspeak wants to merge 75 commits into
block:mainfrom
jawspeak:design/popout-window

Conversation

@jawspeak

@jawspeak jawspeak commented Nov 6, 2026 •

Copy link
Copy Markdown

Pop-out windows (Slack-style) — channel, DM, Solo and thread windows

Opens a channel, DM, Solo chat or thread in its own desktop window ("#channel — Buzz", "Thread in #channel — Buzz"), with the same functionality as the main view. A conversation window drills into one of its threads in place with a < back control, as Slack's does. Design and scope checkpoints: docs/popout-windows-design.md (§10 S1, §11 S2; §9 and §11 review logs). Help text: docs/buzz-help.md → "Pop-out windows".

Model

The pop-out is a companion projection (the Huddle companion-window precedent generalized): the main window is the sole signer, outbox, unread and session owner. The companion renders what main projects and asks main to perform bounded operations against the rows it shows — reply, react, edit/delete/send-to-channel, read state, follow, report, plugin-action handoffs. Every operation ends in explicit terminal evidence acknowledged by the companion; absence is never success.

What's in

  • Native (src-tauri/src/popout_window.rs, capabilities/popout.json, popout.html): per-window binding, bounded DTOs, guarded close (unsent work), ⌘W, focus-main, microphone allowed for pop-out labels on the app origin (Linux/Windows hook).
  • Open from a sidebar row's menu → "Open in new window" or ⌘/Ctrl-click the row (channels and Solo chats), the conversation tab menu → "Open in new window", and a message's ⋯ → "Open thread in new window".
  • Conversation windows: timeline with day dividers, join/leave notices, typing/working status line; drill into a thread in place (< back); files kept across the drill; a recording in progress asks before leaving.
  • Appearance (light/dark, accent, contrast, text scale) mirrored from the main window — also fixes the Huddle window, which had the same defect. A dark window opens dark from its first frame (appearance bootstrap in the companion page + native background colour from the design tokens).
  • Identity: the header shows the conversation's tab icon (hash / lock / DM person / Solo bubble / thread mark) and the title names the kind ("#design", "Ada (DM)", "Planning (Solo chat)", "Thread in …"); DMs are named by their people. Sidebar "Open in new window" carries the same icon and sits after Copy link in every row menu.
  • Parity: reply with draft shared with main, reactions + picker, copy, mark read/unread, follow, report, edit/delete/send-to-channel own messages, delete an owned agent's message after main re-verifies ownership, plugin actions (Start Solo chat, Remind me) handed to main and opened there, View activity beside the conversation in main, voice notes recorded in the pop-out and uploaded by main; buzz:// links labelled as in main (Links plugin renderer, channel names, "‹author› in #‹channel›" bylines resolved by main and projected per row) in messages and composer decorations.
  • Exit holds: switching community / signing out lists pop-outs with unsent work and asks first.

Not in a pop-out (documented)

Member count; agent response previews and stop controls (Solo chats show the conversation as messages); windows are not restored after restart.

Verification

  • Independent agent review (jaw-gpt56sol) of every slice; findings and closures logged in docs/popout-windows-design.md §9. Reviewer notes under the reviewer's workspace.
  • Rebased onto main (2026-11-05). Full vitest suite green at the pushed HEAD via pre-push (types-and-related-unit-tests, design-system, rust-clippy); cargo test _window|microphone green. Note: native_mcp::tests::test_overlay_preserves_normal_capability_selection fails locally on clean origin/main as well (environment-dependent) — not introduced here.
  • Human (jaw) live-accepted open/type/send in the native app at an earlier HEAD; native tryout of the menu-parity and voice slices is pending (steps in thread).

Draft until the AGENTS.md pre-PR checklist holds (agent review ✔; agent exercise of the native flow and human test pending).

jawspeak and others added 27 commits November 10, 2026 12:09
Proposal only; no behavior change. Compares Slack's Open in new window,
records Buzz's Huddle companion precedent and main-only native authority,
and recommends a sliced presentation-companion approach.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Adopt the composer's existing draft-conflict contract, make Open in main a
focus (not a move), add per-window binding/incarnation, a real thread read
projection, reading-lease based unread, and cite Slack's official help.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…exits, delayed reading IPC

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Presentation-only companion windows (popout-<uuid>) modeled on the Huddle
window: main owns identity, relay, signing and read state; each window is
bound to one target and session incarnation; watch/action/download are
gated per label; guarded close asks the companion; Cmd+W closes a focused
pop-out; a main renderer reload detaches companions instead of leaving
them able to act.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Main-window owner projects a session-owned thread view into a pop-out
companion, reusing the Huddle composer bridge (now with thread reply and
thread draft keys) and a shared companion row projection/renderer. The
companion mounts the real composer, reports held work for native close
guards, and measures reading with useReading over a lease proxy whose
leases live in main. Entry point: message menu → Open thread in new window.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…d S1 deviations

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
- Reading moves to a request/response BroadcastChannel bridge: a companion
  observation completes only when main's read-state save is durable, so the
  earned lease outlives the save; a disposed lease answers no late request.
- Replies are offered and admitted only once the exact verified root of the
  thread is loaded in its channel; channel availability stays separate.
- A window is owned before native creation: scope change or disposal during
  the await retires it and destroys what native created; failed creation
  releases the reader and composer.
- Web links in a pop-out go to the OS opener; only buzz: links go to main.
- Image review hides Copy image (no media_copy_image authority).
- Linux/Windows: closing main destroys unguarded companions and asks
  guarded ones first; main destruction closes every companion.
- Native tests: caller gating, per-label download isolation, guarded
  close interception, capability contents.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
… before closing any companion

A companion lease request carries the read-intent revision its event saw;
main grants it only while that revision is current, so intent formed before
a manual unread cannot become a new read when it arrives late. Views carry
main's revision and refresh on unread changes. On Linux/Windows main close
asks guarded companions first and closes nothing until accepted.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
… thread tabs

FOUNDATION edit authorized by jaw (thread buzz-feature-popout-window,
2026-11-04): conversation.registerTabAction adds an entry to a conversation
tab's menu after the host's own actions, shown while its matcher passes for
that tab's {channelId, threadRootId?} target. The Pop-out windows plugin
registers Open in new window for thread tabs.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…; pop-out windows register theirs

FOUNDATION edits authorized by jaw (thread buzz-feature-popout-window,
2026-11-04). The communities service owns exit holds: select() waits as a
pending selection while a registered feature holds work a community exit
would discard, and runs its continuation only once selected. The shell
shows one Switch community? dialog for pending selections and, through the
existing single-slot departure guard composed with unsaved Settings, for
navigations that would change community before their route commits; Keep
working preserves route and community. Navigation-driven selection forces
because the guard already asked; the invite path sequences its open after
selection; the sign-out confirmation lists the holds. Pop-out windows
report held companions (native now forwards the guard action) and
register them through communityReader.holdExit.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…vigation; join keeps selection pending; organization sign-out asks

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…ts session revision

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…enabled by default

The desktop catalog comes from the native plugin manager, not the frontend
bundled list; without this the plugin never activated on desktop.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…rop the window header

The channel summary may carry no roster ('absent means unknown'), so a
members check left every pop-out read-only; threads now trust the relay's
readOnly/cached flags as the main composer does. The window shows only the
thread; the OS title bar names it.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…tes kept

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Seeded thread rows do not complete the session reader. Start its initial refresh before subscribing so the verified root can enable replies without notifying a partially constructed window owner.

Co-authored-by: jaw-gpt56sol <ea4d48fe3c0a6de67bdc4128679b983e511642f2579429941cfcdf0eede927fb@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…pop-outs

The companion stays a projection. Rows carry bounded reaction groups (own
events first, so a capped list still toggles correctly); the shared
MessageReactions/ReactionTool render over a reaction session whose
operations run in main through the composer bridge (react, removeReactions),
admitted against the rows the window shows and main's own view of their
events. A companion-local reaction outbox keeps pending, failed and retry
real. Reaction contract types are narrowed to the ComposerSession subset
they use (type-only; RelaySession still satisfies them), including
ReactionToolProps in the authorized FOUNDATION contracts file. MessageRow
gains a reactionSlot. Edit, delete, read-state, report and plugin actions
remain documented gaps; a thread companion has no spawn operation.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…through delivery; own-event cap matches remove

The view projects main's unresolved reaction operations on shown messages;
the companion's reaction outbox shows them beside its own unadmitted requests
and Retry re-issues main's exact admitted event through the bridge. Main
refuses another reaction change on a message while one is still in flight,
so a companion acknowledgment arriving before its row projection cannot
double-write. Projection keeps at most 100 own reaction events, the number
messages.remove accepts.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…ction; only the view is capped

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
jawspeak and others added 26 commits November 10, 2026 12:10
…d back

A pop-out target is a conversation (channel, DM, Solo chat) or one thread
of it. A window keeps a stack of frames (projection + composer owner +
reading owner per target): a conversation window drills into one of the
threads it shows (openThread, bounded to one level) and returns with back;
a thread window drills no further. Native titles '#channel — Buzz' and
'Thread in #channel — Buzz' follow the frame; Open in main points at the
channel or the thread accordingly.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…y dividers, thread drill-down, back

A conversation window shows its timeline (day dividers, thread affordances)
and the header names the conversation; choosing a row's thread asks main
to drill into it in this window, where the header gains a back control.
Rows carry main's reply count for the affordance.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…u, ⌘/Ctrl-click, tab menu

The pop-out plugin's tab action now matches every conversation target and
claims the modifier-click gesture. Sidebar rows (team channels and Solo
chats) offer contributed conversation actions in their menus and hand a
⌘/Ctrl-click to the action that claims it instead of opening in place;
TabAction gains the optional gesture field for that. Help text describes
the windows as they now are.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…n frames keep files and stop reading

Owner admission gates were thread-shaped: message actions, handoffs and
retries required a thread, and sends without one applied the Huddle roster
rule. Pop-out frames (thread or conversation) now admit against their shown
rows and trust the relay's writability flags, as main's composer does; the
Huddle companion keeps its roster rule and thread-only follow stays refused.

Files a companion editor holds are keyed by its session object, which the
companion rebuilds per connection; a window that drilled into a thread lost
the conversation's files and their close protection. The companion now
retains such drafts (bounded) while their editor is unmounted, counts them
as held work, and transfers them back to the editor that mounts again for
the same draft key.

Reading leases are re-checked for enablement on every request, and the
owner revokes a frame's leases when another frame covers it, so a lease
acquired while shown marks nothing once hidden.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…hat is recording a voice note

Retained drafts are unsent work the person attached by hand and the close
guard counts them, so none is silently dropped; the window's lifetime
bounds the set. Changing frames unmounts the editor, which ends a voice
capture in progress, so the companion asks to discard the recording before
drilling into a thread or going back while one is active (MessageComposer
reports capture through a new optional onCapturing).

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…after rebase

The page's forward provider now subscribes to navigation; a fixture that
returned a fresh snapshot per call looped.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…on windows

A conversation frame keeps relay membership activity in its projection (a
thread frame still shows messages only); the companion groups consecutive
rows into one notice with the shared MembershipRow, named from projected
profiles. Main also projects who is typing and which agents are working in
the frame's conversation — two names plus a count, and agent names — from
the same stores and classification the main indicator uses; the companion
says it in the same words. Native DTOs carry both, bounded.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Work at a shown root with replies belongs to that thread, not the
conversation's status line (the observed thread roots are passed), and an
agent live activity identifies is never also a human typer.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
… hint

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…sage bylines

A pasted buzz://message link showed as a raw URL in a pop-out's rows and as
plain text in its editor, where main shows "<author> in #<channel>" with
the Links plugin's icon. The companion had no link renderers (its
extensions carried only tools/completions/inline) and its rows had no
reference directory; the byline needs a RelaySession to read the linked
message, which a companion never has.

- Composer snapshot projects main's enabled link renderer keys (links);
  the companion table maps buzz.links/links to the plugin's exported
  linkRenderer, in the editor and in CompanionRows.
- CompanionRows passes the bridge session as MessageRow references
  (widened to RelaySession | ComposerSession): channel links and Solo chips
  label from main's channel list.
- The thread projection adds linkLabels per row, resolved in main through
  the shared linkedAuthors lookups and session.names; lookups are held
  only for links shown now (<=64 per window) and released as they leave.
  MessageMarkdown takes linkLabels as a display-only directoryLabel.
- Native DiscussionRow.link_labels: <=64 entries, URL <=8192, label <=1000.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…rofile directory's invalidation

- Message links are taken from the prepared Markdown body as MessageMarkdown
  renders it: none for plain-text bodies or inside code/HTML/images/
  definitions; a bare URL, <url> or [url](url) is looked up; other labels
  stay labels. Bodies are parsed once while shown.
- Profile requests for linked authors are made again after a cache clear
  (generation) or eviction (evictions), and only for authors of links shown
  now; no lifetime cap.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…link in every sidebar row menu

TabAction gains an optional icon (the shape MessageAction already has);
channel and Solo row menus render it in a MenuIcon. Solo rows placed
contributed actions at the top of the menu while channel rows placed them
after Copy link; the Solo menu now takes them in a slot right after Copy
link, so the same action is found in the same place.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…ve background

The companion pages had no appearance bootstrap, so the document painted
light until React applied main's projected appearance, and the native
window used the platform default background before its first paint.
popout.html and huddle.html now load appearance-init.js and startup.css as
index.html does, and the window builder sets background_color from the
opening view's appearance (--bg-app of the applied mode).

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…app resolves

The dark window background used the hover step (#2e2e2e); dark --bg-app is
--neutral-2 (#101010). The pinning test now resolves --bg-app's alias chain
per mode from tokens.css instead of searching for one token anywhere.
The command-capability test gains popout.json, which it had omitted since
the pop-out commands were added.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…nce too

No second copy of the colour literals: a view reporting only dark builds a
bare Appearance and asks it, so the pinned test covers that path as well.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
The header shows the icon the conversation's tab has (hash, lock, the DM's
person, the Solo bubble; the thread mark for a thread frame) with an
accessible kind label, and a DM is named by its people as tabs and Inbox
name it. The native title carries the kind where no icon can: "#design",
"Ada (DM)", "Planning (Solo chat)", "Thread in …". Main projects kind and
the DM picture; the native DTO validates both.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…lugin chat icons

Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Main projects a bounded member preview (count, up to three to picture —
agents for a Solo chat, people otherwise, pictures first, names through
the identity service) and requests their profiles as its own header does.
The companion renders the same avatar stack; choosing it opens the
conversation's members in the main window (the conversation itself for a
Solo chat, which has no Members surface). New companion action openMembers.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…ed before filtering

AvatarStack takes an optional total so a sample of a larger set shows the
right overflow without placeholder items. The projection requests the
bounded roster's profiles as main's header does, so a late agent flag or
picture changes the preview and count.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
Main projects the agents working in a frame's conversation from the same
live evidence its indicator reads (current activity, stop controls, step
and status text, thread scope), bounded for the native DTO. The companion
renders the same incoming-message placeholder with the current step, a row
per agent (View activity opens in main) and Stop. Stop is a composer-bridge
operation admitted by the top frame, which re-derives the controls at that
moment and refuses work that has already ended.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…main's state owner

A conversation frame now includes work in its threads, as main's channel
indicator does (only a row's own live bubble takes it over there, which
companion rows never have). The stop operation answers as main's interrupt
does ({lifecycle, running}) and the companion drives useWorkStops with it:
lifecycle stops complete, hosted work waits the bounded retry window with
main's notices, nothing-running is reported.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
A plugin's chat icon can now describe itself in data (ChatIcon.describer:
describe + watch), so a host can draw it where the component cannot run.
registerChatIcon takes the describer as a second argument and validates
it. The GitHub plugin describes its linked pull request's state; the
pop-out projects a Solo chat's first describing contribution, watches it
while the frame lives, and the companion draws the design-system artwork
with the sidebar's tone colours.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…n; watches and lookup made safe

Only the first chat icon contribution is shown, as in the sidebar; one
that describes nothing leaves the default. Watches are reconciled on every
projection, so a Solo chat converted to a channel releases its watch at
once. The catalog lookup is an own-property check, so a prototype key in a
projected token draws the default instead of failing the renderer. Merged
pull requests take the sidebar's purple.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…ontract now requires

Post-rebase fixup: main's ReadStateStorage gained capture().

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
…ut confirmation too

While server discovery is pending or failed, the root account's own row
is the only one shown; it now receives the exit holds like the listed
rows, so a pop-out's unsent reply is named before signing out.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
@jawspeak
jawspeak force-pushed the design/popout-window branch from 0c6ede9 to 2312303 Compare November 10, 2026 17:11
jawspeak and others added 3 commits November 10, 2026 12:27
…indow

The channel header menu shared the sidebar's action builder and already
had it; the Solo header built its own list. Contributed conversation
actions now render through one shared ConversationActionItems in the Solo
header and the Solo sidebar rows, right after Copy link in each.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
… too

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>
… as its header does

The Solo access dialog lives in the main-view header, not on a route. The
pop-out shows the chat in main, then hands the header a session-fenced
request (soloAccessRequests, like message-action handoffs) that only the
header showing that chat in that session takes.

Co-authored-by: Jaw-fable51-pi <27b9430246cf506d04fedbbb39d0126ad17496a0e41bd82d39e35860de80f3d0@buzz.block.builderlab.xyz>
Signed-off-by: Jonathan Andrew Wolter <44742+jawspeak@users.noreply.github.com>

This branch has not been deployed

No deployments
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