-
Notifications
You must be signed in to change notification settings - Fork 2
Statusline Integration
How the live cost line ends up in the engineer's Claude Code window, Cursor / VS Code status bar, and the cloud dashboard. The shared JSON shape across all three surfaces is pinned in
docs/statusline-contract.md; this page is the integration narrative on top of it.
The same daemon endpoint — GET http://127.0.0.1:7878/analytics/statusline — serves the CLI statusline, the Cursor extension, the VS Code extension, and the cloud dashboard. Provider is an explicit query parameter rather than a per-surface schema. New agent coverage slots into the same shape; new surfaces consume the same JSON.
A single JSON document with cost windows, optional context-scoped fields, and provider-scope hints. The canonical version of the shape, with field-by-field semantics, is in docs/statusline-contract.md. Highlights:
The windows are rolling, not calendar — cost_1d = spend in the last 24 hours, not "today". budi stats and the cloud dashboard's cost charts keep calendar semantics; rolling windows live only on the statusline surface and the editor extensions that render it.
| Scope | Query | Where it's used |
|---|---|---|
| Provider-scoped |
?provider=cursor (single) |
Cloud dashboard provider tiles, Claude Code statusline, per-provider drill-downs. No blending across providers. |
| Host-scoped |
?provider=cursor,copilot_chat (comma-list) |
VS Code / Cursor extension status bar in editors where multiple agents run side-by-side. Aggregates the listed providers and populates contributing_providers for tooltip rendering and click-through routing. |
The repeated-query form ?provider=a&provider=b is not supported (axum's default Query extractor keeps only the last value). Callers that need multi-provider must use the comma-list.
STATUSLINE_SLOTS in crates/budi-core/src/config.rs is the canonical list:
1d 7d 30d session message branch project provider
Default install slots are ["1d", "7d", "30d"]. The legacy today / week / month names are normalized to 1d / 7d / 30d at load time so older statusline.toml files keep rendering after an upgrade.
Legacy preset = "coach" / preset = "full" values in older configs are silently mapped to ["session", "message"] / ["session", "message", "1d"] at load time. The preset key itself has been removed from the documented surface; the legacy health slot (a vestigial alias for session_cost) has been removed entirely.
Every statusline surface hits the local daemon at 127.0.0.1:7878, never the cloud endpoint directly. Three reasons:
- Latency. Claude Code re-renders the statusline on every prompt; we cannot afford a cross-internet round-trip per render.
- Offline. The engineer sees an honest number even on a plane. The local DB has every row; the cloud is an aggregation destination, not the source of truth.
- Auth. The daemon already trusts the local user (loopback-only listener). Flashing the cloud API key on every render is unnecessary.
The cloud dashboard reads its own Postgres tables, populated by the sync worker. It MUST render windows labeled 1d / 7d / 30d and MUST filter by a single provider in provider-scoped tiles, but it serves its own surface — the cloud is not in the statusline hot path.
budi init is the canonical install entry. It is idempotent and wires both integrations by default when their host is detected on PATH:
-
Claude Code statusline. Merges the
statusLinecommand into~/.claude/settings.json. Re-running never duplicates the entry; preserves any user-configured fragment. The line invoked isbudi statusline --format claude --provider claude_code. -
Cursor extension. Installs from the VS Code Marketplace when the Cursor CLI is on
PATH. Skips silently if the extension is already present.
Opt-out:
budi init --no-integrations # skip both at install time
budi integrations install --with claude-code-statusline # add later
budi integrations install --with cursor-extension # add laterbudi doctor flags a missing Claude Code statusline when ~/.claude exists but ~/.claude/settings.json carries no Budi-backed statusLine. The doctor warn includes the exact budi integrations install command to repair it. Install paths that legitimately want no Claude integration (CI, containers, hand-rolled settings) suppress the nudge by running budi init --no-integrations from day one.
The CLI renderer prints a single line, with a state indicator, the product name, and one or more cost slots. Default:
🟢 budi · $1.24 1d · $8.50 7d · $30.10 30d
State indicator semantics:
| Indicator | Meaning |
|---|---|
| 🟢 | Daemon healthy, data fresh |
| 🟡 | Daemon up, data stale (e.g. Cursor Usage API has not caught up yet — see cost_lag_hint) |
| 🔴 | Daemon down — script prints a nudge to run budi doctor and exits 0 (never blocks the host) |
| ⚠ | Daemon running but not enrolled — surfaced when the daemon is installed but budi init has not been completed |
Failure modes always exit 0. We never block Claude Code, Cursor, or VS Code on a budi failure.
The Cursor extension (siropkin/budi-cursor) is a status-bar-only VS Code extension — no sidebar, no session list, no vitals panel. It spawns budi statusline --format json --provider cursor, mirrors the Claude Code line byte-for-byte, and click-through opens the same cloud URL the Claude Code statusline opens. The extension checks the daemon's api_version on startup (MIN_API_VERSION = 1) and warns if incompatible.
- Field names in the contract are stable across minor releases. New optional fields may be added; existing fields are not renamed or re-typed.
- Deprecated fields are kept populated for at least one minor release and removed no sooner than the next major release. Current deprecations:
today_cost,week_cost,month_cost— populated with the same rolling values ascost_1d/cost_7d/cost_30dfor backward compatibility. - Breaking changes to this contract require a design review.
-
docs/statusline-contract.md— canonical schema -
crates/budi-core/src/analytics/queries.rs—StatuslineStats,StatuslineParams -
crates/budi-daemon/src/routes/analytics.rs—analytics_statuslinehandler -
crates/budi-cli/src/commands/statusline.rs— CLI renderer +--format json/--format claudevariants -
crates/budi-core/src/config.rs—STATUSLINE_SLOTS,normalize_statusline_slot - siropkin/budi-cursor — Cursor / VS Code extension consumer
- The wire-format contract itself →
docs/statusline-contract.md - Provider-scoping rationale (why no blended totals on the Claude statusline) → JSONL Tailing as Live Ingestion
- Daemon install / autostart / version mismatch → Daemon Lifecycle and Autostart
- Cursor-specific lag behavior (
cost_lag_hint) → Cursor Usage API Contract (ADR-0090)
budi · Issues · Releases · app.getbudi.dev · getbudi.dev
Start here
ADRs — Data & privacy
ADRs — Ingestion
ADRs — Pricing
- Model Pricing – Embedded Baseline and Runtime Refresh
- Custom Team Pricing and Effective Cost
- Codex Cost Model – Marginal-Token Counting
ADRs — Provider contracts
Operational references
- Daemon Lifecycle and Autostart
- Provider Plugin Contract
- Cloud Sync Mechanics
- Statusline Integration
- Operations and Observability
- Release and Versioning
Ecosystem
{ "cost_1d": 2.34, // rolling last 24 h, dollars "cost_7d": 12.50, // rolling last 7 d, dollars "cost_30d": 48.10, // rolling last 30 d, dollars "provider_scope": "claude_code", // present iff exactly one provider was requested "contributing_providers": [...], // present iff multi-provider host scope "session_cost": 0.41, // present iff session_id was passed "branch_cost": 8.70, // present iff branch was passed "project_cost": 12.10, // present iff project_dir was passed "active_provider": "claude_code", "cost_lag_hint": "..." // present iff Cursor data is in the response }