Clean Copy
Clean a draft from the conversation (or a pasted/file source) and copy it to
the clipboard, formatted for a specific platform. The goal: a paste that looks
right in Gmail / Slack / LinkedIn on the first try, with zero manual cleanup.
Preferences
Before starting, use the Read tool to read
~/.claude/skills/clean-copy/preferences.md. If the file does not exist, treat
as "no preferences set" and use defaults below.
Defaults:
- default-platform:
gmail
- default-source:
last (most recent assistant draft in the conversation)
- reflow-paragraphs:
true (rewrap soft-wrapped paragraphs into single lines)
- bullet-style:
- (preserve as-is)
- preview-after-copy:
true (show first 12 lines + char count)
Command routing
Check $ARGUMENTS:
help → display help, stop
config → interactive setup, stop
reset → delete ~/.claude/skills/clean-copy/preferences.md, confirm, stop
- anything else (including empty) → run the skill
Help
Clean Copy — Clean terminal-formatted text and copy to clipboard for a target platform
Usage:
/clean-copy <platform> Clean latest draft, format, pbcopy
/clean-copy Use default platform from preferences
/clean-copy config Set defaults (default platform, reflow, etc.)
/clean-copy reset Clear preferences
/clean-copy help This help
Platforms:
gmail Plain prose, bullets as "- ", no markdown rendering
slack Slack mrkdwn: *bold*, _italic_, `code`, > quotes
linkedin Plain prose, no markdown (LinkedIn strips it), short paragraphs
plain Strip all markdown, just clean prose
markdown Preserve markdown, only clean terminal whitespace
Options:
--source last Latest assistant draft in conversation (default)
--source paste Prompt the user to paste the source text
--source file:<path> Read source from a file
--no-reflow Keep hard line breaks as-is (don't unwrap paragraphs)
--preview Show full cleaned text before copying
Examples:
/clean-copy gmail Clean my last draft for Gmail compose
/clean-copy slack Format for Slack mrkdwn
/clean-copy linkedin --no-reflow Keep my line breaks (poetry / structured posts)
/clean-copy plain --source paste I'll paste the messy text after invocation
/clean-copy markdown --source file:/tmp/draft.md
Current preferences:
(loaded from preferences.md, or defaults shown above)
Config
Use AskUserQuestion to collect:
- Q1: Default platform —
gmail, slack, linkedin, plain, or markdown. The platform used when /clean-copy is invoked with no platform arg.
- Q2: Reflow paragraphs by default? —
Yes (recommended for prose) or No (preserve hard line breaks). Reflow joins soft-wrapped lines into single paragraphs separated by blank lines.
- Q3: Bullet style —
- (keep as written), • (convert to bullet glyph), or * (asterisk). Affects how list items render after cleaning.
- Q4: Preview after copy? —
Yes (show first 12 lines + char count) or No (silent except for "Copied").
Save to ~/.claude/skills/clean-copy/preferences.md in this format:
# /clean-copy preferences
Updated: <date>
## Defaults
- default-platform: gmail
- reflow-paragraphs: true
- bullet-style: -
- preview-after-copy: true
## Learned
- (patterns observed silently, e.g., "user always picks slack on weekdays mornings")
Reset
Delete ~/.claude/skills/clean-copy/preferences.md and confirm:
"Preferences cleared. Using defaults."
First-time detection
If no preferences file exists, show:
First time using /clean-copy? Run /clean-copy config to set defaults, or
just continue — defaults are gmail / reflow on / dash bullets.
Then proceed.
Workflow
Step 1 — Resolve platform
Parse $ARGUMENTS:
- If a platform keyword (
gmail, slack, linkedin, plain, markdown) is present, use it.
- Otherwise, fall back to
default-platform from preferences (or gmail).
- If still unclear AND the source text strongly hints (e.g., starts with "Hi all," → email; starts with "@channel" → slack), pick that and mention it: "Detected gmail-style draft, formatting for Gmail."
Step 2 — Resolve source
Check for --source flag in $ARGUMENTS:
last (default) — pick the most recent assistant message in the conversation that looks like a finished draft (prose body of >40 words, not a meta reply about the skill itself). Do NOT pick a user message; the user's invocation message is not the source. If no clear draft is found, fall back to paste mode.
paste — ask the user via AskUserQuestion or plain prompt: "Paste the text you want cleaned and copied. Send it as your next message."
file:<path> — read the file at <path> with the Read tool. If it doesn't exist, abort with a clear error.
If multiple plausible drafts are in the conversation, pick the most recent one and say "Using your most recent draft (~N words). Run /clean-copy <platform> --source paste to override."
Step 3 — Clean (platform-agnostic)
Apply these passes in order. Each pass is non-destructive of meaning — only whitespace and terminal artifacts.
- Normalize line endings — convert
\r\n and \r to \n.
- Strip box-drawing artifacts — terminal renderers sometimes inject
│, ─, ┃, or trailing block characters at the right edge. Drop them.
- Detect and strip uniform leading indent (the "terminal padding" pass):
- Look at substantive lines only — non-blank lines longer than 20 characters that aren't inside a fenced code block. (This excludes short greetings like "Hi all," which often have 0 indent even when the body is indented.)
- Find the mode (most common count) of leading spaces across those substantive lines. If the mode is >0, that's the terminal-injected padding.
- Strip up to that many leading spaces from every line (lines with fewer leading spaces just lose what they have — never go negative).
- Inside fenced code blocks, do not touch indentation — code's leading whitespace is meaningful.
- Strip trailing whitespace on every line.
- Collapse runs of blank lines — 3+ blank lines → 2 blank lines (one paragraph break).
- Drop terminal padding artifacts — lines that contain only whitespace + terminal-injected glyphs become empty.
Step 4 — Reflow (optional, default on)
If --no-reflow is set OR the source contains fenced code blocks where line
breaks matter, skip this step for those sections.
For prose paragraphs, rejoin soft-wrapped lines:
- A soft wrap is detected when a line ends without sentence-ending punctuation (
., !, ?, :, ;, …) AND the next line exists, is non-empty, is not a list item (-, *, 1.), is not a heading (#), and is not blockquote (>).
- Join soft-wrapped lines with a single space.
- Preserve paragraph breaks (a blank line) verbatim.
- Preserve list item structure — each list item stays on its own line; if a list item itself has a soft-wrapped continuation, join those into the same item.
This is the most important pass for terminal output: a paragraph wrapped at 80
columns becomes one long line, which Gmail / Slack / LinkedIn will then
re-wrap correctly for their own width.
Step 5 — Format for platform
Apply platform-specific transforms after cleaning:
gmail (rich compose, but markdown is NOT rendered):
- Strip markdown emphasis:
**bold** → bold, *italic* → italic, __bold__ → bold, _italic_ → italic.
- Headings:
# H1 / ## H2 → drop the #s and surrounding hashes; keep the text on its own line. Do NOT bold (Gmail won't render).
- Bullets: keep as
- item (Gmail compose recognizes and renders these as proper bullets when you press Enter inside the editor on the next line; pasting - lines is fine).
- Code blocks: drop the fence markers
```, keep content as-is (monospace is lost, that's expected).
- Inline code:
`code` → code (drop backticks).
- Links:
[text](url) → text (url) so the URL is visible.
slack (mrkdwn — different from CommonMark):
**bold** → *bold* (single asterisk).
*italic* or _italic_ → _italic_.
~~strike~~ → ~strike~.
- Headings
# H1 → *H1* on its own line (slack has no real headings; bold is the convention).
- Bullets: keep as
- item or convert to • item per bullet-style preference. Slack renders both.
> quote lines kept as-is (slack renders them).
- Inline code and code blocks (
```) kept as-is — Slack supports them.
- Links:
[text](url) → <url|text> (slack format).
linkedin (no markdown rendering, anywhere):
- Strip all markdown: emphasis, headings, code fences, inline code backticks.
- Bullets: keep as
- item lines (LinkedIn doesn't auto-format but plain dashes are conventional).
- Links:
[text](url) → text: url (or just url on its own line if text is the same).
- Keep paragraphs short — if reflow joined a paragraph into >400 chars, split at the nearest sentence boundary near 250 chars. (LinkedIn has its own truncation.)
plain:
- Strip ALL markdown completely (emphasis, headings, code fences/inline backticks, links → just
text).
- Bullets: keep as
- item.
- Output is pure text — pastes the same way into anything.
markdown:
- No platform transforms. Markdown is preserved exactly. Only the cleaning passes (Step 3) and optional reflow (Step 4) are applied.
Step 6 — Write and copy
- Write the cleaned, formatted text to
/tmp/clean-copy-output.txt using the Write tool. Use the Write tool, not echo, to avoid quoting issues with special characters in the draft.
- Pipe through pbcopy via Bash:
pbcopy < /tmp/clean-copy-output.txt
- Verify by running
pbpaste | wc -c and confirm the byte count is non-zero and roughly matches the source.
Step 7 — Report
If preview-after-copy is true (default) OR --preview flag is set:
✓ Copied to clipboard — formatted for {platform} ({char_count} chars, {line_count} lines)
{first 12 lines of cleaned output}
...
Source: {last assistant draft / pasted / file:path}
Cleaning: stripped {N}-space indent, reflowed {M} soft wraps, dropped {K} trailing-whitespace lines
If preview is off, just:
✓ Copied for {platform} ({char_count} chars).
Step 8 — Learn
Watch for silent corrections:
- User invokes
/clean-copy (no platform), then immediately reruns with a specific platform → save that as the new default-platform.
- User adds
--no-reflow two times in a row → flip reflow-paragraphs to false.
- User runs
/clean-copy plain repeatedly when their default is gmail → consider suggesting a default change after 3 occurrences.
When something is learned, mention it once: "Noted: you've picked slack three times in a row — want me to make that the default? (/clean-copy config to change.)"
Principles
- Clipboard-first — the whole point is
pbcopy. Always end with a fresh clipboard the user can paste immediately. Never just print.
- Don't change meaning, only formatting — never rephrase, summarize, or "improve" the draft. Cleaning is whitespace + platform syntax conversion only.
- Reflow is the killer feature — terminal output's biggest sin is hard wraps at 80 columns. Reflowing soft-wrapped paragraphs into single lines is what makes Gmail and Slack render the draft correctly.
- Preserve code and lists faithfully — fenced code blocks and list structure must survive untouched. Reflow stops at code fences and list items.
- One clean source of truth — write cleaned text to
/tmp/clean-copy-output.txt first, then pbcopy from the file. Avoids quoting hell from inline shell strings with quotes / backticks / unicode.
- No surprises — if the source is ambiguous (multiple drafts in conversation, or "is this a draft?") say which one you picked and how to override. Never silently pick wrong.
1---2name: clean-copy3description: Cleans terminal-formatted text and copies it to the macOS clipboard via pbcopy, formatted for the target platform (Gmail, Slack, LinkedIn, plain, markdown). Strips uniform leading indentation, trailing whitespace, and soft-wrapped paragraphs that come from copying out of a terminal, then applies platform conventions (Slack `*bold*` vs Gmail plain prose, etc.). Use when the user wants to paste a draft from the chat into Gmail, Slack, LinkedIn, or any other tool without nightmare terminal formatting (extra whitespace, hard wraps, indented blocks) coming along.4---56# Clean Copy78Clean a draft from the conversation (or a pasted/file source) and copy it to9the clipboard, formatted for a specific platform. The goal: a paste that looks10right in Gmail / Slack / LinkedIn on the first try, with zero manual cleanup.1112## Preferences1314Before starting, use the `Read` tool to read15`~/.claude/skills/clean-copy/preferences.md`. If the file does not exist, treat16as "no preferences set" and use defaults below.1718**Defaults:**19- default-platform: `gmail`20- default-source: `last` (most recent assistant draft in the conversation)21- reflow-paragraphs: `true` (rewrap soft-wrapped paragraphs into single lines)22- bullet-style: `-` (preserve as-is)23- preview-after-copy: `true` (show first 12 lines + char count)2425## Command routing2627Check `$ARGUMENTS`:2829- **`help`** → display help, stop30- **`config`** → interactive setup, stop31- **`reset`** → delete `~/.claude/skills/clean-copy/preferences.md`, confirm, stop32- **anything else** (including empty) → run the skill3334### Help3536```37Clean Copy — Clean terminal-formatted text and copy to clipboard for a target platform3839Usage:40 /clean-copy <platform> Clean latest draft, format, pbcopy41 /clean-copy Use default platform from preferences42 /clean-copy config Set defaults (default platform, reflow, etc.)43 /clean-copy reset Clear preferences44 /clean-copy help This help4546Platforms:47 gmail Plain prose, bullets as "- ", no markdown rendering48 slack Slack mrkdwn: *bold*, _italic_, `code`, > quotes49 linkedin Plain prose, no markdown (LinkedIn strips it), short paragraphs50 plain Strip all markdown, just clean prose51 markdown Preserve markdown, only clean terminal whitespace5253Options:54 --source last Latest assistant draft in conversation (default)55 --source paste Prompt the user to paste the source text56 --source file:<path> Read source from a file57 --no-reflow Keep hard line breaks as-is (don't unwrap paragraphs)58 --preview Show full cleaned text before copying5960Examples:61 /clean-copy gmail Clean my last draft for Gmail compose62 /clean-copy slack Format for Slack mrkdwn63 /clean-copy linkedin --no-reflow Keep my line breaks (poetry / structured posts)64 /clean-copy plain --source paste I'll paste the messy text after invocation65 /clean-copy markdown --source file:/tmp/draft.md6667Current preferences:68 (loaded from preferences.md, or defaults shown above)69```7071### Config7273Use `AskUserQuestion` to collect:7475- **Q1: Default platform** — `gmail`, `slack`, `linkedin`, `plain`, or `markdown`. The platform used when `/clean-copy` is invoked with no platform arg.76- **Q2: Reflow paragraphs by default?** — `Yes` (recommended for prose) or `No` (preserve hard line breaks). Reflow joins soft-wrapped lines into single paragraphs separated by blank lines.77- **Q3: Bullet style** — `-` (keep as written), `•` (convert to bullet glyph), or `*` (asterisk). Affects how list items render after cleaning.78- **Q4: Preview after copy?** — `Yes` (show first 12 lines + char count) or `No` (silent except for "Copied").7980Save to `~/.claude/skills/clean-copy/preferences.md` in this format:8182```markdown83# /clean-copy preferences84Updated: <date>8586## Defaults87- default-platform: gmail88- reflow-paragraphs: true89- bullet-style: -90- preview-after-copy: true9192## Learned93- (patterns observed silently, e.g., "user always picks slack on weekdays mornings")94```9596### Reset9798Delete `~/.claude/skills/clean-copy/preferences.md` and confirm:99"Preferences cleared. Using defaults."100101## First-time detection102103If no preferences file exists, show:104105> First time using /clean-copy? Run `/clean-copy config` to set defaults, or106> just continue — defaults are gmail / reflow on / dash bullets.107108Then proceed.109110## Workflow111112### Step 1 — Resolve platform113114Parse `$ARGUMENTS`:115- If a platform keyword (`gmail`, `slack`, `linkedin`, `plain`, `markdown`) is present, use it.116- Otherwise, fall back to `default-platform` from preferences (or `gmail`).117- If still unclear AND the source text strongly hints (e.g., starts with "Hi all," → email; starts with "@channel" → slack), pick that and mention it: "Detected gmail-style draft, formatting for Gmail."118119### Step 2 — Resolve source120121Check for `--source` flag in `$ARGUMENTS`:122123- **`last`** (default) — pick the most recent **assistant** message in the conversation that looks like a finished draft (prose body of >40 words, not a meta reply about the skill itself). Do NOT pick a user message; the user's invocation message is not the source. If no clear draft is found, fall back to `paste` mode.124- **`paste`** — ask the user via AskUserQuestion or plain prompt: "Paste the text you want cleaned and copied. Send it as your next message."125- **`file:<path>`** — read the file at `<path>` with the Read tool. If it doesn't exist, abort with a clear error.126127If multiple plausible drafts are in the conversation, pick the most recent one and say "Using your most recent draft (~N words). Run `/clean-copy <platform> --source paste` to override."128129### Step 3 — Clean (platform-agnostic)130131Apply these passes in order. Each pass is non-destructive of meaning — only whitespace and terminal artifacts.1321331. **Normalize line endings** — convert `\r\n` and `\r` to `\n`.1342. **Strip box-drawing artifacts** — terminal renderers sometimes inject `│`, `─`, `┃`, or trailing block characters at the right edge. Drop them.1353. **Detect and strip uniform leading indent** (the "terminal padding" pass):136 - Look at substantive lines only — non-blank lines longer than 20 characters that aren't inside a fenced code block. (This excludes short greetings like "Hi all," which often have 0 indent even when the body is indented.)137 - Find the **mode** (most common count) of leading spaces across those substantive lines. If the mode is >0, that's the terminal-injected padding.138 - Strip up to that many leading spaces from every line (lines with fewer leading spaces just lose what they have — never go negative).139 - Inside fenced code blocks, do not touch indentation — code's leading whitespace is meaningful.1404. **Strip trailing whitespace** on every line.1415. **Collapse runs of blank lines** — 3+ blank lines → 2 blank lines (one paragraph break).1426. **Drop terminal padding artifacts** — lines that contain only whitespace + terminal-injected glyphs become empty.143144### Step 4 — Reflow (optional, default on)145146If `--no-reflow` is set OR the source contains fenced code blocks where line147breaks matter, **skip this step for those sections**.148149For prose paragraphs, **rejoin soft-wrapped lines**:150151- A soft wrap is detected when a line ends without sentence-ending punctuation (`.`, `!`, `?`, `:`, `;`, `…`) AND the next line exists, is non-empty, is not a list item (`-`, `*`, `1.`), is not a heading (`#`), and is not blockquote (`>`).152- Join soft-wrapped lines with a single space.153- Preserve paragraph breaks (a blank line) verbatim.154- Preserve list item structure — each list item stays on its own line; if a list item itself has a soft-wrapped continuation, join those into the same item.155156This is the most important pass for terminal output: a paragraph wrapped at 80157columns becomes one long line, which Gmail / Slack / LinkedIn will then158re-wrap correctly for their own width.159160### Step 5 — Format for platform161162Apply platform-specific transforms after cleaning:163164**`gmail`** (rich compose, but markdown is NOT rendered):165- Strip markdown emphasis: `**bold**` → `bold`, `*italic*` → `italic`, `__bold__` → `bold`, `_italic_` → `italic`.166- Headings: `# H1` / `## H2` → drop the `#`s and surrounding hashes; keep the text on its own line. Do NOT bold (Gmail won't render).167- Bullets: keep as `- item` (Gmail compose recognizes and renders these as proper bullets when you press Enter inside the editor on the next line; pasting `- ` lines is fine).168- Code blocks: drop the fence markers ` ``` `, keep content as-is (monospace is lost, that's expected).169- Inline code: `` `code` `` → `code` (drop backticks).170- Links: `[text](url)` → `text (url)` so the URL is visible.171172**`slack`** (mrkdwn — different from CommonMark):173- `**bold**` → `*bold*` (single asterisk).174- `*italic*` or `_italic_` → `_italic_`.175- `~~strike~~` → `~strike~`.176- Headings `# H1` → `*H1*` on its own line (slack has no real headings; bold is the convention).177- Bullets: keep as `- item` or convert to `• item` per `bullet-style` preference. Slack renders both.178- `> quote` lines kept as-is (slack renders them).179- Inline code and code blocks (` ``` `) kept as-is — Slack supports them.180- Links: `[text](url)` → `<url|text>` (slack format).181182**`linkedin`** (no markdown rendering, anywhere):183- Strip all markdown: emphasis, headings, code fences, inline code backticks.184- Bullets: keep as `- item` lines (LinkedIn doesn't auto-format but plain dashes are conventional).185- Links: `[text](url)` → `text: url` (or just `url` on its own line if `text` is the same).186- Keep paragraphs short — if reflow joined a paragraph into >400 chars, split at the nearest sentence boundary near 250 chars. (LinkedIn has its own truncation.)187188**`plain`**:189- Strip ALL markdown completely (emphasis, headings, code fences/inline backticks, links → just `text`).190- Bullets: keep as `- item`.191- Output is pure text — pastes the same way into anything.192193**`markdown`**:194- No platform transforms. Markdown is preserved exactly. Only the cleaning passes (Step 3) and optional reflow (Step 4) are applied.195196### Step 6 — Write and copy1971981. Write the cleaned, formatted text to `/tmp/clean-copy-output.txt` using the `Write` tool. Use the `Write` tool, not `echo`, to avoid quoting issues with special characters in the draft.1992. Pipe through pbcopy via Bash: `pbcopy < /tmp/clean-copy-output.txt`2003. Verify by running `pbpaste | wc -c` and confirm the byte count is non-zero and roughly matches the source.201202### Step 7 — Report203204If `preview-after-copy` is true (default) OR `--preview` flag is set:205206> ✓ Copied to clipboard — formatted for **{platform}** ({char_count} chars, {line_count} lines)207>208> ```209> {first 12 lines of cleaned output}210> ...211> ```212>213> Source: {last assistant draft / pasted / file:path}214> Cleaning: stripped {N}-space indent, reflowed {M} soft wraps, dropped {K} trailing-whitespace lines215216If preview is off, just:217218> ✓ Copied for {platform} ({char_count} chars).219220### Step 8 — Learn221222Watch for silent corrections:223224- User invokes `/clean-copy` (no platform), then immediately reruns with a specific platform → save that as the new `default-platform`.225- User adds `--no-reflow` two times in a row → flip `reflow-paragraphs` to `false`.226- User runs `/clean-copy plain` repeatedly when their default is `gmail` → consider suggesting a default change after 3 occurrences.227228When something is learned, mention it once: "Noted: you've picked slack three times in a row — want me to make that the default? (`/clean-copy config` to change.)"229230## Principles231232- **Clipboard-first** — the whole point is `pbcopy`. Always end with a fresh clipboard the user can paste immediately. Never just print.233- **Don't change meaning, only formatting** — never rephrase, summarize, or "improve" the draft. Cleaning is whitespace + platform syntax conversion only.234- **Reflow is the killer feature** — terminal output's biggest sin is hard wraps at 80 columns. Reflowing soft-wrapped paragraphs into single lines is what makes Gmail and Slack render the draft correctly.235- **Preserve code and lists faithfully** — fenced code blocks and list structure must survive untouched. Reflow stops at code fences and list items.236- **One clean source of truth** — write cleaned text to `/tmp/clean-copy-output.txt` first, then pbcopy from the file. Avoids quoting hell from inline shell strings with quotes / backticks / unicode.237- **No surprises** — if the source is ambiguous (multiple drafts in conversation, or "is this a draft?") say which one you picked and how to override. Never silently pick wrong.