https://github.com/brianruggieri/claude-code-pulse
Dynamic terminal titles for Claude Code CLI — see what each agent is doing at a glance
https://github.com/brianruggieri/claude-code-pulse
ai-tools bash claude claude-code cli developer-tools iterm2 pane-titles productivity terminal terminal-title tmux
Last synced: 4 months ago
JSON representation
Dynamic terminal titles for Claude Code CLI — see what each agent is doing at a glance
- Host: GitHub
- URL: https://github.com/brianruggieri/claude-code-pulse
- Owner: brianruggieri
- License: mit
- Created: 2026-03-01T18:16:46.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-03-05T05:53:53.000Z (4 months ago)
- Last Synced: 2026-03-05T06:33:55.588Z (4 months ago)
- Topics: ai-tools, bash, claude, claude-code, cli, developer-tools, iterm2, pane-titles, productivity, terminal, terminal-title, tmux
- Language: Shell
- Size: 11.4 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
Awesome Lists containing this project
README
# **C**laude **C**ode **P**ulse `ccp`
[](https://github.com/brianruggieri/claude-code-pulse/actions/workflows/ci.yml)
[](https://opensource.org/licenses/MIT)
[](https://www.apple.com/macos/)
[](https://www.gnu.org/software/bash/)
`ccp` wraps the Claude Code CLI so your terminal pane titles show what Claude is actually doing. Just run `ccp` and it reads your git branch, figures out a title, and keeps the pane updated in real time as Claude edits, builds, tests, and commits.

### Before ccp
Generic titles. You have no idea what's happening in each pane.

### With ccp
Each pane title shows the project, branch, current task, and live status — independently updated as Claude works.

> **iTerm2 note:** ccp writes to OSC 1 (the per-pane icon title) so every split pane gets its own independent live title. No two panes share a title bar. See [Terminal Support](#terminal-support) for how other terminals compare.
```
my-app (main) | Fix auth bug | ✏️ Editing
my-app (main) | Fix auth bug | 🧪 Testing
my-app (main) | Fix auth bug | ✅ Tests passed
my-app (main) | Fix auth bug | 💾 Committed
my-app (main) | Fix auth bug | ☕ Recharging
```
## Features
- **Auto-title from git**. `ccp` reads the current branch and generates a clean title automatically. `pr/89-fix-auth` becomes `PR #89 - fix auth`, `feature/new-login` becomes `Feature: new login`, and so on.
- **Live status updates**. The title updates as Claude works. Editing, testing, building, pushing, all of it. Branch name refreshes live too — if Claude runs `git checkout`, the title reflects the new branch within one polling cycle.
- **Idle phrase cycling**. 10 different idle phrases cycle on each conversation turn so you can see at a glance whether a pane just went idle or has been sitting for a while.
- **Welcome on startup**. Shows `👋 Welcome back, ` when you open a pane, before you've typed anything.
- **Priority-based display**. Errors always show first. Completions (tests passed, committed) immediately override whatever else is showing.
- **Hook-based**. Uses Claude Code's own hook events for status. No output parsing, no regex, just structured JSON.
- **Session tracking**. Save and re-open sessions by title with `--goto`.
- **AI task summaries**. `--ai-context` refines your prompt into a clean 3-5 word label shown in the title. Two strategies: `haiku` (separate claude-haiku call, fully invisible) or `inline` (zero extra API calls, uses the already-outgoing session). Both are opt-in.
- **Tested on iTerm2, Terminal.app, and tmux**. Detection logic for WezTerm, Ghostty, and Kitty is included but unverified.
- **Full Claude passthrough**. Every Claude Code flag works exactly as expected.
## Quick Start
```bash
# Install
git clone https://github.com/brianruggieri/claude-code-pulse.git
cd claude-code-pulse
./install.sh
# Auto-detect title from your current branch
ccp
# Or give it a custom title
ccp "fixing the login bug"
# Quick formats
ccp --pr 89 "Fix auth bug"
ccp --feature "New login flow"
ccp --bug "Fix crash on startup"
# Go back to a previous session
ccp --goto "PR #89"
# Claude flags pass straight through
ccp -c # resume last conversation
ccp --model opus "My task"
ccp --permission-mode bypassPermissions
# AI-summarized task labels in the title (opt-in, uses your subscription)
ccp --ai-context "Fix the auth bug"
# Inline strategy — zero extra API calls (one echo visible per session)
ccp --ai-context --ai-context-strategy inline "Fix the auth bug"
# Debug mode — structured JSONL logging + live Pulse Monitor (iTerm2: auto-opens in split pane)
ccp --debug-ccp "Fix the auth bug"
```
> See [AI Task Summaries](#ai-task-summaries) for the `--ai-context` flag and strategy options.
## Installation
**Prerequisites:**
- macOS Sonoma or later
- bash 3.2+ (ships with macOS)
- jq: `brew install jq`
- Claude Code CLI: [claude.ai](https://claude.ai)
```bash
git clone https://github.com/brianruggieri/claude-code-pulse.git
cd claude-code-pulse
./install.sh
```
Installs to `~/.local/share/ccp/` and symlinks `~/bin/ccp`.
## Usage
### Auto-title (the default)
Run `ccp` with no arguments. It reads the branch name and builds a title:
| Branch | Title |
|--------|-------|
| `pr/89-fix-auth` | `PR #89 - fix auth` |
| `pull/89-fix-auth` | `PR #89 - fix auth` |
| `issue/12-refactor-api` | `Issue #12 - refactor api` |
| `fix/12-crash` | `Issue #12 - crash` |
| `bug/12-crash` | `Issue #12 - crash` |
| `feature/new-login` | `Feature: new login` |
| `main` or anything else | `project-name (branch)` |
No git repo? Falls back to the current directory name.
### Custom title
```bash
ccp "fixing the login bug"
```
### Quick format helpers
```bash
ccp --pr 89 "Fix memory leak" # PR #89 - Fix memory leak
ccp --issue 12 "Refactor API" # Issue #12 - Refactor API
ccp --feature "OAuth integration" # Feature: OAuth integration
ccp --bug "Login crash on iOS" # Bug: Login crash on iOS
ccp --refactor "Clean up auth" # Refactor: Clean up auth
```
### Working directory
```bash
ccp "PR #89" ~/projects/my-app
```
`ccp` will `cd` into that directory before launching Claude.
## Title Lifecycle
```
Startup my-app (main) | 👋 Welcome back, Brian
-> type my-app (main) | fix the login bug | 💤 Idle
-> reading my-app (main) | fix the login bug | 📖 Reading
-> editing my-app (main) | fix the login bug | ✏️ Editing
-> testing my-app (main) | fix the login bug | 🧪 Testing
-> passed my-app (main) | fix the login bug | ✅ Tests passed
-> commit my-app (main) | fix the login bug | 💾 Committed
-> pushing my-app (main) | fix the login bug | ⬆️ Pushing
-> idle my-app (main) | fix the login bug | ☕ Recharging
```
**Startup.** Before you send anything, the pane shows the welcome message.
**Task summary.** Appears as soon as you send a message. Shows the first words of your prompt right away, then updates to a cleaner 3-5 word summary if `--ai-context` is on.
**Status.** Updates based on what Claude is actually doing. When Claude finishes, the status clears to an idle phrase.
**Idle phrases.** Each time Claude finishes responding, the idle phrase advances. After seeing `☕ Recharging` you know the pane just went idle. After seeing `🫡 Standing by` you know it's been a while.
`💤 Idle` · `☕ Recharging` · `🧘 Centering` · `🎯 Ready` · `🫡 Standing by` · `💡 Listening` · `🌿 At rest` · `👀 Watching` · `🌊 Drifting` · `✨ Floating`
## Status Reference
### Both profiles
| Icon | Status | What triggered it | Priority |
|------|--------|-------------------|----------|
| 🐛 | Error | Any tool fails | 100 |
| ❌ | Tests failed | Test command exits non-zero | 90 |
| ⏸️ | Awaiting approval | Permission request | 88 |
| 🙋 | Input needed | Notification requires action | 85 |
| 🔨 | Building | webpack, tsc, cargo build, make, gradle, etc. | 80 |
| 🧪 | Testing | jest, vitest, pytest, mocha, rspec, go test, etc. | 80 |
| 📦 | Installing | npm install, pip install, yarn add, cargo add | 80 |
| ⬆️ | Pushing | git push | 75 |
| ⬇️ | Pulling | git pull | 75 |
| 🔀 | Merging | git merge | 75 |
| 🤖 | Delegating | Task or Agent tool use | 70 |
| 🐳 | Docker | Any docker command | 70 |
| ✏️ | Editing | Edit, Write, MultiEdit, NotebookEdit | 65 |
| ✅ | Tests passed | `N tests passed` in Bash output | 60 |
| 💾 | Committed | git commit output | 60 |
| 🏁 | Completed | TaskCompleted or terminal SessionEnd | 60 |
| 📖 | Reading | Read, Glob, Grep | 55 |
| 🌐 | Browsing | WebFetch, WebSearch | 55 |
| 🖥️ | Running | Any other Bash command | 55 |
| 🔧 | *ToolName* | Unknown tool (shows the actual tool name) | 50 |
Higher priority always wins. The one exception: completion events (✅, 💾, 🏁) override any active status immediately, regardless of priority.
### Verbose-only
With `--status-profile verbose`, lifecycle events also show up:
| Icon | Status | Event | Priority |
|------|--------|-------|----------|
| 🚀 | Session started | SessionStart | 52 |
| 🧠 | Compacting | PreCompact | 52 |
| 🤖 | Subagent started | SubagentStart | 52 |
| ✅ | Subagent finished | SubagentStop | 52 |
| 👥 | Teammate idle | TeammateIdle | 52 |
| ⚙️ | Config changed | ConfigChange | 52 |
| 🌿 | Worktree created | WorktreeCreate | 52 |
| 🧹 | Worktree removed | WorktreeRemove | 52 |
| 🔔 | *EventName* | Any other event | 52 |
## Status Profiles
```bash
# Default: high-signal statuses only
ccp "PR #89"
# All events including lifecycle, subagents, worktrees, config
ccp --status-profile verbose "PR #89"
# Set a default in your shell
export CCP_STATUS_PROFILE=verbose
```
Precedence: `--status-profile` flag > `CCP_STATUS_PROFILE` env var > `quiet` default.
## AI Task Summaries
With `--ai-context`, ccp distills your prompt into a clean 3-5 word label shown in the title. Without it, the first words of your prompt show as-is.
Two strategies are available:
| | `haiku` (default) | `inline` |
|---|---|---|
| Extra API calls | 1 per prompt | 0 |
| Visible to user | No | One `echo` per session |
| Summary context | Prompt text only | Full codebase + history |
| Reliability | High | Model-dependent |
```bash
# Haiku strategy (default) — invisible, uses your subscription
ccp --ai-context "PR #89 - Fix auth"
# Inline strategy — zero extra API calls, one echo visible per session
ccp --ai-context --ai-context-strategy inline "PR #89 - Fix auth"
# Always on, via environment variables
export CCP_ENABLE_AI_CONTEXT=true
export CCP_AI_CONTEXT_STRATEGY=inline # optional, default is haiku
```
See [docs/ai-context.md](docs/ai-context.md) for the full trade-off analysis.
## Claude Flag Passthrough
Every Claude Code flag passes straight through to `claude`:
```bash
ccp -c # resume last conversation
ccp -r abc-123 # resume by session ID
ccp --model opus "My task"
ccp --model claude-sonnet-4-6 "My task"
ccp --permission-mode bypassPermissions
ccp --permission-mode acceptEdits
ccp --effort high "Big refactor"
ccp -w feat-login "Fix login" # create git worktree
ccp --system-prompt "Be terse" "My task"
ccp --append-system-prompt "Use TypeScript"
ccp --add-dir ~/shared/lib
ccp --allowedTools Bash Edit Read
ccp --mcp-config ./mcp.json
ccp --dangerously-skip-permissions
ccp "My task" -- --resume abc123 # explicit passthrough with --
```
Any unrecognized `-*` flag is also forwarded, so new Claude flags just work.
### Full forwarded flag list
**No value:**
`-c` / `--continue`, `--dangerously-skip-permissions`, `--allow-dangerously-skip-permissions`, `--verbose`, `--ide`, `--no-ide`, `--fork-session`, `--chrome`, `--no-chrome`, `--no-session-persistence`, `--include-partial-messages`, `--replay-user-messages`, `--strict-mcp-config`, `--mcp-debug`
**Required value:**
`--model`, `--permission-mode`, `--effort`, `--system-prompt`, `--append-system-prompt`, `--debug-file`, `--session-id`, `--output-format`, `--input-format`, `--settings`, `--setting-sources`, `--fallback-model`, `--max-budget-usd`, `--json-schema`, `--agent`
**Optional value:**
`-r` / `--resume [ID]`, `--from-pr [VALUE]`, `-w` / `--worktree [NAME]`, `-d` / `--debug [FILTER]`
**One or more values:**
`--add-dir`, `--allowedTools` / `--allowed-tools`, `--disallowedTools` / `--disallowed-tools`, `--mcp-config`, `--tools`, `--betas`, `--plugin-dir`, `--file`, `--agents`
## Session Management
```bash
# List active sessions
ccp --list
# Jump back to a previous session's directory
ccp --goto "auth" # substring match
ccp --goto "PR #89"
```
Sessions are saved to `~/.config/claude-code-pulse/sessions.json` and cleaned up on exit.
`--goto` jumps to the session's saved working directory and launches Claude there. It doesn't resume a conversation. For that, use Claude's own flags:
```bash
ccp -c # resume last conversation
ccp --resume abc-123 # resume by session ID
```
## Debugging & Diagnostics
### `--debug-ccp`
```bash
ccp --debug-ccp "PR #89 - Fix auth"
# Always on via environment variable
export CCP_DEBUG=true
```
Enables structured JSONL logging. Each hook event, status change, and AI summary is written as a JSON line to:
```
~/.config/claude-code-pulse/logs/debug...jsonl
```
Old log files from dead sessions are pruned automatically on startup.
**In iTerm2**, `--debug-ccp` also auto-opens the Pulse Monitor in a horizontal split pane. You don't need to run `ccp-watch` manually — it launches automatically and connects to the session log.
### `ccp-watch` — Pulse Monitor
`ccp-watch` is a live debug monitor that streams events from a JSONL log and flags issues in real time.
```bash
# Watch the latest debug log (auto-detects)
ccp-watch
# Watch a specific log file
ccp-watch ~/.config/claude-code-pulse/logs/debug.20260301-120000.12345.jsonl
# List all available debug logs
ccp-watch --list
```
What it monitors:
| Check | What it catches |
|-------|----------------|
| **Status changes** | Every status transition as it happens |
| **AI summaries** | Delivery confirmation (`N/N delivered`) |
| **Stuck detection** | Status held >45s before changing |
| **Event gaps** | Silence between events >120s |
| **Status mismatches** | Tool fired but wrong status was set |
| **System messages** | `` and `` payloads filtered from title |
| **Title anomalies** | Malformed title strings |
| **Session summary** | Total events, errors, and summary delivery rate at session end |
The pane title updates to `🩺 Pulse Monitor — ` when a session connects.
### JSONL event format
Each line in the debug log is a JSON object:
```json
{"ts":"2026-03-01T12:00:00.000Z","src":"session","pid":"12345","event":"session_start","title":"PR #89 - Fix auth","dir":"/my/project","profile":"quiet","ai_context":"false"}
{"ts":"2026-03-01T12:00:01.000Z","src":"hook","mode":"pre-tool","pid":"12345","event":"status_set","status":"✏️ Editing","tool":"Edit"}
{"ts":"2026-03-01T12:00:02.000Z","src":"hook","mode":"post-tool","pid":"12345","event":"status_set","status":"✅ Tests passed"}
{"ts":"2026-03-01T12:00:03.000Z","src":"session","pid":"12345","event":"session_end"}
```
Key fields: `ts` (ISO 8601), `src` (`session` or `hook`), `mode` (hook mode), `pid`, `event`, `status`, `tool`, `summary`.
## Terminal Support
Tested on:
| Terminal | Notes |
|----------|-------|
| **iTerm2** | Per-pane title (OSC 1). Each split pane updates independently. The primary target. |
| **Terminal.app** | Window title (OSC 2). |
| **tmux 2.9+** | Per-pane title via `select-pane -T` plus OSC 1 passthrough. |
| **tmux < 2.9** | Window rename via `rename-window`. No per-pane title API. |
Detection logic for WezTerm, Ghostty, and Kitty exists in `lib/title.sh` but these have not been verified. If you use one of these terminals, feedback is welcome.
## Multi-Pane Workflow
Open four panes, run a session in each:
```bash
ccp --pr 89 "Fix auth"
ccp --issue 12 "API tests"
ccp --feature "OAuth"
ccp --bug "Login crash"
```
Each pane title updates on its own:
```
my-app (pr/89-fix-auth) | fix auth | ✏️ Editing
my-app (issue/12-api-tests) | api tests | 🧪 Testing
my-app (feat-oauth) | oauth | ✅ Tests passed
my-app (bug/login-crash) | login bug | ⬆️ Pushing
```

## Options Reference
### ccp options
| Option | Description |
|--------|-------------|
| `TITLE` | Task title (first positional arg) |
| `DIRECTORY` | Working directory (second positional arg, must be an existing path) |
| `--pr N DESC` | Quick format: `PR #N - DESC` |
| `--issue N DESC` | Quick format: `Issue #N - DESC` |
| `--feature DESC` | Quick format: `Feature: DESC` |
| `--bug DESC` | Quick format: `Bug: DESC` |
| `--refactor DESC` | Quick format: `Refactor: DESC` |
| `--auto-title` | Auto-detect title from git branch (this is the default) |
| `--no-dynamic` | Static title only, no live updates |
| `--status-profile quiet\|verbose` | Which events to surface (default: `quiet`) |
| `--ai-context` | Summarize prompts into a 3-5 word title label (opt-in) |
| `--ai-context-strategy haiku\|inline` | Summary strategy: `haiku` (default, invisible) or `inline` (zero extra API calls) |
| `--debug-ccp` | Structured JSONL debug logging to `~/.config/claude-code-pulse/logs/`; auto-opens Pulse Monitor in iTerm2 |
| `--goto TITLE` | Re-open a previous session by title |
| `--list`, `-l` | List active ccp sessions |
| `--help`, `-h` | Show help |
| `--version`, `-v` | Show version |
| `--` | Everything after this goes directly to Claude |
| any `-*` flag | Unknown flags are forwarded to Claude |
### Environment variables
| Variable | Default | Description |
|----------|---------|-------------|
| `CCP_STATUS_PROFILE` | `quiet` | Default status profile |
| `CCP_ENABLE_AI_CONTEXT` | `false` | Always-on AI prompt summarization |
| `CCP_AI_CONTEXT_STRATEGY` | `haiku` | Summary strategy: `haiku` or `inline` |
| `CCP_DEBUG` | `false` | Always-on structured JSONL debug logging |
## Documentation
- [Usage Guide](docs/usage.md)
- [Dynamic Titles](docs/dynamic-titles.md)
- [Hook Integration](docs/hooks.md)
- [AI Context Summarization](docs/ai-context.md)
- [Debugging & Diagnostics](#debugging--diagnostics)
- [Installation Guide](docs/installation.md)
- [Contributing](CONTRIBUTING.md)
## Contributing
Contributions welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and guidelines.
```bash
# Fork and clone
git clone https://github.com/YOUR_USERNAME/claude-code-pulse.git
# Create feature branch
git checkout -b feature/amazing-feature
git commit -m 'feat: add amazing feature'
git push origin feature/amazing-feature
```
## License
MIT © Brian Ruggieri. See [LICENSE](LICENSE).
## Acknowledgments
Built for [Claude Code](https://code.claude.com/) by Anthropic. Inspired by the need to keep track of what's happening across multiple concurrent agents.
---
**Star ⭐ this repo if you find it useful!**