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

@promptctl/cc-candybar

v1.117.1

Published

Statusline renderer for Claude Code — a JSON5-configurable DSL with daemon-cached data sources, byte-clean palette-aware composition, and OSC8 click verbs.

Readme

CCCandybar

Powerline statusline for Claude Code — daemon-backed, config-driven, zero-config-file required.

License:MIT npm version Dependencies

Try the live bar in your browser → The real daemon, compiled for the page, replays a few turns of a Claude Code session; every click in the bar is real.

What it is

CCCandybar is a statusline renderer for Claude Code. It shows session cost, context usage, git status, model info, rate-limit utilization, and more, configured through a JSON5 DSL with hot-reloading.

A background daemon caches git state, usage data, and per-session values across concurrent Claude Code sessions. The renderer connects to the daemon over a Unix socket, so every invocation is fast (~50ms budget) and stateful.

Quick start

pnpm dlx @promptctl/cc-candybar@latest install

npm is the only install channel: the GitHub releases are tags plus a changelog with no downloadable assets, and installing from a GitHub tag does not work (the built dist/ is not committed).

pnpm 11 delays freshly published packages (minimumReleaseAge), so on or near a release day @latest can silently resolve to an older version. install compares what it staged against the registry and warns when it is behind; to get a specific release immediately, name it: pnpm dlx @promptctl/cc-candybar@<version> install.

That single command (re-run it any time to update to the latest release):

  1. Stages the runtime at a stable path independent of any package-manager cache — ~/Library/Application Support/CCCandybar/ on macOS, $XDG_DATA_HOME/cc-candybar/ on Linux — as bin/cc-candybar (the prebuilt native render binary for your platform, or a node entry where none exists) beside dist/index.mjs (the daemon + CLI bundle).
  2. On macOS, builds ~/Applications/CCCandybarURLHandler.app and registers the cc-candybar:// URL scheme with Launch Services.
  3. Writes the staged bin/cc-candybar path as the statusline command into ~/.claude/settings.json (skipped with a notice if you've customized the command; --force overwrites).

Restart Claude Code. The statusline appears with the bundled default layout — an identity row (directory, gitaculous, ticket) over a status row (model, context, ceiling, autocompact, cacheTimer, block, weekly, activity). On macOS, Cmd-clicking clickable cells fires cc-candybar:// URL verbs that the daemon dispatches (via the URL handler registered in step 2).

Customization

Drop a .cc-candybar.json5 (or .cc-candybar.json — both extensions are accepted) at any of these locations (highest precedence first):

  1. $CC_CANDYBAR_CONFIG in the statusline command's environment (literal path, supports ~ expansion). It is read by the client on every render and carried to the daemon, so it can differ per session. A path that names no file renders the bundled default under a Config file not found warning, and one the daemon cannot stat (behind an unsearchable directory, say) under Config file could not be read with the error — either way the bar stays live and loads the file once it can.
  2. <project>/.cc-candybar.json5 (then .json at the same location)
  3. <cwd>/.cc-candybar.json5 (then .json)
  4. $XDG_CONFIG_HOME/cc-candybar/config.json5 (then .json; defaults to ~/.config/cc-candybar/config.json5)

JSON is a strict subset of JSON5, so the same parser handles both — .json5 is the documented format (supports inline comments, trailing commas, unquoted keys), .json is the legacy/compat extension. When both exist at the same location, .json5 wins and the bar shows a persistent warning so you can remove the shadowed duplicate.

The file merges onto the bundled default, so it declares only what differs. globals merge per field; the named sections (variables, segments, actions, helpers, …) merge by name, your entry winning; root merges per named row (identity and status in the bundled default; a whole tree at root replaces every row). The bundled default is src/config/default-dsl-config.ts, and fuller starting points live under examples/. Run cc-candybar check <path> to load a file exactly as the daemon will: exit 0 means it renders, exit 1 prints the error with the path and line to fix. Add --render and it prints the bar it rendered, so you can read a config's result without installing it.

// A theme, one new segment, and the row it joins. Everything else — the
// identity row, every other segment and variable — is inherited.
{
  globals: { palette: 'catppuccin-mocha' },
  variables: {
    clock: { kind: 'time', layout: '15:04' }, // Go reference-time layout, re-read every second
  },
  segments: {
    clock: { template: '{{ .clock }}' },
  },
  root: { rows: { status: { h: ['model', 'context', 'clock'] } } },
}

Saving the file triggers a hot-reload of every active session.

Architecture

┌─────────────┐   Unix socket   ┌──────────────────┐
│ Claude Code │ ──────────────► │ cc-candybar daemon│
│  (hook)     │   render req    │                  │
│             │ ◄────────────── │  git cache       │
└─────────────┘   ANSI output   │  usage cache     │
                                │  session state   │
                                │  render cache    │
                                └──────────────────┘
  • Daemon (src/daemon/) — long-lived background process. One per user. Caches git state via filesystem watchers, usage data, and per-session key/value state. Runs until it exits on an RSS backstop (default 512 MB via CC_CANDYBAR_RSS_LIMIT_MB; the V8 heap cap the spawner passes is twice that, a margin wide enough that the graceful backstop fires first under any growth its 60 s poll can see) or the host restarts; there is no idle or age timeout.
  • Client (rust-client/src/main.rs) — the Rust binary installed as bin/cc-candybar, and the only thing on the per-render path: it connects to the daemon, sends the hook JSON, and prints the ANSI response. On a daemon miss it spawns one detached and prints an empty line, so the next refresh finds a warm daemon. Every subcommand (install, daemon, check, doctor, …) execs the Node bundle at dist/index.mjs, which carries a socket relay of its own (src/daemon/client.ts) as the fallback when no native binary is staged.
  • Renderer (src/dsl/render.ts) — renderDsl is the single render path; the daemon, the demo and the tests all call it. It walks the config's layout tree, evaluates each segment's templates against the daemon's payload, and hands the styled cells to src/render/ (strip and joiner selection, pickers and menus, the diagnostic strip). The payload's data comes from the providers in src/segments/ — git, session, context, metrics, tmux, pricing.
  • Themes (src/themes/) — palette construction plus name policy (which theme, style, variation, endcaps, charset and colour depth names resolve to what). The colour arithmetic itself — blending, contrast, OKLCH transposition — lives in the separate rich-js package; this repo does none of it.

Segments

These are the segment names DEFAULT_DSL_CONFIG declares, each available to a user's root whether or not the default bar places it.

| Segment | Shows | Visible | |---------|-------|---------| | directory | the cwd, abbreviated fish-style (~/c/cc-candybar) | always | | model | ✱ and the model's display name | always | | sessionId | ⌗ and the first 8 characters of the session id | always | | version | ◈ v and the Claude Code version | always | | tmux | tmux: and the tmux session name | inside tmux | | host | ⇄ user@host | over SSH | | gitaculous | the git state, collapsed to ⎇ branch, ahead/behind and S/U/?/! flags; the ▸ at its right edge expands it to (git), repo, operation, sha, flags, branch, upstream ±, stashes and time since the last commit, and ◂ collapses it again (per session). Each form and piece is overridable (docs/segment-authoring.md) | in a repo | | gitPr | ⇆ #N linked to the pull request, or ⚠ PR when the forge lookup failed | when a PR or a lookup error is known | | toolbar | click affordances — copy the session id, open the project dir, the transcript and the repo page (also inside the settings menu) | always | | commands | type /compact, /model or /clear into this session; /clear asks for a second click (also inside the settings menu) | inside tmux (not placed by default) | | themeSwitcher | ◀ <theme> ▶ — the theme the bar is wearing; ◀/▶ switch this session to the previous/next theme | always (not placed by default) | | session | § this session's cost and tokens, plus budget status | always | | today | ☉ today's cost and tokens across sessions, plus budget status | always | | block | ◱ the 5-hour rate-limit window's utilization | while that window is active | | weekly | ◑ the 7-day rolling rate limit's utilization | while that window is active | | burnrate | ⚡ cost per hour, then ETA to the 5-hour and weekly limits | while either window is active | | speed | ⇅ output, input and total tokens per second | once the session has tokens | | tokenSparkline | ⚡ a sparkline over the last 24 speed samples | once speed samples exist | | cacheTimer | ◴ minutes until the prompt cache expires, or cold | while a cache expiry is known | | context | ◔ context tokens used and the percentage left | when context tokens are known | | ceiling | ⌈ the memento context ceiling this session hands off at; −/+ move it by 100K, ∞ lifts it, ↺ drops the session's own setting (memento's ceiling set/clear session). Placed beside context | when memento is installed | | autocompact | ⇲ Claude Code's auto-compact window — auto, or the tokens /autocompact last set; −/+ move it by 100K up to the model's context window, ↺ returns it to auto. Each click types /autocompact into the session, so the controls show only inside tmux. Placed beside ceiling | always | | metrics | Δ last response time, ⧖ response time, ⧗ session duration, ◆ message count, lines changed | when any of those exist | | ticket | 🎫 the lit ticket this session started with lit start (click copies the id); the ▸ expands it to the workflow phase (prep, impl, review, groom, handoff) and the epic's done/total once lit has printed it | after a lit start in this session | | activity | ⌘ the slash command that opened the turn, ☐ the in-progress todo with its position, ⟳ tools in flight and ✓ tools finished this turn | while the session is doing something |

Each segment is a DSL declaration with a template (text + interpolation + style functions), a bg/fg palette spec, and optional when predicate. Templates compose freely — every formatter in the bundled function library (formatCost, formatTokens, formatLongTimeRemaining, budgetStatus, link, urlEncode, the sprig string/list/dict library, …) is available in every segment.

Themes

The DSL config picks a base palette via globals.palette (e.g. textual-dark, gruvbox) — or a template evaluated every render, so the theme can follow live data. Each segment may override with its own palette: field, and bg/fg take a palette colour name (primary, surface, panel, accent, foreground, warning, error, …) or a computed colour such as {{ darken (color "primary") 2 }}; a segment that authors no bg wears the theme's decorative tint for its position. Color math runs through OKLCH for perceptual uniformity.

Installation

Requires Node.js 20.19+ (within the 20.x line) or 22.12+, Claude Code, and Git 2.0+. For best display, install a Nerd Font so the powerline glyphs render correctly.

Manual setup

Run the install once to stage the runtime, then point ~/.claude/settings.json at the staged entry (this is also exactly what install writes):

{
  "statusLine": {
    "type": "command",
    "command": "'/Users/you/Library/Application Support/CCCandybar/bin/cc-candybar'"
  }
}

Developing against a checkout

just deploy builds dist/index.mjs and stages the native binary at bin/cc-candybar-native — point your statusline command at that path. On a machine without cargo, pnpm install && pnpm build builds only the bundle — point your statusline at the committed bin/cc-candybar node entry instead. Either way the bar renders HEAD; the daemon watches the built bundle and respawns itself on rebuild.

pnpm bar:web serves the bar at http://127.0.0.1:7317/ in a browser terminal you can click: an isolated daemon (--config my.json5 starts it from a copy of your config, --ssh shows the host segment). pnpm site:build builds the GitHub Pages version into site/dist, the same page with the daemon running inside it against a simulated machine (site/).

Config file

Customization lives in .cc-candybar.json5. See the Customization section above for the resolution order. Saved edits hot-reload — no restart needed.

Contributing

Contributions welcome. See CONTRIBUTORS.md for people who have contributed outside of GitHub PRs.

License

MIT