Skip to content

TTigger/ccpop

Repository files navigation

ccpop

Near-zero-token Claude Code helpers. Inside a Claude Code session, run !ccpop view <md> / !ccpop ide [path] / !ccpop dev / !ccpop log to pop a rendered markdown file into a window, open your editor, background-start a dev server, or review this session's prompts on a timeline — without leaving the conversation and without spending model tokens on the work. Pure Node, zero runtime dependencies, cross-platform (Windows / macOS / Linux / WSL).

npx ccpop install

Then, in Claude Code:

!ccpop view docs/prd.md     # render Claude's markdown into a popup window
!ccpop ide src/auth.ts:42   # open your editor at a line
!ccpop dev                  # start the dev server, wait until ready, open the browser
!ccpop log                  # review this session's prompts + what ran, in a timeline window

Demo

Each command is a single !-prefixed line and prints exactly one line back — and that one line is the only thing that enters the model's context next turn (hence near-zero, see below):

In Claude Code One-line result
!ccpop view docs/spec.md popped docs/spec.md (app window)
!ccpop ide src/auth.ts:42 opened src/auth.ts:42 in code
!ccpop dev dev running (pid 4821) → http://localhost:5173
!ccpop log popped log of 23 prompts (app window)

GIFs for the two highlight commands (view and log) are embedded in their sections below; ide and dev simply hand off to your editor / dev server, so they're shown by example above.

Degraded environments stay usable: no Chromium → a normal browser tab; headless/SSH → it prints the file:// path. Nobody is locked out.

Why this exists

Claude Code is a TUI — it owns the terminal and can't pop a GUI inside itself. So when Claude writes a 300-line spec, or edits your frontend, you're stuck reading raw markdown in the transcript or asking Claude to do fiddly local chores (which is slow and spends tokens). ccpop moves those GUI chores to the ! prefix, which Claude Code runs locally before your message reaches the model.

Why "near-zero" tokens (not zero)

The ! trigger itself costs no model tokens — the model never sees the command. But a command's stdout is inserted into the transcript, so it's read as input tokens on the next turn. That's why every ccpop command prints exactly one short line on success — the minimal-output rule is the whole point, not a nicety. Net effect: ccpop view puts the document in your browser (entirely outside the session) and adds one line to context — far cheaper than having Claude read/render the file (thousands of tokens).

Commands

ccpop view <file.md> — pop markdown into a window

ccpop view demo

Renders markdown to HTML and opens it. Why a popup, not just a tab: the goal is "glance and close." Open method degrades gracefully in three tiers — nobody is locked out:

Tier When Result
app a Chromium-family browser (Chrome/Edge/Brave) is found a chromeless app window (no tabs/URL bar)
tab only Firefox/Safari/other a normal browser tab (identical content)
print headless / SSH / CI prints the file:// path to open manually

Raw HTML is escaped and dangerous link schemes are neutralized (safe to open untrusted AI-generated markdown). ```mermaid blocks render via a single fixed-origin CDN script. Flags: --window app|tab|auto, --theme light|dark, --print (terminal ANSI).

ccpop log [keyword] — review this session in a timeline window

ccpop log demo

Pops a read-only timeline of the current folder's latest Claude Code session: every prompt with what ran (Edits / Bash / …, noise folded) and a one-line result, plus a clickable right-side node rail to jump between prompts. Optional keyword filters to matching turns (!ccpop log table).

Why: reviewing "what did I ask, and what happened" used to mean scrolling the terminal until the prompt was lost. Built-in /Ctrl+R only find your prompt text; /rewind changes state. log is purely for reading — it reads the local session JSONL and never edits code or conversation. And because the Claude Code TUI can't host a persistent timeline widget, log pops it out into a window (where a clickable node rail is trivial). Harness noise (tool results, system reminders, <task-notification>, interrupt markers) is filtered so only real prompts become nodes.

ccpop ide [path] — open your editor

Editor is chosen by: CCK_EDITORconfig.editor → a running editor (process detection) → $VISUAL$EDITORcode. Use <file>:<line> to jump to a line (VS Code family uses code -g). Terminal editors (vim/nano/…) inherit the TTY; GUI editors detach. Windows UNC paths are refused (NTLM-leak guard). Override once with --with <editor>.

ccpop dev — background dev server, opened when ready

Spawns your package.json dev script detached, waits until the server is actually listening (parses the real bound port from its output — handles Vite/Next bumping 3000→3001), then opens the browser and returns immediately. If a known port is already listening it just opens it (no restart).

  • --cmd "<command>" — escape hatch for non-JS / monorepo (uvicorn app:app, rails s, turbo dev, nx serve web)
  • --port <n> --ready tcp|http --timeout <ms> --no-open
  • ccpop dev --status — show the running pid/port · ccpop dev --stop — stop it

Why one-shot, not a status bar: dev prints one line and returns; it does not persist a "running on :5173" indicator. That's a status-line concern (the sibling claude-status project's job). A future integration can have claude-status read ccpop's state file and show 🟢 dev:5173.

Configuration

~/.claude/ccpop.config.json (deep-merge — only changed keys are written):

Key Default Meaning
editor null preferred editor; null → detection chain
dev.script / dev.cmd dev / null npm script / arbitrary start command
dev.ready / dev.timeoutMs tcp / 20000 readiness check & wait cap
view.window auto auto | app | tab
view.theme / view.mermaid auto / true rendered theme / mermaid on
shortAliases false enable !view / !ide / !dev

ccpop config set/get/list/reset.

How it compares

ccpop grip go-grip markview IDE preview npx serve
Renders md to a window
Zero deps / offline ❌ (Python+GitHub API)
Cross-platform popup ❌ macOS only
! near-zero-token in-session ❌ (MCP, spends tokens)
Also opens IDE + dev server n/a

Limitations (honest)

  • Markdown is a pragmatic subset, not GitHub-grade (math/live-reload not yet supported; mermaid is).
  • dev auto-port detection targets a single package.json project; for non-JS / monorepo use --cmd + --port.
  • The app-mode popup needs a Chromium-family browser; otherwise it falls back to a normal tab.
  • Zero-dependency is deliberate — but the cross-platform open path is carefully hardened (Windows quoting, WSL, headless fallback, error-before-unref) where a naive version would break.

Security

See SECURITY.md. ccpop reads only the file you pass to view, reads/writes ~/.claude/ccpop.config.json and ccpop.state.json, spawns your editor / npm / the system opener, renders markdown locally (raw HTML escaped), and sends nothing over the network (except the optional mermaid CDN script in rendered pages).

License

MIT

About

Near-zero-token Claude Code helpers. One !-prefixed command to pop Claude's markdown into a window, open your IDE at a line, background-start a dev server, or review your session on a timeline — without leaving the chat or spending model tokens. Pure Node, zero dependencies, cross-platform.

Topics

Resources

License

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors