unwrap-terminal-text
Fixes copy-paste from Claude Code, Codex CLI, and other terminal AI assistants.
Text copied out of a terminal UI arrives broken. Every line carries the interface's left margin, and long lines contain hard newlines at the wrap column rather than soft wraps — so paragraphs paste as ragged fragments, URLs break in half, and code loses its indentation.
This cleans it up. A command-line filter that works anywhere, plus a GTK4 desktop app for Linux where you pick region by region what gets rejoined.
It is not specific to any one assistant — it works on output from any TUI that
hard-wraps, including plain less, journalctl, and SSH sessions. The problem is
reported repeatedly against
Claude Code
(#26016,
#48768) and
Codex CLI
(#12200,
#8306). Other assistants that render
a left gutter are likely affected the same way, though I have only verified those
two.
▎ Write down what you'd build before running the command, then check
▎ whether the brief changed what you'd build first. If it only changed
▎ things you weren't going to act on, the questions aren't earning it.
becomes
Write down what you'd build before running the command, then check whether the brief changed what you'd build first. If it only changed things you weren't going to act on, the questions aren't earning it.
Why a tool instead of a regex
Stripping the margin is easy. Deciding which line breaks were real is not — the terminal destroyed that information on the way to your clipboard. A paragraph wrapped at column 80 and a deliberately short line look identical afterwards.
So the transforms are conservative, and the GUI hands the ambiguous call back to you: select the prose, rejoin it; select the code, leave its line breaks alone.
Install
The CLI is pure standard library — no dependencies, any OS with Python 3.9+:
pipx install git+https://github.com/Bishop81/unwrap-terminal-text
or from a clone:
git clone https://github.com/Bishop81/unwrap-terminal-text
cd unwrap-terminal-text
pip install --user .
Not on PyPI yet, so install from the repository for now.
Desktop app (Linux)
The GUI additionally needs GTK4, libadwaita and PyGObject, which come from your distribution rather than pip:
sudo apt install python3-gi gir1.2-gtk-4.0 gir1.2-adw-1 # Debian/Ubuntu
sudo dnf install python3-gobject gtk4 libadwaita # Fedora
Then ./install-desktop.sh to register the launcher and icon.
libadwaita targets GNOME, so the GUI is effectively Linux-only. The CLI has no such constraint.
Command line
clipclean notes.txt # unwrap a file
clipclean -s code.txt # keep line breaks, drop the margin
clipclean -b notes.txt # re-bold lead-in labels
xclip -o | clipclean | xclip -i # X11 clipboard round trip
wl-paste | clipclean | wl-copy # Wayland
pbpaste | clipclean | pbcopy # macOS
| Flag | Effect |
|---|---|
-u, --unwrap |
Drop the margin and rejoin wrapped lines (default) |
-s, --strip |
Drop the margin, keep line breaks — use for code |
-b, --bold |
Re-bold lead-in labels before : or an em dash |
--no-markers |
Keep tool glyphs and blockquote rules |
--no-linenos |
Keep line-number prefixes |
Desktop app
Opens with your clipboard already loaded. Operations act on the selected lines, or the whole buffer if nothing is selected.
| Key | Action |
|---|---|
Ctrl+U |
Unwrap — drop the margin, rejoin wrapped lines |
Ctrl+K |
Strip only — drop the margin, keep line breaks |
Ctrl+B |
Bold leads |
Ctrl+Return |
Copy everything back to the clipboard |
Ctrl+R |
Reload from the clipboard |
Ctrl+Z |
Undo |
It also takes a file path, and opens it in the running window.
What it cleans
- Left margin — removes the common leading indent, so relative indentation inside a code block survives.
- Hard wraps — rejoins wrapped lines into paragraphs. Blank lines, bullet lists, numbered lists and table rows stay put.
- Split URLs — a line ending in a hyphen joins with no gap, so
…/claude-+code/issues/1reassembles correctly. - Tool glyphs and blockquote rules —
⏺ ⎿ ▎ │and friends at line start. - Line-number prefixes —
1⇥,1 |,1→, but only when most lines carry one, so a genuine numbered list is never eaten. - ANSI escape codes — always.
Bold leads
Terminals render **bold** as styling and discard the syntax, so it never
reaches your clipboard. This puts it back on lead-in labels:
Why: because the terminal ate it. -> **Why:** because the terminal ate it.
Line numbers — the 1⇥ prefixes. -> **Line numbers** — the 1⇥ prefixes.
It refuses plain hyphens (a well-known thing - not a label), lead-ins over
eight words, and anything starting with a quote or bracket, so dict literals,
JSON and function signatures are left alone. Running it twice is a no-op.
Known limits
- A URL broken at a wrap point without a hyphen still gets a space inserted. Recovering that needs the terminal width, which the clipboard doesn't carry.
- Markdown emphasis other than lead-in labels can't be recovered — the terminal discarded it.
- Nested blockquote depth is flattened rather than preserved.
Tests
python3 tests/test_core.py # transforms, no display needed
python3 tests/test_gui.py # GTK layer, needs a display
samples/ holds fixtures for each transform, including cases that must come
back unchanged.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file unwrap_terminal_text-0.1.0.tar.gz.
File metadata
- Download URL: unwrap_terminal_text-0.1.0.tar.gz
- Upload date:
- Size: 14.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
852560d6de1c576a28b4855f7c02e58a1b3510ea90a6ed123fa81494f691b82a
|
|
| MD5 |
ff5df3706ee0f6d59a3694a1588602b3
|
|
| BLAKE2b-256 |
bcb4cf4e075c66879736be9d963a2306fa41eb78719ffad9fc3e3a9740697f0f
|
File details
Details for the file unwrap_terminal_text-0.1.0-py3-none-any.whl.
File metadata
- Download URL: unwrap_terminal_text-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
87183c2fc2338225b6578c734ecfd450dbcb3aaced79cba745af89b9e883d3b7
|
|
| MD5 |
e854fbdb4ac7ae740b31db0dce8e51e5
|
|
| BLAKE2b-256 |
998dadf4b55c480b312faa5ea1925f0f89c9351219b76630c2baf7adaee112c1
|