---
slug: "bigboss2063-pi-clip"
source_type: "readme"
source_url: "https://cdn.jsdelivr.net/gh/bigboss2063/pi-clip@main/README.md"
repo: "https://github.com/bigboss2063/pi-clip"
source_file: "README.md"
branch: "main"
---
<p align="center">
  <strong>pi-clip</strong>
</p>

<p align="center">
  A <a href="https://github.com/earendil-works/pi-mono">pi</a> extension for copying assistant output to your clipboard — granularly.<br>
  Code blocks, tables (cell / row / column / whole), lists, blockquotes, and arbitrary line ranges — without fighting terminal selection.
</p>

## Why

pi already ships `/copy` and `Ctrl+X` to copy the **whole** last assistant message. `pi-clip` complements that: pick a single code block, navigate a table and copy just a cell, a row, a column, or the whole table, grab a list or blockquote, select any line range, or fall back to the full raw markdown.

Clipboard writes go through pi's built-in `copyToClipboard`, so it works across the native OS clipboard, OSC 52 (SSH/mosh), Wayland, Termux, and WSL — no `pbcopy`/`xclip`/`clip` plumbing required.

## Install

```bash
# From npm
pi install npm:@bigboss2063/pi-clip

# From git
pi install git:github.com/bigboss2063/pi-clip
```

Or try without installing:

```bash
pi -e npm:@bigboss2063/pi-clip
```

## Usage

All commands are accessed via `/clip`:

| Command | Description |
|---------|-------------|
| `/clip` | Searchable picker — lists every copyable block from the last response |
| `/clip code` | Pick a code block (copies directly if there's only one) |
| `/clip list` | Pick a list (copies directly if there's only one) |
| `/clip table` | Pick a table, then open the cell grid |
| `/clip lines` | Visual line-range selector over the last response |
| `/clip lines N-M` | Copy lines `N` through `M` directly (also `N`, `N,M`) |
| `/clip all` | Copy the full conversation (user + assistant) as markdown |
| `Ctrl+Shift+C` | Same as `/clip` |

### How `/clip` works

The picker lists, in order, each tagged with its type:

- `[code]` **Code blocks** — each fenced block, without the fences
- `[table]` **Tables** — opens a grid (see below)
- `[list]` **Lists** — ordered, unordered, and nested lists (raw markdown)
- `[quote]` **Blockquotes** — `>` blocks (raw markdown)
- `[full]` **Full response** — the raw markdown, as a fallback entry

Prose, headings, and horizontal rules are intentionally **not** split into blocks — their boundaries are too ambiguous to guess. For those, use `/clip lines` to select an exact range yourself.

**Type to filter.** As you type, the list narrows by inclusive match across the type badge, label, and first-line description — e.g. type `list` to see only lists, or `install` to see only blocks mentioning install. `⌫` clears one char, `Ctrl+U` clears the filter, `Home`/`End` jump to the first/last match.

**Live preview.** Below the list, the picker shows the first few lines of the currently-highlighted block's actual content, updating as you move with `↑`/`↓` — so a one-line badge like `Code block [ts]` won't get confused for another, since you can read the real code/rows/listing underneath before pressing `enter`.

If the last response has no structural blocks (no code, tables, lists, or quotes), `/clip` copies the whole response immediately without opening a picker. To copy part of a prose response, use `/clip lines`.

Copied text is raw markdown (so `**bold**`, `-` list markers, `>` quote markers are preserved). Table cells copied from the grid are cleaned — no pipes, padding, or inline formatting.

### Table grid

Selecting a table opens an interactive grid. Arrow through cells, then:

| Key | Action |
|-----|--------|
| `enter` | Copy the highlighted cell value |
| `r` | Copy the entire row (tab-separated) |
| `c` | Copy the entire column (newline-separated) |
| `a` | Copy the full table (raw markdown) |
| `esc` | Go back to the picker |

Cell values are cleaned — no pipes, no padding, no inline markdown formatting. Column widths are display-width aware, so CJK/wide characters align correctly.

### Picker keys

| Key | Action |
|-----|--------|
| `↑` / `↓` | Move selection (wraps around) |
| Type text | Filter blocks by type badge, label, or content |
| `⌫` (Backspace) | Delete one filter character |
| `Ctrl+U` | Clear the whole filter |
| `Home` / `End` | Jump to first / last match |
| `enter` | Copy the selected block (tables open the grid) |
| `esc` | Cancel |

### `/clip lines` — visual line selection

For prose that doesn't split into neat blocks (headings, paragraphs, mixed content), `/clip lines` opens a window showing every line of the last response with line numbers. Mark a range and copy exactly that:

| Key | Action |
|-----|--------|
| `↑` / `↓` | Move the cursor (wraps around) |
| `space` | Set the anchor; as you move, the highlight extends from anchor to cursor in real time. Press on the anchor line again to cancel, or on another line to move the anchor there |
| `Home` / `End` | Jump to first / last line |
| `enter` | Copy the highlighted lines (anchor..cursor), or just the cursor line if no anchor is set |
| `esc` | Cancel |

Skip the window with a direct range: `/clip lines 3-5`, `/clip lines 3,5`, or `/clip lines 3` (1-based, inclusive).

## Shortcut

The default shortcut is `Ctrl+Shift+C`. Override it without any extra dependencies:

```bash
# e.g. use Alt+C instead
export PI_CLIP_SHORTCUT=alt+c
```

> **Note:** pi's `keybindings.json` remaps *built-in* action ids (like `app.message.copy` for `Ctrl+X`), not shortcuts registered by extensions. `PI_CLIP_SHORTCUT` is the zero-dependency way to rebind `pi-clip`'s shortcut. The `/clip` command itself is always available regardless of the shortcut.

## Requirements

- [pi](https://github.com/earendil-works/pi-mono) coding agent (uses `@earendil-works/pi-coding-agent` `copyToClipboard`)

## Development

No build step — pi loads TypeScript directly via jiti. Edit `extensions/index.ts` and test with:

```bash
pi -e ./extensions/index.ts
```

Optional typechecking:

```bash
npm install
npm run typecheck
```

## License

MIT
