feat(desktop): developer mode display style — prompt-first UI with pinned/recent channel list, palette, and split-pane side chats - #3459
Draft
joahg wants to merge 33 commits into
Draft
Conversation
Prompt-first, terminal-style UI toggled in Settings > Appearance or Cmd/Ctrl+Shift+D. Tab cycles the composer between chat and agent modes; Enter on a fresh prompt spawns a stream channel named from the prompt, attaches the selected agent, and mentions it so it starts working there. Arrow keys navigate recent session channels. Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
Each prompt in a session channel renders as a card containing the agent's threaded response. With the input empty, Up/Down selects cards; Enter opens the selected card's thread in a 50/50 split side chat with its own composer, so follow-up questions carry that thread's context. Escape unwinds side chat, card selection, then channel. Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
…e polish (AGNTOPS-354) - Amp-style command palette (Ctrl+O or / on empty composer): channel search across all sessions, settings/agent-config entries, standard-UI switch, and a name-color picker - Explicit channel navigation: up from the fresh composer slides a channel navigator out from the left with live preview; enter opens, escape backs out; escape inside a channel returns to the navigator - LLM channel naming via the mesh LLM node's OpenAI-compatible endpoint when running, with async rename and slug fallback - Split-pane side chat: draggable (and keyboard-resizable) divider with persisted split, inactive-pane dimming, left/right arrows switch panes - Deterministic per-author name colors with device-local hex overrides, conservative keyword highlighting (inline code, URLs, mentions) - Square corners on prompt cards, pills, and channel rows Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
…split view Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
…rome polish in dev mode (AGNTOPS-354) - Channel list is always visible, dimmed while a channel is focused; composer covers only the channel pane, full width only for new sessions - Device-local channel categories with per-row assignment menu; uncategorized/new channels always render below all categories - Remove the shared top chrome bar in developer mode; dev-mode gray reaches the window top with macOS traffic-light clearance - Window refocus restores the last-focused input; dead-space clicks no longer blur the composer - Kind-7 reactions render as chips on prompts and replies (doubles as the agent working indicator) - Agent replies align with the prompt's indent; selection hint is absolutely positioned so up/down navigation causes no layout shift - Composer mode pill and caret match the agent's chat name color - Agent-directed prompts carry a visible @agent prefix Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
Channel names now come from the tagged agent's own harness instead of a prompt slug. buzz-acp gains a 'complete' subcommand (bounded one-shot ACP prompt returning JSON text); the desktop bridges it through a new generate_agent_completion Tauri command that resolves the managed agent's effective harness command/model/env exactly like spawn. Channels are created under a neutral unique 'new-session' placeholder and renamed asynchronously when the title arrives, so naming failures stay visible instead of masquerading as generated titles. Mesh inference remains the fallback when no managed agent completion is available. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
…-style * origin/main: fix(acp): per-runtime env defaults at spawn — isolate Hermes from configured MCP startup (block#3420) Signed-off-by: Joah Gerstenberg <joah@squareup.com>
Both the channel and side-chat composers now size to their content — wrapped lines included, not just hard newlines — growing upward to 40% of the window before scrolling internally. The top border doubles as a drag handle (pointer + keyboard) that sets a persisted minimum height. AGNTOPS-354 Signed-off-by: Joah Gerstenberg <joah@squareup.com>
Transcript URLs were blue-underlined spans you couldn't click. They now render as links — link icon plus the page's og:/twitter:/<title> title when a new generic fetch_page_title command can fetch it (https-only, 4s timeout, 256KB cap), falling back to the URL without its scheme, truncated at 64 chars. Clicks open the system browser via the opener plugin. Trailing sentence punctuation stays in the prose instead of breaking the href. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
…ocus AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
…t search AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
Pinned chats render in their own section at the top of the channel list; all other chats sit beneath. Both sections order by last activity, newest first, with unread dots + bold names driven by the shared useUnreadChannels state from AppShell. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
Message @mentions whose name matches one of the event's p-tag members (e.g. the @agent prompt prefix) render as a bordered pill in that author's chat color — visually matching the composer's mode pill. Multi-word agent names like "amp (local)" are matched longest-first; unknown mentions keep the generic highlight. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
The channel name already renders in the app top bar; the in-transcript duplicate wasted space and repeated the first prompt's text as topic. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
…elected Selecting a card with ↑ now blurs the message box (readOnly while inactive) so typing can't land in it; the shell owns ↑/↓/Enter/Escape through a window listener until the selection clears. Clicking the box clears the selection and resumes typing. Window-refocus and click-on-message focus restoration skip the composer during card selection so they can't silently re-arm it. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
⌘N jumps to the fresh composer to start a new channel. ⌘T opens a draft side chat in the open channel: the pane opens with no thread yet, the first send posts a root message to the channel exactly like the main composer, and the pane attaches to that new thread for follow-ups. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
The gutter layout (time · name · content on one line) produced ragged content columns. Every message now renders a header line — author name in its chat color, timestamp, reaction chips — with the content on its own line at the left edge, Slack-style. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
…-style * origin/main: feat(agent): fix Anthropic prompt caching with Databricks (+ MCP proxy/TLS passthrough) (block#3463) Fix mobile attachment and gallery polish (block#3370) Signed-off-by: Joah Gerstenberg <joah@squareup.com>
AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
Typing # in either composer suggests known channels; Tab/Enter inserts a plain-text #channel-name reference (the same wire format the standard UI renders as channel links). Known references in the transcript render as clickable links that open the channel without stealing composer focus. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
⌥↑/⌥↓ in the prompt composer opens the previous/next channel in the visible list (pinned then recent) without moving focus out of the textbox — works with a draft in progress, and from the fresh composer ⌥↑ opens the nearest channel. Suggestion popups ignore modified arrows so the shortcut still works while autocomplete is open. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
The auto-grow hook shrinks the textarea to 0px on every keystroke to measure content; that reflow made the transcript flex sibling taller for an instant, clamping its scrollTop and drifting the chat upward. Freeze the composer wrapper's height during the measurement so siblings never reflow, and have the pinned-scroll observer also watch the scroller so a pinned view stays glued to the bottom when the composer genuinely grows (newlines, drag, split moves). AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
Developer mode now derives its channel-list unread dots from unread top-level posts rather than the standard thread-aware unread set. Opening a channel marks its top-level timeline read, so unopened thread replies do not keep or restore the channel dot. Standard UI unread and notification behavior remains unchanged. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
The composer pill drops its @ sign, and a prompt's leading @name mention no longer renders inside the message body. Dev mode lifts it out and shows a small 'to Name' line (in the agent's chat color) under the author name; the side-chat header preview strips it too. The wire format is unchanged — messages still carry the @name prefix and mention tag so the standard UI and other clients keep seeing who a prompt is for. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
The bordered mode pill below the composer is gone. The Tab-cycled target now sits at the top of the chat box as the same 'to Name' direction line messages use (agent name in its chat color); plain chat mode shows 'chat' and busy shows 'working…'. Applies to both the channel composer and the side-chat composer. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
The dev-mode shell is a flex item without min-w-0, so nowrap content (truncated link labels, thread-header previews) set a huge intrinsic min-content width and pushed the whole shell past the right edge of the window. Let the shell and its content row shrink, and clip any residual horizontal overflow at the transcript / thread scroll viewports so long messages wrap inside their pane. Adds a Playwright regression test that sends a long unbroken message, opens the side chat, and asserts nothing inside the shell extends past the window and transcript content fits its viewport. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
Message bodies now go through a block-level markdown layer built on the existing span-based inline highlighter: fenced code blocks, headings, bullet/numbered lists with hanging indents, blockquotes, and horizontal rules. Inline, the tokenizer picks up **bold**, *italic*/_italic_, ~~strikethrough~~, and [label](url) links (rendered via DevLink with the written label instead of a fetched title). Emphasis delimiters are strict so snake_case and arithmetic stay plain prose, and everything renders as React nodes — never HTML. AGNTOPS-354 Amp-Thread-ID: https://ampcode.com/threads/T-019fabca-7cdc-777d-9ccd-ed829c1e60f0 Co-authored-by: Amp <amp@ampcode.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a developer mode display style to the Buzz desktop app (AGNTOPS-354): a prompt-first, keyboard-driven, Amp/Claude-Code-style surface layered on the existing channel structure.
Core flow
@Agentprefix on the wire (plus the mention tag) so the standard UI and other clients see who a prompt is for — but dev mode lifts it out of the message body and renders it as a small “to Agent” line (in the agent's chat color) under the author name. The composer shows its Tab-cycled target the same way: a “to Agent” line at the top of the chat box (no more bordered pill), with “chat” / “working…” for the other states.Channel list: pinned chats, recency order, unread indicators
pin/unpin): pinned chats render in their own pinned section at the top; all other chats sit beneath. Pins are device-local (localStorage) — the channel protocol has no pin field.Command palette
Window chrome & focus
Split-pane side chat
Channel naming
buzz-acp completesubcommand runs a bounded one-shot ACP prompt through the tagged agent's own harness (same command/model/env resolution as agent spawn), bridged by agenerate_agent_completionTauri command. The exchange is a private subprocess — it never appears in any channel.new-sessionplaceholder and renamed asynchronously when the title arrives; a lingering placeholder makes naming failures visible instead of masquerading as generated titles.Color
inline code, @mentions. Mid-message mentions matching one of the message's p-tag members render as a bordered pill in that author's chat color, in that author's chat color; multi-word agent names likeamp (local)are matched longest-first. A leading mention is treated as direction, not prose — stripped from the body (side-chat header preview included) and shown as the “to Agent” line.#channelreferences: typing#in either composer autocompletes known channel names (↑/↓ select, Tab/Enter insert, Esc dismiss); accepted references serialize as plain#channel-nametext (the same format the standard UI links), and known references in the transcript render as clickable links that open that channel without stealing composer focus. Multi-word names match longest-first, same as mentions.fetch_page_titleTauri command (https-only, 4s timeout, 256KB cap) resolves og:/twitter:/<title>titles.Layout containment
min-w-0so nowrap content (truncated link labels, thread-header previews) can't inflate its intrinsic width, and the transcript/side-chat scroll viewports clip residual horizontal overflow. Long unbroken words wrap; links truncate inside their pane.dev-mode-overflow.spec.ts, smoke project) sends a long unbroken message, opens the side chat, and asserts nothing extends past the window.Markdown rendering
strikethrough, and[label](url)links (labeled links render via the Slack-style link component using the written label, skipping the title fetch). Emphasis delimiters are strict so snake_case and arithmetic stay plain prose; everything renders as React nodes — never HTML — and plain human chat renders exactly as typed.Notes
⌘⇧Dtoggles); standard UI untouched.pnpm typecheck,pnpm check,pnpm test(3792 pass),cargo test -p buzz-acp(639 pass),pnpm buildall green.Linear: AGNTOPS-354