Skip to content

Code blocks have no copy affordance — every agent-authored command needs a manual drag-select #5434

Open

Description

@DocNR

Summary

Fenced code blocks render, but there is no way to copy one directly. No copy button on the block, no "copy code" in the message action menu. The only route is highlight-then-copy, which works but is imprecise: it is easy to over-select into surrounding message text or miss the last line, and on wrapped lines the selection can carry soft line breaks into a command that then has to be cleaned up before it runs.

This is a minor papercut in a generic chat app. It is a more frequent one in Buzz specifically, because agents hand humans shell commands as a routine interaction, so the same imprecise selection gets repeated many times a day.

Steps to reproduce

  1. Have an agent post a message containing a fenced code block — in practice this happens constantly, e.g. an agent proposing a fix:

    bash ~/.buzz/.scratch/clean-buzz-agents.sh
    
  2. Try to get that command onto the clipboard.

Actual: no copy control on the block, and no "copy code" entry in the message action bar. Highlight-and-copy is the only route.

Expected: a copy control on the block (hover-revealed, corner-positioned) that copies the fence contents exactly — no language tag, no surrounding message text, no leading prompt characters.

Why this one matters more than usual here

Buzz's premise is agents as workspace members rather than bots. In practice a large share of agent output is a command or snippet the human is meant to run, so this selection dance repeats constantly — and a mis-selected shell command is worse than a mis-selected sentence, because it either fails confusingly or does something slightly different from what was intended. Slack, Discord, GitHub and ChatGPT all ship a copy button on code blocks; its absence is more noticeable in a product where the code is usually addressed to you, to run now.

It also interacts with an existing quirk: agents sometimes emit literal \n (#4891), so a hand-selected copy is not always faithful to what the agent meant to send.

Suggested scope

Smallest useful version:

  • Copy control on fenced code blocks in the desktop message list, revealed on hover, consistent with the existing MessageActionBar interaction pattern.
  • Copies the fence contents verbatim; excludes the info string and any surrounding markdown.
  • Brief "Copied" confirmation, matching whatever the existing clipboard call sites already do.

Deliberately out of scope for a first pass: inline code (`like this`), mobile (mobile code rendering already diverges — see #5257), and any execute affordance.

A wider version, if it's interesting

The narrow fix above is a chat-app table stake. The more Buzz-shaped question is whether an agent-authored command deserves a first-class treatment rather than being plain markdown that happens to contain a command — copy, and possibly "run in terminal" behind a confirmation, given the agent proposing it is already an identified workspace member with an audit trail.

That is a design conversation rather than a bug, and I would not want it to block the copy button. Raising it because a platform built on agents-as-teammates is a place where it might actually make sense.

Environment

  • Buzz Desktop 0.5.8, macOS 26 (arm64)
  • Self-hosted relay
  • Verified against current main by code search: no copy-on-code-block affordance present

Activity

  1. TheSeydiCharyyev commented on Aug 10, 2026

    @TheSeydiCharyyev
    Contributor

    The per-block copy control already exists in main, and it matches the scope described here.

    MarkdownCodeBlock in desktop/src/shared/ui/markdown/CodeBlock.tsx renders a button in the corner of the block. It is hidden at rest and appears on hover or keyboard focus (opacity-0 plus group-hover:opacity-100 / group-focus-within:opacity-100). Its accessible name is Copy code block, its tooltip says Copy code, and it copies the fence contents through copyCodeBlockToClipboard.

    There is also a regression test: desktop/tests/e2e/messaging.spec.ts, "copy a rendered code block and paste it back as code". It posts a fenced block in a channel, asserts the button goes from opacity: 0 to opacity: 1 on hover, clicks it, and asserts the clipboard holds exactly the code — no language tag and no surrounding message text.

    CodeBlock.tsx last changed on 8 July, so this is in 0.5.8 as well.

    So something else is going on in your case. Two paths in the code would show no control:

    1. Markdown takes an interactive prop. It defaults to true and the message list uses the default. When it is false, the pre renderer returns a plain <span> (desktop/src/shared/ui/markdown.tsx), so there is no block wrapper and no copy control. Today that is the inbox list pane, the drafts panes, the project issues / pull request / readme panels, the persona catalog dialog, and the agent details in a profile.

    2. If the message body carries a literal \n instead of real newlines — the [Bug] buzz-acp agents can still publish literal \n after #2121 #4891 you mention — the fence never closes into a block. The text renders as an inline code chip, and an inline chip has no per-block control.

    Two questions, so this lands in the right place:

    • Which surface is it? The main channel timeline, a thread, the inbox list, or a project panel?
    • Does the message render as a real block, with the rounded border and its own scrollbar, or as inline text?

    If it is case 1, the useful change is giving the non-interactive markdown surfaces the same control, which is a different piece of work from what this issue currently describes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions