[BUG] Copy/paste from terminal has new lines instead of wrapping properly

Status Open
Reported on v2.1.27
Maintainer reply None cached
Activity 15 comments · opened Jan 31, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Because Claude is a TUI, it dynamically renders physical \n unicode to mimic word-wrapping behavior. Can we please inject an invisible unicode character before or after the \n, so that we can use post-processing to fix the copy-paste?

It's incredibly painful right now when you're working in Claude, want to copy a command from Claude and paste into another terminal, and have to manually remove all the line breaks.

What Should Happen?

Inject a character we can parse for programmatically so that we can write scripts or programs to fix the copied text, outside of claude.

Error Messages/Logs

Steps to Reproduce

Copy text
See new lines

Claude Model

Not sure / Multiple models

Is this a regression?

No, this never worked

Last Working Version

_No response_

Claude Code Version

2.1.27

Platform

Anthropic API

Operating System

Other

Terminal/Shell

Other

Additional Information

_No response_

View original on GitHub ↗

14 Comments

github-actions[bot] · 7 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/15199
  2. https://github.com/anthropics/claude-code/issues/6827
  3. https://github.com/anthropics/claude-code/issues/13378

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

nullbio · 7 months ago

Different issues, this is proposing a solution.

mhfowler · 6 months ago

I am also running into this issue. It seems OpenCode handles this well and I'm curious how they do it.

imcdo · 5 months ago

I also am running into this issue +1

kopyl · 5 months ago

This is so annoying.
Can anybody fix it?

The issue is present in iTerm...

kopyl · 5 months ago

I feel like we need to build a new terminal, which would support tools like this nicely.

Or maybe CLI UI is not the best approach?

ajiblock · 5 months ago

Root Cause Analysis

I traced the rendering pipeline through the bundled CLI and upstream dependencies:

  1. Claude Code uses Ink (React for terminals) for its TUI
  2. Ink uses Yoga for layout, calculating available width per component
  3. When text exceeds available width, Ink calls wrapText()wrap-ansi(text, maxWidth, { trim: false, hard: true })
  4. wrap-ansi inserts literal \n characters at wrap boundaries
  5. These are indistinguishable from content newlines in the terminal copy buffer

The 2-space indent reported in related issues (#15199, #13378) comes from Ink's <Box> padding — applyPaddingToText() prepends spaces to each line after wrapping.

Proposed Fix: Let the Terminal Handle Soft Wrapping

The unicode marker idea from the OP would work as a stopgap, but the proper fix is don't application-wrap in the first place.

When you write a line longer than terminal width to stdout, the terminal soft-wraps it visually. The terminal knows it's a single logical line, so copy/paste works correctly — no extra newlines. This is how every other CLI tool works (git log, man, curl output, etc.).

The fix would be in Ink's rendering pipeline:

// Current: Ink wraps text, terminal sees hard newlines
Ink wrapText() → "word1 word2\nword3 word4" → terminal displays 2 lines → copy gets \n

// Proposed: Skip wrapping for full-width text blocks, let terminal soft-wrap  
Ink output → "word1 word2 word3 word4" → terminal displays 2 lines → copy gets no \n

Specifically, for <Text> nodes inside full-width <Box> containers (which is most of Claude Code's markdown output), Ink could skip the wrapAnsi() call and let the terminal handle wrapping natively.

This would need to be opt-in (a new textWrap: 'terminal' style or similar) since Ink's Yoga layout engine needs accurate line counts for multi-component layouts. But for Claude Code's primary use case — streaming markdown into a full-width output area — terminal-native wrapping would work perfectly.

Incremental Path

Quick win (Claude Code side): For the main assistant output <Text> component, skip wrapAnsi and write unwrapped text. This fixes copy/paste for 90% of use cases (the main conversation output). Ink layout still works because the output area is full-terminal-width.

Upstream (Ink): Add a textWrap: 'native' option to <Text> that delegates wrapping to the terminal instead of wrap-ansi. PR to vadimdemedes/ink.

Fallback (if terminal-native doesn't work for the layout engine): Insert U+200B (zero-width space) before each soft-wrap \n as the OP suggests. This at least enables external tools like claude-fix to reliably strip soft-wrap newlines.

Related

This is the root cause behind #15199, #6827, #13378, #4686, #5097, and #859 (37+ upvotes). The community workaround tool claude-code-command-fix exists specifically because of this.

whitezlo · 4 months ago

same issue in Ghostty on macOS, affects both prose and code blocks

jgehrcke · 4 months ago

No literal newlines should be added.

Special case of git commit: we should default to writing a commit message to a file (and try hard to keep the individual command that is to be copy/pasted on a _single_ line).

The issue is still present in 2.1.117.

This is a rather annoying problem. I have had this type of interaction in about every claude session:

[...] run the commit yourself in this prompt so GPG gets the TTY:

  ! git commit -m "$(cat <<'EOF'
  line1

  paragraph-line1
  paragraph-line2.

  Assisted-by: Claude Code:claude-opus-4-7
  EOF
  )"

  Or unlock your GPG agent first and I'll re-run it.

❯ when I copy and paste this I get literal newlines that break the command                                                           
                                                                             
● Here's a single-line version — each -m becomes a paragraph separated by a blank line, so the final commit message is identical:      
                                                                                                                                       
  ! git commit -m "line1" -m "paragraph-line1       
  paragraph-line2." -m "Assisted-by: Claude Code:claude-opus-4-7"                                                                  
                                                                                                                                       
❯ this will also not work because the literal newlines in the copied string will make this many commands instead of one command                
                                                                                                                        
● Right, even the long one-liner can wrap on paste. Let me drop the message into a file instead — then the command is short enough to  
  never wrap.                                                 
nickbwuzhere · 4 months ago
I feel like we need to build a new terminal, which would support tools like this nicely. Or maybe CLI UI is not the best approach?

Suggesting to build a whole new terminal is insane. Just render the output without newlines and take advantage of terminal auto wrapping.

JohnPostlethwait · 3 months ago

I am running into this as well on Ghostty on MacOS.

theshanelynch · 3 months ago

+1 — adding a specific repro flavor that's a sustained productivity tax for power users.

Repro (macOS, Claude Code CLI, also reproduces inside cmux):

  1. Ask Claude to produce a long bash one-liner — e.g. oauth2c https://... --client-id ... --client-secret ... --response-types code --grant-type authorization_code --auth-method client_secret_basic --scopes "openid profile email" --callback "http://localhost:9876/callback" (>100 chars).
  2. Select the rendered command in the terminal and copy with Cmd+C.
  3. Paste into a fresh shell prompt.
  4. Observe hard linebreaks inserted at the terminal column boundary, mid-flag — e.g. --callba on one line and ck "..." on the next.

Expected: pasted text is the logical line with no embedded \n.
Actual: linebreaks appear at the terminal column boundary, breaking the command.

Why it matters: Claude Code generates long gh, curl, oauth2c, gcloud, and git commit -m "$(cat <<EOF...)" commands constantly. Every one of them has to be manually un-wrapped before it can be executed. The friction adds up fast.

Proof the underlying text is fine: asking Claude to pipe the same command through printf '%s' '...' | pbcopy produces a clipboard string with no embedded newlines and pastes cleanly. So the underlying string is unbroken — the corruption is purely in the copy-from-terminal-render path (Ink's wrap-ansi inserting literal \n, per @ajiblock's analysis above).

Also reproduces inside cmux (a multiplexer/wrapper for Claude Code), which suggests the fix needs to land in Claude Code / Ink rather than any downstream terminal layer.

Severity framing: high-severity usability — not a crash, but a sustained tax on every long command. Subscribing for updates.

mmaatouk-glitch · 3 months ago

We need this mate!!!!

allefeld · 3 months ago

Use the /copy command.

Showing cached comments. Read the full discussion on GitHub ↗