Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ Comes with a sleek dark theme, responsive design, and intuitive navigation to ex
<em>🔔 <strong>Settings · Alerts</strong> — rules-based alerting engine and outbound webhooks in one place: alert rules (event pattern / inactivity / stuck agent / token threshold) with per-rule cooldown, a live fired-alert feed, and 14 first-class webhook providers (Slack, Discord, Teams, Google Chat, Mattermost, Rocket.Chat, Telegram, PagerDuty, Opsgenie, Splunk On-Call, Zapier, Make, n8n, Pipedream) plus a generic JSON endpoint with optional HMAC signing</em>
</p>

The sidebar provides quick access to the Dashboard, Kanban Board, Sessions list, Activity Feed, Analytics, Workflows, and Settings. Each page is designed to give you deep insights into your Claude Code agent activity with real-time updates and rich visualizations.
The sidebar provides quick access to the Dashboard, Kanban Board, Sessions list, Activity Feed, Analytics, Budgets, Workflows, and Settings. Each page is designed to give you deep insights into your Claude Code agent activity with real-time updates and rich visualizations.

---

Expand All @@ -281,6 +281,7 @@ The dashboard offers a comprehensive set of features to monitor and analyze your
| **Session Detail** | Per-session real-time overview panel with active-agent banner (current tool + task), six tile counters (events with events/min rate, tool calls, subagents, compactions, errors, ticking duration), top-tool usage bars, subagent type breakdown, stacked token-flow strip, and event-type pill cloud — all live-refreshed on hook events. Below it: agent hierarchy tree, full event timeline with multi-dimension filters (status, event type, tool, agent, text search, date range), Pre/Post grouping by `tool_use_id`, human-readable summary block, tool-aware input/response renderers (terminal for Bash, unified diff for Edit, line-numbered code for Read/Write, match list for Grep, key/value card for MCP tools), and a Conversation tab that renders transcripts with markdown (headings, lists, blockquotes, tables, task lists), syntax-highlighted code blocks (js/ts, python, json, bash, html, css, sql, yaml, diff) with line numbers and copy-to-clipboard, and per-tool styled tool calls (Bash → terminal, Edit → side-by-side old/new, Write → file label, Read → path chip, Grep → pattern card) |
| **Activity Feed** | Real-time streaming event log with pause/resume, multi-dimension filters (same toolbar as Session Detail plus a Session filter), server-driven "Load more" pagination, debounced filter-aware live refresh preserving the loaded page size, grouping toggle, origin prefix showing project › session › subagent, and a "Session →" button per row |
| **Analytics** | Token usage, tool frequency, activity heatmap (centered, day-of-week aligned starting Sunday, day-name tooltips), session trends, live/offline connection indicator. While the analytics payload loads, the chart region (not just the stat tiles) shows **pulsing skeleton placeholders** that mirror the chart layout, so the page never flashes empty/zero charts |
| **Budgets** | Set USD spend limits per rolling period (daily / weekly / monthly) and get alerted before you overspend. Each budget shows live current-period spend with a status-colored progress bar (on-track / warning / over), remaining headroom, and per-threshold alert chips that light up once fired. Configurable alert thresholds (default 80% / 100%); a background scheduler fires web-push + native notifications and live-updates the page over WebSocket when a threshold is newly crossed, re-arming each new period. Spend reuses the same pricing rules as the cost views, so totals match Analytics |
| **Live Updates** | WebSocket push -- no polling, instant UI updates |
| **Auto-Discovery** | Sessions and agents are created automatically from hook events |
| **History Import** | Imports sessions from `~/.claude/` on startup. Enhanced JSONL extraction: API errors (quota/rate/invalid_request), turn durations, entrypoint (cli/sdk-ts), permission modes, thinking block counts, usage extras (service_tier, speed, inference_geo), tool result errors, and subagent JSONL files (`subagents/agent-*.jsonl` with `.meta.json`). Backfills existing sessions on re-import. Recent JSONL files (< 10 min) are imported as "active" |
Expand Down Expand Up @@ -592,6 +593,8 @@ flowchart LR
| `NODE_ENV` | `development` | Set to `production` to serve the built client |
| `DASHBOARD_UPDATE_CHECK` | _(enabled)_ | Set to `0` / `false` / `off` to disable periodic git upstream checks |
| `DASHBOARD_UPDATE_CHECK_INTERVAL_MS` | `300000` (5 min) | Interval between automatic checks; floor 60 000 ms. Users can also click **Check now** in the update modal or in the sidebar to run one on demand. |
| `DASHBOARD_BUDGET_CHECK` | _(enabled)_ | Set to `0` / `false` / `off` to disable the periodic spend-budget evaluator |
| `DASHBOARD_BUDGET_CHECK_INTERVAL_MS` | `60000` (1 min) | Interval between budget re-evaluations; floor 15 000 ms |

For git clones, the server periodically `git fetch`es `origin` and compares your checkout to `origin/master`, `origin/main`, or `origin/HEAD`. When you are behind, a message appears in the server terminal and a modal appears in the UI with the exact command to run. The dashboard never pulls or restarts itself — you copy the command, run it in a terminal, then restart the server the same way you started it.

Expand Down Expand Up @@ -925,6 +928,31 @@ The OpenAPI document is generated from `server/openapi.js`, and Swagger UI is se
| `GET` | `/api/pricing/cost` | Total cost across all sessions |
| `GET` | `/api/pricing/cost/:id` | Cost breakdown for a specific session |

### Budgets

Spend budgets let you cap token cost per rolling period and get alerted before
you overspend. Each budget has a period (`daily` / `weekly` / `monthly`), a USD
`limit_usd`, and a list of `alert_thresholds` (percent-of-limit points, default
`[80, 100]`). Current-period spend is computed from `token_usage` joined to each
session's start date (all period math in UTC) and reuses the same pricing rules
as `/api/pricing/cost`, so the numbers line up. `GET` responses include the live
`spent`, `remaining`, `pct`, `status` (`ok` / `warning` / `exceeded`), the
`period_start` / `period_end` window, and which thresholds have already fired
this period.

| Method | Path | Description |
| -------- | ------------------ | ----------------------------------------------------------------- |
| `GET` | `/api/budgets` | List budgets with live current-period spend and status |
| `POST` | `/api/budgets` | Create a budget. Body: `{ period, limit_usd, label?, enabled?, alert_thresholds? }` |
| `PUT` | `/api/budgets/:id` | Update a budget (any subset of the create fields) |
| `DELETE` | `/api/budgets/:id` | Delete a budget and its alert state |

A background scheduler (`server/budget-scheduler.js`) re-evaluates enabled
budgets on an interval and, when a threshold is newly crossed, fires a web-push +
native notification and broadcasts `budget_alert` / `budgets_updated` over the
WebSocket. Each threshold notifies at most once per period and re-arms when the
next period begins.

### Workflows

| Method | Path | Description |
Expand Down Expand Up @@ -1727,6 +1755,7 @@ graph LR
D["/sessions/:id"] --> DETAIL["SessionDetail<br/>agents + timeline + cost"]
A["/activity"] --> ACT["ActivityFeed<br/>streaming event log"]
AN["/analytics"] --> ANALYTICS["Analytics<br/>tokens + heatmap + trends"]
BU["/budgets"] --> BUDGETS["Budgets<br/>spend limits + threshold alerts"]
WF["/workflows"] --> WORKFLOWS["Workflows<br/>D3 visualizations + drill-in"]
CC["/cc-config"] --> CCCONFIG["CcConfig<br/>12-tab Claude Code config inspector + editor"]
RUN["/run"] --> RUNPAGE["Run<br/>spawn / resume / stream Claude subprocess"]
Expand Down
2 changes: 2 additions & 0 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Sessions } from "./pages/Sessions";
import { SessionDetail } from "./pages/SessionDetail";
import { ActivityFeed } from "./pages/ActivityFeed";
import { Analytics } from "./pages/Analytics";
import { Budgets } from "./pages/Budgets";
import { Workflows } from "./pages/Workflows";
import { Settings } from "./pages/Settings";
import { CcConfig } from "./pages/CcConfig";
Expand Down Expand Up @@ -44,6 +45,7 @@ export default function App() {
<Route path="sessions/:id" element={<SessionDetail />} />
<Route path="activity" element={<ActivityFeed />} />
<Route path="analytics" element={<Analytics />} />
<Route path="budgets" element={<Budgets />} />
<Route path="workflows" element={<Workflows />} />
<Route path="cc-config" element={<CcConfig />} />
<Route path="run" element={<Run />} />
Expand Down
2 changes: 2 additions & 0 deletions client/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
Workflow,
Boxes,
Play,
Wallet,
Settings,
Wifi,
WifiOff,
Expand Down Expand Up @@ -48,6 +49,7 @@ const NAV_KEYS = [
{ to: "/sessions", icon: FolderOpen, key: "nav:sessions" },
{ to: "/activity", icon: Activity, key: "nav:activityFeed" },
{ to: "/analytics", icon: BarChart3, key: "nav:analytics" },
{ to: "/budgets", icon: Wallet, key: "nav:budgets" },
{ to: "/workflows", icon: Workflow, key: "nav:workflows" },
{ to: "/cc-config", icon: Boxes, key: "nav:ccConfig" },
{ to: "/run", icon: Play, key: "nav:run" },
Expand Down
7 changes: 7 additions & 0 deletions client/src/i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ import activity_vi from "./locales/vi/activity.json";
import analytics_en from "./locales/en/analytics.json";
import analytics_zh from "./locales/zh/analytics.json";
import analytics_vi from "./locales/vi/analytics.json";
import budgets_en from "./locales/en/budgets.json";
import budgets_zh from "./locales/zh/budgets.json";
import budgets_vi from "./locales/vi/budgets.json";
import workflows_en from "./locales/en/workflows.json";
import workflows_zh from "./locales/zh/workflows.json";
import workflows_vi from "./locales/vi/workflows.json";
Expand Down Expand Up @@ -66,6 +69,7 @@ i18n
sessions: sessions_en,
activity: activity_en,
analytics: analytics_en,
budgets: budgets_en,
workflows: workflows_en,
settings: settings_en,
kanban: kanban_en,
Expand All @@ -83,6 +87,7 @@ i18n
sessions: sessions_zh,
activity: activity_zh,
analytics: analytics_zh,
budgets: budgets_zh,
workflows: workflows_zh,
settings: settings_zh,
kanban: kanban_zh,
Expand All @@ -100,6 +105,7 @@ i18n
sessions: sessions_vi,
activity: activity_vi,
analytics: analytics_vi,
budgets: budgets_vi,
workflows: workflows_vi,
settings: settings_vi,
kanban: kanban_vi,
Expand All @@ -121,6 +127,7 @@ i18n
"sessions",
"activity",
"analytics",
"budgets",
"workflows",
"settings",
"kanban",
Expand Down
50 changes: 50 additions & 0 deletions client/src/i18n/locales/en/budgets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"title": "Spend Budgets",
"subtitle": "Set USD limits per period and get alerted before you overspend",
"newBudget": "New budget",
"confirmDelete": "Delete this budget? This cannot be undone.",
"alertsAt": "Alerts at",
"thresholdFired": "Alert already sent this period",
"thresholdArmed": "Will alert when crossed",
"periodKey": "Current period: {{key}}",
"remaining": "{{amount}} left",
"over": "{{amount}} over",
"period": {
"daily": "Daily",
"weekly": "Weekly",
"monthly": "Monthly"
},
"status": {
"ok": "On track",
"warning": "Warning",
"exceeded": "Over budget"
},
"summary": {
"budgets": "Budgets",
"activeSpend": "Spent (active)",
"activeLimit": "Limit (active)",
"overBudget": "Over budget"
},
"actions": {
"enable": "Enable",
"disable": "Disable"
},
"form": {
"createTitle": "New budget",
"editTitle": "Edit budget",
"period": "Period",
"limit": "Limit (USD)",
"label": "Label (optional)",
"labelPlaceholder": "e.g. Personal cap, Team budget",
"thresholds": "Alert thresholds",
"enabled": "Enabled",
"create": "Create budget"
},
"errors": {
"invalidLimit": "Enter a limit greater than 0"
},
"empty": {
"title": "No budgets yet",
"description": "Create a daily, weekly, or monthly spend budget to track token cost and get alerted before you blow past your limit."
}
}
1 change: 1 addition & 0 deletions client/src/i18n/locales/en/nav.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"sessions": "Sessions",
"activityFeed": "Activity Feed",
"analytics": "Analytics",
"budgets": "Budgets",
"workflows": "Workflows",
"alerts": "Alerts",
"ccConfig": "Claude Config",
Expand Down
50 changes: 50 additions & 0 deletions client/src/i18n/locales/vi/budgets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"title": "Ngân sách chi tiêu",
"subtitle": "Đặt giới hạn USD theo từng kỳ và được cảnh báo trước khi vượt mức",
"newBudget": "Ngân sách mới",
"confirmDelete": "Xóa ngân sách này? Không thể hoàn tác.",
"alertsAt": "Cảnh báo tại",
"thresholdFired": "Đã gửi cảnh báo trong kỳ này",
"thresholdArmed": "Sẽ cảnh báo khi vượt qua",
"periodKey": "Kỳ hiện tại: {{key}}",
"remaining": "Còn {{amount}}",
"over": "Vượt {{amount}}",
"period": {
"daily": "Hàng ngày",
"weekly": "Hàng tuần",
"monthly": "Hàng tháng"
},
"status": {
"ok": "Trong tầm kiểm soát",
"warning": "Cảnh báo",
"exceeded": "Vượt ngân sách"
},
"summary": {
"budgets": "Ngân sách",
"activeSpend": "Đã chi (đang bật)",
"activeLimit": "Giới hạn (đang bật)",
"overBudget": "Vượt ngân sách"
},
"actions": {
"enable": "Bật",
"disable": "Tắt"
},
"form": {
"createTitle": "Ngân sách mới",
"editTitle": "Sửa ngân sách",
"period": "Kỳ",
"limit": "Giới hạn (USD)",
"label": "Nhãn (tùy chọn)",
"labelPlaceholder": "vd: Giới hạn cá nhân, Ngân sách nhóm",
"thresholds": "Ngưỡng cảnh báo",
"enabled": "Đang bật",
"create": "Tạo ngân sách"
},
"errors": {
"invalidLimit": "Nhập giới hạn lớn hơn 0"
},
"empty": {
"title": "Chưa có ngân sách",
"description": "Tạo ngân sách chi tiêu hàng ngày, hàng tuần hoặc hàng tháng để theo dõi chi phí token và được cảnh báo trước khi vượt giới hạn."
}
}
1 change: 1 addition & 0 deletions client/src/i18n/locales/vi/nav.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"sessions": "Phiên",
"activityFeed": "Luồng hoạt động",
"analytics": "Phân tích",
"budgets": "Ngân sách",
"workflows": "Quy trình",
"alerts": "Cảnh báo",
"ccConfig": "Cấu hình Claude",
Expand Down
50 changes: 50 additions & 0 deletions client/src/i18n/locales/zh/budgets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"title": "支出预算",
"subtitle": "为每个周期设置美元上限,在超支前收到提醒",
"newBudget": "新建预算",
"confirmDelete": "删除此预算?此操作无法撤销。",
"alertsAt": "提醒阈值",
"thresholdFired": "本周期已发送提醒",
"thresholdArmed": "达到时将提醒",
"periodKey": "当前周期:{{key}}",
"remaining": "剩余 {{amount}}",
"over": "超出 {{amount}}",
"period": {
"daily": "每日",
"weekly": "每周",
"monthly": "每月"
},
"status": {
"ok": "正常",
"warning": "警告",
"exceeded": "已超预算"
},
"summary": {
"budgets": "预算数",
"activeSpend": "已花费(启用)",
"activeLimit": "上限(启用)",
"overBudget": "超预算数"
},
"actions": {
"enable": "启用",
"disable": "停用"
},
"form": {
"createTitle": "新建预算",
"editTitle": "编辑预算",
"period": "周期",
"limit": "上限(美元)",
"label": "标签(可选)",
"labelPlaceholder": "例如:个人上限、团队预算",
"thresholds": "提醒阈值",
"enabled": "启用",
"create": "创建预算"
},
"errors": {
"invalidLimit": "请输入大于 0 的上限"
},
"empty": {
"title": "暂无预算",
"description": "创建每日、每周或每月支出预算,跟踪 token 成本,并在超出上限前收到提醒。"
}
}
1 change: 1 addition & 0 deletions client/src/i18n/locales/zh/nav.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"sessions": "会话",
"activityFeed": "活动流",
"analytics": "分析",
"budgets": "预算",
"workflows": "工作流",
"alerts": "警报",
"ccConfig": "Claude 配置",
Expand Down
28 changes: 28 additions & 0 deletions client/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import type {
AlertEvent,
AlertRule,
Analytics,
Budget,
BudgetListResponse,
BudgetPeriod,
CostResult,
DashboardEvent,
ModelPricing,
Expand Down Expand Up @@ -375,6 +378,21 @@ export const api = {
request<{ ok: true }>(`/run/${encodeURIComponent(id)}`, { method: "DELETE" }),
},

budgets: {
list: () => request<BudgetListResponse>("/budgets"),
create: (data: BudgetCreateArgs) =>
request<{ budget: Budget }>("/budgets", {
method: "POST",
body: JSON.stringify(data),
}),
update: (id: number, data: BudgetUpdateArgs) =>
request<{ budget: Budget }>(`/budgets/${id}`, {
method: "PUT",
body: JSON.stringify(data),
}),
remove: (id: number) => request<{ ok: boolean }>(`/budgets/${id}`, { method: "DELETE" }),
},

alerts: {
list: (params?: { unacked?: boolean; limit?: number; offset?: number }) => {
const qs = new URLSearchParams();
Expand Down Expand Up @@ -468,6 +486,16 @@ export const api = {
},
};

export interface BudgetCreateArgs {
period: BudgetPeriod;
limit_usd: number;
label?: string | null;
enabled?: boolean;
alert_thresholds?: number[];
}

export type BudgetUpdateArgs = Partial<BudgetCreateArgs>;

function requestBackupsHelper(params?: { scope?: "user" | "project"; type?: CcArtifactType }) {
const qs = new URLSearchParams();
if (params?.scope) qs.set("scope", params.scope);
Expand Down
Loading
Loading