claude-pager
v0.3.20
Published
Remote notification and response relay for Claude Code CLI sessions
Maintainers
Readme
claude-pager
Get paged on your phone when Claude Code needs input. Reply from Telegram or ntfy, and claude-pager types your response into the correct terminal.

Click the image above to watch the demo (~50s)
How it works
- Claude Code hooks fire when an instance needs user input
- The hook enriches the event (tool name, last assistant message) and sends it to the daemon
- The daemon dispatches a notification to your phone via Telegram or ntfy
- You respond — tap Allow/Deny, type a message, or send a voice note
- The daemon matches the response to the right session and injects it via
tmux send-keys
| Step | Screenshot |
|------|-----------|
| Claude Code asks for permission |
|
| Notification arrives on your phone |
|
| You reply from Telegram |
|
| Claude resumes automatically |
|
Features
- Project notes — capture ideas while agents work, send them when idle. Input via dashboard, Telegram ("Note pour X: ..."), CLI, or voice. Supports image paste.
- Web dashboard — live view of all sessions at
http://localhost:17380/dashboard, with Allow/Deny buttons, text replies, diff previews, notes panel, CI/CD status, and git info - Multi-session — run N Claude Code instances in tmux, responses route to the correct pane
- Telegram — inline keyboards (Allow/Deny), reply-to-message routing, voice transcription (Whisper)
- ntfy — self-hosted or ntfy.sh, mobile push notifications
- CI/CD integration — GitLab and GitHub pipeline status per project (main/staging)
- Smart tmux titles — terminal tabs auto-update with the current session topic
- Session recovery —
claude-pager recoverdetects existing Claude sessions in tmux - Smart routing —
#id responsefor explicit targeting, auto-route for single session, session picker for ambiguous cases - Fallback by project — if a session UUID is no longer registered, matches by
cwd(project directory)
Requirements
- Node.js >= 20
- tmux (for response injection —
brew install tmuxon macOS,apt install tmuxon Debian/Ubuntu) - Linux, macOS, or WSL (see Windows support)
- A Telegram bot or ntfy server for notifications
macOS note: the
xdotoolinjector is X11-only and unavailable. Use the defaulttmuxinjector (recommended) or the VS Code extension for response injection. The daemon, dashboard, and notifications all work natively.
Installation
npm install -g claude-pagerSetup
Interactive configuration — creates ~/.claude-pager/config.json and installs Claude Code hooks in ~/.claude/settings.json:
claude-pager setupThe setup wizard lets you choose between Telegram and ntfy as notification channel, and verifies the connection.
Telegram
You need a Telegram bot token (from @BotFather) and a chat ID. The setup command walks you through obtaining both.
ntfy
Point to your ntfy server (self-hosted or https://ntfy.sh) with a topic and optional authentication (user/password or token).
Usage
Start the daemon
# Foreground (for testing)
claude-pager start
# As a systemd user service (recommended)
cat > ~/.config/systemd/user/claude-pager.service << 'EOF'
[Unit]
Description=Claude Code Relay Daemon
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=%h/.local/bin/claude-pager start
ExecStop=%h/.local/bin/claude-pager stop
Restart=on-failure
RestartSec=5
Environment=NODE_ENV=production
[Install]
WantedBy=default.target
EOF
# If claude-pager is installed via nvm, adjust ExecStart path:
# ExecStart=/home/you/.nvm/versions/node/v22.x.x/bin/claude-pager start
systemctl --user daemon-reload
systemctl --user enable --now claude-pagerLaunch Claude Code in tmux
claude-pager run # opens a new tmux session with claude
claude-pager run --resume # pass args through to claudeOr just run claude directly inside tmux — the SessionStart hook registers the session automatically.
Recover existing sessions
If you already have Claude Code running in tmux panes:
claude-pager recoverOther commands
claude-pager status # daemon status + health check
claude-pager pending # list pending questions
claude-pager stop # stop the daemonResponding to notifications
Telegram
- Permission prompts — tap the inline Allow or Deny button
- Idle prompts — reply to the notification message with your answer
- Voice — send a voice message, it gets transcribed and injected
- Free messages — send a message without replying; if one session is active it goes there, otherwise a session picker appears
ntfy
- Reply with
#<id> <response>to target a specific notification - If only one question is pending, any reply routes to it
allow/denyauto-route to the most recent permission prompt
Web Dashboard
Open http://127.0.0.1:17380/dashboard in your browser. The dashboard shows:
- All active sessions grouped by project
- Allow/Deny buttons for permission prompts — respond without switching to Telegram
- Text input for idle sessions — send a message directly to any Claude instance
- CI/CD pipeline status per project (GitLab / GitHub Actions)
- Git status — branch, modified files, unpushed commits, committed/pushed flags
- "Needs Testing" badge when CI fails or code is unpushed
- Pin projects to lock their dashboard position
- Expandable titles — click "..." to see the full message
- Dismiss button (🗑) to remove stale sessions
- Diff preview for Edit permission prompts — see what will change before allowing
- Notes panel per project — add, reorder, send, and delete notes inline
- SSE push for instant updates, polling as fallback
- tmux tab titles auto-update with the current session topic
Note: Claude Code serializes permission prompts — each sub-agent waits for its response before the next one asks, even when running in parallel. To skip permission prompts for specific tools, configure
permissions.allowin~/.claude/settings.json.
Project Notes
Capture ideas while agents are busy. Notes are stored per project and can be sent to a session when it becomes idle.
Adding notes
# CLI
claude-pager note myproject "fix the login CSS"
claude-pager notes # list all pending notes
# Telegram (text or voice)
Note pour myproject: fix the login CSS
# Dashboard
# Type in the "Add a note..." field, or paste an image (Ctrl+V)API
# Add a note
curl -X POST http://localhost:17380/api/v1/notes \
-H 'Content-Type: application/json' \
-d '{"project":"myproject","text":"fix the CSS"}'
# List notes
curl http://localhost:17380/api/v1/notes?project=myproject
# Send a note to its project's idle session
curl -X POST http://localhost:17380/api/v1/notes/<id>/sendNotes with images are stored in ~/.claude-pager/note-images/ (max 5 MB per image).
Configuration
~/.claude-pager/config.json:
{
"port": 17380,
"channel": {
"type": "telegram",
"telegram": {
"botToken": "123456:ABC...",
"chatId": 12345678
}
},
"injector": "auto"
}| Key | Default | Description |
|-----|---------|-------------|
| port | 17380 | Daemon HTTP port (localhost only) |
| channel.type | "ntfy" | "ntfy" or "telegram" |
| injector | "auto" | "auto", "tmux", or "xdotool" |
| ci.type | — | "gitlab" or "github" (optional) |
| ci.gitlab.url | — | GitLab server URL |
| ci.gitlab.token | — | Personal access token (scope: read_api) |
| ci.github.token | — | Personal access token (scope: actions:read) |
The hook port can be overridden with CLAUDE_PAGER_PORT environment variable.
Windows Support
claude-pager works on Windows through WSL (Windows Subsystem for Linux). This is the recommended setup.
Quick start (WSL)
Install WSL if you don't have it:
wsl --installInside WSL, install Node.js, tmux, and claude-pager:
sudo apt update && sudo apt install -y tmux curl -fsSL https://fnm.vercel.app/install | bash # or nvm fnm install 22 npm install -g claude-pagerConfigure and run:
claude-pager setup claude-pager start & claude-pager runOpen the dashboard from Windows at
http://localhost:17380/dashboard— WSL forwards the port automatically.
Tips
- Notifications work from anywhere — Telegram, ntfy, and the web dashboard all work regardless of OS since they're HTTP-based.
- VS Code + WSL — open your project with
code .from WSL. The integrated terminal runs inside WSL, so tmux works normally. - Windows Terminal — pin a WSL tab for your claude-pager sessions. tmux inside Windows Terminal works great.
- Multiple distros — claude-pager runs in whichever WSL distro you install it in. Sessions don't cross distro boundaries.
Native Windows (without WSL)
Not currently supported. The response injection relies on tmux, which requires a Unix environment. A VS Code extension for native Windows support is on the roadmap.
Architecture
Strategy + Factory pattern for pluggable components:
src/
├── channels/ # Notification channels (ntfy, telegram)
│ ├── channel.ts # ChannelProvider interface
│ └── factory.ts
├── injectors/ # Terminal input injection (tmux, xdotool)
│ ├── injector.ts # InputInjector interface
│ └── factory.ts
├── daemon/ # HTTP server + response routing
│ ├── server.ts # Fastify routes with JSON Schema validation
│ └── handlers.ts # Channel listener logic (routing, picker)
├── dashboard/ # Web dashboard (enricher, transcript, git, CI, HTML)
├── sessions/ # Session tracking + pending question store
├── hooks/ # Claude Code hook entry point
├── utils/ # Shared utilities (html, json, validation)
├── cli/ # Commander CLI
└── voice/ # Telegram voice transcription (Whisper)See docs/ARCHITECTURE.md for the detailed flow.
Security
- HTTP API binds to
127.0.0.1only — no network exposure - Input validation with Fastify JSON Schema + custom validators (
isValidEventType,isValidSessionId) - No shell injection — all child processes use
execFileSyncwith argument arrays - Minimal context in notifications — tool names, project names, and truncated tool input (max 300 chars)
- Memory-bounded maps (capped at 500-1000 entries)
- Safe JSON parsing with fallbacks for corrupted files
Development
npm run build # TypeScript compilation
npm test # Run all tests (node:test)
npm run lint # ESLint with typescript-eslint
npm run dev # Dev mode (tsx watch)License
MIT
