This maintenance release corrects regressions introduced by the v0.3.0 process-handling and terminal-output changes.
- Preserve UTF-8 symbols when cleaning terminal output in named batches.
- Remove recognized Braille spinner prefixes without corrupting other text.
- Preserve piped stdin for ordinary command and batch capture.
- Preserve controlling-terminal access for interactive commands.
- Restore foreground terminal ownership after normal completion, SIGINT and SIGTERM.
- Terminate command process groups when the wrapper is interrupted.
- Avoid replacing the clipboard when a command fails without output.
- Preserve nonempty output from commands that exit unsuccessfully.
The original 30-case regression suite, five targeted regression checks and six integrated pseudo-terminal checks passed.
Separate lifecycle audits verified descendant cleanup and foreground terminal restoration.
Real-X11 xclip detachment remains unverified. The existing mock clipboard tests do not establish real-X11 detachment behavior.
The package includes the Python command runner in addition to
the c and catcopy launchers.
Build from a clean committed checkout:
./build-deb.shThe resulting package is placed in dist/.
catcopy (c) is a Linux command-line clipboard tool for copying multiple files, stdin, command output, and command batches while preserving useful source boundaries.
Use it to copy files or terminal output directly to the clipboard:
c README.md script.py
git diff | c
c -- git status
echo "hello world" | c
When copying multiple files, catcopy keeps each file identifiable with transport headers instead of collapsing everything into an ambiguous text blob. It can also write to stdout or send clipboard payloads to another machine over SSH.
catcopy is designed for developer workflows including:
- copying multiple files to the clipboard
- copying command output from the Linux terminal
- sending Git diffs and diagnostics to LLMs
- preserving filenames and source boundaries
- remote clipboard transport
- headless and SSH workflows
catcopy installs two identical commands:
ccatcopy
Catcopy makes it easy to move terminal output, files, and diagnostics into AI conversations, bug reports, and code reviews.
command 2>&1 | tee >(c)
Keep output visible in the terminal while copying the same stdout and stderr to the clipboard.
c -- git status
c README.md script.py config.json
File boundaries are preserved using transport headers.
git diff | c
{
uname -a
free -h
df -h
} 2>&1 | tee >(c)
c --to workstation README.md
Remote clipboard delivery uses SSH and requires Catcopy on
the receiving machine. c --to HOST -- command runs the command locally,
then sends its captured output to HOST; it does not execute the command remotely.
Remote clipboard setup currently supplies X11 DISPLAY and does not claim
Wayland support. C_REMOTE_SESSION must remain x11.
Privacy: Catcopy does not automatically redact secrets. Review captured data before sharing it externally.
catcopy separates:
- Sources
- Destinations
A source produces text.
A destination receives text.
Examples:
file → clipboard
command → clipboard
stdin → stdout
file → remote clipboard
batch → remote clipboard
This makes catcopy useful for:
- LLM workflows
- debugging
- Git review
- diagnostics
- documentation
- JSON inspection
- remote administration
- copy/paste-heavy development
Copy one or more files with transport headers:
c README.md
c script.py notes.md
File mode preserves boundaries using transport headers:
===== TRANSPORT HEADER (NOT PART OF FILE) =====
PATH: README.md
NOTE: Do NOT include this header in any saved documents.
===============================================
Transport headers are intended for:
- LLM workflows
- code review
- debugging
- multi-file sharing
Capture stdin directly:
echo "hello world" | c
git diff | c
Stdin mode copies raw input without transport headers.
To keep command output visible in the terminal while also copying it, compose
catcopy with tee:
git diff | tee >(c)
To include both stdout and stderr:
command 2>&1 | tee >(c)
Here tee preserves the normal terminal stream while process substitution sends
the same captured stream to catcopy. This is useful for diagnostics and
copy/paste-heavy development sessions where the terminal output and clipboard
capture should contain the same evidence.
Run a command and capture stdout:
c -- git status
c -- jq '.' data.json
c -- hostnamectl
This is useful for:
- diagnostics
- JSON inspection
- Git review
- system snapshots
Default mode behaves as follows:
- clipboard when available
- stdout when no clipboard is available
Examples:
c README.md
git diff | c
This allows catcopy to work in both desktop and headless environments.
Force stdout output:
c --stdout README.md
c --stdout -- hostnamectl
This never touches the clipboard.
Useful for:
- SSH sessions
- pipes
- scripting
- CI environments
Force local clipboard usage:
c --clipboard README.md
c --clipboard -- hostnamectl
If no clipboard backend is available, catcopy exits with an error.
Send a payload to another machine and copy it there:
c --to turbopi README.md
c --to 100.87.218.21 -- hostnamectl
Remote mode transfers payloads over SSH.
The destination machine must:
- be reachable through SSH
- have catcopy installed
- have a usable clipboard backend
Localhost is detected automatically and handled without SSH:
c --to localhost README.md
The opposite direction does not use --to.
To run a command on another machine while copying its output to the clipboard
of the machine where you are sitting, keep c outside SSH:
ssh lucy 'command' 2>&1 | tee >(c)
The data path is:
remote command -> SSH -> local c -> local clipboard
Here c runs locally. The remote machine only produces command output, so it
does not need clipboard access or catcopy installed.
By contrast:
c --to lucy README.md
uses the opposite data path:
local source -> SSH -> remote c -> remote clipboard
Use --to HOST when the destination clipboard is remote. Put c outside
ssh when the destination clipboard is local.
Batch mode accumulates multiple command captures into a single payload.
Clear batch:
c --batch debug --clear
Append commands:
c --batch debug -- git status
c --batch debug -- git diff --stat
c --batch debug -- jq '.' config.json
Show batch:
c --batch debug --show
Print batch path:
c --batch debug --path
Each batch records:
- command
- exit status
- cleaned output
Batch cleaning is intentionally lossy: ANSI control sequences are removed, carriage-return progress updates are reduced to their final line, and selected spinner prefixes/control bytes are stripped. This mode preserves non-UTF-8 bytes, but these cleanup rules can alter payload bytes. Use raw batch mode when the exact command output matters:
c --batch archive --raw -- command-that-emits-binary-data
Raw mode preserves command output bytes within the framed batch record.
Catcopy requires its state directory to be owned by the current user with mode 0700, batch files with mode 0600, and every ancestor directory to be non-writable by other UIDs or protected by the sticky bit. Unsafe pre-existing paths are rejected without changing them. Processes running as the same UID share the trust boundary and can still modify the directory concurrently outside Catcopy.
Example:
===== COMMAND =====
git status
===== EXIT STATUS =====
0
===== OUTPUT =====
On branch main
Batch mode automatically removes common terminal formatting:
- ANSI escape sequences
- progress bars
- spinners
- carriage-return updates
Useful for:
- Ollama
- long-running diagnostics
- terminal captures
- interactive tools
Example:
c --batch llm -- ollama run qwen3:8b "Explain this code"
catcopy supports:
- wl-copy
- xclip
- xsel
- pbcopy
Display detected backends:
c --backends
Select a backend explicitly:
c --backend xclip README.md
c --backend wl-copy README.md
Override auto-selection priority:
CATCOPY_PRIORITY=xsel,xclip,wl-copy,pbcopy c README.md
Remote clipboard defaults:
C_REMOTE_DISPLAY=:0.0
C_REMOTE_SESSION=x11
Override when necessary:
C_REMOTE_DISPLAY=:1 c --to workstation README.md
Install from source:
sudo ./install.sh
Installed commands:
/usr/local/bin/c
/usr/local/bin/catcopy
Build:
./build-deb.sh
Install:
sudo apt install ./dist/catcopy_0.1.0_all.deb
sudo ./uninstall.sh
Copy files:
c README.md script.py
Capture command output:
c -- git status --porcelain=v1 --branch
Copy JSON extraction:
c -- jq '.items[] | .name' data.json
Remote clipboard transport:
c --to turbopi README.md
Remote diagnostics:
c --to 100.87.218.21 -- hostnamectl
Headless output:
c --stdout README.md
catcopy does not attempt to interpret or modify payload content.
Its purpose is to provide:
- deterministic capture
- explicit transport boundaries
- minimal workflow friction
- terminal interoperability
- reliable clipboard transport
- reliable remote transport
If output is malformed, the preferred fix is usually:
- adjusting the command
- disabling formatting at the source
- using cleaner CLI options
rather than mutating payloads aggressively inside catcopy.
catcopy is not:
- a clipboard manager
- a shell replacement
- a terminal multiplexer
catcopy is a text transport utility for terminal workflows.
MIT
Tor Matz Andrén