feat: Claude Code Monitor — lanes, pipelines and a merged workspace

Internal SmartGift build of a Claude Code monitoring dashboard.

Lanes: a durable unit of parallel agent work, one per working directory,
tracked across session restarts. Managed lanes are git worktrees the
dashboard provisions and can reset or remove behind a three-check destroy
guard and a counted preflight; adopted lanes are directories you already
own and are never destroyable.

Pipelines: a lane moves through pipeline stages. A stage the agent declares
with evidence renders green; a stage inferred from the tool-event stream
renders dashed amber and never counts as done. Detection is forward-only
within a 30-minute window, and never writes the declared stage.

Workspace: one page at /run with a lane grid, the selected lane's pipeline,
and a full Claude console behind a disclosure.
This commit is contained in:
2026-07-29 17:07:45 +07:00
commit 57dc91585d
783 changed files with 221743 additions and 0 deletions
@@ -0,0 +1,62 @@
---
description: >
Roll up Claude Code sessions by working directory (project) from Agent Monitor
data — session count, total cost, total tokens, and last-active timestamp per cwd
— so per-project activity can be compared at a glance. Use when summarizing where
effort and spend went across projects.
---
# CWD Rollup
Aggregate session activity per working directory (project).
## Input
The user provides: **$ARGUMENTS**
- Empty → roll up **all** working directories.
- A path / project substring → restrict the rollup to matching cwds.
- `top N` → keep only the N highest-cost (or highest-count) projects.
## Data Sources
| Endpoint | Returns |
|----------|---------|
| `GET /api/run/cwds` | the distinct working directories that have sessions — the rollup key set |
| `GET /api/sessions?limit=N` | session list: id, status, model, cwd, started_at, ended_at, cost, metadata (usage_extras with token counts) |
| `GET /api/pricing/cost` | fleet cost: total_cost, breakdown[{ model, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, cost, matched_rule }] — for the fleet total to compute each cwd's share |
## Report Sections
### 1. Key set
`GET /api/run/cwds` for the canonical list of working directories. Apply the
`$ARGUMENTS` filter (substring match) if one was given.
### 2. Pull sessions
`GET /api/sessions?limit=1000`. Bucket sessions by `cwd`.
### 3. Aggregate per cwd
For each working directory compute:
- **sessions** — count.
- **cost** — sum of the inline `cost` field across the bucket.
- **tokens** — sum of input / output / cache-read / cache-write from each session's
metadata `usage_extras` (sum the four into a total, and keep input + output as the
"billable text" subtotal).
- **last active** — the max `started_at` (or `ended_at`) in the bucket.
- **models** — the distinct models seen.
### 4. Share of fleet
`GET /api/pricing/cost` for `total_cost`; show each cwd's cost as a percentage of the
fleet total.
### 5. Ranking
Sort by cost descending by default (or count if the user asked); apply `top N`.
## Output
Markdown table: `project (cwd basename) | sessions | total tokens | cost | % of fleet | last active | models`.
Currency as USD to 4 decimal places; token counts with thousands separators; sort
cost-descending. Add a final TOTAL row summing the columns. Only count tokens that
the session metadata actually carries — if `usage_extras` is absent for a session,
note it as excluded rather than guessing. If the dashboard is unreachable, tell the
user to start it with `npm start` from the repo root.
@@ -0,0 +1,76 @@
---
description: >
Identify stale and empty Claude Code sessions in the Agent Monitor and explain the
cleanup endpoint (POST /api/settings/cleanup), always showing the exact list of
what WOULD be removed before anything is deleted. Cleanup permanently deletes data,
so this skill previews first and requires explicit user confirmation. Use when
tidying the monitoring database.
---
# Session Cleanup
Find prune-worthy sessions and explain cleanup — preview first, delete only on
explicit confirmation.
## Input
The user provides: **$ARGUMENTS**
- Empty / `preview` → only show what would be removed (the safe default).
- `confirm` → the user has reviewed the preview and explicitly authorizes deletion.
- An optional staleness threshold (e.g. `older than 7d`) for what counts as stale.
## Data Sources
| Endpoint | Returns |
|----------|---------|
| `GET /api/sessions?limit=N` | session list: id, status, model, cwd, started_at, ended_at, cost, metadata (turn_count, total_turn_duration_ms) |
| `GET /api/stats` | totals: total_sessions, active_sessions, total_events, events_today, sessions_by_status, agents_by_status |
| `POST /api/settings/cleanup` | runs the cleanup routine and returns what was removed — DESTRUCTIVE, only after confirmation |
## Report Sections
### 1. Baseline
`GET /api/stats` — record total_sessions, sessions_by_status, total_events. This is
the before-state to compare against.
### 2. Identify candidates
`GET /api/sessions?limit=1000`. Flag sessions that are:
- **Empty** — zero events and `turn_count` 0 / null and `cost` 0 (started but never
did anything).
- **Stale active** — `status` active/working but last activity older than the
threshold (default 24h), i.e. never cleanly stopped.
- **Truncated** — no `ended_at` and no recent events.
### 3. Preview table (ALWAYS shown)
List every candidate with the reason it qualifies. State the total count and confirm
that **nothing has been deleted yet**.
### 4. Explain the endpoint
Describe `POST /api/settings/cleanup`: it prunes empty / orphaned sessions and their
dangling events server-side and returns a summary of removed rows. Make clear this
is **permanent** and **not reversible** from the dashboard.
### 5. Execute only on confirmation
If — and only if — `$ARGUMENTS` is `confirm` (or the user has explicitly approved
this run), call `POST /api/settings/cleanup`, then re-read `/api/stats` and report
the before → after delta. Otherwise stop after the preview and tell the user to
re-run with `confirm`.
## Output
A preview Markdown table: `id (short) | status | reason | cwd basename | started_at | cost`,
then a one-line count and the explicit "nothing deleted — re-run with `confirm` to
proceed" notice. On a confirmed run, add a before → after summary using ▲/▼ on the
counts. Currency as USD to 4 decimal places.
## Safety
- This is the ONLY skill in the plugin that mutates data, and only via the one
documented endpoint.
- NEVER call `POST /api/settings/cleanup` without an explicit `confirm` from the
user in this turn — previewing is the default.
- Never widen scope to `POST /api/settings/clear-data` or any other destructive
endpoint; cleanup of stale/empty sessions only.
- If the dashboard is unreachable, tell the user to start it with `npm start` from
the repo root.
@@ -0,0 +1,64 @@
---
description: >
Find Claude Code sessions tracked by the Agent Monitor by project (cwd), model,
status, or date, then rank the matches by cost or recency. Pulls the session list
and the distinct cwd / facet values so filters use real values rather than guesses.
Use when locating a session — "find my EstateWise sessions", "which Opus runs
errored this week", "most expensive sessions in /repo".
---
# Session Search
Locate Claude Code sessions in the Agent Monitor by project, model, status, or date.
## Input
The user provides: **$ARGUMENTS**
A free-form query naming any combination of:
- **project / cwd** — a working-directory path or basename (e.g. `EstateWise`, `/Users/.../repo`)
- **model** — `opus`, `sonnet`, `haiku`, or a full model id substring
- **status** — `active`, `working`, `completed`, `error`
- **date** — `today`, `this week`, or an ISO date / range matched against `started_at`
- **ranking** — `by cost` (default when cost is mentioned) or `recent` (default otherwise)
If the query is empty, return the most recent sessions ranked by recency.
## Data Sources
| Endpoint | Returns |
|----------|---------|
| `GET /api/sessions?limit=N` | session list: id, status, model, cwd, started_at, ended_at, cost, metadata (thinking_blocks, turn_count, total_turn_duration_ms, usage_extras) |
| `GET /api/run/cwds` | the distinct working directories that have sessions — use to resolve a fuzzy project name to exact cwd values |
| `GET /api/events/facets` | distinct facet values (event types, tool names, models, statuses) for validating filters |
## Report Sections
### 1. Resolve filters
Fetch `/api/run/cwds` and `/api/events/facets` to map the user's loose terms to
real values: pick the cwd(s) whose path contains the project term, confirm the
model substring exists, and validate the status against known statuses. State
which concrete filters you settled on.
### 2. Pull candidates
`GET /api/sessions?limit=200` (raise the limit if the date window is wide). Filter
in-memory by cwd, model (substring, case-insensitive), status, and `started_at`
date window.
### 3. Rank
Sort by `cost` descending when the user asked "by cost"; otherwise by `started_at`
descending (most recent first). Keep the top 20 unless the user asked for more.
### 4. Matches
One row per session.
### 5. Summary
Count of matches, summed cost across matches, and the model / status distribution.
## Output
Markdown table: `# | id (short) | status | model | cwd (basename) | started_at | cost`.
Currency as USD to 4 decimal places; token / count fields with thousands separators.
If a filter resolved to zero rows, say so and show the closest available values
(e.g. the cwds that *do* exist) rather than fabricating results. If the dashboard
is unreachable, tell the user to start it with `npm start` from the repo root.
@@ -0,0 +1,61 @@
---
description: >
Render an ordered timeline of one Claude Code session's events (every event type)
with per-event durations and tool names, reconstructed from Agent Monitor data.
Pairs PreToolUse with PostToolUse to compute tool durations and surfaces gaps,
errors, and compaction points. Use when reconstructing what happened in a session
step by step.
---
# Session Timeline
Reconstruct the chronological event timeline of a single Claude Code session.
## Input
The user provides: **$ARGUMENTS**
- A **session ID** to time-line, or
- "latest" / "last" for the most recent session.
## Data Sources
| Endpoint | Returns |
|----------|---------|
| `GET /api/sessions/:id` | session header: status, model, cwd, started_at, ended_at, cost, metadata (thinking_blocks, turn_count, total_turn_duration_ms) — and nested events |
| `GET /api/events?session_id=X` | the full event stream: event_type (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, Notification, Compaction, APIError, TurnDuration), tool_name, summary, data, timestamp |
## Report Sections
### 1. Resolve & header
If "latest", `GET /api/sessions?limit=1` to get the id, then `GET /api/sessions/:id`.
Print a one-line header: id, status, model, cwd basename, started_at → ended_at,
turn_count, total_turn_duration_ms, cost.
### 2. Build the ordered timeline
`GET /api/events?session_id=X`. Sort strictly by `timestamp`. For each event emit a
row with: relative offset from `started_at` (e.g. `+00:03.412`), event_type,
tool_name (when present), and a one-line `summary`.
### 3. Compute durations
Pair each `PreToolUse` with its matching `PostToolUse` (same tool_name, next
occurrence) and show the tool's wall-clock duration. For `TurnDuration` events use
the recorded duration directly. Flag any `PreToolUse` with no matching `PostToolUse`
as **unclosed**.
### 4. Annotate notable points
Mark `APIError` (❌), `Compaction` (⚠️ context compressed), `SubagentStop`
(subagent finished), `Notification` (), and any timeline gap > 30s between
consecutive events as an idle window.
### 5. Tallies
Event count by type, total tool time vs. session wall time, and the longest single
tool call.
## Output
A Markdown table — `offset | event_type | tool_name | duration | summary` — in
strict timestamp order, preceded by the header line and followed by the tallies.
Durations in ms or `mm:ss.mmm`; currency as USD to 4 decimal places. Never invent a
duration when a PostToolUse is missing — label it `unclosed`. If the dashboard is
unreachable, tell the user to start it with `npm start` from the repo root.
@@ -0,0 +1,58 @@
---
description: >
Walk a Claude Code session transcript turn-by-turn from Agent Monitor data,
summarizing each user, assistant, and tool message in order so a long conversation
can be reviewed quickly. Anchors the recap to the session header (model, cost,
turn_count). Use when reviewing what was actually said and done in a conversation.
---
# Transcript Replay
Replay a session transcript one turn at a time with a concise summary of each message.
## Input
The user provides: **$ARGUMENTS**
- A **session ID** to replay, or
- "latest" / "last" for the most recent session.
- Optionally a turn range (e.g. `1-10`) or `errors` to focus on tool failures.
## Data Sources
| Endpoint | Returns |
|----------|---------|
| `GET /api/sessions/:id/transcript` | ordered transcript messages: role (user / assistant / tool), content, tool_name and tool result where applicable, timestamps |
| `GET /api/sessions/:id` | session header: status, model, cwd, started_at, ended_at, cost, metadata (thinking_blocks, turn_count, total_turn_duration_ms) |
## Report Sections
### 1. Header
`GET /api/sessions/:id`. Print id, model, cwd basename, status, turn_count,
thinking_blocks, total_turn_duration_ms, and cost in one block.
### 2. Turn-by-turn walk
`GET /api/sessions/:id/transcript`. Iterate messages in order. For each turn emit
one compact entry:
- **user** — the request in one sentence (quote the literal ask only if short).
- **assistant** — the decision / action taken, plus which tools it invoked.
- **tool** — the tool name and a one-line result (success value or the error text);
do not paste large tool payloads.
Group an assistant message with the tool calls it triggered so each "turn" reads as
intent → action → result.
### 3. Thread highlights
After the walk, pull out: the original goal, the key turning points, any tool
failures or retries, and how the session ended (resolved / errored / abandoned).
## Output
A numbered turn list (`Turn N — <role>: <one-line summary>`), grouped intent →
action → result, preceded by the header block and followed by the highlights.
Truncate any quoted content past ~200 chars with `…`. Currency as USD to 4 decimal
places. Summarize faithfully — never invent message content that is not in the
transcript. If the transcript endpoint returns empty, say the session has no stored
transcript (it may predate transcript capture or need a reimport) rather than
fabricating turns. If the dashboard is unreachable, tell the user to start it with
`npm start` from the repo root.