---
name: preview-markdown
description: "Present a markdown file to the user in a separate terminal pane with rich rendering, instead of pasting its content into the conversation. Use when writing a tmp markdown doc for a long explanation, plan, report, or complex point, or when the user says \"preview this\", \"show me the doc\", \"open it in a pane\", or asks to view a markdown file alongside the terminal. Works in herdr, cmux, Ghostty (≥1.3), and iTerm2; falls back gracefully elsewhere."
---

# Previewing markdown files in a separate pane

When presenting a markdown doc to the user — a long explanation, plan, report, or anything written to a tmp file — open it in a split pane rather than pasting the content into the conversation.

## 1. Detect the terminal and viewer

One command discovers the terminal and whether `glow` is installed:

```sh
echo HERDR_ENV=$HERDR_ENV CMUX_WORKSPACE_ID=$CMUX_WORKSPACE_ID TERM_PROGRAM=$TERM_PROGRAM TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION GLOW=$(command -v glow || echo missing)
```

Check in priority order — multiplexers run *inside* a terminal, so they must win over `TERM_PROGRAM`:

1. `HERDR_ENV` set → herdr
2. `CMUX_WORKSPACE_ID` set → cmux
3. `TERM_PROGRAM=ghostty` and version ≥ 1.3.0 → Ghostty (AppleScript)
4. `TERM_PROGRAM=iTerm.app` → iTerm2 (AppleScript)
5. None of the above → no pane support; give the file path and summarise inline instead

Viewer (matters for every branch except cmux, which renders markdown itself):

- `GLOW` is a path → viewer is `glow -t` (interactive TUI, live-reloads on file changes)
- `missing` → viewer is `less` (plain text, no live-reload — tell the user to press `R` in the pane after edits). Also advise the user that installing glow gives rendered, live-reloading previews, showing the command: `brew install glow`. Do **not** install it (or offer to) unless they explicitly ask you to

## 2. Open the preview

### cmux

One command — opens the doc in a read-only markdown panel split to the right of the focused surface:

```sh
cmux markdown open <path>
```

Then:

- The output is `OK surface=surface:N pane=pane:N path=...` — capture the surface id for cleanup
- The panel live-reloads when the file changes on disk (no viewer needed — cmux renders markdown itself)
- For routing options (`--workspace`, `--surface`, `--window`) or troubleshooting, load the `cmux-markdown` skill

### Ghostty (≥ 1.3.0)

Split right of the focused terminal with the viewer as the new surface's command — returns the new terminal's id (a UUID):

```sh
osascript <<EOF
tell application "Ghostty"
    set cfg to new surface configuration
    set command of cfg to "<viewer> '$DOC_PATH'"
    set newTerm to split (focused terminal of selected tab of front window) direction right with configuration cfg
    return id of newTerm
end tell
EOF
```

- First use triggers a macOS Automation (TCC) prompt — if it fails with a permissions error, tell the user to approve it (or it's disabled via `macos-applescript = false` in their Ghostty config)
- The AppleScript API is a **preview feature** in 1.3 — expect breaking changes in 1.4
- There's no way to read the pane back to verify; trust a clean exit

### iTerm2

Split side-by-side ("vertically" = vertical divider) with the viewer as the session command — returns the new session's id:

```sh
osascript <<EOF
tell application "iTerm2"
    tell current session of current tab of current window
        return id of (split vertically with default profile command "<viewer> '$DOC_PATH'")
    end tell
end tell
EOF
```

- Same one-time TCC prompt as Ghostty
- The pane may auto-close when the viewer exits (profile-dependent "close on exit")

In every branch, substitute `<viewer>` with the one detected in step 1 (`glow -t` or `less`), and report the captured pane/surface/terminal/session id so it can be closed later. With `glow -t`, file edits live-reload in the pane automatically — never re-open the pane after editing the doc.

### herdr

Split a new pane to the right of the focused pane, capture its id, then run the viewer in it:

```sh
DOC_PATH=<path>
PANE_ID=$(herdr pane split "$(herdr pane list | jq -r '.result.panes[] | select(.focused) | .pane_id')" --direction right --no-focus | jq -r '.result.pane.pane_id')
herdr pane run "$PANE_ID" "<viewer> '$DOC_PATH'" && echo "$PANE_ID"
```

- Run all three lines in **one** shell call (variables don't survive across calls)
- Capture the id from the split response as above — do **not** infer it from `herdr pane list`; its ordering doesn't reflect creation order
- Verify it rendered: `herdr pane read $PANE_ID | head`

## 3. Clean up

When the user is finished with the preview, close the pane (the tmp file can stay unless asked):

```sh
# herdr
herdr pane close <pane_id>

# cmux — use the surface id captured from `cmux markdown open`
cmux close-surface --surface <surface_id>

# Ghostty — use the terminal id (UUID) returned by the split; quotes required
osascript -e 'tell application "Ghostty" to close (first terminal whose id is "<terminal_id>")'

# iTerm2 — use the session id returned by the split
osascript -e 'tell application "iTerm2" to close (first session of current tab of current window whose id is "<session_id>")'
```
