npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@quantthieres/ping-balloon

v0.4.0

Published

Ping Balloon — floating desktop notification bubble for terminal coding agents

Readme

npm version license MIT CI GitHub release Claude Code macOS Windows Ubuntu

Ping Balloon — desktop notification bubble for terminal coding agents.

A floating bubble that sits in the corner of your screen and tells you when Claude finishes a task or needs your approval. The bubble is hidden by default — it only appears when something actually requires your attention.

| State | Colour | Behaviour | |---|---|---| | complete | Green | Appears, plays a short sound, auto-hides after 6 s | | permission | Amber | Appears, plays a sound, stays visible until you act | | waiting | Blue | Hidden by default — debug/optional (see Environment Variables) |

Clicking the bubble brings your terminal or editor back into focus, then hides the bubble.


Quick Start

1. Install from npm

npm install -g @quantthieres/ping-balloon@latest

Verify the installation:

ping-balloon help
ping-balloon doctor

2. Start Ping Balloon

ping-balloon start

This starts the app. The window opens but the bubble stays hidden until an event arrives — no visible clutter while you work. Keep this terminal open for as long as you want to receive notifications.

3. Test manually

In a second terminal:

ping-balloon health                    # confirm the server is up
ping-balloon notify complete           # bubble appears, plays sound, auto-hides
ping-balloon notify permission         # bubble appears, plays sound, stays visible

4. Use with Claude Code

Terminal 1 — start Ping Balloon (keep running):

ping-balloon start

Terminal 2 — inside your project:

cd path/to/your/project
ping-balloon hooks install
claude

hooks install needs to be run once per project. It writes to .claude/settings.local.json. If Ping Balloon is not running when Claude triggers a hook, the hook exits silently — it will never interrupt or block Claude Code.

5. Remove hooks

ping-balloon hooks uninstall

Removes only Ping Balloon entries from .claude/settings.local.json. Other hooks are untouched.

6. Update Ping Balloon

npm install -g @quantthieres/ping-balloon@latest

7. Optional — run without installing

npx --package=@quantthieres/ping-balloon ping-balloon help
npx --package=@quantthieres/ping-balloon ping-balloon start

For everyday use the global install (npm install -g) is simpler.


Requirements

  • Node.js >= 18
  • macOS (10.15+), Windows (10+), or Ubuntu (22.04 / 24.04 with GNOME)
  • Claude Code for hook integration (optional but recommended)

CLI Commands

ping-balloon <command> [args]

| Command | Description | |---|---| | start | Start using the production build in dist/ | | dev | Start in dev mode — Vite dev server + Electron (source clone only) | | health | Check if the HTTP server is reachable | | notify <state> | Send a state change to the bubble | | hooks install | Wire Claude Code hooks in .claude/settings.local.json | | hooks uninstall | Remove Ping Balloon hooks | | doctor | Print a diagnostics report | | help | Show usage and examples |

notify flags

ping-balloon notify complete
ping-balloon notify permission --title "Approval needed" --message "Allow bash?" --meta "Bash"
ping-balloon notify waiting     # debug/optional — hidden by default from hooks

HTTP API

When Ping Balloon is running it exposes a local server on http://127.0.0.1:47321.

GET /health

curl http://127.0.0.1:47321/health
# → {"ok":true,"app":"agent-ping"}

Note: "app":"agent-ping" is an internal server identifier kept for compatibility.

POST /notify

curl -X POST http://127.0.0.1:47321/notify \
  -H 'Content-Type: application/json' \
  -d '{"state":"complete"}'

| Field | Type | Required | |---|---|---| | state | "complete" | "waiting" | "permission" | ✓ | | title | string | — | | message | string | — | | meta | string | — |


Claude Code Integration

Ping Balloon hooks into Claude Code to update the bubble automatically as Claude works.

Install hooks

# Terminal 1 — Ping Balloon must be running
ping-balloon start

# Terminal 2 — inside your project
ping-balloon hooks install

This writes to .claude/settings.local.json (project-scoped, typically git-ignored). Existing hooks from other tools are preserved.

Event routing

| Claude Code event | Condition | Bubble behaviour | |---|---|---| | Stop (task done) | always | complete — plays sound, auto-hides after 6 s | | Notification | message contains a permission keyword | permission — plays sound, stays until dismissed | | Notification | generic / idle | ignored by default — set PING_BALLOON_SHOW_WAITING=1 to re-enable |

Permission keywords (case-insensitive): permission, allow, approve, authorize, grant, blocked, requires approval, do you want to, confirm

Generic idle notifications are suppressed so the bubble does not flash every time Claude is just thinking. Only task completion and permission requests produce a visible notification.

Debug mode

AGENT_PING_HOOK_DEBUG=1 node scripts/claude-hook-notify.js Stop
cat .claude/agent-ping-hook-debug.log

Each hook invocation appends a JSON line with timestamp, event, payload, chosen state (or skip), and HTTP result.

Remove hooks

ping-balloon hooks uninstall

Only Ping Balloon entries are removed. Other hooks in the same file are preserved.


Environment Variables

Set these before starting Ping Balloon or before running a hook.

| Variable | Default | Effect | |---|---|---| | PING_BALLOON_SOUND=0 | sound on | Silence all notification sounds | | PING_BALLOON_SHOW_WAITING=1 | suppressed | Show the waiting bubble for generic Claude Code notifications | | AGENT_PING_HOOK_DEBUG=1 | off | Append debug JSON to .claude/agent-ping-hook-debug.log | | PING_BALLOON_FOCUS_CMD | — | Custom shell command used instead of built-in focus logic on Ubuntu/Linux |

Disabling sounds

PING_BALLOON_SOUND=0 ping-balloon start

Re-enabling waiting/idle notifications

By default, generic Notification events from Claude Code (idle, thinking) are silently ignored. To restore the previous behaviour:

PING_BALLOON_SHOW_WAITING=1 ping-balloon start

PING_BALLOON_SHOW_WAITING is read by claude-hook-notify.js at hook invocation time. Set it as a shell environment variable or in your shell profile.


Terminal Focus on Click

Clicking the notification bubble tries to bring your terminal or editor to the front.

  • If focus succeeds, the bubble hides automatically.
  • If focus fails (no supported app found, permission not granted), the bubble stays visible — dismiss it manually with ×.

macOS

Apps tried in order:

| Priority | App | |---|---| | 1 | Warp | | 2 | iTerm2 | | 3 | Terminal | | 4 | Visual Studio Code |

Uses AppleScript tell application X to activate. On first use macOS may show an Automation permission dialog — approve it for focus to work.

Windows

Apps tried in order:

| Priority | App | |---|---| | 1 | Windows Terminal | | 2 | PowerShell (pwsh, powershell) | | 3 | cmd | | 4 | Visual Studio Code |

Uses PowerShell AppActivate by PID. The Windows foreground lock may cause the app to flash in the taskbar rather than fully focus.

Ubuntu

Ubuntu 22.04 and 24.04 with GNOME are the initial targets. Other distributions may work but are not tested.

Install

npm install -g @quantthieres/ping-balloon@latest

Usage

ping-balloon start
ping-balloon notify complete
ping-balloon notify permission

Optional dependencies for terminal focus

Without these tools the bubble will still appear and can be dismissed manually, but clicking it will not focus your terminal.

sudo apt update
sudo apt install -y wmctrl xdotool

Focus is attempted in this order:

  1. PING_BALLOON_FOCUS_CMD (if set) — run as a custom shell command
  2. wmctrl -a <name> — tries GNOME Terminal, Terminal, Visual Studio Code, Code
  3. xdotool search --class <class> + windowactivate — tries gnome-terminal, org.gnome.Terminal, code, Code
  4. Returns ok: false with guidance if nothing works

Custom focus command

Use PING_BALLOON_FOCUS_CMD to override the built-in logic with any shell command you prefer:

PING_BALLOON_FOCUS_CMD='wmctrl -a Terminal' ping-balloon start

Wayland

Wayland restricts which applications can raise windows belonging to other processes. If focus does not work on Wayland, install wmctrl or xdotool, or set PING_BALLOON_FOCUS_CMD. Notifications will still appear and sounds will still play regardless of whether focus succeeds.

ping-balloon doctor on Ubuntu

doctor shows Ubuntu-specific checks:

✓  Platform: linux x64  6.8.0-57-generic
✓  XDG_SESSION_TYPE: x11
✓  wmctrl: available
✗  xdotool: missing  optional — sudo apt install -y xdotool
✓  PING_BALLOON_FOCUS_CMD: not set (optional)

Optional checks (wmctrl, xdotool, PING_BALLOON_FOCUS_CMD) are shown but do not cause doctor to exit with an error.


npm Scripts

| Command | Description | |---|---| | npm run dev | Start Vite + Electron in development mode | | npm run build | Build the React app into dist/ | | npm start | Start Electron loading dist/ (production) | | npm run doctor | Run ping-balloon doctor | | npm run health | Check if the server is up | | npm run notify:complete | Send complete state | | npm run notify:waiting | Send waiting state (debug) | | npm run notify:permission | Send permission state | | npm run hooks:install | Install Claude Code hooks | | npm run hooks:uninstall | Remove Claude Code hooks |


Manual Test Checklist

Use this checklist before tagging a release.

App startup

  • [ ] npm run build completes without errors
  • [ ] ping-balloon start starts the process — no bubble visible on launch
  • [ ] ping-balloon health returns {"ok":true,"app":"agent-ping"}
  • [ ] ping-balloon doctor reports all ✓

Bubble states and timing

  • [ ] ping-balloon notify complete → green bubble, DONE label, sound plays, auto-hides after ~6 s
  • [ ] ping-balloon notify permission → amber bubble, HOLD label, sound plays, stays visible
  • [ ] ping-balloon notify waiting → blue bubble, IDLE label, sound plays, auto-hides after ~8 s
  • [ ] Dismiss (×) hides the bubble immediately (cancels any auto-hide timer)
  • [ ] Any notify call re-shows the bubble regardless of current visibility

Sound

  • [ ] Sound plays on complete, permission, waiting events
  • [ ] Theme toggle (☾/☀) produces no sound
  • [ ] PING_BALLOON_SOUND=0 ping-balloon start → bubble appears but no sound

Theme

  • [ ] ☾/☀ button toggles light/dark theme
  • [ ] Clicking the theme button does not dismiss the bubble or focus the terminal

Bubble click — terminal focus (macOS)

  • [ ] Single click on the bubble body attempts terminal focus
  • [ ] If focus succeeds → terminal comes to front, bubble hides
  • [ ] If focus fails → bubble stays visible
  • [ ] Double-click does not trigger two focus calls (guard active)

Claude Code hook routing

  • [ ] echo '{"hook_event_name":"Stop"}' | node scripts/claude-hook-notify.js Stop → complete bubble appears
  • [ ] echo '{"hook_event_name":"Notification","message":"Permission required"}' | node scripts/claude-hook-notify.js Notification → permission bubble
  • [ ] echo '{"hook_event_name":"Notification","message":"Waiting for input"}' | node scripts/claude-hook-notify.js Notificationno bubble (suppressed)
  • [ ] PING_BALLOON_SHOW_WAITING=1 echo '...' | node scripts/claude-hook-notify.js Notification → waiting bubble
  • [ ] ping-balloon hooks install writes to .claude/settings.local.json
  • [ ] Claude Code Stop hook → complete bubble
  • [ ] ping-balloon hooks uninstall removes entries cleanly

Bubble click — terminal focus (Ubuntu, manual — requires Ubuntu machine)

  • [ ] wmctrl and/or xdotool installed
  • [ ] Single click on the bubble body attempts terminal focus
  • [ ] If wmctrl or xdotool finds a window → terminal comes to front, bubble hides
  • [ ] If neither tool is available → bubble stays visible, error logged
  • [ ] PING_BALLOON_FOCUS_CMD='wmctrl -a Terminal' ping-balloon start → custom command used on click
  • [ ] ping-balloon doctor on Ubuntu shows XDG_SESSION_TYPE, wmctrl, xdotool, PING_BALLOON_FOCUS_CMD
  • [ ] On Wayland (XDG_SESSION_TYPE=wayland), doctor shows Wayland note

CLI edge cases

  • [ ] ping-balloon notify invalid → error, exit 1
  • [ ] ping-balloon foobar → "Unknown command", exit 1
  • [ ] ping-balloon health when not running → clear error, exit 1
  • [ ] ping-balloon start when dist/ is missing → clear error, exit 1

Package

  • [ ] npm pack --dry-run lists only expected files (no src/, node_modules/, .claude/)
  • [ ] Version shown is 0.3.0

Known Limitations

  • ping-balloon dev is only available when running from a source clone (requires src/ and Vite). Shows a clear error from an installed package.
  • Hook routing (permission vs ignored) depends on Claude Code's Notification payload text. If Claude Code changes its message format, keywords in scripts/claude-hook-notify.js may need updating.
  • Stop hook cannot distinguish a completed task from a cancelled one — always shows complete.
  • Rapid notifications overwrite each other; the bubble shows the last state received.
  • macOS Automation permission must be granted to Ping Balloon on first use for terminal focus to work. macOS will show a permission dialog automatically.
  • Windows terminal focus is best-effort — the foreground lock may cause the app to flash in the taskbar rather than fully focus.
  • Notification sound depends on OS audio output being available and not muted at the system level.
  • Ubuntu terminal focus is best-effort — requires wmctrl or xdotool, or a custom PING_BALLOON_FOCUS_CMD. Wayland may restrict focus further. See Ubuntu.
  • Other Linux distributions are not tested. The Electron window may open but terminal focus is not implemented beyond Ubuntu.
  • Fixed port — the server runs on 47321. If that port is in use, the server will fail silently.
  • Internal identifiers ("app":"agent-ping" in the HTTP response, agent-ping-hook-debug.log, AGENT_PING_HOOK_DEBUG) are legacy names kept for backward compatibility.

VS Code Integration

The vscode-extension/ folder contains a companion VS Code extension (local/dev only — not published to the Marketplace).

What it does

  • Shows a status bar item (bottom-right) reflecting Ping Balloon's running/offline state, refreshed every 30 s
  • Exposes six Command Palette commands: Start, Check Status, Install Claude Code Hooks, Test Complete, Test Permission, Doctor
  • Clicking the status bar opens a quick-pick menu with all commands
  • All invocations pass PING_BALLOON_FOCUS_TARGET=vscode so the bubble click focuses VS Code first

VS Code focus target

When PING_BALLOON_FOCUS_TARGET=vscode is set, clicking the bubble promotes VS Code to the top of the focus order on macOS, Windows, and Ubuntu/Linux.

You can also set this from the CLI without the extension:

ping-balloon start --focus vscode
# or
PING_BALLOON_FOCUS_TARGET=vscode ping-balloon start

Using the extension locally

cd vscode-extension
npm install
npm run compile
# Then open the folder in VS Code and press F5 to launch an Extension Development Host.

Development

git clone https://github.com/quantthieres/ping-claude-balloon.git
cd ping-claude-balloon/agent-ping-desktop

npm install       # install all dependencies
npm run dev       # Vite hot-reload + Electron

Project structure

agent-ping-desktop/
├── bin/
│   └── agent-ping.js            ← CLI entry point (ping-balloon command)
├── electron/
│   ├── main.js                  ← Electron main process + HTTP server
│   ├── preload.js               ← IPC bridge (contextBridge)
│   └── focus-terminal.js        ← macOS / Windows / Ubuntu terminal focus
├── scripts/
│   ├── claude-hook-notify.js    ← Hook entry point (reads stdin, routes state)
│   ├── electron-dev.js          ← Cross-platform Electron dev launcher
│   ├── notify.js                ← HTTP helper for npm scripts
│   ├── install-claude-hooks.js
│   └── uninstall-claude-hooks.js
├── src/
│   ├── App.jsx                  ← State switcher, IPC listener, sound, timers
│   ├── main.jsx
│   └── components/
│       ├── BubbleNotification.jsx
│       ├── BubbleNotification.css
│       ├── state-config.js
│       └── mascots/             ← complete.png, waiting.png, permission.png
├── dist/                        ← Production build (generated by npm run build)
├── package.json
├── README.md
├── CHANGELOG.md
└── LICENSE

Building

npm run build           # build React app into dist/
npm pack                # creates .tgz (runs build first via prepack)
npm pack --dry-run      # preview contents without writing the file

License

MIT — © 2026 quantthieres