b291091e14
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.
9696 lines
371 KiB
YAML
9696 lines
371 KiB
YAML
# DO NOT EDIT BY HAND. Generated from server/openapi.js via `npm run openapi:yaml`.
|
||
# This YAML mirrors the live spec served at GET /api/openapi.json.
|
||
openapi: 3.0.3
|
||
info:
|
||
title: Agent Dashboard for Claude Code API
|
||
version: 1.4.6
|
||
description: HTTP API for real-time Claude Code session monitoring, agent lifecycle tracking, analytics, pricing, hooks ingestion, and workflow intelligence.
|
||
contact:
|
||
name: Nguyễn Ngọc Trí Vĩ
|
||
email: vinnt@smartgift.vn
|
||
url: https://git.smartgift.io.vn/Smartgift-AI/Claude-Code-Monitor
|
||
externalDocs:
|
||
description: Project documentation
|
||
url: https://git.smartgift.io.vn/Smartgift-AI/Claude-Code-Monitor#readme
|
||
servers:
|
||
- url: http://localhost:4820
|
||
description: Local dashboard server (default)
|
||
- url: http://127.0.0.1:4820
|
||
description: Local loopback endpoint used by hook-handler
|
||
tags:
|
||
- name: Health
|
||
description: Service liveness checks
|
||
- name: Metrics
|
||
description: Prometheus / OpenMetrics scrape endpoint
|
||
- name: Sessions
|
||
description: Claude Code session lifecycle
|
||
- name: Agents
|
||
description: Main/subagent records and status
|
||
- name: Events
|
||
description: Event stream persistence
|
||
- name: Stats
|
||
description: High-level dashboard counters
|
||
- name: Analytics
|
||
description: Aggregated analytics views
|
||
- name: Hooks
|
||
description: Claude hook ingestion endpoint
|
||
- name: Pricing
|
||
description: Model pricing and token cost calculations
|
||
- name: Workflows
|
||
description: Workflow intelligence and session drill-in
|
||
- name: Settings
|
||
description: Operational maintenance endpoints
|
||
- name: Updates
|
||
description: Detect upstream git changes so users can pull and restart manually (local dashboard installs)
|
||
- name: Alerts
|
||
description: 'Rules-based alerting: rule CRUD, fired-alert feed, acknowledgement'
|
||
- name: Webhooks
|
||
description: 'Universal webhook delivery for fired alerts: target CRUD (Slack/Discord/Teams/generic), test probe, and delivery log. Secrets are never returned.'
|
||
- name: Remote Sources
|
||
description: Config for remote SSH machines the dashboard pulls Claude Code history from. No secrets are stored — SSH auth defers to the host's SSH stack (agent, ~/.ssh/config, keys).
|
||
- name: Documentation
|
||
description: OpenAPI/Swagger endpoints
|
||
- name: CcConfig
|
||
description: 'Claude Code configuration explorer: discover and (for low-risk artifacts) edit skills, agents, commands, output styles, MCP servers, hooks, settings, memory, plugins, marketplaces, keybindings, statusline'
|
||
- name: Run
|
||
description: Spawn and supervise Claude Code runs from the dashboard (headless or interactive conversation), stream output over WebSocket, and manage run history
|
||
- name: Lanes
|
||
description: Durable parallel-work lanes and dashboard-managed git worktrees
|
||
- name: Push
|
||
description: Web Push notification subscriptions and broadcast (VAPID); also fires native Electron notifications when hosted in the desktop app
|
||
components:
|
||
parameters:
|
||
SessionIdPath:
|
||
name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: Session ID
|
||
AgentIdPath:
|
||
name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: Agent ID
|
||
PatternPath:
|
||
name: pattern
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: Model pattern (URL-encoded)
|
||
LimitQuery:
|
||
name: limit
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
minimum: 0
|
||
description: Page size
|
||
OffsetQuery:
|
||
name: offset
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
minimum: 0
|
||
description: Pagination offset
|
||
SessionStatusQuery:
|
||
name: status
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
enum:
|
||
- active
|
||
- completed
|
||
- error
|
||
- abandoned
|
||
description: Filter by session status
|
||
AgentStatusQuery:
|
||
name: status
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
enum:
|
||
- working
|
||
- waiting
|
||
- completed
|
||
- error
|
||
description: Filter by agent status
|
||
SessionFilterQuery:
|
||
name: session_id
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Filter by session ID
|
||
WorkflowStatusQuery:
|
||
name: status
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
enum:
|
||
- all
|
||
- active
|
||
- completed
|
||
- error
|
||
- abandoned
|
||
description: Filter workflow aggregates by session status
|
||
SourcesQuery:
|
||
name: sources
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Comma-separated list of data-source ids to include. The built-in local history is the id `local`; remote SSH machines use their `remote_sources.id`. Omit to include every source. Filters on the `sessions.source` column.
|
||
schemas:
|
||
ErrorObject:
|
||
type: object
|
||
required:
|
||
- code
|
||
- message
|
||
properties:
|
||
code:
|
||
type: string
|
||
message:
|
||
type: string
|
||
ErrorResponse:
|
||
type: object
|
||
required:
|
||
- error
|
||
properties:
|
||
error:
|
||
$ref: '#/components/schemas/ErrorObject'
|
||
MessageErrorObject:
|
||
type: object
|
||
required:
|
||
- message
|
||
properties:
|
||
message:
|
||
type: string
|
||
MessageErrorResponse:
|
||
type: object
|
||
required:
|
||
- error
|
||
properties:
|
||
error:
|
||
$ref: '#/components/schemas/MessageErrorObject'
|
||
CountMap:
|
||
type: object
|
||
additionalProperties:
|
||
type: integer
|
||
Session:
|
||
type: object
|
||
required:
|
||
- id
|
||
- status
|
||
- started_at
|
||
- updated_at
|
||
properties:
|
||
id:
|
||
type: string
|
||
name:
|
||
type: string
|
||
nullable: true
|
||
status:
|
||
type: string
|
||
enum:
|
||
- active
|
||
- completed
|
||
- error
|
||
- abandoned
|
||
cwd:
|
||
type: string
|
||
nullable: true
|
||
model:
|
||
type: string
|
||
nullable: true
|
||
started_at:
|
||
type: string
|
||
format: date-time
|
||
ended_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
metadata:
|
||
type: string
|
||
nullable: true
|
||
description: JSON-encoded session metadata
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
agent_count:
|
||
type: integer
|
||
nullable: true
|
||
last_activity:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
cost:
|
||
type: number
|
||
nullable: true
|
||
awaiting_input_since:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
description: ISO timestamp set when Claude Code is blocked waiting for the user (permission prompt or input request). Null when not waiting; cleared on the next non-Notification hook event.
|
||
awaiting_reason:
|
||
type: string
|
||
enum:
|
||
- notification
|
||
- stop
|
||
- session_start
|
||
- interrupted
|
||
nullable: true
|
||
description: 'Why the session is awaiting input: ''notification'' (Claude asked the user something), ''stop'' (turn completed, waiting for the next prompt), ''session_start'' (new/resumed session waiting for the first prompt), or ''interrupted'' (watchdog/Esc recovery). Null when not waiting; cleared alongside awaiting_input_since.'
|
||
Agent:
|
||
type: object
|
||
required:
|
||
- id
|
||
- session_id
|
||
- name
|
||
- type
|
||
- status
|
||
- started_at
|
||
- updated_at
|
||
properties:
|
||
id:
|
||
type: string
|
||
session_id:
|
||
type: string
|
||
name:
|
||
type: string
|
||
type:
|
||
type: string
|
||
enum:
|
||
- main
|
||
- subagent
|
||
subagent_type:
|
||
type: string
|
||
nullable: true
|
||
status:
|
||
type: string
|
||
enum:
|
||
- working
|
||
- waiting
|
||
- completed
|
||
- error
|
||
task:
|
||
type: string
|
||
nullable: true
|
||
current_tool:
|
||
type: string
|
||
nullable: true
|
||
started_at:
|
||
type: string
|
||
format: date-time
|
||
ended_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
parent_agent_id:
|
||
type: string
|
||
nullable: true
|
||
metadata:
|
||
type: string
|
||
nullable: true
|
||
description: JSON-encoded agent metadata
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
awaiting_input_since:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
description: ISO timestamp set when this agent is blocked waiting for user input. Cleared on the next non-Notification hook event for the session.
|
||
awaiting_reason:
|
||
type: string
|
||
enum:
|
||
- notification
|
||
- stop
|
||
- session_start
|
||
- interrupted
|
||
nullable: true
|
||
description: 'Why this agent is awaiting input: ''notification'' (Claude asked the user something), ''stop'' (turn completed, waiting for the next prompt), ''session_start'' (new/resumed session waiting for the first prompt), or ''interrupted'' (watchdog/Esc recovery). Null when not waiting; cleared alongside awaiting_input_since.'
|
||
DashboardEvent:
|
||
type: object
|
||
required:
|
||
- session_id
|
||
- event_type
|
||
- created_at
|
||
properties:
|
||
id:
|
||
type: integer
|
||
nullable: true
|
||
session_id:
|
||
type: string
|
||
agent_id:
|
||
type: string
|
||
nullable: true
|
||
event_type:
|
||
type: string
|
||
tool_name:
|
||
type: string
|
||
nullable: true
|
||
summary:
|
||
type: string
|
||
nullable: true
|
||
data:
|
||
type: string
|
||
nullable: true
|
||
description: JSON-encoded event payload
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
HealthResponse:
|
||
type: object
|
||
required:
|
||
- status
|
||
- timestamp
|
||
- version
|
||
properties:
|
||
status:
|
||
type: string
|
||
enum:
|
||
- ok
|
||
version:
|
||
type: string
|
||
description: Dashboard release version from package.json
|
||
example: 1.4.6
|
||
timestamp:
|
||
type: string
|
||
format: date-time
|
||
SessionsListResponse:
|
||
type: object
|
||
required:
|
||
- sessions
|
||
- limit
|
||
- offset
|
||
- total
|
||
properties:
|
||
sessions:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Session'
|
||
limit:
|
||
type: integer
|
||
offset:
|
||
type: integer
|
||
total:
|
||
type: integer
|
||
description: Total sessions matching the filters (independent of limit/offset). Used by paginators.
|
||
SessionCreateRequest:
|
||
type: object
|
||
required:
|
||
- id
|
||
properties:
|
||
id:
|
||
type: string
|
||
name:
|
||
type: string
|
||
cwd:
|
||
type: string
|
||
model:
|
||
type: string
|
||
metadata:
|
||
type: object
|
||
additionalProperties: true
|
||
SessionCreateResponse:
|
||
type: object
|
||
required:
|
||
- session
|
||
- created
|
||
properties:
|
||
session:
|
||
$ref: '#/components/schemas/Session'
|
||
created:
|
||
type: boolean
|
||
SessionDetailResponse:
|
||
type: object
|
||
required:
|
||
- session
|
||
- agents
|
||
- events
|
||
properties:
|
||
session:
|
||
$ref: '#/components/schemas/Session'
|
||
agents:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Agent'
|
||
events:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/DashboardEvent'
|
||
TranscriptInfo:
|
||
type: object
|
||
required:
|
||
- id
|
||
- name
|
||
- type
|
||
- has_transcript
|
||
properties:
|
||
id:
|
||
type: string
|
||
description: '''main'' for the session''s main transcript, otherwise a subagent or compaction id.'
|
||
name:
|
||
type: string
|
||
type:
|
||
type: string
|
||
enum:
|
||
- main
|
||
- subagent
|
||
- compaction
|
||
subagent_type:
|
||
type: string
|
||
nullable: true
|
||
has_transcript:
|
||
type: boolean
|
||
db_agent_id:
|
||
type: string
|
||
nullable: true
|
||
description: Foreign key into agents.id when this transcript belongs to a tracked subagent.
|
||
TranscriptListResponse:
|
||
type: object
|
||
required:
|
||
- transcripts
|
||
properties:
|
||
transcripts:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/TranscriptInfo'
|
||
TranscriptContent:
|
||
type: object
|
||
required:
|
||
- type
|
||
properties:
|
||
type:
|
||
type: string
|
||
enum:
|
||
- text
|
||
- tool_use
|
||
- tool_result
|
||
- thinking
|
||
text:
|
||
type: string
|
||
name:
|
||
type: string
|
||
description: Tool name when type === tool_use.
|
||
id:
|
||
type: string
|
||
description: Tool-use id used to pair tool_use with tool_result.
|
||
input:
|
||
description: 'Tool input payload (object) or { _truncated: string } when oversized.'
|
||
oneOf:
|
||
- type: object
|
||
additionalProperties: true
|
||
- type: string
|
||
output:
|
||
type: string
|
||
description: Tool output text when type === tool_result.
|
||
is_error:
|
||
type: boolean
|
||
TranscriptMessage:
|
||
type: object
|
||
required:
|
||
- type
|
||
- content
|
||
properties:
|
||
type:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- assistant
|
||
- session_event
|
||
description: Raw line type. session_event is a synthetic marker (e.g. a /rename) injected by the server, not a real transcript line. Mid-turn queued messages (queued_command attachments) surface as type user.
|
||
sender:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- assistant
|
||
- orchestrator
|
||
- system
|
||
- tool
|
||
description: 'TRUE sender of the line: the human (user), the agent (assistant), a subagent''s task assigned by its parent (orchestrator), a harness injection such as a task-notification or [SYSTEM NOTIFICATION …] banner (system), or a tool_result echoed on a user line (tool).'
|
||
timestamp:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
content:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/TranscriptContent'
|
||
line:
|
||
type: integer
|
||
minimum: 1
|
||
description: JSONL line number the message was parsed from (pagination cursor).
|
||
model:
|
||
type: string
|
||
usage:
|
||
type: object
|
||
properties:
|
||
input_tokens:
|
||
type: integer
|
||
minimum: 0
|
||
output_tokens:
|
||
type: integer
|
||
minimum: 0
|
||
cache_read_input_tokens:
|
||
type: integer
|
||
minimum: 0
|
||
cache_creation_input_tokens:
|
||
type: integer
|
||
minimum: 0
|
||
event_kind:
|
||
type: string
|
||
enum:
|
||
- rename
|
||
description: 'For type === session_event: the TUI action this marker represents.'
|
||
title:
|
||
type: string
|
||
description: 'For type === session_event: the new session title.'
|
||
TranscriptResponse:
|
||
type: object
|
||
required:
|
||
- messages
|
||
- total
|
||
- has_more
|
||
- last_line
|
||
- first_line
|
||
properties:
|
||
messages:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/TranscriptMessage'
|
||
total:
|
||
type: integer
|
||
minimum: 0
|
||
description: Total messages available in the transcript.
|
||
has_more:
|
||
type: boolean
|
||
description: True when older messages remain (use `before` to load them).
|
||
last_line:
|
||
type: integer
|
||
minimum: 0
|
||
description: JSONL line number of the newest returned message — pass back as `after` for incremental fetches.
|
||
first_line:
|
||
type: integer
|
||
minimum: 0
|
||
description: JSONL line number of the oldest returned message — pass back as `before` to page backwards.
|
||
SessionStatsResponse:
|
||
type: object
|
||
description: Aggregated counts powering the SessionOverview panel on the Session Detail page. All aggregation runs in SQL.
|
||
required:
|
||
- session_id
|
||
- total_events
|
||
- events_by_type
|
||
- tools_used
|
||
- error_count
|
||
- first_event_at
|
||
- last_event_at
|
||
- agents
|
||
- subagent_types
|
||
- tokens
|
||
properties:
|
||
session_id:
|
||
type: string
|
||
total_events:
|
||
type: integer
|
||
minimum: 0
|
||
events_by_type:
|
||
type: array
|
||
items:
|
||
type: object
|
||
required:
|
||
- event_type
|
||
- count
|
||
properties:
|
||
event_type:
|
||
type: string
|
||
count:
|
||
type: integer
|
||
minimum: 0
|
||
tools_used:
|
||
type: array
|
||
description: Top 15 tools used in this session, sorted by count descending.
|
||
items:
|
||
type: object
|
||
required:
|
||
- tool_name
|
||
- count
|
||
properties:
|
||
tool_name:
|
||
type: string
|
||
count:
|
||
type: integer
|
||
minimum: 0
|
||
error_count:
|
||
type: integer
|
||
minimum: 0
|
||
description: Events whose event_type or summary matches /error/i or /failed/i (case-insensitive).
|
||
first_event_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
last_event_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
agents:
|
||
type: object
|
||
required:
|
||
- total
|
||
- main
|
||
- subagent
|
||
- compaction
|
||
- by_status
|
||
properties:
|
||
total:
|
||
type: integer
|
||
minimum: 0
|
||
main:
|
||
type: integer
|
||
minimum: 0
|
||
subagent:
|
||
type: integer
|
||
minimum: 0
|
||
compaction:
|
||
type: integer
|
||
minimum: 0
|
||
by_status:
|
||
type: object
|
||
additionalProperties:
|
||
type: integer
|
||
minimum: 0
|
||
subagent_types:
|
||
type: array
|
||
description: Subagent types in this session with counts. Excludes the special 'compaction' type which is surfaced via agents.compaction.
|
||
items:
|
||
type: object
|
||
required:
|
||
- subagent_type
|
||
- count
|
||
properties:
|
||
subagent_type:
|
||
type: string
|
||
count:
|
||
type: integer
|
||
minimum: 0
|
||
tokens:
|
||
type: object
|
||
required:
|
||
- input_tokens
|
||
- output_tokens
|
||
- cache_read_tokens
|
||
- cache_write_tokens
|
||
properties:
|
||
input_tokens:
|
||
type: integer
|
||
minimum: 0
|
||
output_tokens:
|
||
type: integer
|
||
minimum: 0
|
||
cache_read_tokens:
|
||
type: integer
|
||
minimum: 0
|
||
cache_write_tokens:
|
||
type: integer
|
||
minimum: 0
|
||
SessionUpdateRequest:
|
||
type: object
|
||
properties:
|
||
name:
|
||
type: string
|
||
status:
|
||
type: string
|
||
enum:
|
||
- active
|
||
- completed
|
||
- error
|
||
- abandoned
|
||
ended_at:
|
||
type: string
|
||
format: date-time
|
||
metadata:
|
||
type: object
|
||
additionalProperties: true
|
||
SessionUpdateResponse:
|
||
type: object
|
||
required:
|
||
- session
|
||
properties:
|
||
session:
|
||
$ref: '#/components/schemas/Session'
|
||
AgentsListResponse:
|
||
type: object
|
||
required:
|
||
- agents
|
||
- limit
|
||
- offset
|
||
properties:
|
||
agents:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Agent'
|
||
limit:
|
||
type: integer
|
||
offset:
|
||
type: integer
|
||
AgentCreateRequest:
|
||
type: object
|
||
required:
|
||
- id
|
||
- session_id
|
||
- name
|
||
properties:
|
||
id:
|
||
type: string
|
||
session_id:
|
||
type: string
|
||
name:
|
||
type: string
|
||
type:
|
||
type: string
|
||
enum:
|
||
- main
|
||
- subagent
|
||
subagent_type:
|
||
type: string
|
||
status:
|
||
type: string
|
||
enum:
|
||
- working
|
||
- waiting
|
||
- completed
|
||
- error
|
||
task:
|
||
type: string
|
||
parent_agent_id:
|
||
type: string
|
||
metadata:
|
||
type: object
|
||
additionalProperties: true
|
||
AgentCreateResponse:
|
||
type: object
|
||
required:
|
||
- agent
|
||
- created
|
||
properties:
|
||
agent:
|
||
$ref: '#/components/schemas/Agent'
|
||
created:
|
||
type: boolean
|
||
AgentDetailResponse:
|
||
type: object
|
||
required:
|
||
- agent
|
||
properties:
|
||
agent:
|
||
$ref: '#/components/schemas/Agent'
|
||
AgentUpdateRequest:
|
||
type: object
|
||
properties:
|
||
name:
|
||
type: string
|
||
status:
|
||
type: string
|
||
enum:
|
||
- working
|
||
- waiting
|
||
- completed
|
||
- error
|
||
task:
|
||
type: string
|
||
current_tool:
|
||
type: string
|
||
nullable: true
|
||
ended_at:
|
||
type: string
|
||
format: date-time
|
||
metadata:
|
||
type: object
|
||
additionalProperties: true
|
||
AgentUpdateResponse:
|
||
type: object
|
||
required:
|
||
- agent
|
||
properties:
|
||
agent:
|
||
$ref: '#/components/schemas/Agent'
|
||
EventsListResponse:
|
||
type: object
|
||
required:
|
||
- events
|
||
- limit
|
||
- offset
|
||
- total
|
||
properties:
|
||
events:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/DashboardEvent'
|
||
limit:
|
||
type: integer
|
||
offset:
|
||
type: integer
|
||
total:
|
||
type: integer
|
||
description: Total rows matching the current filter (for UI pagination)
|
||
EventsFacetsResponse:
|
||
type: object
|
||
required:
|
||
- event_types
|
||
- tool_names
|
||
properties:
|
||
event_types:
|
||
type: array
|
||
items:
|
||
type: string
|
||
tool_names:
|
||
type: array
|
||
items:
|
||
type: string
|
||
StatsResponse:
|
||
type: object
|
||
required:
|
||
- total_sessions
|
||
- active_sessions
|
||
- active_agents
|
||
- total_agents
|
||
- total_events
|
||
- events_today
|
||
- ws_connections
|
||
- agents_by_status
|
||
- sessions_by_status
|
||
properties:
|
||
total_sessions:
|
||
type: integer
|
||
active_sessions:
|
||
type: integer
|
||
active_agents:
|
||
type: integer
|
||
total_agents:
|
||
type: integer
|
||
total_events:
|
||
type: integer
|
||
events_today:
|
||
type: integer
|
||
ws_connections:
|
||
type: integer
|
||
agents_by_status:
|
||
$ref: '#/components/schemas/CountMap'
|
||
sessions_by_status:
|
||
$ref: '#/components/schemas/CountMap'
|
||
AnalyticsResponse:
|
||
type: object
|
||
required:
|
||
- tokens
|
||
- tool_usage
|
||
- daily_events
|
||
- daily_sessions
|
||
- agent_types
|
||
- event_types
|
||
- avg_events_per_session
|
||
- total_subagents
|
||
- overview
|
||
- agents_by_status
|
||
- sessions_by_status
|
||
properties:
|
||
tokens:
|
||
type: object
|
||
required:
|
||
- total_input
|
||
- total_output
|
||
- total_cache_read
|
||
- total_cache_write
|
||
properties:
|
||
total_input:
|
||
type: integer
|
||
total_output:
|
||
type: integer
|
||
total_cache_read:
|
||
type: integer
|
||
total_cache_write:
|
||
type: integer
|
||
tool_usage:
|
||
type: array
|
||
items:
|
||
type: object
|
||
required:
|
||
- tool_name
|
||
- count
|
||
properties:
|
||
tool_name:
|
||
type: string
|
||
count:
|
||
type: integer
|
||
daily_events:
|
||
type: array
|
||
items:
|
||
type: object
|
||
required:
|
||
- date
|
||
- count
|
||
properties:
|
||
date:
|
||
type: string
|
||
count:
|
||
type: integer
|
||
daily_sessions:
|
||
type: array
|
||
items:
|
||
type: object
|
||
required:
|
||
- date
|
||
- count
|
||
properties:
|
||
date:
|
||
type: string
|
||
count:
|
||
type: integer
|
||
agent_types:
|
||
type: array
|
||
items:
|
||
type: object
|
||
required:
|
||
- subagent_type
|
||
- count
|
||
properties:
|
||
subagent_type:
|
||
type: string
|
||
nullable: true
|
||
count:
|
||
type: integer
|
||
event_types:
|
||
type: array
|
||
items:
|
||
type: object
|
||
required:
|
||
- event_type
|
||
- count
|
||
properties:
|
||
event_type:
|
||
type: string
|
||
count:
|
||
type: integer
|
||
avg_events_per_session:
|
||
type: number
|
||
total_subagents:
|
||
type: integer
|
||
overview:
|
||
type: object
|
||
required:
|
||
- total_sessions
|
||
- active_sessions
|
||
- active_agents
|
||
- total_agents
|
||
- total_events
|
||
properties:
|
||
total_sessions:
|
||
type: integer
|
||
active_sessions:
|
||
type: integer
|
||
active_agents:
|
||
type: integer
|
||
total_agents:
|
||
type: integer
|
||
total_events:
|
||
type: integer
|
||
agents_by_status:
|
||
$ref: '#/components/schemas/CountMap'
|
||
sessions_by_status:
|
||
$ref: '#/components/schemas/CountMap'
|
||
HookEventRequest:
|
||
type: object
|
||
required:
|
||
- hook_type
|
||
- data
|
||
properties:
|
||
hook_type:
|
||
type: string
|
||
description: 'Hook type from Claude Code (common values: PreToolUse, PostToolUse, Stop, SubagentStop, Notification, SessionStart, SessionEnd)'
|
||
data:
|
||
type: object
|
||
required:
|
||
- session_id
|
||
properties:
|
||
session_id:
|
||
type: string
|
||
tool_name:
|
||
type: string
|
||
transcript_path:
|
||
type: string
|
||
additionalProperties: true
|
||
HookEventResponse:
|
||
type: object
|
||
required:
|
||
- ok
|
||
- event
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
event:
|
||
$ref: '#/components/schemas/DashboardEvent'
|
||
PricingRule:
|
||
type: object
|
||
required:
|
||
- model_pattern
|
||
- display_name
|
||
- input_per_mtok
|
||
- output_per_mtok
|
||
- cache_read_per_mtok
|
||
- cache_write_per_mtok
|
||
- cache_write_1h_per_mtok
|
||
- updated_at
|
||
properties:
|
||
model_pattern:
|
||
type: string
|
||
display_name:
|
||
type: string
|
||
input_per_mtok:
|
||
type: number
|
||
output_per_mtok:
|
||
type: number
|
||
cache_read_per_mtok:
|
||
type: number
|
||
cache_write_per_mtok:
|
||
type: number
|
||
description: 5m ephemeral cache-write rate
|
||
cache_write_1h_per_mtok:
|
||
type: number
|
||
description: 1h ephemeral cache-write rate
|
||
fast_input_per_mtok:
|
||
type: number
|
||
description: Fast-mode input rate (0 = none)
|
||
fast_output_per_mtok:
|
||
type: number
|
||
description: Fast-mode output rate (0 = none)
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
PricingUpsertRequest:
|
||
type: object
|
||
required:
|
||
- model_pattern
|
||
- display_name
|
||
properties:
|
||
model_pattern:
|
||
type: string
|
||
display_name:
|
||
type: string
|
||
input_per_mtok:
|
||
type: number
|
||
output_per_mtok:
|
||
type: number
|
||
cache_read_per_mtok:
|
||
type: number
|
||
cache_write_per_mtok:
|
||
type: number
|
||
description: 5m ephemeral cache-write rate
|
||
cache_write_1h_per_mtok:
|
||
type: number
|
||
description: 1h ephemeral cache-write rate
|
||
fast_input_per_mtok:
|
||
type: number
|
||
description: Fast-mode input rate (0 = none)
|
||
fast_output_per_mtok:
|
||
type: number
|
||
description: Fast-mode output rate (0 = none)
|
||
PricingListResponse:
|
||
type: object
|
||
required:
|
||
- pricing
|
||
properties:
|
||
pricing:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/PricingRule'
|
||
PricingUpsertResponse:
|
||
type: object
|
||
required:
|
||
- pricing
|
||
properties:
|
||
pricing:
|
||
$ref: '#/components/schemas/PricingRule'
|
||
CostBreakdownItem:
|
||
type: object
|
||
required:
|
||
- model
|
||
- input_tokens
|
||
- output_tokens
|
||
- cache_read_tokens
|
||
- cache_write_tokens
|
||
- cost
|
||
- matched_rule
|
||
properties:
|
||
model:
|
||
type: string
|
||
speed:
|
||
type: string
|
||
inference_geo:
|
||
type: string
|
||
service_tier:
|
||
type: string
|
||
input_tokens:
|
||
type: integer
|
||
output_tokens:
|
||
type: integer
|
||
cache_read_tokens:
|
||
type: integer
|
||
cache_write_tokens:
|
||
type: integer
|
||
cache_write_1h_tokens:
|
||
type: integer
|
||
web_search_requests:
|
||
type: integer
|
||
web_fetch_requests:
|
||
type: integer
|
||
code_execution_requests:
|
||
type: integer
|
||
cost:
|
||
type: number
|
||
matched_rule:
|
||
type: string
|
||
nullable: true
|
||
DailyCostItem:
|
||
type: object
|
||
required:
|
||
- date
|
||
- cost
|
||
properties:
|
||
date:
|
||
type: string
|
||
format: date
|
||
cost:
|
||
type: number
|
||
CostResult:
|
||
type: object
|
||
required:
|
||
- total_cost
|
||
- breakdown
|
||
- daily_costs
|
||
properties:
|
||
total_cost:
|
||
type: number
|
||
breakdown:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/CostBreakdownItem'
|
||
daily_costs:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/DailyCostItem'
|
||
feature_costs:
|
||
type: object
|
||
description: Server-tool surcharges separate from token cost
|
||
properties:
|
||
web_search_cost:
|
||
type: number
|
||
web_fetch_cost:
|
||
type: number
|
||
code_execution_cost:
|
||
type: number
|
||
code_execution_hours_estimated:
|
||
type: number
|
||
code_execution_free_hours:
|
||
type: number
|
||
unpriced_models:
|
||
type: array
|
||
description: Models with usage but no matching pricing rule (cost not counted)
|
||
items:
|
||
type: object
|
||
properties:
|
||
model:
|
||
type: string
|
||
input_tokens:
|
||
type: integer
|
||
output_tokens:
|
||
type: integer
|
||
cache_read_tokens:
|
||
type: integer
|
||
cache_write_tokens:
|
||
type: integer
|
||
DeleteOkResponse:
|
||
type: object
|
||
required:
|
||
- ok
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
WorkflowAggregateResponse:
|
||
type: object
|
||
required:
|
||
- stats
|
||
- orchestration
|
||
- toolFlow
|
||
- effectiveness
|
||
- patterns
|
||
- modelDelegation
|
||
- errorPropagation
|
||
- concurrency
|
||
- complexity
|
||
- compaction
|
||
- cooccurrence
|
||
properties:
|
||
stats:
|
||
type: object
|
||
required:
|
||
- totalSessions
|
||
- totalAgents
|
||
- totalSubagents
|
||
- avgSubagents
|
||
- successRate
|
||
- avgDepth
|
||
- avgDurationSec
|
||
- totalCompactions
|
||
- avgCompactions
|
||
properties:
|
||
totalSessions:
|
||
type: integer
|
||
totalAgents:
|
||
type: integer
|
||
totalSubagents:
|
||
type: integer
|
||
avgSubagents:
|
||
type: number
|
||
successRate:
|
||
type: number
|
||
avgDepth:
|
||
type: number
|
||
avgDurationSec:
|
||
type: integer
|
||
totalCompactions:
|
||
type: integer
|
||
avgCompactions:
|
||
type: number
|
||
topFlow:
|
||
type: object
|
||
nullable: true
|
||
properties:
|
||
source:
|
||
type: string
|
||
target:
|
||
type: string
|
||
count:
|
||
type: integer
|
||
orchestration:
|
||
type: object
|
||
additionalProperties: true
|
||
toolFlow:
|
||
type: object
|
||
additionalProperties: true
|
||
effectiveness:
|
||
type: array
|
||
items:
|
||
type: object
|
||
additionalProperties: true
|
||
patterns:
|
||
type: object
|
||
additionalProperties: true
|
||
modelDelegation:
|
||
type: object
|
||
additionalProperties: true
|
||
errorPropagation:
|
||
type: object
|
||
additionalProperties: true
|
||
concurrency:
|
||
type: object
|
||
additionalProperties: true
|
||
complexity:
|
||
type: array
|
||
items:
|
||
type: object
|
||
additionalProperties: true
|
||
compaction:
|
||
type: object
|
||
additionalProperties: true
|
||
cooccurrence:
|
||
type: array
|
||
items:
|
||
type: object
|
||
additionalProperties: true
|
||
AgentTreeNode:
|
||
type: object
|
||
required:
|
||
- id
|
||
- name
|
||
- type
|
||
- status
|
||
- children
|
||
properties:
|
||
id:
|
||
type: string
|
||
name:
|
||
type: string
|
||
type:
|
||
type: string
|
||
enum:
|
||
- main
|
||
- subagent
|
||
subagent_type:
|
||
type: string
|
||
nullable: true
|
||
status:
|
||
type: string
|
||
task:
|
||
type: string
|
||
nullable: true
|
||
started_at:
|
||
type: string
|
||
format: date-time
|
||
ended_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
children:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/AgentTreeNode'
|
||
WorkflowSessionResponse:
|
||
type: object
|
||
required:
|
||
- session
|
||
- tree
|
||
- toolTimeline
|
||
- swimLanes
|
||
- events
|
||
properties:
|
||
session:
|
||
$ref: '#/components/schemas/Session'
|
||
tree:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/AgentTreeNode'
|
||
toolTimeline:
|
||
type: array
|
||
items:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
tool_name:
|
||
type: string
|
||
event_type:
|
||
type: string
|
||
agent_id:
|
||
type: string
|
||
nullable: true
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
summary:
|
||
type: string
|
||
nullable: true
|
||
swimLanes:
|
||
type: array
|
||
items:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: string
|
||
name:
|
||
type: string
|
||
type:
|
||
type: string
|
||
subagent_type:
|
||
type: string
|
||
nullable: true
|
||
status:
|
||
type: string
|
||
started_at:
|
||
type: string
|
||
format: date-time
|
||
ended_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
parent_agent_id:
|
||
type: string
|
||
nullable: true
|
||
events:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/DashboardEvent'
|
||
SettingsInfoResponse:
|
||
type: object
|
||
required:
|
||
- db
|
||
- hooks
|
||
- server
|
||
- transcript_cache
|
||
properties:
|
||
db:
|
||
type: object
|
||
required:
|
||
- path
|
||
- size
|
||
- counts
|
||
properties:
|
||
path:
|
||
type: string
|
||
size:
|
||
type: integer
|
||
counts:
|
||
type: object
|
||
additionalProperties:
|
||
type: integer
|
||
hooks:
|
||
type: object
|
||
required:
|
||
- installed
|
||
- path
|
||
- hooks
|
||
properties:
|
||
installed:
|
||
type: boolean
|
||
path:
|
||
type: string
|
||
hooks:
|
||
type: object
|
||
additionalProperties:
|
||
type: boolean
|
||
server:
|
||
type: object
|
||
required:
|
||
- version
|
||
- uptime
|
||
- node_version
|
||
- platform
|
||
- ws_connections
|
||
properties:
|
||
version:
|
||
type: string
|
||
description: Dashboard release version from package.json
|
||
uptime:
|
||
type: number
|
||
node_version:
|
||
type: string
|
||
platform:
|
||
type: string
|
||
ws_connections:
|
||
type: integer
|
||
transcript_cache:
|
||
type: object
|
||
required:
|
||
- entries
|
||
- paths
|
||
properties:
|
||
entries:
|
||
type: integer
|
||
paths:
|
||
type: array
|
||
items:
|
||
type: string
|
||
ClearDataResponse:
|
||
type: object
|
||
required:
|
||
- ok
|
||
- cleared
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
cleared:
|
||
type: object
|
||
additionalProperties:
|
||
type: integer
|
||
ReimportResponse:
|
||
type: object
|
||
required:
|
||
- ok
|
||
- imported
|
||
- skipped
|
||
- errors
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
imported:
|
||
type: integer
|
||
skipped:
|
||
type: integer
|
||
errors:
|
||
type: integer
|
||
ImportGuideResponse:
|
||
type: object
|
||
properties:
|
||
platform:
|
||
type: string
|
||
default_projects_dir:
|
||
type: string
|
||
default_projects_dir_display:
|
||
type: string
|
||
default_projects_dir_exists:
|
||
type: boolean
|
||
default_projects_dir_stats:
|
||
type: object
|
||
properties:
|
||
projects:
|
||
type: integer
|
||
jsonl_files:
|
||
type: integer
|
||
archive_command:
|
||
type: string
|
||
supported_extensions:
|
||
type: array
|
||
items:
|
||
type: string
|
||
max_upload_bytes:
|
||
type: integer
|
||
max_upload_files:
|
||
type: integer
|
||
steps:
|
||
type: array
|
||
items:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: string
|
||
title:
|
||
type: string
|
||
body:
|
||
type: string
|
||
ImportResultResponse:
|
||
type: object
|
||
required:
|
||
- ok
|
||
- source
|
||
- imported
|
||
- skipped
|
||
- errors
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
source:
|
||
type: string
|
||
enum:
|
||
- default
|
||
- path
|
||
- upload
|
||
path:
|
||
type: string
|
||
nullable: true
|
||
imported:
|
||
type: integer
|
||
backfilled:
|
||
type: integer
|
||
skipped:
|
||
type: integer
|
||
errors:
|
||
type: integer
|
||
sessions_seen:
|
||
type: integer
|
||
files_scanned:
|
||
type: integer
|
||
files_received:
|
||
type: integer
|
||
rejected_files:
|
||
type: array
|
||
items:
|
||
type: string
|
||
entries_extracted:
|
||
type: integer
|
||
entries_skipped:
|
||
type: integer
|
||
ReinstallHooksResponse:
|
||
type: object
|
||
required:
|
||
- ok
|
||
- hooks
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
hooks:
|
||
type: object
|
||
required:
|
||
- installed
|
||
- path
|
||
- hooks
|
||
properties:
|
||
installed:
|
||
type: boolean
|
||
path:
|
||
type: string
|
||
hooks:
|
||
type: object
|
||
additionalProperties:
|
||
type: boolean
|
||
ResetPricingResponse:
|
||
type: object
|
||
required:
|
||
- ok
|
||
- pricing
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
pricing:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/PricingRule'
|
||
ExportResponse:
|
||
type: object
|
||
required:
|
||
- exported_at
|
||
- sessions
|
||
- agents
|
||
- events
|
||
- token_usage
|
||
- model_pricing
|
||
properties:
|
||
format:
|
||
type: string
|
||
description: Bundle format marker (always "ccam-export" for exports from this version).
|
||
example: ccam-export
|
||
version:
|
||
type: integer
|
||
description: Bundle schema version.
|
||
example: 1
|
||
exported_at:
|
||
type: string
|
||
format: date-time
|
||
sessions:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Session'
|
||
agents:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Agent'
|
||
events:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/DashboardEvent'
|
||
token_usage:
|
||
type: array
|
||
items:
|
||
type: object
|
||
additionalProperties: true
|
||
workflows:
|
||
type: array
|
||
items:
|
||
type: object
|
||
additionalProperties: true
|
||
dashboard_runs:
|
||
type: array
|
||
items:
|
||
type: object
|
||
additionalProperties: true
|
||
alert_rules:
|
||
type: array
|
||
items:
|
||
type: object
|
||
additionalProperties: true
|
||
model_pricing:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/PricingRule'
|
||
ImportResponse:
|
||
type: object
|
||
required:
|
||
- ok
|
||
- sessions_imported
|
||
- sessions_skipped
|
||
- agents
|
||
- events
|
||
- token_usage
|
||
- workflows
|
||
- dashboard_runs
|
||
- alert_rules
|
||
- model_pricing
|
||
- errors
|
||
description: Per-table counts from restoring an export bundle. Session-scoped counts are rows newly inserted; sessions_skipped counts sessions already present (skipped whole to stay idempotent).
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
source:
|
||
type: string
|
||
description: Uploaded filename or server-side path read.
|
||
format:
|
||
type: string
|
||
nullable: true
|
||
description: Bundle format marker, or null for a legacy export.
|
||
sessions_imported:
|
||
type: integer
|
||
sessions_skipped:
|
||
type: integer
|
||
agents:
|
||
type: integer
|
||
events:
|
||
type: integer
|
||
token_usage:
|
||
type: integer
|
||
workflows:
|
||
type: integer
|
||
dashboard_runs:
|
||
type: integer
|
||
alert_rules:
|
||
type: integer
|
||
model_pricing:
|
||
type: integer
|
||
errors:
|
||
type: integer
|
||
CleanupRequest:
|
||
type: object
|
||
properties:
|
||
abandon_hours:
|
||
type: number
|
||
minimum: 0
|
||
description: Mark active sessions abandoned if stale for this many hours
|
||
purge_days:
|
||
type: number
|
||
minimum: 0
|
||
description: Delete old completed/error/abandoned sessions older than this many days
|
||
CleanupResponse:
|
||
type: object
|
||
required:
|
||
- ok
|
||
- abandoned
|
||
- purged_sessions
|
||
- purged_events
|
||
- purged_agents
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
abandoned:
|
||
type: integer
|
||
purged_sessions:
|
||
type: integer
|
||
purged_events:
|
||
type: integer
|
||
purged_agents:
|
||
type: integer
|
||
CcConfigScope:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
- all
|
||
description: Discovery scope. `user` = ~/.claude (or CLAUDE_HOME); `project` = <cwd>/.claude (and project CLAUDE.md); `all` = both, merged. Defaults to `all` when omitted or unrecognized.
|
||
example: all
|
||
CcConfigFrontmatter:
|
||
type: object
|
||
additionalProperties:
|
||
type: string
|
||
description: Parsed YAML frontmatter from the artifact's markdown header (key → string value). Empty object when the file has no parseable frontmatter. Multi-line values are preserved as raw strings; quotes are stripped.
|
||
example:
|
||
name: code-reviewer
|
||
description: Reviews diffs for regressions
|
||
model: sonnet
|
||
CcConfigSkill:
|
||
type: object
|
||
description: 'A discovered skill: a directory containing a SKILL.md file under <root>/skills/<name>/.'
|
||
required:
|
||
- scope
|
||
- name
|
||
- path
|
||
- file
|
||
- size
|
||
- mtime
|
||
- truncated
|
||
- frontmatter
|
||
- preview
|
||
properties:
|
||
scope:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
description: Which root this skill was discovered under.
|
||
example: user
|
||
name:
|
||
type: string
|
||
description: Skill directory name.
|
||
example: code-reviewer
|
||
path:
|
||
type: string
|
||
description: Absolute path to the skill directory.
|
||
example: /Users/son/.claude/skills/code-reviewer
|
||
file:
|
||
type: string
|
||
description: Absolute path to the SKILL.md file.
|
||
example: /Users/son/.claude/skills/code-reviewer/SKILL.md
|
||
size:
|
||
type: integer
|
||
description: Size of SKILL.md in bytes.
|
||
example: 2048
|
||
mtime:
|
||
type: number
|
||
description: Last-modified time of SKILL.md in epoch milliseconds.
|
||
example: 1718900000000
|
||
truncated:
|
||
type: boolean
|
||
description: True when SKILL.md exceeds 256 KiB and the read was truncated to the first 256 KiB.
|
||
example: false
|
||
frontmatter:
|
||
$ref: '#/components/schemas/CcConfigFrontmatter'
|
||
preview:
|
||
type: string
|
||
description: First 320 characters of the markdown body (after frontmatter).
|
||
example: Use this skill to review pull requests for correctness and style...
|
||
CcConfigMdItem:
|
||
type: object
|
||
description: A single-file markdown artifact (subagent, slash command, or output style) found under <root>/<subdir>/<name>.md.
|
||
required:
|
||
- scope
|
||
- name
|
||
- file
|
||
- size
|
||
- mtime
|
||
- truncated
|
||
- frontmatter
|
||
- preview
|
||
properties:
|
||
scope:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
description: Which root this artifact was discovered under.
|
||
example: project
|
||
name:
|
||
type: string
|
||
description: Artifact name (filename with the trailing .md stripped).
|
||
example: backend-reviewer
|
||
file:
|
||
type: string
|
||
description: Absolute path to the .md file.
|
||
example: /repo/.claude/agents/backend-reviewer.md
|
||
size:
|
||
type: integer
|
||
description: File size in bytes.
|
||
example: 1536
|
||
mtime:
|
||
type: number
|
||
description: Last-modified time in epoch milliseconds.
|
||
example: 1718900000000
|
||
truncated:
|
||
type: boolean
|
||
description: True when the file exceeded 256 KiB and was truncated.
|
||
example: false
|
||
frontmatter:
|
||
$ref: '#/components/schemas/CcConfigFrontmatter'
|
||
preview:
|
||
type: string
|
||
description: First 320 characters of the markdown body (after frontmatter).
|
||
example: Review backend route and hook logic for regressions...
|
||
CcConfigPluginContributions:
|
||
type: object
|
||
nullable: true
|
||
description: Counts of artifacts a plugin contributes, plus its parsed .claude-plugin/plugin.json. Null when the plugin's installPath does not exist on disk.
|
||
required:
|
||
- skills
|
||
- agents
|
||
- commands
|
||
- outputStyles
|
||
- hooks
|
||
- pluginJson
|
||
properties:
|
||
skills:
|
||
type: integer
|
||
description: Number of skill directories (containing SKILL.md) under the plugin.
|
||
example: 3
|
||
agents:
|
||
type: integer
|
||
description: Number of .md agent files under the plugin.
|
||
example: 2
|
||
commands:
|
||
type: integer
|
||
description: Number of .md command files under the plugin.
|
||
example: 5
|
||
outputStyles:
|
||
type: integer
|
||
description: Number of .md output-style files under the plugin.
|
||
example: 0
|
||
hooks:
|
||
type: integer
|
||
description: Number of files under the plugin's hooks/ directory.
|
||
example: 1
|
||
pluginJson:
|
||
type: object
|
||
nullable: true
|
||
additionalProperties: true
|
||
description: Parsed contents of .claude-plugin/plugin.json, or null when absent/unparseable.
|
||
example:
|
||
name: superpowers
|
||
version: 1.2.0
|
||
CcConfigPlugin:
|
||
type: object
|
||
description: An installed plugin instance derived from the plugins manifest.
|
||
required:
|
||
- key
|
||
- name
|
||
- marketplace
|
||
- scope
|
||
- version
|
||
- installPath
|
||
- installedAt
|
||
- lastUpdated
|
||
- gitCommitSha
|
||
- installPathExists
|
||
- enabled
|
||
- contributes
|
||
properties:
|
||
key:
|
||
type: string
|
||
description: Manifest key for this plugin, either the bare name or `<name>@<marketplace>`.
|
||
example: superpowers@obra
|
||
name:
|
||
type: string
|
||
description: Plugin name (the portion of `key` before any `@`).
|
||
example: superpowers
|
||
marketplace:
|
||
type: string
|
||
nullable: true
|
||
description: Marketplace portion of `key` (after `@`), or null when unscoped.
|
||
example: obra
|
||
scope:
|
||
type: string
|
||
description: Install scope reported by the manifest instance (defaults to `user`).
|
||
example: user
|
||
version:
|
||
type: string
|
||
nullable: true
|
||
description: Installed plugin version, or null.
|
||
example: 1.2.0
|
||
installPath:
|
||
type: string
|
||
nullable: true
|
||
description: Absolute install path, or null.
|
||
example: /Users/son/.claude/plugins/superpowers
|
||
installedAt:
|
||
type: string
|
||
nullable: true
|
||
description: Install timestamp from the manifest, or null.
|
||
example: '2026-05-01T12:00:00.000Z'
|
||
lastUpdated:
|
||
type: string
|
||
nullable: true
|
||
description: Last-updated timestamp from the manifest, or null.
|
||
example: '2026-06-01T09:30:00.000Z'
|
||
gitCommitSha:
|
||
type: string
|
||
nullable: true
|
||
description: Pinned git commit SHA from the manifest, or null.
|
||
example: a1b2c3d4e5f6
|
||
installPathExists:
|
||
type: boolean
|
||
description: True when installPath resolves to an existing directory on disk.
|
||
example: true
|
||
enabled:
|
||
type: boolean
|
||
nullable: true
|
||
description: 'Tri-state enabled flag from settings.json `enabledPlugins`: true, false, or null when the plugin is not listed there.'
|
||
example: true
|
||
contributes:
|
||
$ref: '#/components/schemas/CcConfigPluginContributions'
|
||
CcConfigPluginsResponse:
|
||
type: object
|
||
description: Plugins manifest summary plus the resolved plugin list (user scope only).
|
||
required:
|
||
- manifestPath
|
||
- manifestExists
|
||
- plugins
|
||
properties:
|
||
manifestPath:
|
||
type: string
|
||
description: Absolute path to plugins/installed_plugins.json under the Claude home.
|
||
example: /Users/son/.claude/plugins/installed_plugins.json
|
||
manifestExists:
|
||
type: boolean
|
||
description: True when the manifest file was found and parsed.
|
||
example: true
|
||
plugins:
|
||
type: array
|
||
description: Plugins sorted by `key`.
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigPlugin'
|
||
CcConfigMcpServer:
|
||
type: object
|
||
description: A summarized MCP server definition. Sensitive details (header values, env values) are NOT returned — only their key NAMES are surfaced.
|
||
required:
|
||
- name
|
||
- source
|
||
- kind
|
||
properties:
|
||
name:
|
||
type: string
|
||
description: Server name (object key in the source config).
|
||
example: github
|
||
source:
|
||
type: string
|
||
description: Where the definition was found, e.g. `~/.claude.json (top-level)`, `~/.claude.json (projects[<root>])`, or `~/.claude/settings.json`.
|
||
example: ~/.claude.json (top-level)
|
||
kind:
|
||
type: string
|
||
enum:
|
||
- http
|
||
- stdio
|
||
- unknown
|
||
description: 'Transport kind inferred from the definition: `http` (has url), `stdio` (has command), or `unknown`.'
|
||
example: stdio
|
||
url:
|
||
type: string
|
||
description: Endpoint URL — present only for `http` servers.
|
||
example: https://mcp.example.com/sse
|
||
headers:
|
||
type: array
|
||
items:
|
||
type: string
|
||
description: Header NAMES (values redacted) — present only for `http` servers. Empty array when no headers.
|
||
example:
|
||
- Authorization
|
||
command:
|
||
type: string
|
||
description: Executable — present only for `stdio` servers.
|
||
example: npx
|
||
args:
|
||
type: array
|
||
items:
|
||
type: string
|
||
description: Command arguments — present only for `stdio` servers.
|
||
example:
|
||
- '-y'
|
||
- '@modelcontextprotocol/server-github'
|
||
envNames:
|
||
type: array
|
||
items:
|
||
type: string
|
||
description: Environment-variable NAMES (values redacted) — present only for `stdio` servers.
|
||
example:
|
||
- GITHUB_TOKEN
|
||
CcConfigMcpResponse:
|
||
type: object
|
||
description: 'MCP servers split by where they apply: globally to the user, or scoped to the resolved project (cwd) in ~/.claude.json projects[<root>].'
|
||
required:
|
||
- user
|
||
- projectScoped
|
||
properties:
|
||
user:
|
||
type: array
|
||
description: User/global MCP servers (top-level ~/.claude.json plus ~/.claude/settings.json).
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigMcpServer'
|
||
projectScoped:
|
||
type: array
|
||
description: MCP servers scoped to the current project root in ~/.claude.json.
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigMcpServer'
|
||
CcConfigHookEntry:
|
||
type: object
|
||
description: A single flattened hook command bound to a matcher.
|
||
required:
|
||
- matcher
|
||
- type
|
||
- command
|
||
- timeout
|
||
properties:
|
||
matcher:
|
||
type: string
|
||
description: Tool/event matcher pattern (defaults to `*`).
|
||
example: Bash
|
||
type:
|
||
type: string
|
||
description: Hook type (defaults to `command`).
|
||
example: command
|
||
command:
|
||
type: string
|
||
nullable: true
|
||
description: Shell command to run, or null.
|
||
example: node ~/.claude/hooks/handler.js
|
||
timeout:
|
||
type: integer
|
||
nullable: true
|
||
description: Per-hook timeout in seconds, or null when unset.
|
||
example: 30
|
||
CcConfigHookSource:
|
||
type: object
|
||
description: Hooks read from one settings file. `hooks` is keyed by event name (e.g. PreToolUse, PostToolUse, Stop); each known-event value is an array of flattened hook entries, while unknown events are passed through verbatim.
|
||
required:
|
||
- scope
|
||
- file
|
||
- exists
|
||
- hooks
|
||
properties:
|
||
scope:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
- project-local
|
||
description: Which settings file this hook block came from.
|
||
example: user
|
||
file:
|
||
type: string
|
||
description: Absolute path to the settings file.
|
||
example: /Users/son/.claude/settings.json
|
||
exists:
|
||
type: boolean
|
||
description: True when the settings file was found and parsed.
|
||
example: true
|
||
hooks:
|
||
type: object
|
||
description: Event name → array of hook entries (for the known event types) or the raw matcher array (for unknown events). Only non-empty events are included.
|
||
additionalProperties:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigHookEntry'
|
||
example:
|
||
PreToolUse:
|
||
- matcher: Bash
|
||
type: command
|
||
command: node guard.js
|
||
timeout: null
|
||
CcConfigSettingsSource:
|
||
type: object
|
||
description: One settings file's redacted contents. Secret-like keys (matching /token|secret|password|api[_-]?key|auth/i with string values) are replaced with the literal string `<redacted>`.
|
||
required:
|
||
- scope
|
||
- file
|
||
- exists
|
||
properties:
|
||
scope:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
- project-local
|
||
description: Which settings file this entry represents.
|
||
example: user
|
||
file:
|
||
type: string
|
||
description: Absolute path to the settings file.
|
||
example: /Users/son/.claude/settings.json
|
||
exists:
|
||
type: boolean
|
||
description: True when the file was found and parsed. When false, `data`/`raw_size` are omitted.
|
||
example: true
|
||
data:
|
||
type: object
|
||
additionalProperties: true
|
||
description: Parsed, secret-redacted settings JSON. Present only when `exists` is true.
|
||
example:
|
||
model: sonnet
|
||
apiKey: <redacted>
|
||
statusLine:
|
||
type: command
|
||
raw_size:
|
||
type: integer
|
||
description: Byte length of the raw file contents. Present only when `exists` is true.
|
||
example: 412
|
||
CcConfigMemoryItem:
|
||
type: object
|
||
description: 'A memory artifact: either a primary CLAUDE.md (scope `user`/`project`) or a per-project file-based auto-memory markdown file (scope `auto-memory`). Auto-memory items additionally carry `project`, `name`, `isIndex`, and parsed `frontmatter`.'
|
||
required:
|
||
- scope
|
||
- file
|
||
- size
|
||
- mtime
|
||
- truncated
|
||
- preview
|
||
properties:
|
||
scope:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
- auto-memory
|
||
description: '`user`/`project` = the two primary CLAUDE.md files; `auto-memory` = a *.md file under ~/.claude/projects/<slug>/memory/.'
|
||
example: auto-memory
|
||
project:
|
||
type: string
|
||
description: 'Auto-memory only: the ~/.claude/projects/<slug> directory name the file belongs to.'
|
||
example: '-Users-son-repo'
|
||
name:
|
||
type: string
|
||
description: 'Auto-memory only: the markdown filename.'
|
||
example: MEMORY.md
|
||
isIndex:
|
||
type: boolean
|
||
description: 'Auto-memory only: true for index/manifest files (MEMORY.md, INDEX-*.md), which sort first.'
|
||
example: true
|
||
file:
|
||
type: string
|
||
description: Absolute path to the memory file.
|
||
example: /Users/son/.claude/projects/-Users-son-repo/memory/MEMORY.md
|
||
size:
|
||
type: integer
|
||
description: File size in bytes.
|
||
example: 980
|
||
mtime:
|
||
type: number
|
||
description: Last-modified time in epoch milliseconds.
|
||
example: 1718900000000
|
||
truncated:
|
||
type: boolean
|
||
description: True when the file exceeded 256 KiB and was truncated.
|
||
example: false
|
||
frontmatter:
|
||
$ref: '#/components/schemas/CcConfigFrontmatter'
|
||
preview:
|
||
type: string
|
||
description: First 480 characters of the body (frontmatter stripped for auto-memory files; raw head for CLAUDE.md).
|
||
example: '## Persistent facts\n- Never run destructive ops without confirmation...'
|
||
CcConfigMarketplace:
|
||
type: object
|
||
description: A known plugin marketplace and (best-effort) its parsed manifest summary.
|
||
required:
|
||
- name
|
||
- source
|
||
- installLocation
|
||
- lastUpdated
|
||
- pluginCount
|
||
- marketplaceName
|
||
- marketplaceDescription
|
||
- marketplaceOwner
|
||
properties:
|
||
name:
|
||
type: string
|
||
description: Marketplace key/name.
|
||
example: obra
|
||
source:
|
||
type: object
|
||
nullable: true
|
||
additionalProperties: true
|
||
description: Source descriptor object (e.g. git/github source), or null.
|
||
example:
|
||
source: github
|
||
repo: obra/superpowers-marketplace
|
||
installLocation:
|
||
type: string
|
||
nullable: true
|
||
description: Absolute path where the marketplace is checked out, or null.
|
||
example: /Users/son/.claude/plugins/marketplaces/obra
|
||
lastUpdated:
|
||
type: string
|
||
nullable: true
|
||
description: Last-updated timestamp, or null.
|
||
example: '2026-06-10T00:00:00.000Z'
|
||
pluginCount:
|
||
type: integer
|
||
nullable: true
|
||
description: Number of plugins in the marketplace manifest, or null when no manifest was readable.
|
||
example: 12
|
||
marketplaceName:
|
||
type: string
|
||
nullable: true
|
||
description: '`name` from the marketplace manifest, or null.'
|
||
example: Superpowers
|
||
marketplaceDescription:
|
||
type: string
|
||
nullable: true
|
||
description: '`description` from the marketplace manifest, or null.'
|
||
example: Curated agent skills
|
||
marketplaceOwner:
|
||
description: '`owner` from the marketplace manifest (object or string), or null.'
|
||
nullable: true
|
||
oneOf:
|
||
- type: object
|
||
additionalProperties: true
|
||
- type: string
|
||
example:
|
||
name: obra
|
||
CcConfigMarketplacesResponse:
|
||
type: object
|
||
description: Known-marketplaces manifest summary plus the resolved marketplace list.
|
||
required:
|
||
- knownPath
|
||
- knownExists
|
||
- items
|
||
properties:
|
||
knownPath:
|
||
type: string
|
||
description: Absolute path to plugins/known_marketplaces.json under the Claude home.
|
||
example: /Users/son/.claude/plugins/known_marketplaces.json
|
||
knownExists:
|
||
type: boolean
|
||
description: True when the known-marketplaces file was found and parsed.
|
||
example: true
|
||
items:
|
||
type: array
|
||
description: Marketplaces sorted by name.
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigMarketplace'
|
||
CcConfigKeybinding:
|
||
type: object
|
||
description: A single key → action binding.
|
||
required:
|
||
- key
|
||
- action
|
||
properties:
|
||
key:
|
||
type: string
|
||
description: Key chord.
|
||
example: ctrl+s
|
||
action:
|
||
type: string
|
||
description: Action name (stringified).
|
||
example: submit
|
||
CcConfigKeybindingGroup:
|
||
type: object
|
||
description: A context-scoped group of keybindings.
|
||
required:
|
||
- context
|
||
- bindings
|
||
properties:
|
||
context:
|
||
type: string
|
||
description: The context the bindings apply in (empty string when global).
|
||
example: editor
|
||
bindings:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigKeybinding'
|
||
CcConfigKeybindingsResponse:
|
||
type: object
|
||
description: 'Parsed ~/.claude/keybindings.json. When the file is absent, only `{ file, exists: false }` is returned.'
|
||
required:
|
||
- file
|
||
- exists
|
||
properties:
|
||
file:
|
||
type: string
|
||
description: Absolute path to keybindings.json.
|
||
example: /Users/son/.claude/keybindings.json
|
||
exists:
|
||
type: boolean
|
||
description: True when the file was found and parsed.
|
||
example: true
|
||
schema:
|
||
type: string
|
||
nullable: true
|
||
description: '`$schema` value from the file, or null. Present only when `exists` is true.'
|
||
example: https://json.schemastore.org/claude-keybindings
|
||
docs:
|
||
type: string
|
||
nullable: true
|
||
description: '`$docs` value from the file, or null. Present only when `exists` is true.'
|
||
example: https://docs.claude.com/keybindings
|
||
groups:
|
||
type: array
|
||
description: Binding groups. Present only when `exists` is true.
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigKeybindingGroup'
|
||
CcConfigStatuslineScript:
|
||
type: object
|
||
description: A statusline script (statusline.py or statusline-command.sh) discovered under the Claude home.
|
||
required:
|
||
- file
|
||
- size
|
||
- mtime
|
||
- truncated
|
||
- preview
|
||
properties:
|
||
file:
|
||
type: string
|
||
description: Absolute path to the script.
|
||
example: /Users/son/.claude/statusline.py
|
||
size:
|
||
type: integer
|
||
description: File size in bytes.
|
||
example: 1280
|
||
mtime:
|
||
type: number
|
||
description: Last-modified time in epoch milliseconds.
|
||
example: 1718900000000
|
||
truncated:
|
||
type: boolean
|
||
description: True when the file exceeded 256 KiB and was truncated.
|
||
example: false
|
||
preview:
|
||
type: string
|
||
description: First 4000 characters of the script body.
|
||
example: '#!/usr/bin/env python3\nimport json, sys\n...'
|
||
CcConfigStatuslineResponse:
|
||
type: object
|
||
description: The statusLine config block from user settings.json plus any statusline scripts.
|
||
required:
|
||
- config
|
||
- scripts
|
||
properties:
|
||
config:
|
||
type: object
|
||
nullable: true
|
||
additionalProperties: true
|
||
description: The `statusLine` object from ~/.claude/settings.json, or null when unset.
|
||
example:
|
||
type: command
|
||
command: python3 ~/.claude/statusline.py
|
||
scripts:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigStatuslineScript'
|
||
CcConfigHookScript:
|
||
type: object
|
||
description: A file in the ~/.claude/hooks/ directory.
|
||
required:
|
||
- name
|
||
- file
|
||
- size
|
||
- mtime
|
||
properties:
|
||
name:
|
||
type: string
|
||
description: File name.
|
||
example: post-tool-use.js
|
||
file:
|
||
type: string
|
||
description: Absolute path to the script.
|
||
example: /Users/son/.claude/hooks/post-tool-use.js
|
||
size:
|
||
type: integer
|
||
description: File size in bytes.
|
||
example: 640
|
||
mtime:
|
||
type: number
|
||
description: Last-modified time in epoch milliseconds.
|
||
example: 1718900000000
|
||
CcConfigHookScriptsResponse:
|
||
type: object
|
||
description: Listing of the ~/.claude/hooks/ directory (files only, sorted by name).
|
||
required:
|
||
- dir
|
||
- items
|
||
properties:
|
||
dir:
|
||
type: string
|
||
description: Absolute path to the hooks directory.
|
||
example: /Users/son/.claude/hooks
|
||
items:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigHookScript'
|
||
CcConfigScopeCount:
|
||
type: object
|
||
description: Per-scope counts (user vs project).
|
||
required:
|
||
- user
|
||
- project
|
||
properties:
|
||
user:
|
||
type: integer
|
||
description: Count under the user root.
|
||
example: 12
|
||
project:
|
||
type: integer
|
||
description: Count under the project root.
|
||
example: 3
|
||
CcConfigOverviewResponse:
|
||
type: object
|
||
description: 'Top-level summary for the Claude Config Explorer landing page: resolved roots plus aggregate counts across every surface.'
|
||
required:
|
||
- roots
|
||
- counts
|
||
properties:
|
||
roots:
|
||
type: object
|
||
description: The four filesystem roots the explorer reads from.
|
||
required:
|
||
- claudeHome
|
||
- projectClaudeDir
|
||
- projectRoot
|
||
- claudeJson
|
||
properties:
|
||
claudeHome:
|
||
type: string
|
||
description: Claude home (CLAUDE_HOME or ~/.claude).
|
||
example: /Users/son/.claude
|
||
projectClaudeDir:
|
||
type: string
|
||
description: Project .claude directory under the resolved cwd.
|
||
example: /repo/.claude
|
||
projectRoot:
|
||
type: string
|
||
description: Resolved project root (the cwd).
|
||
example: /repo
|
||
claudeJson:
|
||
type: string
|
||
description: Path to ~/.claude.json (resolved from $HOME, not CLAUDE_HOME).
|
||
example: /Users/son/.claude.json
|
||
counts:
|
||
type: object
|
||
description: Aggregate counts by surface.
|
||
required:
|
||
- skills
|
||
- agents
|
||
- commands
|
||
- outputStyles
|
||
- plugins
|
||
- pluginsEnabled
|
||
- pluginsDisabled
|
||
- marketplaces
|
||
- keybindings
|
||
- mcpServers
|
||
- hooks
|
||
- memory
|
||
- settingsFiles
|
||
properties:
|
||
skills:
|
||
$ref: '#/components/schemas/CcConfigScopeCount'
|
||
agents:
|
||
$ref: '#/components/schemas/CcConfigScopeCount'
|
||
commands:
|
||
$ref: '#/components/schemas/CcConfigScopeCount'
|
||
outputStyles:
|
||
$ref: '#/components/schemas/CcConfigScopeCount'
|
||
plugins:
|
||
type: integer
|
||
description: Total plugins.
|
||
example: 8
|
||
pluginsEnabled:
|
||
type: integer
|
||
description: Plugins explicitly enabled in settings.
|
||
example: 6
|
||
pluginsDisabled:
|
||
type: integer
|
||
description: Plugins explicitly disabled in settings.
|
||
example: 1
|
||
marketplaces:
|
||
type: integer
|
||
description: Known marketplaces.
|
||
example: 2
|
||
keybindings:
|
||
type: integer
|
||
description: Total individual key bindings across all groups.
|
||
example: 24
|
||
mcpServers:
|
||
type: object
|
||
description: MCP server counts by scope.
|
||
required:
|
||
- user
|
||
- project
|
||
properties:
|
||
user:
|
||
type: integer
|
||
example: 3
|
||
project:
|
||
type: integer
|
||
example: 1
|
||
hooks:
|
||
type: object
|
||
description: Total hook entries per settings scope.
|
||
required:
|
||
- user
|
||
- project
|
||
- project-local
|
||
properties:
|
||
user:
|
||
type: integer
|
||
example: 2
|
||
project:
|
||
type: integer
|
||
example: 0
|
||
project-local:
|
||
type: integer
|
||
example: 1
|
||
memory:
|
||
type: integer
|
||
description: Total memory items.
|
||
example: 5
|
||
settingsFiles:
|
||
type: integer
|
||
description: Number of settings files that exist (of the three scopes).
|
||
example: 2
|
||
CcConfigSkillsResponse:
|
||
type: object
|
||
required:
|
||
- items
|
||
properties:
|
||
items:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigSkill'
|
||
CcConfigAgentsResponse:
|
||
type: object
|
||
required:
|
||
- items
|
||
properties:
|
||
items:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigMdItem'
|
||
CcConfigCommandsResponse:
|
||
type: object
|
||
required:
|
||
- items
|
||
properties:
|
||
items:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigMdItem'
|
||
CcConfigOutputStylesResponse:
|
||
type: object
|
||
required:
|
||
- items
|
||
properties:
|
||
items:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigMdItem'
|
||
CcConfigHooksResponse:
|
||
type: object
|
||
required:
|
||
- items
|
||
properties:
|
||
items:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigHookSource'
|
||
CcConfigSettingsResponse:
|
||
type: object
|
||
required:
|
||
- items
|
||
properties:
|
||
items:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigSettingsSource'
|
||
CcConfigMemoryResponse:
|
||
type: object
|
||
required:
|
||
- items
|
||
properties:
|
||
items:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigMemoryItem'
|
||
CcConfigFileReadResponse:
|
||
type: object
|
||
description: Body of a single file resolved under an allowed root. Returned only on success; failures return an ErrorResponse with HTTP 400.
|
||
required:
|
||
- ok
|
||
- file
|
||
- truncated
|
||
- size
|
||
- text
|
||
- mtime
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
description: Always true on success.
|
||
example: true
|
||
file:
|
||
type: string
|
||
description: Absolute, resolved path that was read.
|
||
example: /Users/son/.claude/skills/code-reviewer/SKILL.md
|
||
truncated:
|
||
type: boolean
|
||
description: True when the file exceeded 256 KiB and only the first 256 KiB are in `text`.
|
||
example: false
|
||
size:
|
||
type: integer
|
||
description: Full file size in bytes.
|
||
example: 2048
|
||
text:
|
||
type: string
|
||
description: File contents (truncated to 256 KiB).
|
||
example: '---\nname: code-reviewer\n---\n# Code Reviewer\n...'
|
||
mtime:
|
||
type: number
|
||
description: Last-modified time in epoch milliseconds.
|
||
example: 1718900000000
|
||
CcConfigFileWriteRequest:
|
||
type: object
|
||
description: Create-or-overwrite request for a low-risk text artifact. `name` is required for every type except `memory` (which targets CLAUDE.md). `project` is required for `auto-memory`. `scope` is ignored for `auto-memory` (always under the Claude home).
|
||
required:
|
||
- scope
|
||
- type
|
||
- content
|
||
properties:
|
||
scope:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
description: 'Target root: `user` (Claude home) or `project` (<cwd>/.claude, or project root for memory). Ignored for `auto-memory`.'
|
||
example: user
|
||
type:
|
||
type: string
|
||
enum:
|
||
- skills
|
||
- agents
|
||
- commands
|
||
- output-styles
|
||
- memory
|
||
- auto-memory
|
||
description: Artifact type. `skills` writes <root>/skills/<name>/SKILL.md; `agents`/`commands`/`output-styles` write <root>/<type>/<name>.md; `memory` writes the scope's CLAUDE.md; `auto-memory` writes ~/.claude/projects/<project>/memory/<name>.
|
||
example: agents
|
||
name:
|
||
type: string
|
||
description: Artifact name. Required for all types except `memory`. For skills/agents/commands/output-styles must match /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/. For auto-memory must be a flat *.md filename (/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}\.md$/i, no `..`).
|
||
example: my-reviewer
|
||
content:
|
||
type: string
|
||
description: Full file contents to write. Must be a string and ≤ 256 KiB (UTF-8 bytes).
|
||
example: '---\nname: my-reviewer\n---\n# My Reviewer\nReview the diff...'
|
||
project:
|
||
type: string
|
||
description: 'Required for `auto-memory`: the ~/.claude/projects/<slug> directory name. Validated against /^[A-Za-z0-9_-][A-Za-z0-9._-]{0,255}$/ and rejected if it contains `..`.'
|
||
example: '-Users-son-repo'
|
||
CcConfigFileWriteResponse:
|
||
type: object
|
||
description: Result of a successful create-or-overwrite.
|
||
required:
|
||
- ok
|
||
- file
|
||
- target
|
||
- backupPath
|
||
- created
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
example: true
|
||
file:
|
||
type: string
|
||
description: Absolute path to the .md file that was written.
|
||
example: /Users/son/.claude/agents/my-reviewer.md
|
||
target:
|
||
type: string
|
||
description: Absolute path to the artifact target (the skill directory for skills; same as `file` otherwise).
|
||
example: /Users/son/.claude/agents/my-reviewer.md
|
||
backupPath:
|
||
type: string
|
||
nullable: true
|
||
description: Absolute path to the timestamped backup created before overwriting, or null when this was a fresh create (nothing to back up).
|
||
example: /Users/son/.claude/cc-config-backups/agents/my-reviewer.md.2026-06-25T12-00-00.000Z.bak
|
||
created:
|
||
type: boolean
|
||
description: True when the artifact did not exist before this write.
|
||
example: true
|
||
CcConfigFileDeleteRequest:
|
||
type: object
|
||
description: Delete request for a low-risk text artifact. Same (scope, type, name, project) semantics as the write request, without `content`.
|
||
required:
|
||
- scope
|
||
- type
|
||
properties:
|
||
scope:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
description: Target root. Ignored for `auto-memory`.
|
||
example: user
|
||
type:
|
||
type: string
|
||
enum:
|
||
- skills
|
||
- agents
|
||
- commands
|
||
- output-styles
|
||
- memory
|
||
- auto-memory
|
||
description: Artifact type to delete.
|
||
example: agents
|
||
name:
|
||
type: string
|
||
description: Artifact name. Required for all types except `memory`.
|
||
example: my-reviewer
|
||
project:
|
||
type: string
|
||
description: 'Required for `auto-memory`: the projects/<slug> directory name.'
|
||
example: '-Users-son-repo'
|
||
CcConfigFileDeleteResponse:
|
||
type: object
|
||
description: Result of a successful delete (a mandatory backup is created first).
|
||
required:
|
||
- ok
|
||
- file
|
||
- target
|
||
- backupPath
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
example: true
|
||
file:
|
||
type: string
|
||
description: Absolute path to the .md file inside the deleted target.
|
||
example: /Users/son/.claude/agents/my-reviewer.md
|
||
target:
|
||
type: string
|
||
description: Absolute path to the deleted artifact (skill directory for skills).
|
||
example: /Users/son/.claude/agents/my-reviewer.md
|
||
backupPath:
|
||
type: string
|
||
nullable: true
|
||
description: Absolute path to the backup taken before deletion.
|
||
example: /Users/son/.claude/cc-config-backups/agents/my-reviewer.md.2026-06-25T12-00-00.000Z.bak
|
||
CcConfigBackup:
|
||
type: object
|
||
description: A single backup entry under a cc-config-backups directory.
|
||
required:
|
||
- scope
|
||
- type
|
||
- name
|
||
- backupPath
|
||
- isDir
|
||
- mtime
|
||
- size
|
||
properties:
|
||
scope:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
- auto-memory
|
||
description: Scope the backup belongs to. `auto-memory` backups are per-project.
|
||
example: user
|
||
project:
|
||
type: string
|
||
description: 'Auto-memory only: the projects/<slug> directory name.'
|
||
example: '-Users-son-repo'
|
||
type:
|
||
type: string
|
||
enum:
|
||
- skills
|
||
- agents
|
||
- commands
|
||
- output-styles
|
||
- memory
|
||
- auto-memory
|
||
description: Artifact type the backup was taken from.
|
||
example: agents
|
||
name:
|
||
type: string
|
||
description: Backup file/directory name (includes the timestamp and .bak suffix).
|
||
example: my-reviewer.md.2026-06-25T12-00-00.000Z.bak
|
||
backupPath:
|
||
type: string
|
||
description: Absolute path to the backup.
|
||
example: /Users/son/.claude/cc-config-backups/agents/my-reviewer.md.2026-06-25T12-00-00.000Z.bak
|
||
isDir:
|
||
type: boolean
|
||
description: True when the backup is a directory (skill backups).
|
||
example: false
|
||
mtime:
|
||
type: number
|
||
description: Backup modification time in epoch milliseconds (results sort newest first).
|
||
example: 1718900000000
|
||
size:
|
||
type: integer
|
||
nullable: true
|
||
description: Backup size in bytes, or null for directory backups.
|
||
example: 2048
|
||
CcConfigBackupsResponse:
|
||
type: object
|
||
required:
|
||
- items
|
||
properties:
|
||
items:
|
||
type: array
|
||
description: Backups across the requested scope/type buckets, sorted newest first.
|
||
items:
|
||
$ref: '#/components/schemas/CcConfigBackup'
|
||
RunHandle:
|
||
type: object
|
||
description: Live, in-memory view of a spawned `claude` subprocess. Returned by GET /api/run (in `items`), POST /api/run (201), and GET /api/run/{id}. Backed by the spawner's handle map, which reaps each handle 5 minutes after the process exits — after that the run is only visible via GET /api/run/history.
|
||
required:
|
||
- id
|
||
- pid
|
||
- mode
|
||
- cwd
|
||
- model
|
||
- permissionMode
|
||
- effort
|
||
- prompt
|
||
- argv
|
||
- resumeSessionId
|
||
- status
|
||
- startedAt
|
||
- endedAt
|
||
- exitCode
|
||
- signal
|
||
- error
|
||
- sessionId
|
||
- envelopeCount
|
||
- stdoutTail
|
||
- stderrTail
|
||
properties:
|
||
id:
|
||
type: string
|
||
format: uuid
|
||
description: Server-generated run id (UUID v4). Distinct from the Claude session id.
|
||
example: 3f2c9a1e-7b4d-4e21-9b6a-1d2e3f4a5b6c
|
||
pid:
|
||
type: integer
|
||
nullable: true
|
||
description: OS process id of the spawned `claude` child, or null if the spawn failed.
|
||
example: 48213
|
||
mode:
|
||
type: string
|
||
enum:
|
||
- headless
|
||
- conversation
|
||
description: '`headless`: single-shot — prompt is passed via argv `-p`, stdin is closed, the process exits after one turn. `conversation`: multi-turn — stdin stays open (`--input-format stream-json`) and follow-up turns are delivered via POST /api/run/{id}/message.'
|
||
example: conversation
|
||
cwd:
|
||
type: string
|
||
description: Absolute working directory the child was spawned in (sanitised at request time — must be an existing absolute directory).
|
||
example: /Users/dev/projects/my-app
|
||
model:
|
||
type: string
|
||
nullable: true
|
||
description: Model alias/id passed via `--model`, or null to inherit the user's default.
|
||
example: claude-opus-4-8
|
||
permissionMode:
|
||
type: string
|
||
enum:
|
||
- acceptEdits
|
||
- default
|
||
- plan
|
||
- bypassPermissions
|
||
description: Permission mode passed via `--permission-mode`. Defaults to `acceptEdits` when omitted or invalid.
|
||
example: acceptEdits
|
||
effort:
|
||
type: string
|
||
enum:
|
||
- low
|
||
- medium
|
||
- high
|
||
- xhigh
|
||
- max
|
||
nullable: true
|
||
description: Thinking-effort level passed via `--effort` (higher = more reasoning tokens before the assistant turn). Null inherits the model default.
|
||
example: high
|
||
prompt:
|
||
type: string
|
||
description: The initial user prompt. May be empty only when resuming a conversation (the child idles on the resumed transcript until a follow-up arrives).
|
||
example: Refactor the auth module and add tests.
|
||
argv:
|
||
type: array
|
||
items:
|
||
type: string
|
||
description: Exact argv vector passed to the `claude` binary (always includes `--output-format stream-json --verbose --include-partial-messages` plus the resolved flags).
|
||
example:
|
||
- '--output-format'
|
||
- stream-json
|
||
- '--verbose'
|
||
- '--include-partial-messages'
|
||
- '--permission-mode'
|
||
- acceptEdits
|
||
- '--input-format'
|
||
- stream-json
|
||
- '--model'
|
||
- claude-opus-4-8
|
||
resumeSessionId:
|
||
type: string
|
||
nullable: true
|
||
description: Claude session id this run resumed (`--resume`), or null for a fresh run. Conversation mode only.
|
||
example: null
|
||
status:
|
||
type: string
|
||
enum:
|
||
- spawning
|
||
- running
|
||
- completed
|
||
- error
|
||
- killed
|
||
description: Lifecycle status. `spawning` -> `running` on the first parsed output envelope; terminal states are `completed` (exit 0), `error` (non-zero exit or spawn error), or `killed` (terminated via DELETE). Each transition is broadcast as a `run_status` WebSocket message.
|
||
example: running
|
||
startedAt:
|
||
type: integer
|
||
format: int64
|
||
description: Spawn time in epoch milliseconds.
|
||
example: 1718000000000
|
||
endedAt:
|
||
type: integer
|
||
format: int64
|
||
nullable: true
|
||
description: Exit time in epoch milliseconds, or null while still live.
|
||
example: null
|
||
exitCode:
|
||
type: integer
|
||
nullable: true
|
||
description: Process exit code once the child exits; null while running or if killed by signal.
|
||
example: null
|
||
signal:
|
||
type: string
|
||
nullable: true
|
||
description: Terminating signal name (e.g. `SIGTERM`/`SIGKILL`) if the child was killed by a signal; null otherwise.
|
||
example: null
|
||
error:
|
||
type: string
|
||
nullable: true
|
||
description: Spawn/runtime error message if the child failed to start or errored; null otherwise.
|
||
example: null
|
||
sessionId:
|
||
type: string
|
||
nullable: true
|
||
description: Claude session id, captured from the `system/init` stream envelope (optimistically pre-seeded with resumeSessionId). Used to deep-link to /api/sessions/{id}. Null until the init envelope arrives.
|
||
example: a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d
|
||
envelopeCount:
|
||
type: integer
|
||
minimum: 0
|
||
description: Total stream-json envelopes parsed for this run so far (monotonic; not capped by the in-memory replay buffer).
|
||
example: 12
|
||
stdoutTail:
|
||
type: string
|
||
description: Trailing slice of the child's raw stdout (capped at ~4 KiB) for quick diagnostics.
|
||
example: |
|
||
{"type":"result","subtype":"success",...}
|
||
stderrTail:
|
||
type: string
|
||
description: Trailing slice of the child's raw stderr (capped at ~4 KiB); also captures parse errors.
|
||
example: ''
|
||
RunHandleWithEnvelopes:
|
||
allOf:
|
||
- $ref: '#/components/schemas/RunHandle'
|
||
- type: object
|
||
description: RunHandle plus the in-memory envelope replay buffer, returned by GET /api/run/{id}?envelopes=1.
|
||
required:
|
||
- envelopes
|
||
properties:
|
||
envelopes:
|
||
type: array
|
||
description: The most recent stream-json envelopes (capped at 500 per handle) passed through verbatim from the `claude` child — system/init, assistant text + tool_use, user tool_result, result/success, partial stream_event deltas, etc. Lets a late-attaching client replay what it missed. Full transcript is always available via /api/sessions/{id}.
|
||
items:
|
||
type: object
|
||
additionalProperties: true
|
||
RunListResponse:
|
||
type: object
|
||
description: All currently-tracked run handles (newest first) plus concurrency telemetry.
|
||
required:
|
||
- items
|
||
- maxConcurrent
|
||
- activeCount
|
||
properties:
|
||
items:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/RunHandle'
|
||
description: Live + recently-exited handles, sorted by startedAt descending. Handles are reaped 5 minutes after exit.
|
||
maxConcurrent:
|
||
type: integer
|
||
description: Concurrency cap (env `RUN_MAX_CONCURRENT`, default effectively uncapped at 10000). Spawns over this throw ECONCURRENCY (HTTP 429).
|
||
example: 10000
|
||
activeCount:
|
||
type: integer
|
||
minimum: 0
|
||
description: Number of handles currently in `spawning` or `running` status.
|
||
example: 2
|
||
RunHistoryItem:
|
||
type: object
|
||
description: A persisted run record from the `dashboard_runs` sqlite table. Survives the 5-minute in-memory reap so past runs remain visible and resumable. Fields are snake_case (DB column names) and timestamps are ISO-8601 strings, distinct from the camelCase epoch-ms fields on RunHandle.
|
||
required:
|
||
- id
|
||
- session_id
|
||
- mode
|
||
- cwd
|
||
- model
|
||
- permission_mode
|
||
- effort
|
||
- resume_session_id
|
||
- prompt_preview
|
||
- status
|
||
- exit_code
|
||
- started_at
|
||
- ended_at
|
||
- isLive
|
||
- lane_id
|
||
properties:
|
||
id:
|
||
type: string
|
||
format: uuid
|
||
description: Run id (matches RunHandle.id).
|
||
example: 3f2c9a1e-7b4d-4e21-9b6a-1d2e3f4a5b6c
|
||
session_id:
|
||
type: string
|
||
nullable: true
|
||
description: Claude session id once known (from system/init), else null.
|
||
example: a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d
|
||
mode:
|
||
type: string
|
||
enum:
|
||
- headless
|
||
- conversation
|
||
description: Run mode at spawn time.
|
||
example: conversation
|
||
cwd:
|
||
type: string
|
||
description: Absolute working directory the run was spawned in.
|
||
example: /Users/dev/projects/my-app
|
||
model:
|
||
type: string
|
||
nullable: true
|
||
description: Model used, or null for the default.
|
||
example: claude-opus-4-8
|
||
permission_mode:
|
||
type: string
|
||
nullable: true
|
||
enum:
|
||
- acceptEdits
|
||
- default
|
||
- plan
|
||
- bypassPermissions
|
||
description: Permission mode recorded at spawn time.
|
||
example: acceptEdits
|
||
effort:
|
||
type: string
|
||
nullable: true
|
||
enum:
|
||
- low
|
||
- medium
|
||
- high
|
||
- xhigh
|
||
- max
|
||
description: Effort level recorded at spawn time, or null.
|
||
example: high
|
||
resume_session_id:
|
||
type: string
|
||
nullable: true
|
||
description: Session id this run resumed, or null.
|
||
example: null
|
||
prompt_preview:
|
||
type: string
|
||
nullable: true
|
||
description: First 500 characters of the initial prompt (truncated preview for the history list), or null.
|
||
example: Refactor the auth module and add tests.
|
||
status:
|
||
type: string
|
||
enum:
|
||
- spawning
|
||
- running
|
||
- completed
|
||
- error
|
||
- killed
|
||
- abandoned
|
||
description: Persisted status. `abandoned` is set on server boot for rows left `running`/`spawning` by a previous process (their in-memory handles were wiped by the restart) so the UI does not show them as live.
|
||
example: completed
|
||
exit_code:
|
||
type: integer
|
||
nullable: true
|
||
description: Recorded process exit code, or null.
|
||
example: 0
|
||
started_at:
|
||
type: string
|
||
format: date-time
|
||
description: Spawn time (ISO-8601).
|
||
example: '2026-06-25T17:00:00.000Z'
|
||
ended_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
description: Exit time (ISO-8601), or null if still running / never recorded.
|
||
example: '2026-06-25T17:01:42.500Z'
|
||
isLive:
|
||
type: boolean
|
||
description: 'Computed at request time: true when a live in-memory handle for this id is currently `running` or `spawning`. Lets the UI mark which history rows are re-attachable.'
|
||
example: false
|
||
lane_id:
|
||
type: integer
|
||
nullable: true
|
||
description: Lane this run was started through (POST /api/lanes/{id}/start), or null for a run spawned straight from POST /api/run. Filterable via ?laneId=.
|
||
example: null
|
||
RunHistoryResponse:
|
||
type: object
|
||
description: Persisted run history, most recent first. Empty `items` when the persistence DB is unavailable.
|
||
required:
|
||
- items
|
||
properties:
|
||
items:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/RunHistoryItem'
|
||
RunCwdSuggestion:
|
||
type: object
|
||
description: A suggested working directory for spawning a run. Only directories that still exist on disk are returned.
|
||
required:
|
||
- kind
|
||
- path
|
||
- label
|
||
properties:
|
||
kind:
|
||
type: string
|
||
enum:
|
||
- dashboard
|
||
- home
|
||
- recent
|
||
description: '`dashboard`: the dashboard server''s own cwd (always first). `home`: $HOME. `recent`: distinct cwds Claude Code has been used in, sourced from the sessions table.'
|
||
example: recent
|
||
path:
|
||
type: string
|
||
description: Absolute, resolved directory path.
|
||
example: /Users/dev/projects/my-app
|
||
label:
|
||
type: string
|
||
description: Human-friendly label (defaults to the directory basename).
|
||
example: my-app
|
||
RunCwdsResponse:
|
||
type: object
|
||
description: Working-directory suggestions for the Run launcher.
|
||
required:
|
||
- items
|
||
properties:
|
||
items:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/RunCwdSuggestion'
|
||
RunFilesResponse:
|
||
type: object
|
||
description: File-path autocomplete results for the prompt editor's `@` references — up to 40 paths relative to the given cwd, shortest first.
|
||
required:
|
||
- items
|
||
properties:
|
||
items:
|
||
type: array
|
||
items:
|
||
type: string
|
||
description: Paths relative to the resolved cwd. Dotfiles (except .env/.gitignore) and heavy build dirs (node_modules, .git, dist, build, etc.) are skipped.
|
||
example:
|
||
- package.json
|
||
- src/index.ts
|
||
- server/routes/run.js
|
||
RunBinaryResponse:
|
||
type: object
|
||
description: Whether the `claude` binary is resolvable on PATH (probed via which/where; the binary is not invoked). Lets the UI warn before the user clicks Run.
|
||
required:
|
||
- found
|
||
- path
|
||
properties:
|
||
found:
|
||
type: boolean
|
||
description: True when `claude` resolves on PATH.
|
||
example: true
|
||
path:
|
||
type: string
|
||
nullable: true
|
||
description: Absolute path to the resolved `claude` binary, or null when not found.
|
||
example: /usr/local/bin/claude
|
||
RunSpawnRequest:
|
||
type: object
|
||
description: 'Request body for spawning a run. SIDE EFFECT: a successful call spawns a real `claude` process in `cwd`, begins streaming `run_stream`/`run_status` WebSocket messages, and persists a row to `dashboard_runs`.'
|
||
required:
|
||
- prompt
|
||
properties:
|
||
prompt:
|
||
type: string
|
||
description: Initial user prompt. Required and non-empty UNLESS mode is `conversation` AND resumeSessionId is set (a resumed conversation may start empty and idle on stdin).
|
||
example: Refactor the auth module and add tests.
|
||
mode:
|
||
type: string
|
||
enum:
|
||
- headless
|
||
- conversation
|
||
default: conversation
|
||
description: '`headless` for a single-shot run; `conversation` for a multi-turn run that accepts follow-ups via POST /api/run/{id}/message. Any value other than `headless` is treated as `conversation`.'
|
||
example: conversation
|
||
cwd:
|
||
type: string
|
||
description: Absolute working directory for the child. Must exist as a directory at request time. Omitted/empty defaults to the dashboard server's cwd. Non-absolute or missing paths are rejected with EBADCWD.
|
||
example: /Users/dev/projects/my-app
|
||
model:
|
||
type: string
|
||
description: Optional model alias/id passed via `--model`. Omit to inherit the user's default.
|
||
example: claude-opus-4-8
|
||
resumeSessionId:
|
||
type: string
|
||
description: Optional Claude session id to resume via `--resume`. Must match /^[A-Za-z0-9-]{8,}$/ and requires conversation mode, else EBADSESSION / EBADMODE.
|
||
example: a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d
|
||
effort:
|
||
type: string
|
||
enum:
|
||
- low
|
||
- medium
|
||
- high
|
||
- xhigh
|
||
- max
|
||
description: Optional thinking-effort level passed via `--effort`. An invalid value is rejected with EBADEFFORT.
|
||
example: high
|
||
permissionMode:
|
||
type: string
|
||
enum:
|
||
- acceptEdits
|
||
- default
|
||
- plan
|
||
- bypassPermissions
|
||
default: acceptEdits
|
||
description: Permission mode passed via `--permission-mode`. Unknown values silently fall back to `acceptEdits`.
|
||
example: acceptEdits
|
||
RunSpawnConcurrencyResponse:
|
||
type: object
|
||
description: HTTP 429 body when the concurrency cap is reached (ECONCURRENCY). In addition to the standard `error` envelope, this response carries a top-level `running` array listing the runs currently occupying the cap.
|
||
required:
|
||
- error
|
||
- running
|
||
properties:
|
||
error:
|
||
$ref: '#/components/schemas/ErrorObject'
|
||
running:
|
||
type: array
|
||
description: The live runs (status running/spawning) that are holding the concurrency slots.
|
||
items:
|
||
type: object
|
||
required:
|
||
- id
|
||
- pid
|
||
- startedAt
|
||
- mode
|
||
properties:
|
||
id:
|
||
type: string
|
||
format: uuid
|
||
example: 3f2c9a1e-7b4d-4e21-9b6a-1d2e3f4a5b6c
|
||
pid:
|
||
type: integer
|
||
nullable: true
|
||
example: 48213
|
||
startedAt:
|
||
type: integer
|
||
format: int64
|
||
example: 1718000000000
|
||
mode:
|
||
type: string
|
||
enum:
|
||
- headless
|
||
- conversation
|
||
example: conversation
|
||
RunMessageRequest:
|
||
type: object
|
||
description: 'Request body for sending a follow-up turn into a running conversation. SIDE EFFECT: writes a stream-json user envelope to the child''s stdin and broadcasts a `run_input_ack` WebSocket message.'
|
||
required:
|
||
- text
|
||
properties:
|
||
text:
|
||
type: string
|
||
description: The follow-up user message. Required and non-empty (else EBADINPUT).
|
||
example: Also update the README to document the new flags.
|
||
RunMessageResponse:
|
||
type: object
|
||
description: Acknowledgement that the follow-up turn was written to the child's stdin.
|
||
required:
|
||
- messageId
|
||
properties:
|
||
messageId:
|
||
type: string
|
||
format: uuid
|
||
description: Server-generated id for this input turn; echoed in the `run_input_ack` WebSocket message.
|
||
example: 9c0d1e2f-3a4b-5c6d-7e8f-9a0b1c2d3e4f
|
||
RunKillResponse:
|
||
type: object
|
||
description: Acknowledgement that a kill was issued (or that the run had already terminated).
|
||
required:
|
||
- ok
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
example: true
|
||
LaneWorktreeCreateRequest:
|
||
type: object
|
||
required:
|
||
- sourceRepo
|
||
properties:
|
||
sourceRepo:
|
||
type: string
|
||
description: Existing absolute path to the source git repository.
|
||
example: /Users/me/src/project
|
||
title:
|
||
type: string
|
||
description: Human-readable lane title.
|
||
example: Criteria form
|
||
base:
|
||
type: string
|
||
description: Preferred base branch. Defaults to the LANE_BASE_BRANCH env var, or `main` when that is also unset.
|
||
example: main
|
||
slug:
|
||
type: string
|
||
description: Optional branch/directory slug override.
|
||
example: criteria-form
|
||
LaneEnsureRequest:
|
||
type: object
|
||
required:
|
||
- cwd
|
||
properties:
|
||
cwd:
|
||
type: string
|
||
description: Absolute working directory to find or adopt a lane for. A lane whose own cwd is this path, or the closest path-boundary parent of it, is returned as-is.
|
||
example: /Users/me/src/project/packages/app
|
||
title:
|
||
type: string
|
||
description: Title for the lane if one has to be created; ignored when one already exists.
|
||
example: App package
|
||
LaneDestructiveActionRequest:
|
||
type: object
|
||
required:
|
||
- confirm
|
||
- expect
|
||
properties:
|
||
confirm:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
force:
|
||
type: boolean
|
||
description: Required by reset/remove when unpushed commits exist.
|
||
expect:
|
||
type: object
|
||
description: 'Required complete facts returned by the preceding preflight: head, dirty, untracked, unpushed for reset/remove; sessions, events, tokenRows for purge. Differences return 409 ESTALE without destructive work.'
|
||
additionalProperties: true
|
||
LaneStageDetectionFields:
|
||
type: object
|
||
description: Fields the server's stage-detection heuristic (server/lib/stage-detect.js) adds to every lane returned by GET /api/lanes and GET /api/lanes/:id. An inferred stage is never evidence and never renders as done — see docs/LANES.md#stage-detection.
|
||
properties:
|
||
detected_stage:
|
||
type: string
|
||
nullable: true
|
||
description: Stage id inferred from ingested tool events, or null if no signal has been seen. Independent of the agent's own declared `stage`.
|
||
detected_signal:
|
||
type: string
|
||
nullable: true
|
||
description: The tool-event signal that produced detected_stage, capped at 120 characters; null when detected_stage is null.
|
||
detected:
|
||
type: boolean
|
||
description: Present on each entry of pipeline_nodes. True for the inferred node and any node before it that carries no declared record; decorates that node's state without ever upgrading it to done.
|
||
PushVapidKeyResponse:
|
||
type: object
|
||
required:
|
||
- publicKey
|
||
description: The server's VAPID public key. The browser passes this base64url-encoded key to `PushManager.subscribe({ applicationServerKey })` so the push service will accept deliveries signed by this server's private key.
|
||
properties:
|
||
publicKey:
|
||
type: string
|
||
description: Base64url-encoded VAPID (P-256 ECDSA) public application server key. Generated once and persisted alongside the SQLite DB so the web app and native apps share one key pair.
|
||
example: BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8
|
||
PushSubscriptionKeys:
|
||
type: object
|
||
required:
|
||
- p256dh
|
||
- auth
|
||
description: Client encryption keys produced by the browser's PushManager subscription. Both are required to encrypt Web Push payloads for the endpoint.
|
||
properties:
|
||
p256dh:
|
||
type: string
|
||
description: Base64url-encoded P-256 ECDH public key from the browser subscription (`subscription.getKey('p256dh')`). Stored verbatim in the `push_subscriptions` table.
|
||
example: BNcRdreALRFXTkOOUHK1EtK2wtaz5Ry4YfYCA_0QTpQtUbVlUls0VJXg7A8u-Ts1XbjhazAkj7I99e8QcYP7DkM
|
||
auth:
|
||
type: string
|
||
description: Base64url-encoded auth secret from the browser subscription (`subscription.getKey('auth')`). Stored verbatim in the `push_subscriptions` table.
|
||
example: tBHItJI5svbpez7KI4CCXg
|
||
PushSubscribeRequest:
|
||
type: object
|
||
required:
|
||
- endpoint
|
||
- keys
|
||
description: A browser PushSubscription serialized for storage. Persisted via `INSERT OR REPLACE` keyed on `endpoint`, so re-subscribing the same endpoint is idempotent (it overwrites the stored keys rather than duplicating the row).
|
||
properties:
|
||
endpoint:
|
||
type: string
|
||
format: uri
|
||
description: The push service delivery URL from `subscription.endpoint`. Acts as the primary key in `push_subscriptions`; sending later POSTs encrypted payloads here. Subscriptions that return HTTP 410 (Gone) during `/send` are pruned automatically.
|
||
example: https://fcm.googleapis.com/fcm/send/dGhpcy1pcy1hLWZha2UtZW5kcG9pbnQ
|
||
keys:
|
||
$ref: '#/components/schemas/PushSubscriptionKeys'
|
||
PushSubscribeResponse:
|
||
type: object
|
||
required:
|
||
- ok
|
||
description: Confirmation that the subscription was stored (or overwritten).
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
description: Always `true` on success.
|
||
example: true
|
||
PushUnsubscribeRequest:
|
||
type: object
|
||
required:
|
||
- endpoint
|
||
description: 'Identifies the subscription to delete by its push-service endpoint. NOTE: the endpoint is supplied in the request BODY (DELETE with a JSON body), not as a query parameter.'
|
||
properties:
|
||
endpoint:
|
||
type: string
|
||
format: uri
|
||
description: 'The `endpoint` of the subscription to remove from `push_subscriptions`. Deletion is idempotent — removing an endpoint that is not stored still returns `{ ok: true }`.'
|
||
example: https://fcm.googleapis.com/fcm/send/dGhpcy1pcy1hLWZha2UtZW5kcG9pbnQ
|
||
PushOkResponse:
|
||
type: object
|
||
required:
|
||
- ok
|
||
description: Generic success acknowledgement returned by subscribe/unsubscribe.
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
description: Always `true` on success.
|
||
example: true
|
||
PushSendRequest:
|
||
type: object
|
||
required:
|
||
- title
|
||
- body
|
||
description: Notification content to broadcast. Both fields are mandatory; a missing title or body yields a 400. The same title/body is delivered to every reachable surface (native Electron notification + all stored Web Push subscriptions).
|
||
properties:
|
||
title:
|
||
type: string
|
||
description: Notification title line.
|
||
example: Session completed
|
||
body:
|
||
type: string
|
||
description: Notification body text.
|
||
example: Your Claude Code session finished with 3 subagents.
|
||
PushSendResponse:
|
||
type: object
|
||
required:
|
||
- ok
|
||
- native
|
||
- pushed
|
||
- failed
|
||
description: Reports which delivery surfaces actually fired. This lets the client distinguish a real delivery from a silent no-op (no subscribers AND no Electron host), which would otherwise look like success.
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
description: Always `true` when dispatch ran without throwing.
|
||
example: true
|
||
native:
|
||
type: boolean
|
||
description: '`true` when a native OS notification was shown via Electron''s main-process Notification API (i.e. the server is hosted inside the desktop app and notifications are supported). `false` under a plain `npm start` host.'
|
||
example: false
|
||
pushed:
|
||
type: integer
|
||
minimum: 0
|
||
description: Count of stored Web Push subscriptions that accepted the encrypted payload (fulfilled `web-push` sends).
|
||
example: 2
|
||
failed:
|
||
type: integer
|
||
minimum: 0
|
||
description: Count of Web Push sends that were rejected. Subscriptions rejected with HTTP 410 (Gone) are deleted from `push_subscriptions` as part of this request.
|
||
example: 1
|
||
SessionsFacetsResponse:
|
||
type: object
|
||
description: 'Facet values for the Sessions page filter UI: the distinct working directories (cwd) and the distinct data-source ids seen across all sessions.'
|
||
required:
|
||
- cwds
|
||
- sources
|
||
properties:
|
||
cwds:
|
||
type: array
|
||
description: Distinct, non-empty session working directories (the `cwd` column), sorted ascending. Powers the cwd filter dropdown.
|
||
items:
|
||
type: string
|
||
example:
|
||
- /Users/son/WebstormProjects/Claude-Code-Agent-Monitor
|
||
- /Users/son/code/another-project
|
||
sources:
|
||
type: array
|
||
description: Distinct data-source ids seen across all sessions (the `sessions.source` column). Always includes the built-in `local` history; each configured remote SSH machine contributes its `remote_sources.id`. Powers the source filter dropdown and the `sources` query param on the list/analytics endpoints.
|
||
items:
|
||
type: string
|
||
example:
|
||
- local
|
||
- 4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
RemoteSource:
|
||
type: object
|
||
description: A configured remote SSH machine the dashboard pulls Claude Code history from. NO secrets are stored on this record — SSH authentication defers entirely to the host's SSH stack (ssh-agent, `~/.ssh/config`, and key files). `host` is an SSH destination (`user@host`) or a `~/.ssh/config` alias.
|
||
required:
|
||
- id
|
||
- label
|
||
- host
|
||
- ssh_port
|
||
- identity_file
|
||
- remote_home
|
||
- enabled
|
||
- status
|
||
- last_error
|
||
- last_sync_at
|
||
- last_sync_counts
|
||
- created_at
|
||
- updated_at
|
||
properties:
|
||
id:
|
||
type: string
|
||
description: Primary key — the remote-source id (also used as `sessions.source`).
|
||
example: 4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
label:
|
||
type: string
|
||
description: Human-readable name shown in the UI.
|
||
example: Work laptop
|
||
host:
|
||
type: string
|
||
description: SSH destination (`user@host`) or a `~/.ssh/config` alias resolved by the host SSH stack.
|
||
example: son@studio.local
|
||
ssh_port:
|
||
type: integer
|
||
nullable: true
|
||
description: Optional SSH port; null defers to the SSH default / `~/.ssh/config`.
|
||
example: 22
|
||
identity_file:
|
||
type: string
|
||
nullable: true
|
||
description: Optional path to a private-key file passed to ssh (`-i`); null to omit.
|
||
example: ~/.ssh/id_ed25519
|
||
remote_home:
|
||
type: string
|
||
nullable: true
|
||
description: Optional remote Claude home to read transcripts from; null defaults to the remote `~/.claude`.
|
||
example: ~/.claude
|
||
enabled:
|
||
type: boolean
|
||
description: Whether this source is eligible for scheduled/manual syncs.
|
||
example: true
|
||
status:
|
||
type: string
|
||
enum:
|
||
- idle
|
||
- syncing
|
||
- ok
|
||
- error
|
||
description: Last known sync status of the source.
|
||
example: ok
|
||
last_error:
|
||
type: string
|
||
nullable: true
|
||
description: Error message from the last failed sync/test, or null.
|
||
example: null
|
||
last_sync_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
description: ISO-8601 timestamp of the last successful sync, or null.
|
||
example: '2026-07-22T18:41:55.117Z'
|
||
last_sync_counts:
|
||
type: object
|
||
nullable: true
|
||
additionalProperties: true
|
||
description: Counters from the last sync (imported / skipped / backfilled / errors / sessions_seen / sessions_tagged), or null if never synced.
|
||
example:
|
||
imported: 9
|
||
skipped: 41
|
||
backfilled: 0
|
||
errors: 0
|
||
sessions_seen: 50
|
||
sessions_tagged: 50
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
description: ISO-8601 creation timestamp.
|
||
example: '2026-07-20T09:15:00.000Z'
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
description: ISO-8601 timestamp of the last edit.
|
||
example: '2026-07-22T18:41:55.117Z'
|
||
RemoteSourceCreateRequest:
|
||
type: object
|
||
description: Request body to register a remote SSH source. `label` and `host` are required; the rest are optional. No credentials are ever accepted or stored — auth defers to the host SSH stack.
|
||
required:
|
||
- label
|
||
- host
|
||
properties:
|
||
label:
|
||
type: string
|
||
description: Human-readable name.
|
||
example: Work laptop
|
||
host:
|
||
type: string
|
||
description: SSH destination (`user@host`) or a `~/.ssh/config` alias.
|
||
example: son@studio.local
|
||
ssh_port:
|
||
type: integer
|
||
description: Optional SSH port.
|
||
example: 22
|
||
identity_file:
|
||
type: string
|
||
description: Optional private-key path passed to ssh (`-i`).
|
||
example: ~/.ssh/id_ed25519
|
||
remote_home:
|
||
type: string
|
||
description: Optional remote Claude home; defaults to the remote `~/.claude`.
|
||
example: ~/.claude
|
||
enabled:
|
||
type: boolean
|
||
description: Whether the source is enabled for syncing (default true).
|
||
example: true
|
||
RemoteSourceUpdateRequest:
|
||
type: object
|
||
description: Partial update for a remote source. Only the keys present in the body are changed; omitted keys are left as-is. Same field set as create; both `label` and `host` are optional here.
|
||
properties:
|
||
label:
|
||
type: string
|
||
example: Studio Mac
|
||
host:
|
||
type: string
|
||
example: son@studio.local
|
||
ssh_port:
|
||
type: integer
|
||
nullable: true
|
||
example: 2222
|
||
identity_file:
|
||
type: string
|
||
nullable: true
|
||
example: ~/.ssh/id_ed25519
|
||
remote_home:
|
||
type: string
|
||
nullable: true
|
||
example: ~/.claude
|
||
enabled:
|
||
type: boolean
|
||
example: false
|
||
RemoteSourceResponse:
|
||
type: object
|
||
required:
|
||
- source
|
||
properties:
|
||
source:
|
||
$ref: '#/components/schemas/RemoteSource'
|
||
RemoteSourceListResponse:
|
||
type: object
|
||
required:
|
||
- sources
|
||
properties:
|
||
sources:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/RemoteSource'
|
||
RemoteSourceTestResponse:
|
||
type: object
|
||
description: Result of an SSH connectivity probe.
|
||
required:
|
||
- ok
|
||
- message
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
example: true
|
||
message:
|
||
type: string
|
||
description: Human-readable probe result.
|
||
example: Connected; found 24 project directories under ~/.claude/projects.
|
||
remoteProjects:
|
||
type: array
|
||
description: Optional list of remote project directories discovered during the probe (present on success).
|
||
items:
|
||
type: string
|
||
example:
|
||
- '-Users-son-code-foo'
|
||
- '-Users-son-code-bar'
|
||
RemoteSourceSyncResponse:
|
||
type: object
|
||
description: Counters from a pull-now sync against the remote source.
|
||
required:
|
||
- ok
|
||
- imported
|
||
- skipped
|
||
- backfilled
|
||
- errors
|
||
- sessions_seen
|
||
- sessions_tagged
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
example: true
|
||
imported:
|
||
type: integer
|
||
example: 9
|
||
skipped:
|
||
type: integer
|
||
example: 41
|
||
backfilled:
|
||
type: integer
|
||
example: 0
|
||
errors:
|
||
type: integer
|
||
example: 0
|
||
sessions_seen:
|
||
type: integer
|
||
example: 50
|
||
sessions_tagged:
|
||
type: integer
|
||
description: Number of imported sessions stamped with this source's id.
|
||
example: 50
|
||
SettingsClaudeHomeResponse:
|
||
type: object
|
||
description: The Claude Code home directory the dashboard reads transcripts and settings from. Defaults to `~/.claude` unless overridden via the CLAUDE_HOME environment variable.
|
||
required:
|
||
- claude_home
|
||
properties:
|
||
claude_home:
|
||
type: string
|
||
description: Absolute path to the active Claude Code home directory (CLAUDE_HOME, or `<homedir>/.claude` when unset).
|
||
example: /Users/son/.claude
|
||
SettingsClaudeHomeUpdateRequest:
|
||
type: object
|
||
description: Request body for changing the Claude Code home directory. A leading `~` is expanded to the user's home directory; the resolved path must be absolute and point to an existing directory.
|
||
required:
|
||
- path
|
||
properties:
|
||
path:
|
||
type: string
|
||
description: New Claude Code home directory. A leading `~/` is expanded to the OS home directory before validation. Must resolve to an absolute path that exists and is a directory.
|
||
example: ~/.codefuse/engine/cc
|
||
SettingsClaudeHomeUpdateResponse:
|
||
type: object
|
||
description: Confirmation that CLAUDE_HOME was updated. The new value is applied to process.env immediately and persisted to the project `.env` file.
|
||
required:
|
||
- ok
|
||
- claude_home
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
claude_home:
|
||
type: string
|
||
description: The resolved absolute path now in effect (after `~` expansion).
|
||
example: /Users/son/.codefuse/engine/cc
|
||
WorkflowToolRun:
|
||
type: object
|
||
description: 'A Claude Code Workflow-tool run (issue #167): a fleet of sub-agents spawned by the ''Workflow'' tool (or self-paced /loop). These emit no hooks; the source of truth is the on-disk run journal, ingested into the `workflows` table (see server/lib/workflow-ingest.js). Keyed by `run_id` and parented to the launching session. The JSON-blob columns `phases` and `progress` are parsed into arrays before serialization.'
|
||
required:
|
||
- run_id
|
||
- session_id
|
||
- status
|
||
- agent_count
|
||
- total_tokens
|
||
- total_tool_calls
|
||
- phases
|
||
- progress
|
||
- source
|
||
- created_at
|
||
- updated_at
|
||
properties:
|
||
run_id:
|
||
type: string
|
||
description: Primary key — the workflow run id.
|
||
example: wf_a1b2c3d4
|
||
session_id:
|
||
type: string
|
||
description: The session that launched this run (FK into sessions.id).
|
||
example: 5f3c0e2a-1b9d-4c77-8a21-9e0f7b6d4c11
|
||
task_id:
|
||
type: string
|
||
nullable: true
|
||
description: Optional task/issue identifier associated with the run.
|
||
example: ISSUE-167
|
||
name:
|
||
type: string
|
||
nullable: true
|
||
description: Human-readable run name from the journal, if present.
|
||
example: Refactor pricing engine
|
||
status:
|
||
type: string
|
||
description: Open status string (e.g. running | completed | error | failed). Intentionally not constrained to an enum so new harness states never trip a stale constraint.
|
||
example: completed
|
||
default_model:
|
||
type: string
|
||
nullable: true
|
||
description: Default model the run delegated work to, when recorded.
|
||
example: claude-opus-4-8
|
||
started_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
description: When the run started, if known.
|
||
example: '2026-06-25T18:04:11.122Z'
|
||
ended_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
description: When the run finished, if known.
|
||
example: '2026-06-25T18:09:47.530Z'
|
||
duration_ms:
|
||
type: integer
|
||
nullable: true
|
||
description: Total run duration in milliseconds, if known.
|
||
example: 336408
|
||
agent_count:
|
||
type: integer
|
||
minimum: 0
|
||
description: Number of inner agents in this run.
|
||
example: 6
|
||
total_tokens:
|
||
type: integer
|
||
minimum: 0
|
||
description: Aggregate token usage across the run's inner agents.
|
||
example: 1284750
|
||
total_tool_calls:
|
||
type: integer
|
||
minimum: 0
|
||
description: Aggregate tool-call count across the run's inner agents.
|
||
example: 412
|
||
phases:
|
||
type: array
|
||
description: Parsed `phases[]` array from the run journal (verbatim journal payload, opaque to this API). Empty array when absent or unparseable.
|
||
items:
|
||
type: object
|
||
additionalProperties: true
|
||
example:
|
||
- name: plan
|
||
status: completed
|
||
- name: implement
|
||
status: completed
|
||
progress:
|
||
type: array
|
||
description: Parsed `workflowProgress[]` array from the run journal (verbatim journal payload, opaque to this API). Empty array when absent or unparseable.
|
||
items:
|
||
type: object
|
||
additionalProperties: true
|
||
example:
|
||
- step: 1
|
||
label: scaffold
|
||
done: true
|
||
script_path:
|
||
type: string
|
||
nullable: true
|
||
description: Path to the run's driving script, if recorded.
|
||
example: /Users/son/.claude/projects/-Users-son-code/wf_a1b2c3d4.sh
|
||
journal_path:
|
||
type: string
|
||
nullable: true
|
||
description: Path to the on-disk run journal this row was ingested from.
|
||
example: /Users/son/.claude/projects/-Users-son-code/5f3c0e2a/workflows/wf_a1b2c3d4.json
|
||
source:
|
||
type: string
|
||
description: Ingestion source for the row (defaults to 'journal').
|
||
example: journal
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
description: Row creation timestamp.
|
||
example: '2026-06-25T18:09:48.001Z'
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
description: Row last-update timestamp.
|
||
example: '2026-06-25T18:09:48.001Z'
|
||
WorkflowRunsListResponse:
|
||
type: object
|
||
description: Paginated list of Workflow-tool runs with status counts. `total` reflects the active filter (status when supplied, otherwise the full table); `counts` is always the whole-table breakdown by status.
|
||
required:
|
||
- runs
|
||
- total
|
||
- counts
|
||
- limit
|
||
- offset
|
||
properties:
|
||
runs:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/WorkflowToolRun'
|
||
total:
|
||
type: integer
|
||
minimum: 0
|
||
description: 'Total runs matching the current filter (independent of limit/offset). Equals the status-filtered count when `status` is supplied, otherwise the full-table count. Note: not narrowed by `session_id`.'
|
||
example: 42
|
||
counts:
|
||
type: object
|
||
description: Whole-table run counts grouped by status (not affected by filters).
|
||
additionalProperties:
|
||
type: integer
|
||
minimum: 0
|
||
example:
|
||
completed: 30
|
||
error: 5
|
||
running: 7
|
||
limit:
|
||
type: integer
|
||
description: Effective page size used.
|
||
example: 50
|
||
offset:
|
||
type: integer
|
||
description: Effective pagination offset used.
|
||
example: 0
|
||
WorkflowRunDetailResponse:
|
||
type: object
|
||
description: A single Workflow-tool run with its linked inner agents and the events attributed to those agents (chronological, capped at 5000).
|
||
required:
|
||
- workflow
|
||
- agents
|
||
- events
|
||
properties:
|
||
workflow:
|
||
$ref: '#/components/schemas/WorkflowToolRun'
|
||
agents:
|
||
type: array
|
||
description: Inner agents linked to this run via agents.workflow_run_id.
|
||
items:
|
||
$ref: '#/components/schemas/Agent'
|
||
events:
|
||
type: array
|
||
description: Events attributed to this run's inner agents, ordered by created_at then id. Capped at 5000 rows.
|
||
items:
|
||
$ref: '#/components/schemas/DashboardEvent'
|
||
paths:
|
||
/api/health:
|
||
get:
|
||
tags:
|
||
- Health
|
||
summary: Health check
|
||
operationId: getHealth
|
||
responses:
|
||
'200':
|
||
description: Service is healthy
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/HealthResponse'
|
||
/api/sessions:
|
||
get:
|
||
tags:
|
||
- Sessions
|
||
summary: List sessions
|
||
description: Returns a paginated list of sessions, newest activity first, each enriched with a SQL `agent_count` (LEFT JOIN onto agents), a `last_activity` alias of `updated_at`, and a `cost` computed from the session's token usage against the current pricing rules. The `status` and `q` filters compose (AND) with each other and with pagination; `q` is a case-insensitive LIKE across `id`, `name`, and `cwd`. `total` reflects all rows matching the filters independent of `limit`/`offset` so paginators stay accurate, while `cost` is only calculated for the rows on the returned page (when `sort_by=price` it is computed across all matching rows so the price sort is correct). The endpoint is read-only with no side effects; `metadata` on each session is returned as a raw JSON-encoded string, not a parsed object.
|
||
operationId: listSessions
|
||
parameters:
|
||
- $ref: '#/components/parameters/SessionStatusQuery'
|
||
example: active
|
||
- name: q
|
||
in: query
|
||
schema:
|
||
type: string
|
||
description: Case-insensitive search across `id` / `name` / `cwd`. Composes with the status filter when both are present.
|
||
example: pricing
|
||
- $ref: '#/components/parameters/SourcesQuery'
|
||
example: local,4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
- $ref: '#/components/parameters/LimitQuery'
|
||
example: 50
|
||
- $ref: '#/components/parameters/OffsetQuery'
|
||
example: 0
|
||
responses:
|
||
'200':
|
||
description: Session list
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SessionsListResponse'
|
||
example:
|
||
sessions:
|
||
- id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Refactor pricing route + add cost endpoint
|
||
status: active
|
||
cwd: /Users/son/WebstormProjects/Claude-Code-Agent-Monitor
|
||
model: claude-opus-4-20250514
|
||
started_at: '2026-06-25T14:02:11.004Z'
|
||
ended_at: null
|
||
metadata: '{"source":"hook","git_branch":"feat/spend-budgets"}'
|
||
updated_at: '2026-06-25T14:31:50.119Z'
|
||
agent_count: 4
|
||
last_activity: '2026-06-25T14:31:50.119Z'
|
||
cost: 0.8421
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
- id: 1a2b3c4d-5e6f-4071-8293-a4b5c6d7e8f9
|
||
name: Fix flaky transcript pagination test
|
||
status: completed
|
||
cwd: /Users/son/WebstormProjects/Claude-Code-Agent-Monitor
|
||
model: claude-sonnet-4-20250514
|
||
started_at: '2026-06-24T09:12:00.000Z'
|
||
ended_at: '2026-06-24T09:48:32.501Z'
|
||
metadata: null
|
||
updated_at: '2026-06-24T09:48:32.501Z'
|
||
agent_count: 1
|
||
last_activity: '2026-06-24T09:48:32.501Z'
|
||
cost: 0.1532
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
limit: 50
|
||
offset: 0
|
||
total: 137
|
||
post:
|
||
tags:
|
||
- Sessions
|
||
summary: Create session (idempotent)
|
||
description: 'Creates a session keyed by `id`. The operation is idempotent: if a session with that `id` already exists it is returned untouched with `created: false` and HTTP 200; only a brand-new row yields `created: true` and HTTP 201. New sessions are inserted with `status: "active"` and any omitted optional fields stored as null. The `metadata` field is accepted as a JSON object in the request but persisted (and returned on the session) as a JSON-encoded string. A successful create broadcasts a `session_created` websocket frame. A missing `id` returns 400 with code `INVALID_INPUT`.'
|
||
operationId: createSession
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SessionCreateRequest'
|
||
example:
|
||
id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Refactor pricing route + add cost endpoint
|
||
cwd: /Users/son/WebstormProjects/Claude-Code-Agent-Monitor
|
||
model: claude-opus-4-20250514
|
||
metadata:
|
||
source: hook
|
||
git_branch: feat/spend-budgets
|
||
responses:
|
||
'200':
|
||
description: Session already exists
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SessionCreateResponse'
|
||
example:
|
||
session:
|
||
id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Refactor pricing route + add cost endpoint
|
||
status: active
|
||
cwd: /Users/son/WebstormProjects/Claude-Code-Agent-Monitor
|
||
model: claude-opus-4-20250514
|
||
started_at: '2026-06-25T14:02:11.004Z'
|
||
ended_at: null
|
||
metadata: '{"source":"hook","git_branch":"feat/spend-budgets"}'
|
||
updated_at: '2026-06-25T14:31:50.119Z'
|
||
agent_count: 4
|
||
last_activity: '2026-06-25T14:31:50.119Z'
|
||
cost: 0.8421
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
created: false
|
||
'201':
|
||
description: Session created
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SessionCreateResponse'
|
||
example:
|
||
session:
|
||
id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Refactor pricing route + add cost endpoint
|
||
status: active
|
||
cwd: /Users/son/WebstormProjects/Claude-Code-Agent-Monitor
|
||
model: claude-opus-4-20250514
|
||
started_at: '2026-06-25T14:02:11.004Z'
|
||
ended_at: null
|
||
metadata: '{"source":"hook","git_branch":"feat/spend-budgets"}'
|
||
updated_at: '2026-06-25T14:02:11.004Z'
|
||
agent_count: 0
|
||
last_activity: '2026-06-25T14:02:11.004Z'
|
||
cost: 0
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
created: true
|
||
'400':
|
||
description: Invalid request body
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: INVALID_INPUT
|
||
message: id is required
|
||
/api/sessions/{id}:
|
||
get:
|
||
tags:
|
||
- Sessions
|
||
summary: Get session details
|
||
description: Returns a single session together with all of its agents (chronological) and persisted events. Read-only, no side effects. The session's `metadata` and each event's `data` are returned as raw JSON-encoded strings, not parsed objects. Returns 404 with code `NOT_FOUND` when no session matches the path `id`.
|
||
operationId: getSession
|
||
parameters:
|
||
- $ref: '#/components/parameters/SessionIdPath'
|
||
example: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
responses:
|
||
'200':
|
||
description: Session with associated agents/events
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SessionDetailResponse'
|
||
example:
|
||
session:
|
||
id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Refactor pricing route + add cost endpoint
|
||
status: active
|
||
cwd: /Users/son/WebstormProjects/Claude-Code-Agent-Monitor
|
||
model: claude-opus-4-20250514
|
||
started_at: '2026-06-25T14:02:11.004Z'
|
||
ended_at: null
|
||
metadata: '{"source":"hook","git_branch":"feat/spend-budgets"}'
|
||
updated_at: '2026-06-25T14:31:50.119Z'
|
||
agent_count: 4
|
||
last_activity: '2026-06-25T14:31:50.119Z'
|
||
cost: 0.8421
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
agents:
|
||
- id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d-main
|
||
session_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Main Agent
|
||
type: main
|
||
subagent_type: null
|
||
status: working
|
||
task: null
|
||
current_tool: Edit
|
||
started_at: '2026-06-25T14:02:11.004Z'
|
||
ended_at: null
|
||
parent_agent_id: null
|
||
metadata: '{"model":"claude-opus-4-20250514"}'
|
||
updated_at: '2026-06-25T14:31:50.119Z'
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
- id: ad18a79192af10ed1
|
||
session_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Explore pricing module
|
||
type: subagent
|
||
subagent_type: Explore
|
||
status: completed
|
||
task: Map every caller of calculateCost() across server/routes
|
||
current_tool: null
|
||
started_at: '2026-06-25T14:10:22.310Z'
|
||
ended_at: '2026-06-25T14:14:09.882Z'
|
||
parent_agent_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d-main
|
||
metadata: null
|
||
updated_at: '2026-06-25T14:14:09.882Z'
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
events:
|
||
- id: 48213
|
||
session_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
agent_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d-main
|
||
event_type: PostToolUse
|
||
tool_name: Edit
|
||
summary: Edited server/routes/pricing.js
|
||
data: '{"tool_input":{"file_path":"server/routes/pricing.js"},"tool_response":{"success":true}}'
|
||
created_at: '2026-06-25T14:31:50.119Z'
|
||
'404':
|
||
description: Session not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Session not found
|
||
patch:
|
||
tags:
|
||
- Sessions
|
||
summary: Update session
|
||
description: Partially updates a session by `id`. Only `name`, `status`, `ended_at`, and `metadata` are accepted; any field omitted from the body is passed as null and the underlying UPDATE uses COALESCE, so a null leaves the existing column value unchanged (partial-update semantics) — you cannot clear a field to null through this endpoint. `metadata` is supplied as a JSON object but stored and returned as a JSON-encoded string. A successful update re-reads the row and broadcasts a `session_updated` websocket frame. Returns 404 with code `NOT_FOUND` when the session does not exist.
|
||
operationId: updateSession
|
||
parameters:
|
||
- $ref: '#/components/parameters/SessionIdPath'
|
||
example: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SessionUpdateRequest'
|
||
example:
|
||
status: completed
|
||
ended_at: '2026-06-25T15:07:44.220Z'
|
||
metadata:
|
||
source: hook
|
||
git_branch: feat/spend-budgets
|
||
outcome: merged
|
||
responses:
|
||
'200':
|
||
description: Session updated
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SessionUpdateResponse'
|
||
example:
|
||
session:
|
||
id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Refactor pricing route + add cost endpoint
|
||
status: completed
|
||
cwd: /Users/son/WebstormProjects/Claude-Code-Agent-Monitor
|
||
model: claude-opus-4-20250514
|
||
started_at: '2026-06-25T14:02:11.004Z'
|
||
ended_at: '2026-06-25T15:07:44.220Z'
|
||
metadata: '{"source":"hook","git_branch":"feat/spend-budgets","outcome":"merged"}'
|
||
updated_at: '2026-06-25T15:07:44.220Z'
|
||
agent_count: 4
|
||
last_activity: '2026-06-25T15:07:44.220Z'
|
||
cost: 0.8421
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
'404':
|
||
description: Session not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Session not found
|
||
/api/sessions/{id}/stats:
|
||
get:
|
||
tags:
|
||
- Sessions
|
||
summary: Get aggregated session stats
|
||
description: 'Returns aggregated counts for the SessionOverview panel: total events, events-by-type, the top 15 tools by usage, an error count (events whose `event_type`/`summary` match /error/i or /failed/i), the event time range, agent type/status counts, the subagent-type breakdown (excluding the special `compaction` type, which is surfaced under `agents.compaction`), and token totals. All aggregation runs in SQL, so it stays cheap even for sessions with tens of thousands of events; the endpoint is read-only with no side effects. The frontend debounces calls on `new_event` / `agent_*` / `session_updated` websocket frames so the counters track a running session. Returns 404 with code `NOT_FOUND` when the session does not exist.'
|
||
operationId: getSessionStats
|
||
parameters:
|
||
- $ref: '#/components/parameters/SessionIdPath'
|
||
example: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
responses:
|
||
'200':
|
||
description: Aggregated session stats
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SessionStatsResponse'
|
||
example:
|
||
session_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
total_events: 1284
|
||
events_by_type:
|
||
- event_type: PostToolUse
|
||
count: 612
|
||
- event_type: PreToolUse
|
||
count: 612
|
||
- event_type: Notification
|
||
count: 41
|
||
- event_type: Stop
|
||
count: 19
|
||
tools_used:
|
||
- tool_name: Bash
|
||
count: 188
|
||
- tool_name: Edit
|
||
count: 143
|
||
- tool_name: Read
|
||
count: 121
|
||
- tool_name: Grep
|
||
count: 77
|
||
error_count: 6
|
||
first_event_at: '2026-06-25T14:02:11.052Z'
|
||
last_event_at: '2026-06-25T14:31:50.119Z'
|
||
agents:
|
||
total: 4
|
||
main: 1
|
||
subagent: 3
|
||
compaction: 1
|
||
by_status:
|
||
working: 1
|
||
completed: 2
|
||
error: 1
|
||
subagent_types:
|
||
- subagent_type: Explore
|
||
count: 2
|
||
- subagent_type: general-purpose
|
||
count: 1
|
||
tokens:
|
||
input_tokens: 18422
|
||
output_tokens: 9134
|
||
cache_read_tokens: 1204880
|
||
cache_write_tokens: 88210
|
||
'404':
|
||
description: Session not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Session not found
|
||
/api/sessions/{id}/transcripts:
|
||
get:
|
||
tags:
|
||
- Sessions
|
||
summary: List available transcripts for a session
|
||
description: Lists every JSONL transcript file associated with a session — the main agent's transcript plus any subagent and compaction transcripts — by scanning the on-disk Claude project directory (live files, falling back to import-time snapshots). Read-only, no side effects. Each entry carries a best-effort `db_agent_id` resolved by matching transcripts to tracked agents (exact id first, then positional-by-time within each type group); it may be null when a transcript has no matching agent row. Used by the Conversation tab to populate the transcript switcher. Returns 404 with code `NOT_FOUND` when the session does not exist.
|
||
operationId: listSessionTranscripts
|
||
parameters:
|
||
- $ref: '#/components/parameters/SessionIdPath'
|
||
example: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
responses:
|
||
'200':
|
||
description: List of transcripts available for the session
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/TranscriptListResponse'
|
||
example:
|
||
transcripts:
|
||
- id: main
|
||
name: Main Agent
|
||
type: main
|
||
has_transcript: true
|
||
db_agent_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d-main
|
||
- id: ad18a79192af10ed1
|
||
name: Explore pricing module
|
||
type: subagent
|
||
subagent_type: Explore
|
||
has_transcript: true
|
||
db_agent_id: ad18a79192af10ed1
|
||
- id: acompact-7c1e2f90
|
||
name: Context Compaction
|
||
type: compaction
|
||
subagent_type: null
|
||
has_transcript: true
|
||
db_agent_id: null
|
||
'404':
|
||
description: Session not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Session not found
|
||
/api/sessions/{id}/transcript:
|
||
get:
|
||
tags:
|
||
- Sessions
|
||
summary: Stream messages from a specific transcript
|
||
description: 'Returns parsed, renderable messages from a JSONL transcript with cursor-based pagination, reading the live file under ~/.claude/projects and falling back to the durable import-time snapshot. Pass `agent_id` to select a specific subagent or compaction transcript (default is the session''s main transcript). Pagination cursors are mutually exclusive: `after` returns messages strictly newer than a JSONL line number (incremental live updates on `new_event`), `before` returns messages strictly older than a line (load-on-scroll-up), and `offset` is legacy start-offset paging. `last_line`/`first_line` are the JSONL line numbers of the newest/oldest returned message — feed them back as `after`/`before`. When the session, transcript file, or path cannot be found the endpoint degrades gracefully to an empty result (`messages: []`, `total: 0`, `has_more: false`) rather than erroring. Read-only, no side effects.'
|
||
operationId: getSessionTranscript
|
||
parameters:
|
||
- $ref: '#/components/parameters/SessionIdPath'
|
||
example: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
- name: agent_id
|
||
in: query
|
||
schema:
|
||
type: string
|
||
description: Transcript identifier — 'main' for the session's main transcript, or a subagent / compaction id from /transcripts.
|
||
example: main
|
||
- name: limit
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
default: 50
|
||
minimum: 1
|
||
maximum: 500
|
||
description: Maximum number of messages to return.
|
||
example: 50
|
||
- name: offset
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
minimum: 0
|
||
description: Offset from the start of the transcript (mutually exclusive with after/before).
|
||
example: 0
|
||
- name: after
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
minimum: 0
|
||
description: Only return messages whose JSONL line number is strictly greater than this value. Used for incremental live updates.
|
||
example: 842
|
||
- name: before
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
minimum: 0
|
||
description: Only return messages whose JSONL line number is strictly less than this value. Used to load older messages on scroll-up.
|
||
example: 200
|
||
responses:
|
||
'200':
|
||
description: Parsed messages with cursor metadata
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/TranscriptResponse'
|
||
example:
|
||
messages:
|
||
- type: user
|
||
timestamp: '2026-06-25T14:02:11.004Z'
|
||
content:
|
||
- type: text
|
||
text: Refactor the pricing route and add a cost endpoint.
|
||
- type: assistant
|
||
timestamp: '2026-06-25T14:02:18.771Z'
|
||
model: claude-opus-4-20250514
|
||
content:
|
||
- type: thinking
|
||
text: I'll start by reading server/routes/pricing.js.
|
||
- type: tool_use
|
||
name: Read
|
||
id: toolu_01A7c2Df9
|
||
input:
|
||
file_path: server/routes/pricing.js
|
||
usage:
|
||
input_tokens: 412
|
||
output_tokens: 96
|
||
- type: user
|
||
timestamp: '2026-06-25T14:02:19.330Z'
|
||
content:
|
||
- type: tool_result
|
||
id: toolu_01A7c2Df9
|
||
output: |-
|
||
const { Router } = require("express");
|
||
...
|
||
is_error: false
|
||
total: 1284
|
||
has_more: true
|
||
last_line: 5310
|
||
first_line: 5301
|
||
'404':
|
||
description: Session or transcript not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Session not found
|
||
/api/agents:
|
||
get:
|
||
tags:
|
||
- Agents
|
||
summary: List agents
|
||
description: 'Returns agents, most recent first. Filters are applied with precedence rather than composition: when `session_id` is supplied it wins and returns every agent for that session (ignoring `status` and pagination); otherwise a `status` filter returns paginated agents in that lifecycle state; otherwise all agents are returned paginated. `limit` defaults to 10000 when not a positive integer. Read-only, no side effects. Each agent''s `metadata` is returned as a raw JSON-encoded string, not a parsed object.'
|
||
operationId: listAgents
|
||
parameters:
|
||
- $ref: '#/components/parameters/AgentStatusQuery'
|
||
example: working
|
||
- $ref: '#/components/parameters/SessionFilterQuery'
|
||
example: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
- $ref: '#/components/parameters/SourcesQuery'
|
||
example: local,4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
- $ref: '#/components/parameters/LimitQuery'
|
||
example: 50
|
||
- $ref: '#/components/parameters/OffsetQuery'
|
||
example: 0
|
||
responses:
|
||
'200':
|
||
description: Agent list
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/AgentsListResponse'
|
||
example:
|
||
agents:
|
||
- id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d-main
|
||
session_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Main Agent
|
||
type: main
|
||
subagent_type: null
|
||
status: working
|
||
task: null
|
||
current_tool: Edit
|
||
started_at: '2026-06-25T14:02:11.004Z'
|
||
ended_at: null
|
||
parent_agent_id: null
|
||
metadata: '{"model":"claude-opus-4-20250514"}'
|
||
updated_at: '2026-06-25T14:31:50.119Z'
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
- id: ad18a79192af10ed1
|
||
session_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Explore pricing module
|
||
type: subagent
|
||
subagent_type: Explore
|
||
status: completed
|
||
task: Map every caller of calculateCost() across server/routes
|
||
current_tool: null
|
||
started_at: '2026-06-25T14:10:22.310Z'
|
||
ended_at: '2026-06-25T14:14:09.882Z'
|
||
parent_agent_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d-main
|
||
metadata: null
|
||
updated_at: '2026-06-25T14:14:09.882Z'
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
limit: 50
|
||
offset: 0
|
||
post:
|
||
tags:
|
||
- Agents
|
||
summary: Create agent (idempotent)
|
||
description: 'Creates an agent keyed by `id`. The operation is idempotent: if an agent with that `id` already exists it is returned untouched with `created: false` and HTTP 200; only a brand-new row yields `created: true` and HTTP 201. Omitted optional fields default server-side — `type` to `"main"`, `status` to `"waiting"` — and other unspecified columns are stored as null. `metadata` is accepted as a JSON object but persisted (and returned) as a JSON-encoded string. A successful create broadcasts an `agent_created` websocket frame. Missing `id`, `session_id`, or `name` returns 400 with code `INVALID_INPUT`.'
|
||
operationId: createAgent
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/AgentCreateRequest'
|
||
example:
|
||
id: ad18a79192af10ed1
|
||
session_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Explore pricing module
|
||
type: subagent
|
||
subagent_type: Explore
|
||
status: working
|
||
task: Map every caller of calculateCost() across server/routes
|
||
parent_agent_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d-main
|
||
metadata:
|
||
spawned_by: Task
|
||
responses:
|
||
'200':
|
||
description: Agent already exists
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/AgentCreateResponse'
|
||
example:
|
||
agent:
|
||
id: ad18a79192af10ed1
|
||
session_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Explore pricing module
|
||
type: subagent
|
||
subagent_type: Explore
|
||
status: completed
|
||
task: Map every caller of calculateCost() across server/routes
|
||
current_tool: null
|
||
started_at: '2026-06-25T14:10:22.310Z'
|
||
ended_at: '2026-06-25T14:14:09.882Z'
|
||
parent_agent_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d-main
|
||
metadata: null
|
||
updated_at: '2026-06-25T14:14:09.882Z'
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
created: false
|
||
'201':
|
||
description: Agent created
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/AgentCreateResponse'
|
||
example:
|
||
agent:
|
||
id: ad18a79192af10ed1
|
||
session_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Explore pricing module
|
||
type: subagent
|
||
subagent_type: Explore
|
||
status: working
|
||
task: Map every caller of calculateCost() across server/routes
|
||
current_tool: null
|
||
started_at: '2026-06-25T14:10:22.310Z'
|
||
ended_at: null
|
||
parent_agent_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d-main
|
||
metadata: '{"spawned_by":"Task"}'
|
||
updated_at: '2026-06-25T14:10:22.310Z'
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
created: true
|
||
'400':
|
||
description: Invalid request body
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: INVALID_INPUT
|
||
message: id, session_id, and name are required
|
||
/api/agents/{id}:
|
||
get:
|
||
tags:
|
||
- Agents
|
||
summary: Get agent
|
||
description: Returns a single agent by `id`. Read-only, no side effects. The agent's `metadata` is returned as a raw JSON-encoded string, not a parsed object. Returns 404 with code `NOT_FOUND` when no agent matches the path `id`.
|
||
operationId: getAgent
|
||
parameters:
|
||
- $ref: '#/components/parameters/AgentIdPath'
|
||
example: ad18a79192af10ed1
|
||
responses:
|
||
'200':
|
||
description: Agent details
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/AgentDetailResponse'
|
||
example:
|
||
agent:
|
||
id: ad18a79192af10ed1
|
||
session_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Explore pricing module
|
||
type: subagent
|
||
subagent_type: Explore
|
||
status: completed
|
||
task: Map every caller of calculateCost() across server/routes
|
||
current_tool: null
|
||
started_at: '2026-06-25T14:10:22.310Z'
|
||
ended_at: '2026-06-25T14:14:09.882Z'
|
||
parent_agent_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d-main
|
||
metadata: null
|
||
updated_at: '2026-06-25T14:14:09.882Z'
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
'404':
|
||
description: Agent not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Agent not found
|
||
patch:
|
||
tags:
|
||
- Agents
|
||
summary: Update agent
|
||
description: 'Partially updates an agent by `id`. Accepts `name`, `status`, `task`, `current_tool`, `ended_at`, and `metadata`. The UPDATE uses COALESCE, so any field omitted (passed as null) leaves the existing column value unchanged — with one deliberate exception: `current_tool` is written through verbatim when present in the body, so it can be explicitly cleared to null (e.g. when a tool call finishes). `metadata` is supplied as a JSON object but stored and returned as a JSON-encoded string. A successful update re-reads the row and broadcasts an `agent_updated` websocket frame. Returns 404 with code `NOT_FOUND` when the agent does not exist.'
|
||
operationId: updateAgent
|
||
parameters:
|
||
- $ref: '#/components/parameters/AgentIdPath'
|
||
example: ad18a79192af10ed1
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/AgentUpdateRequest'
|
||
example:
|
||
status: completed
|
||
current_tool: null
|
||
ended_at: '2026-06-25T14:14:09.882Z'
|
||
responses:
|
||
'200':
|
||
description: Agent updated
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/AgentUpdateResponse'
|
||
example:
|
||
agent:
|
||
id: ad18a79192af10ed1
|
||
session_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d
|
||
name: Explore pricing module
|
||
type: subagent
|
||
subagent_type: Explore
|
||
status: completed
|
||
task: Map every caller of calculateCost() across server/routes
|
||
current_tool: null
|
||
started_at: '2026-06-25T14:10:22.310Z'
|
||
ended_at: '2026-06-25T14:14:09.882Z'
|
||
parent_agent_id: b7f3a2c1-4e5d-4a8b-9c2f-1d6e8a0b3c4d-main
|
||
metadata: null
|
||
updated_at: '2026-06-25T14:14:09.882Z'
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
'404':
|
||
description: Agent not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Agent not found
|
||
/api/events:
|
||
get:
|
||
tags:
|
||
- Events
|
||
summary: List events with multi-dimensional filtering
|
||
operationId: listEvents
|
||
description: |-
|
||
Returns a paginated, reverse-chronological slice of the `events` table (ordered by `created_at DESC, id DESC`) together with the total row count matching the active filters, so the UI can drive a paginator without a second request.
|
||
|
||
All four entity filters — `event_type`, `tool_name`, `agent_id`, and `session_id` — accept a **comma-separated list (CSV)** of values and match with `IN (...)` semantics: passing `event_type=Stop,PreToolUse` returns rows whose `event_type` is either `Stop` OR `PreToolUse`. Values are trimmed and blank entries are dropped. Filters are combined with one another using AND.
|
||
|
||
`q` performs a case-insensitive substring (`LIKE %q%`) search across the `summary`, `tool_name`, and the JSON-encoded `data` columns. `from`/`to` are inclusive ISO-8601 datetime bounds on `created_at`; unparseable values are ignored rather than rejected. `limit` is clamped to 1–500 (default 50) and `offset` is clamped to >= 0 (default 0).
|
||
|
||
Note: each returned event's `data` field is a **JSON-encoded string**, not a nested object — callers must `JSON.parse` it to inspect the payload.
|
||
parameters:
|
||
- in: query
|
||
name: event_type
|
||
description: 'Comma-separated (CSV) list of `event_type` values; matched with IN semantics (OR within the list). Common values: PreToolUse, PostToolUse, Stop, SubagentStop, Notification, SessionStart, SessionEnd.'
|
||
schema:
|
||
type: string
|
||
example: Stop,PreToolUse
|
||
- in: query
|
||
name: tool_name
|
||
description: 'Comma-separated (CSV) list of `tool_name` values; matched with IN semantics (OR within the list). Common values: Bash, Edit, Read, Write, Grep, Glob, Task.'
|
||
schema:
|
||
type: string
|
||
example: Bash,Edit
|
||
- in: query
|
||
name: agent_id
|
||
description: Comma-separated (CSV) list of `agent_id` values; matched with IN semantics. The main agent of a session uses the id `<session_id>-main`.
|
||
schema:
|
||
type: string
|
||
example: 8f3c2a10-1b2c-4d5e-9f80-112233445566-main
|
||
- in: query
|
||
name: session_id
|
||
description: Comma-separated (CSV) list of `session_id` values; matched with IN semantics (OR within the list).
|
||
schema:
|
||
type: string
|
||
example: 8f3c2a10-1b2c-4d5e-9f80-112233445566,2a7d9e44-3c1f-4a6b-bc20-aabbccddeeff
|
||
- in: query
|
||
name: q
|
||
description: Case-insensitive substring search (`LIKE %q%`) applied across the `summary`, `tool_name`, and JSON-encoded `data` columns.
|
||
schema:
|
||
type: string
|
||
example: curl
|
||
- in: query
|
||
name: from
|
||
description: ISO-8601 datetime lower bound (inclusive) on `created_at`. Unparseable values are ignored.
|
||
schema:
|
||
type: string
|
||
format: date-time
|
||
example: '2026-06-25T00:00:00.000Z'
|
||
- in: query
|
||
name: to
|
||
description: ISO-8601 datetime upper bound (inclusive) on `created_at`. Unparseable values are ignored.
|
||
schema:
|
||
type: string
|
||
format: date-time
|
||
example: '2026-06-26T00:00:00.000Z'
|
||
- $ref: '#/components/parameters/SourcesQuery'
|
||
example: local,4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
- in: query
|
||
name: limit
|
||
description: Max rows to return; clamped to 1–500 (default 50).
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
maximum: 500
|
||
default: 50
|
||
example: 50
|
||
- $ref: '#/components/parameters/OffsetQuery'
|
||
responses:
|
||
'200':
|
||
description: Event list with total count for pagination
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/EventsListResponse'
|
||
example:
|
||
events:
|
||
- id: 48213
|
||
session_id: 8f3c2a10-1b2c-4d5e-9f80-112233445566
|
||
agent_id: 8f3c2a10-1b2c-4d5e-9f80-112233445566-main
|
||
event_type: PreToolUse
|
||
tool_name: Bash
|
||
summary: 'Bash: curl -s https://api.example.com/health'
|
||
data: '{"session_id":"8f3c2a10-1b2c-4d5e-9f80-112233445566","hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"curl -s https://api.example.com/health","description":"Check upstream health"},"cwd":"/Users/dev/project"}'
|
||
created_at: '2026-06-25T18:42:07.512Z'
|
||
- id: 48212
|
||
session_id: 8f3c2a10-1b2c-4d5e-9f80-112233445566
|
||
agent_id: 8f3c2a10-1b2c-4d5e-9f80-112233445566-main
|
||
event_type: Stop
|
||
tool_name: null
|
||
summary: Session finished responding
|
||
data: '{"session_id":"8f3c2a10-1b2c-4d5e-9f80-112233445566","hook_event_name":"Stop"}'
|
||
created_at: '2026-06-25T18:41:55.004Z'
|
||
limit: 50
|
||
offset: 0
|
||
total: 1342
|
||
/api/events/facets:
|
||
get:
|
||
tags:
|
||
- Events
|
||
summary: Distinct event_type and tool_name values available in the DB
|
||
operationId: listEventFacets
|
||
description: Returns the distinct, non-null `event_type` and `tool_name` values currently present in the `events` table, each sorted alphabetically. The UI uses this to populate the filter dropdowns on the Events screen without hardcoding the set of tools or hook types — so the lists automatically reflect whatever has actually been ingested. Both arrays are independent and may be empty when the table holds no matching rows.
|
||
responses:
|
||
'200':
|
||
description: Facet values for populating filter dropdowns
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/EventsFacetsResponse'
|
||
example:
|
||
event_types:
|
||
- Notification
|
||
- PostToolUse
|
||
- PreToolUse
|
||
- SessionEnd
|
||
- SessionStart
|
||
- Stop
|
||
- SubagentStop
|
||
tool_names:
|
||
- Bash
|
||
- Edit
|
||
- Glob
|
||
- Grep
|
||
- Read
|
||
- Task
|
||
- Write
|
||
/api/stats:
|
||
get:
|
||
tags:
|
||
- Stats
|
||
summary: Get aggregate dashboard stats
|
||
operationId: getStats
|
||
description: |-
|
||
Returns the headline counters shown across the top of the dashboard: total and active session/agent counts, total event count, today's event count, and the current number of live WebSocket connections.
|
||
|
||
The overview counters are spread at the top level of the response object. Two additional maps, `agents_by_status` and `sessions_by_status`, break the counts down by lifecycle status (e.g. agents: working/waiting/completed/error; sessions: active/completed/error/abandoned). **Statuses with a zero count are omitted from these maps**, so callers must not assume every status key is present.
|
||
|
||
`events_today` is computed in the caller's local day. Pass `tz_offset` as the minutes value from JavaScript's `Date.prototype.getTimezoneOffset()` (for example `420` for US Pacific Daylight Time, `300` for US Eastern Daylight Time, `0` for UTC). When omitted or non-numeric, the server falls back to UTC (offset 0).
|
||
parameters:
|
||
- in: query
|
||
name: tz_offset
|
||
description: Caller timezone offset in MINUTES, as returned by JS `Date.prototype.getTimezoneOffset()` (e.g. 420 for PDT, 300 for EDT, 0 for UTC). Used to bucket `events_today` into the caller's local day. Defaults to 0 (UTC) when omitted or non-numeric.
|
||
schema:
|
||
type: integer
|
||
example: 420
|
||
- $ref: '#/components/parameters/SourcesQuery'
|
||
example: local,4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
responses:
|
||
'200':
|
||
description: Statistics overview
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/StatsResponse'
|
||
example:
|
||
total_sessions: 184
|
||
active_sessions: 3
|
||
active_agents: 5
|
||
total_agents: 372
|
||
total_events: 28451
|
||
events_today: 612
|
||
ws_connections: 2
|
||
agents_by_status:
|
||
working: 4
|
||
waiting: 1
|
||
completed: 360
|
||
error: 7
|
||
sessions_by_status:
|
||
active: 3
|
||
completed: 175
|
||
error: 6
|
||
/api/metrics:
|
||
get:
|
||
tags:
|
||
- Metrics
|
||
summary: Prometheus metrics exposition
|
||
operationId: getMetrics
|
||
description: Exposes the dashboard's live counters (sessions/agents by status, event and token totals, connected realtime clients, configured remote sources, process uptime/memory, build version) in the Prometheus text-exposition format (v0.0.4) for scraping into Prometheus / Grafana. Read-only. Mounted under `/api`, so it honors the optional `DASHBOARD_TOKEN` guard — point the scrape job's bearer token at it when the server is bound to a LAN.
|
||
responses:
|
||
'200':
|
||
description: Prometheus text exposition (v0.0.4).
|
||
content:
|
||
text/plain:
|
||
schema:
|
||
type: string
|
||
example: |
|
||
# HELP ccam_up 1 when the dashboard API is serving this scrape.
|
||
# TYPE ccam_up gauge
|
||
ccam_up 1
|
||
# HELP ccam_sessions Number of sessions by lifecycle status.
|
||
# TYPE ccam_sessions gauge
|
||
ccam_sessions{status="active"} 3
|
||
/api/analytics:
|
||
get:
|
||
tags:
|
||
- Analytics
|
||
summary: Get analytics aggregates
|
||
operationId: getAnalytics
|
||
description: |-
|
||
Returns the full analytics rollup powering the Analytics screen: aggregate token usage (`tokens`), total estimated spend across all sessions (`total_cost`, in USD, computed from the configured pricing rules), per-tool invocation counts (`tool_usage`), per-day event and session time series (`daily_events`, `daily_sessions`), the distribution of subagent types (`agent_types`), per-type event counts (`event_types`), the mean number of events per session (`avg_events_per_session`), the total subagent count (`total_subagents`), and a nested `overview` object mirroring the headline session/agent/event counters.
|
||
|
||
As with `/api/stats`, the top-level `agents_by_status` and `sessions_by_status` maps **omit statuses whose count is zero**. The `agent_types[].subagent_type` field may be `null` for the main agent / untyped subagents.
|
||
|
||
The daily time series are bucketed by the caller's local day. Pass `tz_offset` as the minutes value from JS `Date.prototype.getTimezoneOffset()` (e.g. `420` for PDT). When omitted or non-numeric, the server buckets in UTC.
|
||
parameters:
|
||
- in: query
|
||
name: tz_offset
|
||
description: Caller timezone offset in MINUTES, as returned by JS `Date.prototype.getTimezoneOffset()` (e.g. 420 for PDT, 300 for EDT, 0 for UTC). Used to bucket the `daily_events` / `daily_sessions` time series into the caller's local day. Defaults to UTC when omitted or non-numeric.
|
||
schema:
|
||
type: integer
|
||
example: 420
|
||
- $ref: '#/components/parameters/SourcesQuery'
|
||
example: local,4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
responses:
|
||
'200':
|
||
description: Analytics response
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/AnalyticsResponse'
|
||
example:
|
||
tokens:
|
||
total_input: 4821002
|
||
total_output: 1933517
|
||
total_cache_read: 19288440
|
||
total_cache_write: 2044120
|
||
total_cost: 42.7183
|
||
tool_usage:
|
||
- tool_name: Bash
|
||
count: 5821
|
||
- tool_name: Read
|
||
count: 4310
|
||
- tool_name: Edit
|
||
count: 2980
|
||
- tool_name: Grep
|
||
count: 1744
|
||
daily_events:
|
||
- date: '2026-06-23'
|
||
count: 488
|
||
- date: '2026-06-24'
|
||
count: 921
|
||
- date: '2026-06-25'
|
||
count: 612
|
||
daily_sessions:
|
||
- date: '2026-06-23'
|
||
count: 4
|
||
- date: '2026-06-24'
|
||
count: 9
|
||
- date: '2026-06-25'
|
||
count: 6
|
||
agent_types:
|
||
- subagent_type: null
|
||
count: 184
|
||
- subagent_type: general-purpose
|
||
count: 96
|
||
- subagent_type: Explore
|
||
count: 71
|
||
- subagent_type: code-reviewer
|
||
count: 21
|
||
event_types:
|
||
- event_type: PreToolUse
|
||
count: 14210
|
||
- event_type: PostToolUse
|
||
count: 13988
|
||
- event_type: Stop
|
||
count: 168
|
||
- event_type: SubagentStop
|
||
count: 85
|
||
avg_events_per_session: 154.6
|
||
total_subagents: 188
|
||
overview:
|
||
total_sessions: 184
|
||
active_sessions: 3
|
||
active_agents: 5
|
||
total_agents: 372
|
||
total_events: 28451
|
||
agents_by_status:
|
||
working: 4
|
||
waiting: 1
|
||
completed: 360
|
||
error: 7
|
||
sessions_by_status:
|
||
active: 3
|
||
completed: 175
|
||
error: 6
|
||
/api/hooks/event:
|
||
post:
|
||
tags:
|
||
- Hooks
|
||
summary: Ingest Claude Code hook event
|
||
operationId: ingestHookEvent
|
||
description: |-
|
||
Primary ingestion endpoint for Claude Code lifecycle hooks. The hook handler posts an envelope of the form `{ hook_type, data }`, where `hook_type` is the Claude Code hook name (PreToolUse, PostToolUse, Stop, SubagentStop, Notification, SessionStart, SessionEnd) and `data` carries the raw hook payload — at minimum a `session_id`. The server upserts the session and its main agent on first sight, applies the appropriate lifecycle state transition, extracts token usage and compaction signals from the transcript when present, persists an `events` row (storing `data` as a JSON-encoded string), and broadcasts a `new_event` message over the WebSocket.
|
||
|
||
On success the response is `{ ok: true, event: { ... } }`, where `event` echoes the normalized row that was just inserted (`session_id`, `agent_id`, `event_type`, `tool_name`, `summary`, `created_at`). Ingestion is designed to be fail-safe and non-blocking for the hook caller.
|
||
|
||
Validation failures return HTTP 400 with an `ErrorResponse` body (`{ error: { code, message } }`): `INVALID_INPUT` when `hook_type` or `data` is missing, and `MISSING_SESSION` when `data.session_id` is absent.
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/HookEventRequest'
|
||
example:
|
||
hook_type: PreToolUse
|
||
data:
|
||
session_id: 8f3c2a10-1b2c-4d5e-9f80-112233445566
|
||
hook_event_name: PreToolUse
|
||
tool_name: Bash
|
||
tool_input:
|
||
command: curl -s https://api.example.com/health
|
||
description: Check upstream health
|
||
cwd: /Users/dev/project
|
||
transcript_path: /Users/dev/.claude/projects/-Users-dev-project/8f3c2a10-1b2c-4d5e-9f80-112233445566.jsonl
|
||
responses:
|
||
'200':
|
||
description: Event processed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/HookEventResponse'
|
||
example:
|
||
ok: true
|
||
event:
|
||
session_id: 8f3c2a10-1b2c-4d5e-9f80-112233445566
|
||
agent_id: 8f3c2a10-1b2c-4d5e-9f80-112233445566-main
|
||
event_type: PreToolUse
|
||
tool_name: Bash
|
||
summary: 'Bash: curl -s https://api.example.com/health'
|
||
created_at: '2026-06-25T18:42:07.512Z'
|
||
'400':
|
||
description: Invalid hook payload
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: MISSING_SESSION
|
||
message: session_id is required in data
|
||
/api/pricing:
|
||
get:
|
||
tags:
|
||
- Pricing
|
||
summary: List pricing rules
|
||
operationId: listPricingRules
|
||
description: 'Returns every stored pricing rule, wrapped as `{ pricing: [ ... ] }`. Each rule carries per-MTok (per-million-token) rates for input, output, cache reads, and the two cache-write tiers (5-minute and 1-hour ephemeral), plus optional fast-mode input/output rates (0 = not configured). Rules are matched against model ids by treating the SQL `%` wildcard in `model_pattern` as `.*`; when several rules match, the longest (most specific) pattern wins. Rates here feed the cost calculations under `/api/pricing/cost`.'
|
||
responses:
|
||
'200':
|
||
description: Pricing rules
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PricingListResponse'
|
||
example:
|
||
pricing:
|
||
- model_pattern: claude-opus-4%
|
||
display_name: Claude Opus 4 (family)
|
||
input_per_mtok: 15
|
||
output_per_mtok: 75
|
||
cache_read_per_mtok: 1.5
|
||
cache_write_per_mtok: 18.75
|
||
cache_write_1h_per_mtok: 30
|
||
fast_input_per_mtok: 0
|
||
fast_output_per_mtok: 0
|
||
updated_at: '2026-06-25T18:42:11.000Z'
|
||
- model_pattern: claude-haiku%
|
||
display_name: Claude Haiku (family)
|
||
input_per_mtok: 0.8
|
||
output_per_mtok: 4
|
||
cache_read_per_mtok: 0.08
|
||
cache_write_per_mtok: 1
|
||
cache_write_1h_per_mtok: 1.6
|
||
fast_input_per_mtok: 0
|
||
fast_output_per_mtok: 0
|
||
updated_at: '2026-06-20T09:15:00.000Z'
|
||
put:
|
||
tags:
|
||
- Pricing
|
||
summary: Create/update pricing rule
|
||
operationId: upsertPricingRule
|
||
description: 'Creates a pricing rule or updates the existing one with the same `model_pattern` (upsert keyed on `model_pattern`). `model_pattern` and `display_name` are required; every `*_per_mtok` rate is optional and defaults to 0 when omitted. Use the SQL `%` wildcard in `model_pattern` to match a model family (e.g. `claude-opus-4%`). Set `fast_input_per_mtok` / `fast_output_per_mtok` only if the model bills fast-mode usage at a premium; leave them 0 otherwise. Note the asymmetry with the list endpoint: the response wraps a SINGLE stored rule as `{ pricing: <rule> }` (not an array). A missing `model_pattern` or `display_name` returns 400 `INVALID_INPUT`, and so does any `*_per_mtok` rate that is not a non-negative finite number (numeric strings are coerced; NaN and negative rates are rejected before anything is written).'
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PricingUpsertRequest'
|
||
example:
|
||
model_pattern: claude-opus-4%
|
||
display_name: Claude Opus 4 (family)
|
||
input_per_mtok: 15
|
||
output_per_mtok: 75
|
||
cache_read_per_mtok: 1.5
|
||
cache_write_per_mtok: 18.75
|
||
cache_write_1h_per_mtok: 30
|
||
fast_input_per_mtok: 0
|
||
fast_output_per_mtok: 0
|
||
responses:
|
||
'200':
|
||
description: Pricing rule stored
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PricingUpsertResponse'
|
||
example:
|
||
pricing:
|
||
model_pattern: claude-opus-4%
|
||
display_name: Claude Opus 4 (family)
|
||
input_per_mtok: 15
|
||
output_per_mtok: 75
|
||
cache_read_per_mtok: 1.5
|
||
cache_write_per_mtok: 18.75
|
||
cache_write_1h_per_mtok: 30
|
||
fast_input_per_mtok: 0
|
||
fast_output_per_mtok: 0
|
||
updated_at: '2026-06-25T18:42:11.000Z'
|
||
'400':
|
||
description: Invalid request body
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: INVALID_INPUT
|
||
message: model_pattern and display_name are required
|
||
/api/pricing/{pattern}:
|
||
delete:
|
||
tags:
|
||
- Pricing
|
||
summary: Delete pricing rule
|
||
operationId: deletePricingRule
|
||
description: 'Deletes the pricing rule whose `model_pattern` exactly matches the `pattern` path segment. The pattern is URL-ENCODED: the SQL `%` wildcard must be sent as `%25` (so `claude-opus-4%` becomes `claude-opus-4%25`). The server decodes it before lookup. Returns `{ ok: true }` on success, or 404 `NOT_FOUND` if no rule matches.'
|
||
parameters:
|
||
- name: pattern
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: Model pattern (URL-encoded). The SQL `%` wildcard must be escaped as `%25` (e.g. `claude-opus-4%25` for the rule `claude-opus-4%`).
|
||
example: claude-opus-4%25
|
||
responses:
|
||
'200':
|
||
description: Rule deleted
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DeleteOkResponse'
|
||
example:
|
||
ok: true
|
||
'404':
|
||
description: Pricing rule not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Pricing rule not found
|
||
/api/pricing/cost:
|
||
get:
|
||
tags:
|
||
- Pricing
|
||
summary: Get total token cost across all sessions
|
||
operationId: getTotalCost
|
||
description: Computes the aggregate token cost across EVERY session by matching each (model, speed, inference_geo, service_tier) usage bucket against the most specific pricing rule. Returns `total_cost`, a per-bucket `breakdown`, `feature_costs` (web-search surcharge, code-execution container time with the org free-hours allowance applied), `unpriced_models` (usage with no matching rule, contributing $0 so the total stays honest), and `daily_costs` bucketed by local calendar day. Pass `tz_offset` (minutes; the JS `Date.getTimezoneOffset()` value, e.g. 300 for US Eastern, -120 for CEST) so day boundaries align with the viewer's timezone; omitted/invalid offsets fall back to UTC. Honors the `sources` data-scope filter, like the sessions / stats / analytics endpoints, so the reported cost matches the active scope.
|
||
parameters:
|
||
- name: tz_offset
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
description: Viewer timezone offset in minutes, as returned by `Date.getTimezoneOffset()` (positive for zones behind UTC, e.g. 300 = US Eastern, -120 = CEST). Shifts the `daily_costs` day boundaries; invalid or omitted values default to UTC.
|
||
example: 300
|
||
- name: sources
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Comma-separated data-source ids to include (local history is `local`; remote SSH machines use their `remote_sources.id`). Omit for all sources. Narrows the aggregate cost to the given origins.
|
||
example: local
|
||
responses:
|
||
'200':
|
||
description: Cost result
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CostResult'
|
||
example:
|
||
total_cost: 12.8431
|
||
breakdown:
|
||
- model: claude-opus-4-8
|
||
speed: standard
|
||
inference_geo: global
|
||
service_tier: standard
|
||
input_tokens: 184320
|
||
output_tokens: 51200
|
||
cache_read_tokens: 920000
|
||
cache_write_tokens: 64000
|
||
cache_write_1h_tokens: 12000
|
||
web_search_requests: 8
|
||
web_fetch_requests: 3
|
||
code_execution_requests: 2
|
||
cost: 8.4127
|
||
matched_rule: claude-opus-4%
|
||
- model: claude-haiku-4-5
|
||
speed: fast
|
||
inference_geo: us
|
||
service_tier: standard
|
||
input_tokens: 512000
|
||
output_tokens: 128000
|
||
cache_read_tokens: 64000
|
||
cache_write_tokens: 8000
|
||
cache_write_1h_tokens: 0
|
||
web_search_requests: 0
|
||
web_fetch_requests: 0
|
||
code_execution_requests: 0
|
||
cost: 1.5904
|
||
matched_rule: claude-haiku%
|
||
feature_costs:
|
||
web_search_cost: 0.08
|
||
web_fetch_cost: 0
|
||
code_execution_cost: 0
|
||
code_execution_hours_estimated: 0.1667
|
||
code_execution_free_hours: 50
|
||
unpriced_models:
|
||
- model: claude-experimental-preview
|
||
input_tokens: 4096
|
||
output_tokens: 2048
|
||
cache_read_tokens: 0
|
||
cache_write_tokens: 0
|
||
daily_costs:
|
||
- date: '2026-06-23'
|
||
cost: 3.1102
|
||
- date: '2026-06-24'
|
||
cost: 5.7421
|
||
- date: '2026-06-25'
|
||
cost: 3.9908
|
||
/api/pricing/cost/{sessionId}:
|
||
get:
|
||
tags:
|
||
- Pricing
|
||
summary: Get token cost for one session
|
||
operationId: getSessionCost
|
||
description: Same cost computation as `/api/pricing/cost`, but scoped to a single session's token usage. Returns the identical `CostResult` shape (`total_cost`, `breakdown`, `feature_costs`, `unpriced_models`, `daily_costs`); `daily_costs` holds at most one entry — the session's start date in the viewer's local day, or an empty array if the session id is unknown. Pass `tz_offset` (minutes, `Date.getTimezoneOffset()`) to place that start date in the viewer's timezone; defaults to UTC.
|
||
parameters:
|
||
- name: sessionId
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: Session ID to price.
|
||
example: sess_8f2a3b1c
|
||
- name: tz_offset
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
description: Viewer timezone offset in minutes (`Date.getTimezoneOffset()`; 300 = US Eastern, -120 = CEST). Places the session start date in the viewer's local day; defaults to UTC when omitted or invalid.
|
||
example: 300
|
||
responses:
|
||
'200':
|
||
description: Session cost result
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CostResult'
|
||
example:
|
||
total_cost: 8.4127
|
||
breakdown:
|
||
- model: claude-opus-4-8
|
||
speed: standard
|
||
inference_geo: global
|
||
service_tier: standard
|
||
input_tokens: 184320
|
||
output_tokens: 51200
|
||
cache_read_tokens: 920000
|
||
cache_write_tokens: 64000
|
||
cache_write_1h_tokens: 12000
|
||
web_search_requests: 8
|
||
web_fetch_requests: 3
|
||
code_execution_requests: 2
|
||
cost: 8.4127
|
||
matched_rule: claude-opus-4%
|
||
- model: claude-haiku-4-5
|
||
speed: fast
|
||
inference_geo: us
|
||
service_tier: standard
|
||
input_tokens: 512000
|
||
output_tokens: 128000
|
||
cache_read_tokens: 64000
|
||
cache_write_tokens: 8000
|
||
cache_write_1h_tokens: 0
|
||
web_search_requests: 0
|
||
web_fetch_requests: 0
|
||
code_execution_requests: 0
|
||
cost: 1.5904
|
||
matched_rule: claude-haiku%
|
||
feature_costs:
|
||
web_search_cost: 0.08
|
||
web_fetch_cost: 0
|
||
code_execution_cost: 0
|
||
code_execution_hours_estimated: 0.1667
|
||
code_execution_free_hours: 50
|
||
unpriced_models:
|
||
- model: claude-experimental-preview
|
||
input_tokens: 4096
|
||
output_tokens: 2048
|
||
cache_read_tokens: 0
|
||
cache_write_tokens: 0
|
||
daily_costs:
|
||
- date: '2026-06-25'
|
||
cost: 8.4127
|
||
/api/workflows:
|
||
get:
|
||
tags:
|
||
- Workflows
|
||
summary: Get workflow intelligence aggregates
|
||
description: 'Returns the full workflow-intelligence aggregate powering the Workflows analytics page — 11 sections in one payload: `stats` (headline counters: sessions, agents, subagents, success rate, avg depth/duration, compactions, top tool flow), `orchestration` (subagent-type breakdown + delegation edges + outcomes), `toolFlow` (tool-to-tool transitions + tool counts), `effectiveness` (per-subagent-type success rate, avg duration, weekly trend), `patterns` (frequent subagent sequences + solo-session share), `modelDelegation` (model usage for main/sub agents + tokens by model), `errorPropagation` (errors by depth/type + error rate), `concurrency` (averaged agent swim-lane start/end), `complexity` (per-session agent/token/duration rows), `compaction` (compaction counts + tokens recovered), and `cooccurrence` (directed subagent-after-subagent pairs). The optional `status` query filter scopes every section to sessions of one status. Errors use the SHORT `{ error: { message } }` shape.'
|
||
operationId: getWorkflowIntelligence
|
||
parameters:
|
||
- $ref: '#/components/parameters/WorkflowStatusQuery'
|
||
responses:
|
||
'200':
|
||
description: Workflow aggregate data
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/WorkflowAggregateResponse'
|
||
example:
|
||
stats:
|
||
totalSessions: 412
|
||
totalAgents: 1893
|
||
totalSubagents: 1481
|
||
avgSubagents: 3.6
|
||
successRate: 94.2
|
||
avgDepth: 1.4
|
||
avgDurationSec: 1187
|
||
totalCompactions: 96
|
||
avgCompactions: 0.2
|
||
topFlow:
|
||
source: Read
|
||
target: Edit
|
||
count: 3120
|
||
orchestration:
|
||
sessionCount: 412
|
||
mainCount: 412
|
||
subagentTypes:
|
||
- subagent_type: general-purpose
|
||
count: 612
|
||
completed: 590
|
||
errors: 8
|
||
- subagent_type: Explore
|
||
count: 388
|
||
completed: 380
|
||
errors: 2
|
||
edges:
|
||
- source: main
|
||
target: general-purpose
|
||
weight: 612
|
||
outcomes:
|
||
- status: completed
|
||
count: 1402
|
||
- status: error
|
||
count: 79
|
||
compactions:
|
||
total: 96
|
||
sessions: 71
|
||
toolFlow:
|
||
transitions:
|
||
- source: Read
|
||
target: Edit
|
||
value: 3120
|
||
toolCounts:
|
||
- tool_name: Read
|
||
count: 9821
|
||
- tool_name: Edit
|
||
count: 5402
|
||
- tool_name: Bash
|
||
count: 4810
|
||
effectiveness:
|
||
- subagent_type: general-purpose
|
||
total: 612
|
||
completed: 590
|
||
errors: 8
|
||
sessions: 281
|
||
successRate: 98.7
|
||
avgDuration: 142
|
||
trend:
|
||
- 88
|
||
- 91
|
||
- 102
|
||
- 97
|
||
- 110
|
||
- 24
|
||
- 12
|
||
patterns:
|
||
patterns:
|
||
- steps:
|
||
- Explore
|
||
- general-purpose
|
||
count: 142
|
||
percentage: 34.5
|
||
soloSessionCount: 120
|
||
soloPercentage: 29.1
|
||
modelDelegation:
|
||
mainModels:
|
||
- model: claude-opus-4-8
|
||
agent_count: 290
|
||
session_count: 290
|
||
subagentModels:
|
||
- model: claude-opus-4-8
|
||
agent_count: 980
|
||
tokensByModel:
|
||
- model: claude-opus-4-8
|
||
input_tokens: 4820112
|
||
output_tokens: 1920334
|
||
cache_read_tokens: 88201442
|
||
cache_write_tokens: 12044210
|
||
errorPropagation:
|
||
byDepth:
|
||
- depth: 0
|
||
count: 41
|
||
- depth: 1
|
||
count: 38
|
||
byType:
|
||
- subagent_type: general-purpose
|
||
count: 8
|
||
eventErrors:
|
||
- summary: 'Error in Bash: command not found'
|
||
count: 5
|
||
sessionsWithErrors: 33
|
||
totalSessions: 412
|
||
errorRate: 8
|
||
concurrency:
|
||
aggregateLanes:
|
||
- name: Main Agent
|
||
avgStart: 0
|
||
avgEnd: 1
|
||
count: 412
|
||
- name: Explore
|
||
avgStart: 0.12
|
||
avgEnd: 0.31
|
||
count: 388
|
||
complexity:
|
||
- id: 5f3c0e2a-1b9d-4c77-8a21-9e0f7b6d4c11
|
||
name: Refactor auth flow
|
||
status: completed
|
||
duration: 2538
|
||
agentCount: 6
|
||
subagentCount: 5
|
||
totalTokens: 940212
|
||
model: claude-opus-4-8
|
||
compaction:
|
||
totalCompactions: 96
|
||
tokensRecovered: 18402991
|
||
perSession:
|
||
- session_id: 5f3c0e2a-1b9d-4c77-8a21-9e0f7b6d4c11
|
||
compactions: 3
|
||
sessionsWithCompactions: 71
|
||
totalSessions: 412
|
||
cooccurrence:
|
||
- source: Explore
|
||
target: general-purpose
|
||
weight: 142
|
||
'500':
|
||
description: Internal server error
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/MessageErrorResponse'
|
||
example:
|
||
error:
|
||
message: 'no such table: agents'
|
||
/api/workflows/session/{id}:
|
||
get:
|
||
tags:
|
||
- Workflows
|
||
summary: Get workflow drill-in for one session
|
||
description: 'Returns the workflow drill-in for a single session, used by the session-level Workflow view: `session` (the session row), `tree` (the recursive parent→child agent tree rooted at the main agent), `toolTimeline` (chronological tool events with tool_name/event_type/agent_id/summary), `swimLanes` (a flat per-agent start/end lane list for the Gantt-style view), and `events` (the chronological event stream, capped at the first 500 rows). Returns 404 with the SHORT `{ error: { message } }` shape when the session id is unknown.'
|
||
operationId: getWorkflowSession
|
||
parameters:
|
||
- $ref: '#/components/parameters/SessionIdPath'
|
||
responses:
|
||
'200':
|
||
description: Workflow session detail
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/WorkflowSessionResponse'
|
||
example:
|
||
session:
|
||
id: 5f3c0e2a-1b9d-4c77-8a21-9e0f7b6d4c11
|
||
name: Refactor auth flow
|
||
status: completed
|
||
cwd: /Users/son/code/foo
|
||
model: claude-opus-4-8
|
||
started_at: '2026-06-25T13:00:00.000Z'
|
||
ended_at: '2026-06-25T13:42:18.220Z'
|
||
metadata: null
|
||
updated_at: '2026-06-25T13:42:18.220Z'
|
||
tree:
|
||
- id: agent_main_5f3c0e2a
|
||
name: Main agent
|
||
type: main
|
||
subagent_type: null
|
||
status: completed
|
||
task: null
|
||
started_at: '2026-06-25T13:00:00.000Z'
|
||
ended_at: '2026-06-25T13:42:18.220Z'
|
||
children:
|
||
- id: agent_sub_a1
|
||
name: Explore the auth module
|
||
type: subagent
|
||
subagent_type: Explore
|
||
status: completed
|
||
task: Map auth call sites
|
||
started_at: '2026-06-25T13:02:10.000Z'
|
||
ended_at: '2026-06-25T13:06:55.000Z'
|
||
children: []
|
||
toolTimeline:
|
||
- id: 91021
|
||
tool_name: Read
|
||
event_type: PreToolUse
|
||
agent_id: agent_main_5f3c0e2a
|
||
created_at: '2026-06-25T13:01:02.500Z'
|
||
summary: Read server/auth.js
|
||
swimLanes:
|
||
- id: agent_main_5f3c0e2a
|
||
name: Main agent
|
||
type: main
|
||
subagent_type: null
|
||
status: completed
|
||
started_at: '2026-06-25T13:00:00.000Z'
|
||
ended_at: '2026-06-25T13:42:18.220Z'
|
||
parent_agent_id: null
|
||
events:
|
||
- id: 91021
|
||
session_id: 5f3c0e2a-1b9d-4c77-8a21-9e0f7b6d4c11
|
||
agent_id: agent_main_5f3c0e2a
|
||
event_type: PreToolUse
|
||
tool_name: Read
|
||
summary: Read server/auth.js
|
||
data: null
|
||
created_at: '2026-06-25T13:01:02.500Z'
|
||
'404':
|
||
description: Session not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/MessageErrorResponse'
|
||
example:
|
||
error:
|
||
message: Session not found
|
||
'500':
|
||
description: Internal server error
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/MessageErrorResponse'
|
||
example:
|
||
error:
|
||
message: 'no such table: agents'
|
||
/api/settings/info:
|
||
get:
|
||
tags:
|
||
- Settings
|
||
summary: Get system/database/hook diagnostics
|
||
description: 'Returns a diagnostics snapshot used by the Settings page: `db` (database file path, on-disk size in bytes, per-table row counts, SQLite pragmas, and recent event load over the last 5/15/60 minutes), `hooks` (whether the Claude Code hook-handler is installed in `settings.json`, the settings path, and a per-hook-type installed map), `server` (process uptime, Node version, platform, live WebSocket connection count, memory/CPU/host stats), and `transcript_cache` (number of cached transcript entries and the cached paths). Read-only and cheap to poll.'
|
||
operationId: getSettingsInfo
|
||
responses:
|
||
'200':
|
||
description: Settings and diagnostics
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SettingsInfoResponse'
|
||
example:
|
||
db:
|
||
path: /Users/son/WebstormProjects/Claude-Code-Agent-Monitor/server/data/agent-monitor.db
|
||
size: 48922624
|
||
counts:
|
||
sessions: 412
|
||
agents: 1893
|
||
events: 58117
|
||
model_pricing: 11
|
||
token_usage: 401
|
||
pragmas:
|
||
journal_mode: wal
|
||
synchronous: 1
|
||
auto_vacuum: 0
|
||
encoding: UTF-8
|
||
foreign_keys: 1
|
||
busy_timeout: 5000
|
||
load_stats:
|
||
m5: 23
|
||
m15: 88
|
||
h1: 511
|
||
hooks:
|
||
installed: true
|
||
path: /Users/son/.claude/settings.json
|
||
hooks:
|
||
PreToolUse: true
|
||
PostToolUse: true
|
||
Stop: true
|
||
SubagentStop: true
|
||
Notification: true
|
||
SessionStart: true
|
||
SessionEnd: true
|
||
server:
|
||
uptime: 14523.91
|
||
node_version: v22.14.0
|
||
platform: darwin
|
||
ws_connections: 2
|
||
memory:
|
||
rss: 142802944
|
||
heapTotal: 71303168
|
||
heapUsed: 58392104
|
||
external: 3211884
|
||
arrayBuffers: 1048576
|
||
cpu_load:
|
||
- 2.13
|
||
- 2.45
|
||
- 2.31
|
||
arch: arm64
|
||
total_mem: 17179869184
|
||
free_mem: 2147483648
|
||
cpus: 10
|
||
transcript_cache:
|
||
entries: 37
|
||
paths:
|
||
- /Users/son/.claude/projects/-Users-son-code-foo/abc123.jsonl
|
||
- /Users/son/.claude/projects/-Users-son-code-bar/def456.jsonl
|
||
/api/settings/clear-data:
|
||
post:
|
||
tags:
|
||
- Settings
|
||
summary: Delete all dashboard data
|
||
description: '⚠ DESTRUCTIVE — IRREVERSIBLE. Deletes ALL sessions, agents, events, token_usage rows, the fired-alert feed (alert_events), and the webhook delivery log. There is no confirmation step and no undo — export first via GET /api/settings/export if you need a backup. User CONFIGURATION survives: alert *rules*, webhook *targets*, and model_pricing are preserved (they''re settings, not captured data). The response echoes the row counts that existed BEFORE the wipe so the UI can report what was removed.'
|
||
operationId: clearData
|
||
responses:
|
||
'200':
|
||
description: Data cleared
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ClearDataResponse'
|
||
example:
|
||
ok: true
|
||
cleared:
|
||
sessions: 412
|
||
agents: 1893
|
||
events: 58117
|
||
model_pricing: 11
|
||
token_usage: 401
|
||
/api/settings/reimport:
|
||
post:
|
||
tags:
|
||
- Settings
|
||
summary: Re-import legacy sessions from ~/.claude
|
||
description: Re-runs the legacy history importer against the default `~/.claude` projects directory, funneling every transcript through the same parser + importSession pipeline the live server uses. This is IDEMPOTENT and ADDITIVE — already-imported sessions are deduplicated (counted under `skipped`), token counts and compaction baselines are preserved so cost never double-counts, and nothing existing is deleted. The response reports how many sessions were `imported` vs `skipped`, plus an `errors` count for transcripts that failed to parse.
|
||
operationId: reimportLegacySessions
|
||
responses:
|
||
'200':
|
||
description: Import completed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ReimportResponse'
|
||
example:
|
||
ok: true
|
||
imported: 38
|
||
skipped: 374
|
||
errors: 0
|
||
'500':
|
||
description: Import failed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: IMPORT_FAILED
|
||
message: 'ENOENT: no such file or directory, scandir ''/Users/son/.claude/projects'''
|
||
/api/settings/reinstall-hooks:
|
||
post:
|
||
tags:
|
||
- Settings
|
||
summary: Reinstall Claude Code hooks
|
||
description: 'Re-runs the hook installer to (re)wire the dashboard''s hook-handler into Claude Code''s `settings.json` for all seven hook types (PreToolUse, PostToolUse, Stop, SubagentStop, Notification, SessionStart, SessionEnd). Safe to re-run — it overwrites/repairs the dashboard''s own hook entries without touching unrelated user hooks. The response returns the post-install hook status so the UI can confirm every hook type is now `installed: true`.'
|
||
operationId: reinstallHooks
|
||
responses:
|
||
'200':
|
||
description: Hooks reinstall result
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ReinstallHooksResponse'
|
||
example:
|
||
ok: true
|
||
hooks:
|
||
installed: true
|
||
path: /Users/son/.claude/settings.json
|
||
hooks:
|
||
PreToolUse: true
|
||
PostToolUse: true
|
||
Stop: true
|
||
SubagentStop: true
|
||
Notification: true
|
||
SessionStart: true
|
||
SessionEnd: true
|
||
'500':
|
||
description: Hook installation failed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: HOOK_INSTALL_FAILED
|
||
message: 'EACCES: permission denied, open ''/Users/son/.claude/settings.json'''
|
||
/api/settings/reset-pricing:
|
||
post:
|
||
tags:
|
||
- Settings
|
||
summary: Reset pricing table to defaults
|
||
description: ⚠ DESTRUCTIVE to pricing customizations. Deletes EVERY row in the model_pricing table and re-seeds it from the dashboard's built-in DEFAULT_PRICING list. Any custom rates or custom model patterns you added are permanently lost — there is no undo. Captured session/token data is untouched (only the pricing rules used to *compute* cost change). The response returns the full freshly-seeded pricing table.
|
||
operationId: resetPricing
|
||
responses:
|
||
'200':
|
||
description: Pricing defaults restored
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ResetPricingResponse'
|
||
example:
|
||
ok: true
|
||
pricing:
|
||
- model_pattern: claude-opus-4*
|
||
display_name: Claude Opus 4
|
||
input_per_mtok: 15
|
||
output_per_mtok: 75
|
||
cache_read_per_mtok: 1.5
|
||
cache_write_per_mtok: 18.75
|
||
cache_write_1h_per_mtok: 30
|
||
fast_input_per_mtok: 0
|
||
fast_output_per_mtok: 0
|
||
updated_at: '2026-06-26T00:00:00.000Z'
|
||
- model_pattern: claude-sonnet-4*
|
||
display_name: Claude Sonnet 4
|
||
input_per_mtok: 3
|
||
output_per_mtok: 15
|
||
cache_read_per_mtok: 0.3
|
||
cache_write_per_mtok: 3.75
|
||
cache_write_1h_per_mtok: 6
|
||
fast_input_per_mtok: 0
|
||
fast_output_per_mtok: 0
|
||
updated_at: '2026-06-26T00:00:00.000Z'
|
||
/api/settings/export:
|
||
get:
|
||
tags:
|
||
- Settings
|
||
summary: Export all dashboard data as JSON
|
||
description: 'Exports the entire dataset as a single versioned JSON document — all sessions, agents, events, token_usage rows, workflows, dashboard_runs, alert_rules, and model_pricing — stamped with `format: "ccam-export"`, `version`, and `exported_at`. Served with a `Content-Disposition: attachment` header (filename `agent-monitor-export-YYYY-MM-DD.json`) so browsers download it. Use it to back up before a destructive operation (clear-data / cleanup with purge_days) or to migrate/consolidate data across machines — the bundle is re-importable via POST /api/settings/import. Read-only; nothing is modified.'
|
||
operationId: exportData
|
||
responses:
|
||
'200':
|
||
description: Export payload (served as attachment)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ExportResponse'
|
||
example:
|
||
format: ccam-export
|
||
version: 1
|
||
exported_at: '2026-06-26T01:12:44.913Z'
|
||
sessions:
|
||
- id: 5f3c0e2a-1b9d-4c77-8a21-9e0f7b6d4c11
|
||
name: Refactor auth flow
|
||
status: completed
|
||
cwd: /Users/son/code/foo
|
||
model: claude-opus-4-8
|
||
started_at: '2026-06-25T13:00:00.000Z'
|
||
ended_at: '2026-06-25T13:42:18.220Z'
|
||
metadata: null
|
||
updated_at: '2026-06-25T13:42:18.220Z'
|
||
agents:
|
||
- id: agent_main_5f3c0e2a
|
||
session_id: 5f3c0e2a-1b9d-4c77-8a21-9e0f7b6d4c11
|
||
name: Main agent
|
||
type: main
|
||
subagent_type: null
|
||
status: completed
|
||
task: null
|
||
current_tool: null
|
||
started_at: '2026-06-25T13:00:00.000Z'
|
||
ended_at: '2026-06-25T13:42:18.220Z'
|
||
parent_agent_id: null
|
||
metadata: null
|
||
updated_at: '2026-06-25T13:42:18.220Z'
|
||
events:
|
||
- id: 91021
|
||
session_id: 5f3c0e2a-1b9d-4c77-8a21-9e0f7b6d4c11
|
||
agent_id: agent_main_5f3c0e2a
|
||
event_type: PreToolUse
|
||
tool_name: Edit
|
||
summary: Edit server/auth.js
|
||
data: null
|
||
created_at: '2026-06-25T13:05:42.001Z'
|
||
token_usage:
|
||
- session_id: 5f3c0e2a-1b9d-4c77-8a21-9e0f7b6d4c11
|
||
model: claude-opus-4-8
|
||
input_tokens: 18422
|
||
output_tokens: 9120
|
||
cache_read_tokens: 220184
|
||
cache_write_tokens: 41002
|
||
model_pricing:
|
||
- model_pattern: claude-opus-4*
|
||
display_name: Claude Opus 4
|
||
input_per_mtok: 15
|
||
output_per_mtok: 75
|
||
cache_read_per_mtok: 1.5
|
||
cache_write_per_mtok: 18.75
|
||
cache_write_1h_per_mtok: 30
|
||
fast_input_per_mtok: 0
|
||
fast_output_per_mtok: 0
|
||
updated_at: '2026-06-26T00:00:00.000Z'
|
||
- model_pattern: claude-sonnet-4*
|
||
display_name: Claude Sonnet 4
|
||
input_per_mtok: 3
|
||
output_per_mtok: 15
|
||
cache_read_per_mtok: 0.3
|
||
cache_write_per_mtok: 3.75
|
||
cache_write_1h_per_mtok: 6
|
||
fast_input_per_mtok: 0
|
||
fast_output_per_mtok: 0
|
||
updated_at: '2026-06-26T00:00:00.000Z'
|
||
/api/settings/cleanup:
|
||
post:
|
||
tags:
|
||
- Settings
|
||
summary: Abandon stale sessions and optionally purge old history
|
||
description: 'Two-phase maintenance. Phase 1 (`abandon_hours`, non-destructive): marks any still-`active` session with no events newer than that many hours as `abandoned`, and completes its lingering agents — a tidy-up of crashed/orphaned sessions. Phase 2 (`purge_days`) is ⚠ DESTRUCTIVE and IRREVERSIBLE: it permanently DELETES completed/error/abandoned sessions (and their events, agents, and token_usage) whose `started_at` is older than that many days. Active sessions are NEVER purged. Both fields are optional and independent — send only `abandon_hours` for a safe tidy-up, or include `purge_days` to also reclaim disk. Export first if the purged history matters. The response reports counts for each phase.'
|
||
operationId: cleanupData
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CleanupRequest'
|
||
examples:
|
||
tidyOnly:
|
||
summary: 'Safe: abandon stale sessions only (no deletion)'
|
||
value:
|
||
abandon_hours: 12
|
||
abandonAndPurge:
|
||
summary: Abandon stale sessions, then purge history older than 90 days (destructive)
|
||
value:
|
||
abandon_hours: 12
|
||
purge_days: 90
|
||
responses:
|
||
'200':
|
||
description: Cleanup result
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CleanupResponse'
|
||
example:
|
||
ok: true
|
||
abandoned: 3
|
||
purged_sessions: 57
|
||
purged_events: 14820
|
||
purged_agents: 241
|
||
/api/import/guide:
|
||
get:
|
||
tags:
|
||
- Import
|
||
summary: Import guide with OS-aware defaults and step-by-step instructions
|
||
description: 'Returns the OS-aware import guide the Import page renders verbatim: the detected `platform`, the default `~/.claude/projects` directory (raw + display form), whether it exists and how many projects/JSONL files it holds, an OS-specific `archive_command` for bundling history off another machine, the supported file extensions, the upload size/count limits, and four ordered `steps` (locate → archive → choose mode → verify). Read-only; performs no import.'
|
||
operationId: importGuide
|
||
responses:
|
||
'200':
|
||
description: Guide payload
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ImportGuideResponse'
|
||
example:
|
||
platform: darwin
|
||
default_projects_dir: /Users/son/.claude/projects
|
||
default_projects_dir_display: ~/.claude/projects
|
||
default_projects_dir_exists: true
|
||
default_projects_dir_stats:
|
||
projects: 24
|
||
jsonl_files: 312
|
||
archive_command: tar -czf claude-history.tar.gz -C ~/.claude projects
|
||
supported_extensions:
|
||
- .jsonl
|
||
- .meta.json
|
||
- .zip
|
||
- .tar
|
||
- .tar.gz
|
||
- .tgz
|
||
- .gz
|
||
max_upload_bytes: 1073741824
|
||
max_upload_files: 2000
|
||
steps:
|
||
- id: locate
|
||
title: Locate your Claude Code history
|
||
body: Claude Code stores every session as a JSONL transcript under ~/.claude/projects. Each subdirectory is named after the working directory where the session started (with slashes replaced by dashes).
|
||
- id: archive
|
||
title: Bundle it for transfer (optional)
|
||
body: |-
|
||
If you're importing from another machine, archive the whole projects folder first:
|
||
|
||
tar -czf claude-history.tar.gz -C ~/.claude projects
|
||
|
||
Move claude-history.tar.gz to this machine however you like (AirDrop, scp, USB, cloud storage).
|
||
- id: choose
|
||
title: Pick an import mode
|
||
body: 'Rescan default: re-read ~/.claude/projects on this machine and import anything new. From folder: point the dashboard at any directory you''ve extracted history into. Upload: drag-drop JSONL files or an archive directly into the browser.'
|
||
- id: verify
|
||
title: Verify tokens and cost
|
||
body: 'Imports are idempotent: re-running is always safe. Token counts are deduplicated per session ID, with compaction baselines preserved so cost never double-counts. After import, open Analytics → Cost to confirm the breakdown.'
|
||
/api/import/rescan:
|
||
post:
|
||
tags:
|
||
- Import
|
||
summary: Rescan the default ~/.claude/projects directory
|
||
description: 'Re-scans the default `~/.claude/projects` directory and imports anything new through the live ingestion pipeline. IDEMPOTENT and ADDITIVE — re-running is always safe, already-imported sessions are deduplicated (`skipped`), and token/compaction baselines are preserved so cost never double-counts. Progress is broadcast over the WebSocket as `import.progress` frames while it runs. The response reports `imported` / `skipped` / `backfilled` / `errors` plus `sessions_seen` and `files_scanned`, with `source: "default"`.'
|
||
operationId: importRescan
|
||
responses:
|
||
'200':
|
||
description: Import result
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ImportResultResponse'
|
||
example:
|
||
ok: true
|
||
source: default
|
||
imported: 14
|
||
skipped: 298
|
||
backfilled: 2
|
||
errors: 0
|
||
sessions_seen: 312
|
||
files_scanned: 312
|
||
'500':
|
||
description: Import failed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: IMPORT_FAILED
|
||
message: Failed to read projects directory
|
||
/api/import/scan-path:
|
||
post:
|
||
tags:
|
||
- Import
|
||
summary: Import transcripts from an arbitrary absolute directory
|
||
description: 'Imports transcripts from an arbitrary directory you point the dashboard at (e.g. history extracted from another machine). The `path` must resolve to an existing directory: a leading `~` is expanded to the home directory, the result must be absolute, and subdirectories are walked recursively for `.jsonl` files. Same idempotent, baseline-preserving pipeline as the default rescan; progress is broadcast as `import.progress`. The response echoes the resolved `path` and the per-run counters with `source: "path"`.'
|
||
operationId: importScanPath
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- path
|
||
properties:
|
||
path:
|
||
type: string
|
||
description: Absolute directory path. Tilde (~) is expanded. Walks subdirectories recursively.
|
||
examples:
|
||
absolute:
|
||
summary: Absolute directory
|
||
value:
|
||
path: /Users/son/Downloads/claude-history/projects
|
||
tilde:
|
||
summary: Tilde expanded to home directory
|
||
value:
|
||
path: ~/Downloads/claude-history/projects
|
||
responses:
|
||
'200':
|
||
description: Import result
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ImportResultResponse'
|
||
example:
|
||
ok: true
|
||
source: path
|
||
path: /Users/son/Downloads/claude-history/projects
|
||
imported: 9
|
||
skipped: 41
|
||
backfilled: 0
|
||
errors: 0
|
||
sessions_seen: 50
|
||
files_scanned: 50
|
||
'400':
|
||
description: Path validation failed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
examples:
|
||
missing:
|
||
summary: path omitted
|
||
value:
|
||
error:
|
||
code: INVALID_INPUT
|
||
message: '`path` is required'
|
||
notAbsolute:
|
||
summary: path is not absolute
|
||
value:
|
||
error:
|
||
code: INVALID_INPUT
|
||
message: '`path` must be an absolute path'
|
||
notFound:
|
||
summary: path does not exist
|
||
value:
|
||
error:
|
||
code: PATH_NOT_FOUND
|
||
message: 'Path does not exist: /tmp/nope'
|
||
notDir:
|
||
summary: path is a file, not a directory
|
||
value:
|
||
error:
|
||
code: NOT_A_DIRECTORY
|
||
message: 'Path is not a directory: /tmp/foo.jsonl'
|
||
'500':
|
||
description: Import failed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: IMPORT_FAILED
|
||
message: Unexpected end of JSON input
|
||
/api/import/upload:
|
||
post:
|
||
tags:
|
||
- Import
|
||
summary: Upload JSONL files or archives (.zip, .tar, .tar.gz, .tgz, .gz)
|
||
description: 'Imports history uploaded directly from the browser as `multipart/form-data` under the `files` field. Accepts raw `.jsonl` / `.meta.json` transcripts and/or archives (`.zip`, `.tar`, `.tar.gz`, `.tgz`, `.gz`), which are extracted into a temp dir and walked for JSONL content. Unsupported extensions are silently rejected and reported in `rejected_files`. Extraction is bounded to defend against zip bombs — exceeding the limit returns 413. Same idempotent import pipeline; progress is broadcast as `import.progress`. On success the response carries `source: "upload"` plus `files_received`, `rejected_files`, `entries_extracted`, `entries_skipped`, and the standard import counters. (Requires the optional `multer` dependency; a missing install yields a 500.)'
|
||
operationId: importUpload
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
multipart/form-data:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
files:
|
||
type: array
|
||
items:
|
||
type: string
|
||
format: binary
|
||
description: Files to import. Supports .jsonl, .meta.json, .zip, .tar, .tar.gz, .tgz, .gz.
|
||
example:
|
||
files:
|
||
- claude-history.tar.gz
|
||
- session-extra.jsonl
|
||
responses:
|
||
'200':
|
||
description: Import result
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ImportResultResponse'
|
||
example:
|
||
ok: true
|
||
source: upload
|
||
files_received: 3
|
||
rejected_files:
|
||
- notes.txt
|
||
entries_extracted: 128
|
||
entries_skipped: 2
|
||
imported: 12
|
||
skipped: 116
|
||
backfilled: 0
|
||
errors: 0
|
||
sessions_seen: 128
|
||
files_scanned: 128
|
||
'400':
|
||
description: No files or no JSONL content
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
examples:
|
||
noFiles:
|
||
summary: No supported files in the upload
|
||
value:
|
||
error:
|
||
code: NO_FILES
|
||
message: No supported files in upload. 1 file(s) rejected (unsupported extension).
|
||
noJsonl:
|
||
summary: Archive extracted but contained no .jsonl
|
||
value:
|
||
error:
|
||
code: NO_JSONL
|
||
message: 'No .jsonl files were found in the uploaded content. Supported inputs: .jsonl, .meta.json, .zip, .tar, .tar.gz, .tgz, .gz.'
|
||
'413':
|
||
description: Extraction limit exceeded (possible zip bomb)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EXTRACTION_LIMIT_EXCEEDED
|
||
message: Archive exceeded the extraction size limit (possible zip bomb).
|
||
'500':
|
||
description: Upload or import failed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
examples:
|
||
noMulter:
|
||
summary: Optional multer dependency not installed
|
||
value:
|
||
error:
|
||
code: UPLOADER_UNAVAILABLE
|
||
message: File upload requires `multer`. Run `npm install` to pick up new deps.
|
||
importFailed:
|
||
summary: Import pipeline error
|
||
value:
|
||
error:
|
||
code: IMPORT_FAILED
|
||
message: Unexpected end of JSON input
|
||
/api/updates/status:
|
||
get:
|
||
tags:
|
||
- Updates
|
||
summary: Check whether the dashboard git checkout is behind origin
|
||
description: 'Reports whether the dashboard''s own git checkout is behind its upstream remote, so a user can pull and restart manually (the dashboard never self-restarts). The response is a variant object: when it IS a git checkout it includes `git_repo: true`, `repo_root`, `update_available`, `commits_behind`, `remote_ref`, `local_sha`, `remote_sha`, and a copy-pasteable `manual_command`; when it is NOT a git checkout (e.g. an npm/tarball install) it returns `git_repo: false` with a `message` and no diff fields. Read-only — this only inspects git, it does not fetch destructively or modify the working tree.'
|
||
operationId: getUpdatesStatus
|
||
responses:
|
||
'200':
|
||
description: Update check result
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
description: Includes git_repo, update_available, commits_behind, remote_ref, local_sha, remote_sha, manual_command, and optional error/message fields.
|
||
examples:
|
||
updateAvailable:
|
||
summary: Behind origin — update available
|
||
value:
|
||
git_repo: true
|
||
repo_root: /Users/son/WebstormProjects/Claude-Code-Agent-Monitor
|
||
update_available: true
|
||
commits_behind: 4
|
||
remote_ref: origin/master
|
||
local_sha: de5d0891a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7
|
||
remote_sha: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
|
||
manual_command: npm run self-update
|
||
checked_at: '2026-06-26T01:20:09.553Z'
|
||
upToDate:
|
||
summary: Up to date with origin
|
||
value:
|
||
git_repo: true
|
||
repo_root: /Users/son/WebstormProjects/Claude-Code-Agent-Monitor
|
||
update_available: false
|
||
commits_behind: 0
|
||
remote_ref: origin/master
|
||
local_sha: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
|
||
remote_sha: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
|
||
manual_command: npm run self-update
|
||
checked_at: '2026-06-26T01:25:41.002Z'
|
||
notARepo:
|
||
summary: Not a git checkout — detection unavailable
|
||
value:
|
||
git_repo: false
|
||
update_available: false
|
||
message: Not a git checkout — update detection is unavailable for this install.
|
||
'500':
|
||
description: Update status query failed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: UPDATE_STATUS_FAILED
|
||
message: 'git: command not found'
|
||
/api/updates/check:
|
||
post:
|
||
tags:
|
||
- Updates
|
||
summary: Run an update check immediately and broadcast the result
|
||
description: Runs the same upstream check as GET /api/updates/status immediately and, in addition to returning the result, broadcasts it to every connected client as an `update_status` WebSocket message — so all open dashboard tabs refresh their update banner at once. The response shape is identical to GET /api/updates/status (the same git_repo / update_available / commits_behind / manual_command variant object). Read-only with respect to the working tree.
|
||
operationId: triggerUpdatesCheck
|
||
responses:
|
||
'200':
|
||
description: Fresh update status payload (also broadcast over WebSocket)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
description: Same shape as GET /api/updates/status. Also sent as an update_status WebSocket message to all connected clients.
|
||
examples:
|
||
updateAvailable:
|
||
summary: Behind origin — update available
|
||
value:
|
||
git_repo: true
|
||
repo_root: /Users/son/WebstormProjects/Claude-Code-Agent-Monitor
|
||
update_available: true
|
||
commits_behind: 4
|
||
remote_ref: origin/master
|
||
local_sha: de5d0891a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7
|
||
remote_sha: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
|
||
manual_command: npm run self-update
|
||
checked_at: '2026-06-26T01:20:09.553Z'
|
||
upToDate:
|
||
summary: Up to date with origin
|
||
value:
|
||
git_repo: true
|
||
repo_root: /Users/son/WebstormProjects/Claude-Code-Agent-Monitor
|
||
update_available: false
|
||
commits_behind: 0
|
||
remote_ref: origin/master
|
||
local_sha: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
|
||
remote_sha: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
|
||
manual_command: npm run self-update
|
||
checked_at: '2026-06-26T01:25:41.002Z'
|
||
'500':
|
||
description: Update check failed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: UPDATE_CHECK_FAILED
|
||
message: 'git fetch failed: network unreachable'
|
||
/api/alerts:
|
||
get:
|
||
tags:
|
||
- Alerts
|
||
summary: List fired alerts, newest first
|
||
operationId: listAlerts
|
||
description: Returns the fired-alert feed, newest first, as `{ alerts, total, unacked, limit, offset }`. Each alert event carries the originating rule's id/name/type, a human-readable `message`, an `acknowledged` flag (0/1), `created_at`, and `details` — which is a JSON STRING (not an object) that callers must `JSON.parse`. `limit` is clamped to 1–200 (default 50) and negative `offset` is clamped to 0. Set `unacked=true` to return only unacknowledged alerts; `total` then counts only unacked rows, while `unacked` always reports the global unacknowledged count.
|
||
parameters:
|
||
- name: limit
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
maximum: 200
|
||
default: 50
|
||
description: Page size, clamped to the 1–200 range (default 50). Values outside the range are clamped, not rejected.
|
||
example: 50
|
||
- name: offset
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
minimum: 0
|
||
description: Pagination offset; negative values are clamped to 0.
|
||
example: 0
|
||
- name: unacked
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: boolean
|
||
description: When the literal string "true", return only unacknowledged alerts (and scope `total` to that subset).
|
||
example: 'true'
|
||
responses:
|
||
'200':
|
||
description: Paginated alert feed with total and unacked counts
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
description: Includes alerts[], total, unacked, limit, offset.
|
||
example:
|
||
alerts:
|
||
- id: 42
|
||
rule_id: 7c1d8e2a-9b34-4f50-a1c2-6d8e0f3b5a91
|
||
rule_name: Idle session watchdog
|
||
rule_type: inactivity
|
||
message: Session sess_8f2a has been inactive for 35 minutes
|
||
details: '{"session_id":"sess_8f2a","minutes":35,"threshold":30}'
|
||
acknowledged: 0
|
||
created_at: '2026-06-25T17:05:44.000Z'
|
||
- id: 41
|
||
rule_id: 1a2b3c4d-5e6f-7081-9201-aabbccddeeff
|
||
rule_name: Heavy token burn
|
||
rule_type: token_threshold
|
||
message: Session sess_3c1d crossed 5,000,000 total tokens
|
||
details: '{"session_id":"sess_3c1d","total_tokens":5120000,"threshold":5000000}'
|
||
acknowledged: 1
|
||
created_at: '2026-06-25T16:40:02.000Z'
|
||
total: 2
|
||
unacked: 1
|
||
limit: 50
|
||
offset: 0
|
||
/api/alerts/rules:
|
||
get:
|
||
tags:
|
||
- Alerts
|
||
summary: List alert rules
|
||
operationId: listAlertRules
|
||
description: 'Returns all alert rules as `{ rules: [ ... ] }`. Each rule''s `config` is returned as a PARSED object (the column is stored as JSON text), and `enabled` is coerced to a boolean. The `config` shape depends on `rule_type`: `event_pattern` uses event_type / tool_name / summary_contains plus optional count + window_minutes; `inactivity` uses `minutes`; `status_duration` uses `status` + `minutes`; `token_threshold` uses `total_tokens`.'
|
||
responses:
|
||
'200':
|
||
description: All alert rules with parsed config objects
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
example:
|
||
rules:
|
||
- id: 7c1d8e2a-9b34-4f50-a1c2-6d8e0f3b5a91
|
||
name: Idle session watchdog
|
||
rule_type: inactivity
|
||
config:
|
||
minutes: 30
|
||
enabled: true
|
||
cooldown_seconds: 300
|
||
created_at: '2026-06-10T12:00:00.000Z'
|
||
updated_at: '2026-06-24T08:30:00.000Z'
|
||
- id: 1a2b3c4d-5e6f-7081-9201-aabbccddeeff
|
||
name: Heavy token burn
|
||
rule_type: token_threshold
|
||
config:
|
||
total_tokens: 5000000
|
||
enabled: true
|
||
cooldown_seconds: 600
|
||
created_at: '2026-06-12T14:20:00.000Z'
|
||
updated_at: '2026-06-12T14:20:00.000Z'
|
||
post:
|
||
tags:
|
||
- Alerts
|
||
summary: Create an alert rule
|
||
operationId: createAlertRule
|
||
description: |-
|
||
Creates an alert rule and returns it serialized as `{ rule: { ... } }` with HTTP 201. `name`, `rule_type`, and `config` are required; the `config` shape is validated per `rule_type`:
|
||
- `event_pattern`: `{ event_type?, tool_name?, summary_contains?, count?, window_minutes? }` — fires when matching events accumulate.
|
||
- `inactivity`: `{ minutes }` — fires when a session goes idle.
|
||
- `status_duration`: `{ status, minutes }` — fires when a session holds a status too long.
|
||
- `token_threshold`: `{ total_tokens }` — fires when usage crosses a ceiling.
|
||
`enabled` defaults to true and `cooldown_seconds` defaults to 300 (must be a non-negative integer). A bad name, unknown `rule_type`, invalid `config`, or negative cooldown returns 400 `INVALID_INPUT`.
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- name
|
||
- rule_type
|
||
- config
|
||
properties:
|
||
name:
|
||
type: string
|
||
rule_type:
|
||
type: string
|
||
enum:
|
||
- event_pattern
|
||
- inactivity
|
||
- status_duration
|
||
- token_threshold
|
||
config:
|
||
type: object
|
||
additionalProperties: true
|
||
description: 'Type-specific config. event_pattern: event_type/tool_name/summary_contains + optional count/window_minutes. inactivity: minutes. status_duration: status + minutes. token_threshold: total_tokens.'
|
||
enabled:
|
||
type: boolean
|
||
default: true
|
||
cooldown_seconds:
|
||
type: integer
|
||
default: 300
|
||
examples:
|
||
inactivity:
|
||
summary: Inactivity rule
|
||
value:
|
||
name: Idle session watchdog
|
||
rule_type: inactivity
|
||
config:
|
||
minutes: 30
|
||
enabled: true
|
||
cooldown_seconds: 300
|
||
event_pattern:
|
||
summary: Event-pattern rule (repeated tool errors)
|
||
value:
|
||
name: Repeated Bash failures
|
||
rule_type: event_pattern
|
||
config:
|
||
event_type: PostToolUse
|
||
tool_name: Bash
|
||
summary_contains: error
|
||
count: 3
|
||
window_minutes: 10
|
||
enabled: true
|
||
cooldown_seconds: 600
|
||
status_duration:
|
||
summary: Status-duration rule
|
||
value:
|
||
name: Stuck waiting too long
|
||
rule_type: status_duration
|
||
config:
|
||
status: waiting
|
||
minutes: 15
|
||
enabled: true
|
||
cooldown_seconds: 300
|
||
token_threshold:
|
||
summary: Token-threshold rule
|
||
value:
|
||
name: Heavy token burn
|
||
rule_type: token_threshold
|
||
config:
|
||
total_tokens: 5000000
|
||
enabled: true
|
||
cooldown_seconds: 600
|
||
responses:
|
||
'201':
|
||
description: Created rule
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
example:
|
||
rule:
|
||
id: 7c1d8e2a-9b34-4f50-a1c2-6d8e0f3b5a91
|
||
name: Idle session watchdog
|
||
rule_type: inactivity
|
||
config:
|
||
minutes: 30
|
||
enabled: true
|
||
cooldown_seconds: 300
|
||
created_at: '2026-06-10T12:00:00.000Z'
|
||
updated_at: '2026-06-24T08:30:00.000Z'
|
||
'400':
|
||
description: Validation error
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: INVALID_INPUT
|
||
message: name is required
|
||
/api/alerts/rules/{id}:
|
||
patch:
|
||
tags:
|
||
- Alerts
|
||
summary: Update an alert rule (partial; rule_type is immutable)
|
||
operationId: updateAlertRule
|
||
description: 'Partially updates an alert rule and returns it serialized as `{ rule: { ... } }`. Only the fields present in the body change; `rule_type` CANNOT be changed and any supplied `config` is validated against the rule''s STORED type. `name` (if present) must be a non-empty string and `cooldown_seconds` (if present) must be a non-negative integer. Returns 404 `NOT_FOUND` for an unknown id, or 400 `INVALID_INPUT` for a bad name, invalid config, or negative cooldown.'
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: Alert rule ID (UUID).
|
||
example: 7c1d8e2a-9b34-4f50-a1c2-6d8e0f3b5a91
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
name:
|
||
type: string
|
||
config:
|
||
type: object
|
||
additionalProperties: true
|
||
enabled:
|
||
type: boolean
|
||
cooldown_seconds:
|
||
type: integer
|
||
examples:
|
||
disableRule:
|
||
summary: Disable a rule without touching its config
|
||
value:
|
||
enabled: false
|
||
retuneInactivity:
|
||
summary: Re-tune an inactivity rule's threshold + cooldown
|
||
value:
|
||
config:
|
||
minutes: 45
|
||
cooldown_seconds: 900
|
||
rename:
|
||
summary: Rename a rule
|
||
value:
|
||
name: Idle session watchdog (prod)
|
||
responses:
|
||
'200':
|
||
description: Updated rule
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
example:
|
||
rule:
|
||
id: 7c1d8e2a-9b34-4f50-a1c2-6d8e0f3b5a91
|
||
name: Idle session watchdog
|
||
rule_type: inactivity
|
||
config:
|
||
minutes: 30
|
||
enabled: false
|
||
cooldown_seconds: 900
|
||
created_at: '2026-06-10T12:00:00.000Z'
|
||
updated_at: '2026-06-24T08:30:00.000Z'
|
||
'400':
|
||
description: Validation error
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: INVALID_INPUT
|
||
message: cooldown_seconds must be a non-negative integer
|
||
'404':
|
||
description: Rule not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Alert rule not found
|
||
delete:
|
||
tags:
|
||
- Alerts
|
||
summary: Delete an alert rule and its fired-alert history
|
||
operationId: deleteAlertRule
|
||
description: 'Deletes the alert rule with the given id. Its fired-alert history cascades away with it (the foreign key is ON DELETE CASCADE), so any alerts previously raised by this rule are also removed from the feed. Returns `{ ok: true }` on success or 404 `NOT_FOUND` for an unknown id.'
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: Alert rule ID (UUID).
|
||
example: 7c1d8e2a-9b34-4f50-a1c2-6d8e0f3b5a91
|
||
responses:
|
||
'200':
|
||
description: Deletion confirmation
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
example:
|
||
ok: true
|
||
'404':
|
||
description: Rule not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Alert rule not found
|
||
/api/alerts/{id}/ack:
|
||
post:
|
||
tags:
|
||
- Alerts
|
||
summary: Acknowledge one fired alert
|
||
operationId: ackAlert
|
||
description: 'Marks a single fired alert (by its integer event id) as acknowledged and returns the updated row as `{ alert: { ... } }` (with `acknowledged: 1`). Acknowledging also broadcasts an `alert_updated` WebSocket message so connected dashboards refresh their unacked badge. The id must be numeric; an unknown id returns 404 `NOT_FOUND`.'
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
description: Alert event ID (numeric).
|
||
example: 42
|
||
responses:
|
||
'200':
|
||
description: Acknowledged alert row
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
example:
|
||
alert:
|
||
id: 42
|
||
rule_id: 7c1d8e2a-9b34-4f50-a1c2-6d8e0f3b5a91
|
||
rule_name: Idle session watchdog
|
||
rule_type: inactivity
|
||
message: Session sess_8f2a has been inactive for 35 minutes
|
||
details: '{"session_id":"sess_8f2a","minutes":35,"threshold":30}'
|
||
acknowledged: 1
|
||
created_at: '2026-06-25T17:05:44.000Z'
|
||
'404':
|
||
description: Alert not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Alert not found
|
||
/api/alerts/ack-all:
|
||
post:
|
||
tags:
|
||
- Alerts
|
||
summary: Acknowledge all unacked alerts
|
||
operationId: ackAllAlerts
|
||
description: 'Acknowledges every currently unacknowledged alert in one call and returns `{ ok: true, acknowledged: <count> }` where `acknowledged` is the number of rows actually updated. When at least one alert is acknowledged, an `alert_updated` WebSocket message (`{ acked_all: true }`) is broadcast so dashboards clear their unacked badge. Calling this when nothing is unacked returns `acknowledged: 0`.'
|
||
responses:
|
||
'200':
|
||
description: Count of acknowledged alerts
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
example:
|
||
ok: true
|
||
acknowledged: 3
|
||
/api/webhooks/providers:
|
||
get:
|
||
tags:
|
||
- Webhooks
|
||
summary: List supported providers + their config fields (for the UI)
|
||
description: 'Returns the redacted provider catalog the webhook-target editor renders. For each of the 14 supported providers (Slack, Discord, Teams, Google Chat, Mattermost, Rocket.Chat, Telegram, PagerDuty, Opsgenie, Splunk On-Call, Zapier, Make, n8n, Pipedream) plus the `generic` family, it lists: a human label, the provider family, whether the URL must be https / is user-supplied, and the per-provider config field definitions (key, label, type, required, options, and whether the field is secret). No secret values are ever included — this is purely the *shape* of the form, not stored credentials.'
|
||
operationId: listWebhookProviders
|
||
responses:
|
||
'200':
|
||
description: 'Provider catalog: label, family, url requirements, fields'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
example:
|
||
providers:
|
||
slack:
|
||
label: Slack
|
||
family: chat
|
||
https: true
|
||
urlRequired: true
|
||
fields: []
|
||
telegram:
|
||
label: Telegram
|
||
family: chat
|
||
https: true
|
||
urlRequired: false
|
||
fields:
|
||
- key: bot_token
|
||
label: Bot token
|
||
type: string
|
||
required: true
|
||
secret: true
|
||
- key: chat_id
|
||
label: Chat ID
|
||
type: string
|
||
required: true
|
||
secret: false
|
||
pagerduty:
|
||
label: PagerDuty
|
||
family: incident
|
||
https: true
|
||
urlRequired: false
|
||
fields:
|
||
- key: routing_key
|
||
label: Routing key
|
||
type: string
|
||
required: true
|
||
secret: true
|
||
- key: severity
|
||
label: Severity
|
||
type: enum
|
||
required: false
|
||
options:
|
||
- critical
|
||
- error
|
||
- warning
|
||
- info
|
||
secret: false
|
||
generic:
|
||
label: Generic webhook
|
||
family: generic
|
||
https: false
|
||
urlRequired: true
|
||
fields: []
|
||
/api/webhooks:
|
||
get:
|
||
tags:
|
||
- Webhooks
|
||
summary: List webhook targets (URLs masked, secrets redacted)
|
||
description: 'Lists every configured webhook target. Responses are always redacted: the full URL is never returned — only `url_preview` (protocol + host + a `…` + the last 4 chars), `has_secret` is a boolean (never the secret itself), and any secret-flagged provider config fields (routing keys, API keys, bot tokens) and custom header values are masked to `••••`. Each target also carries its most recent delivery outcome in `last_delivery` (or null if it has never fired).'
|
||
operationId: listWebhooks
|
||
responses:
|
||
'200':
|
||
description: All configured webhook targets
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
example:
|
||
targets:
|
||
- id: 9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e
|
||
name: Eng on-call (Slack)
|
||
type: slack
|
||
enabled: true
|
||
url_preview: https://hooks.slack.com/…BXqZ
|
||
has_secret: false
|
||
headers: null
|
||
config: null
|
||
rule_ids:
|
||
- rule_inactivity_30m
|
||
created_at: '2026-06-25T14:03:11.482Z'
|
||
updated_at: '2026-06-25T14:03:11.482Z'
|
||
last_delivery:
|
||
status: success
|
||
status_code: 200
|
||
attempts: 1
|
||
error: null
|
||
created_at: '2026-06-25T18:41:55.117Z'
|
||
- id: 1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d
|
||
name: Internal alert sink
|
||
type: generic
|
||
enabled: true
|
||
url_preview: https://alerts.internal.example.com/…hook
|
||
has_secret: true
|
||
headers:
|
||
X-Api-Key: ••••
|
||
Authorization: ••••
|
||
config: null
|
||
rule_ids: null
|
||
created_at: '2026-06-20T09:15:00.000Z'
|
||
updated_at: '2026-06-24T22:48:30.901Z'
|
||
last_delivery:
|
||
status: failed
|
||
status_code: 503
|
||
attempts: 3
|
||
error: Service Unavailable
|
||
created_at: '2026-06-24T22:48:30.901Z'
|
||
post:
|
||
tags:
|
||
- Webhooks
|
||
summary: Create a webhook target
|
||
description: Creates a webhook target that fires when alerts match. `name` and `type` are required. `url` is required for most providers but is derived or defaulted for a few (Telegram and Opsgenie derive it from config; PagerDuty defaults it) — consult GET /api/webhooks/providers for which fields each provider needs. `config` carries provider-specific params (e.g. `{ chat_id }` for Telegram, `{ routing_key, severity }` for PagerDuty, `{ api_key, region }` for Opsgenie). `secret` (HMAC-SHA256 signing) and custom `headers` apply only to the generic family and are silently ignored for other providers. `rule_ids` optionally scopes the target to specific alert rules; omit it to fire for all rules. The response is the created target, REDACTED the same way as the list endpoint (URL masked, secrets shown only as `has_secret`/`••••`).
|
||
operationId: createWebhook
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- name
|
||
- type
|
||
properties:
|
||
name:
|
||
type: string
|
||
type:
|
||
type: string
|
||
enum:
|
||
- slack
|
||
- discord
|
||
- teams
|
||
- google_chat
|
||
- mattermost
|
||
- rocketchat
|
||
- telegram
|
||
- pagerduty
|
||
- opsgenie
|
||
- splunk_oncall
|
||
- zapier
|
||
- make
|
||
- n8n
|
||
- pipedream
|
||
- generic
|
||
url:
|
||
type: string
|
||
format: uri
|
||
description: Required for most providers; omit for those that derive their URL (Telegram, Opsgenie) or default it (PagerDuty). See GET /api/webhooks/providers.
|
||
enabled:
|
||
type: boolean
|
||
default: true
|
||
config:
|
||
type: object
|
||
additionalProperties: true
|
||
description: Provider-specific params, e.g. { chat_id } (Telegram), { routing_key, severity } (PagerDuty), { api_key, region } (Opsgenie).
|
||
secret:
|
||
type: string
|
||
description: 'Generic family only: HMAC-SHA256 signing secret'
|
||
headers:
|
||
type: object
|
||
additionalProperties:
|
||
type: string
|
||
description: 'Generic family only: extra request headers'
|
||
rule_ids:
|
||
type: array
|
||
items:
|
||
type: string
|
||
description: 'Optional: scope to specific alert rules (omit for all)'
|
||
examples:
|
||
slack:
|
||
summary: Slack incoming webhook scoped to one rule
|
||
value:
|
||
name: Eng on-call (Slack)
|
||
type: slack
|
||
url: https://hooks.slack.com/services/T0000/B0000/XXXXXXXXXXXXXXXXXXXXBXqZ
|
||
enabled: true
|
||
rule_ids:
|
||
- rule_inactivity_30m
|
||
pagerduty:
|
||
summary: PagerDuty (URL defaulted, routing key in config)
|
||
value:
|
||
name: Sev1 pager
|
||
type: pagerduty
|
||
config:
|
||
routing_key: R0ABCDEF0123456789ABCDEF01
|
||
severity: critical
|
||
generic:
|
||
summary: Generic webhook with HMAC secret and custom headers
|
||
value:
|
||
name: Internal alert sink
|
||
type: generic
|
||
url: https://alerts.internal.example.com/cc-monitor/hook
|
||
secret: whsec_4f8c2a9e1b6d7f0a3c5e8b1d2f4a6c8e
|
||
headers:
|
||
X-Api-Key: k_live_abc123
|
||
Authorization: Bearer t0ken
|
||
responses:
|
||
'201':
|
||
description: Created target (redacted)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
example:
|
||
target:
|
||
id: 9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e
|
||
name: Eng on-call (Slack)
|
||
type: slack
|
||
enabled: true
|
||
url_preview: https://hooks.slack.com/…BXqZ
|
||
has_secret: false
|
||
headers: null
|
||
config: null
|
||
rule_ids:
|
||
- rule_inactivity_30m
|
||
created_at: '2026-06-25T14:03:11.482Z'
|
||
updated_at: '2026-06-25T14:03:11.482Z'
|
||
last_delivery:
|
||
status: success
|
||
status_code: 200
|
||
attempts: 1
|
||
error: null
|
||
created_at: '2026-06-25T18:41:55.117Z'
|
||
'400':
|
||
description: Validation error
|
||
/api/webhooks/{id}:
|
||
patch:
|
||
tags:
|
||
- Webhooks
|
||
summary: Update a webhook target (partial; type is immutable)
|
||
description: Partially updates a webhook target. Only the keys present in the body are changed; omitted keys are left as-is. The provider `type` is immutable. `config` is MERGED over the existing config and re-validated, so a single field (e.g. `severity`, `region`) can change without re-sending the secret fields. For the generic family, `secret` may be omitted (keep current) or sent as `null` (clear it); `headers` and `rule_ids` replace their stored value when present. The response is the updated target, REDACTED (URL masked, secrets shown only as `has_secret`/`••••`).
|
||
operationId: updateWebhook
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
example: 9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
name:
|
||
type: string
|
||
url:
|
||
type: string
|
||
format: uri
|
||
description: Omit to keep current
|
||
enabled:
|
||
type: boolean
|
||
config:
|
||
type: object
|
||
additionalProperties: true
|
||
description: Provider params; merged over existing (secrets kept if omitted)
|
||
secret:
|
||
type:
|
||
- string
|
||
- 'null'
|
||
description: 'Generic family only: omit to keep, null to clear'
|
||
headers:
|
||
type: object
|
||
additionalProperties:
|
||
type: string
|
||
rule_ids:
|
||
type: array
|
||
items:
|
||
type: string
|
||
examples:
|
||
disable:
|
||
summary: Disable a target without touching anything else
|
||
value:
|
||
enabled: false
|
||
renameAndRescope:
|
||
summary: Rename and re-scope to different rules
|
||
value:
|
||
name: Eng on-call (Slack) — muted weekends
|
||
rule_ids:
|
||
- rule_token_threshold_5m
|
||
mergeConfig:
|
||
summary: Change one PagerDuty config field (routing key kept)
|
||
value:
|
||
config:
|
||
severity: warning
|
||
clearSecret:
|
||
summary: 'Generic family: clear the signing secret'
|
||
value:
|
||
secret: null
|
||
responses:
|
||
'200':
|
||
description: Updated target (redacted)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
example:
|
||
target:
|
||
id: 9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e
|
||
name: Eng on-call (Slack) — muted weekends
|
||
type: slack
|
||
enabled: true
|
||
url_preview: https://hooks.slack.com/…BXqZ
|
||
has_secret: false
|
||
headers: null
|
||
config: null
|
||
rule_ids:
|
||
- rule_inactivity_30m
|
||
created_at: '2026-06-25T14:03:11.482Z'
|
||
updated_at: '2026-06-25T14:03:11.482Z'
|
||
last_delivery:
|
||
status: success
|
||
status_code: 200
|
||
attempts: 1
|
||
error: null
|
||
created_at: '2026-06-25T18:41:55.117Z'
|
||
'400':
|
||
description: Validation error
|
||
'404':
|
||
description: Target not found
|
||
delete:
|
||
tags:
|
||
- Webhooks
|
||
summary: Delete a webhook target and its delivery log
|
||
description: 'Permanently deletes a webhook target. Its delivery-log history cascades away with it. Returns `{ ok: true }` on success. This only removes the delivery channel — alert *rules* and the fired-alert feed are untouched.'
|
||
operationId: deleteWebhook
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
example: 9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e
|
||
responses:
|
||
'200':
|
||
description: Deleted
|
||
'404':
|
||
description: Target not found
|
||
/api/webhooks/{id}/test:
|
||
post:
|
||
tags:
|
||
- Webhooks
|
||
summary: Send a synthetic test alert to a target
|
||
description: Sends a synthetic test alert to the target and reports the delivery outcome synchronously. The HTTP status is always 200 when the target exists — the *request itself* succeeded — and the `ok` flag carries the downstream delivery result. `status` is the HTTP status code returned by the provider (or null if the request never completed), `attempts` is how many tries were made (the delivery layer retries transient failures), and `error` is a human-readable failure reason or null on success.
|
||
operationId: testWebhook
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
example: 9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e
|
||
responses:
|
||
'200':
|
||
description: Delivery result (ok flag carries the downstream outcome)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
examples:
|
||
success:
|
||
summary: Provider accepted the test payload
|
||
value:
|
||
ok: true
|
||
status: 200
|
||
attempts: 1
|
||
error: null
|
||
failure:
|
||
summary: Provider rejected or was unreachable after retries
|
||
value:
|
||
ok: false
|
||
status: 503
|
||
attempts: 3
|
||
error: Service Unavailable
|
||
'404':
|
||
description: Target not found
|
||
/api/webhooks/{id}/deliveries:
|
||
get:
|
||
tags:
|
||
- Webhooks
|
||
summary: Recent delivery log for a target
|
||
description: Returns the recent delivery log for a target, newest first. Each row records the alert that fired, the resulting HTTP status, the number of attempts, any error text, and a timestamp. `limit` is clamped to 1–200 (default 20) and `offset` to ≥0 (default 0). This is an audit trail of past sends — it does not trigger a new delivery (use POST /{id}/test for that).
|
||
operationId: listWebhookDeliveries
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
example: 9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e
|
||
- name: limit
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
default: 20
|
||
description: Max rows to return (clamped to 1–200).
|
||
example: 20
|
||
- name: offset
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
default: 0
|
||
description: Pagination offset (clamped to ≥0).
|
||
example: 0
|
||
responses:
|
||
'200':
|
||
description: Delivery rows, newest first
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
example:
|
||
deliveries:
|
||
- id: 5012
|
||
target_id: 9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e
|
||
alert_event_id: 8841
|
||
status: success
|
||
status_code: 200
|
||
attempts: 1
|
||
error: null
|
||
created_at: '2026-06-25T18:41:55.117Z'
|
||
- id: 5008
|
||
target_id: 9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e
|
||
alert_event_id: 8839
|
||
status: failed
|
||
status_code: 429
|
||
attempts: 3
|
||
error: Too Many Requests
|
||
created_at: '2026-06-25T18:30:02.004Z'
|
||
limit: 20
|
||
offset: 0
|
||
'404':
|
||
description: Target not found
|
||
/api/openapi.json:
|
||
get:
|
||
tags:
|
||
- Documentation
|
||
summary: Get OpenAPI specification JSON
|
||
description: 'Returns this OpenAPI 3.0 document as JSON. Both API explorers consume it: Swagger UI (`/api/docs`) for interactive try-it-out requests, and ReDoc (`/api/redoc`) for a read-optimized reference.'
|
||
operationId: getOpenApiJson
|
||
responses:
|
||
'200':
|
||
description: OpenAPI document
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
/api/docs:
|
||
get:
|
||
tags:
|
||
- Documentation
|
||
summary: Swagger UI explorer
|
||
description: Interactive Swagger UI rendering of this specification, with try-it-out request execution against the live local server.
|
||
operationId: getSwaggerUi
|
||
responses:
|
||
'200':
|
||
description: Swagger UI HTML page
|
||
content:
|
||
text/html:
|
||
schema:
|
||
type: string
|
||
/api/redoc:
|
||
get:
|
||
tags:
|
||
- Documentation
|
||
summary: ReDoc API reference
|
||
description: Read-optimized, three-panel ReDoc rendering of this specification. The ReDoc bundle is served locally from `/api/redoc/redoc.standalone.js` (bundled with the server, never fetched from a CDN), so the reference works fully offline.
|
||
operationId: getRedoc
|
||
responses:
|
||
'200':
|
||
description: ReDoc HTML page
|
||
content:
|
||
text/html:
|
||
schema:
|
||
type: string
|
||
/api/cc-config/overview:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: Config explorer overview
|
||
description: Read-only. Returns the four resolved filesystem roots plus aggregate counts across every surface (skills, agents, commands, output styles, plugins, marketplaces, keybindings, MCP servers, hooks, memory, settings files). All sub-reads degrade to empty on any I/O error, so this endpoint never errors.
|
||
operationId: ccConfigGetOverview
|
||
parameters:
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Override the working directory used to resolve the project root and project .claude dir. Defaults to the dashboard server's own cwd.
|
||
example: /repo
|
||
responses:
|
||
'200':
|
||
description: Overview of roots and counts.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigOverviewResponse'
|
||
example:
|
||
roots:
|
||
claudeHome: /Users/son/.claude
|
||
projectClaudeDir: /repo/.claude
|
||
projectRoot: /repo
|
||
claudeJson: /Users/son/.claude.json
|
||
counts:
|
||
skills:
|
||
user: 12
|
||
project: 3
|
||
agents:
|
||
user: 5
|
||
project: 2
|
||
commands:
|
||
user: 8
|
||
project: 0
|
||
outputStyles:
|
||
user: 1
|
||
project: 0
|
||
plugins: 8
|
||
pluginsEnabled: 6
|
||
pluginsDisabled: 1
|
||
marketplaces: 2
|
||
keybindings: 24
|
||
mcpServers:
|
||
user: 3
|
||
project: 1
|
||
hooks:
|
||
user: 2
|
||
project: 0
|
||
project-local: 1
|
||
memory: 5
|
||
settingsFiles: 2
|
||
/api/cc-config/skills:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: List discovered skills
|
||
description: Read-only. Lists skill directories (each containing a SKILL.md) under the user and/or project roots, with parsed frontmatter and a 320-char body preview. Files over 256 KiB are read truncated. Degrades to an empty list on I/O errors.
|
||
operationId: ccConfigGetSkills
|
||
parameters:
|
||
- name: scope
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
- all
|
||
default: all
|
||
description: 'Discovery scope: `user`, `project`, or `all` (default). Unrecognized values fall back to `all`.'
|
||
example: all
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Override the working directory used to resolve the project root and project .claude dir. Defaults to the dashboard server's own cwd.
|
||
example: /repo
|
||
responses:
|
||
'200':
|
||
description: Skills list.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigSkillsResponse'
|
||
example:
|
||
items:
|
||
- scope: user
|
||
name: code-reviewer
|
||
path: /Users/son/.claude/skills/code-reviewer
|
||
file: /Users/son/.claude/skills/code-reviewer/SKILL.md
|
||
size: 2048
|
||
mtime: 1718900000000
|
||
truncated: false
|
||
frontmatter:
|
||
name: code-reviewer
|
||
description: Reviews diffs
|
||
preview: Use this skill to review pull requests...
|
||
/api/cc-config/agents:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: List subagents
|
||
description: Read-only. Lists single-file subagent definitions (<root>/agents/*.md) under the user and/or project roots, with parsed frontmatter and a 320-char preview. Truncated above 256 KiB; degrades to empty on errors.
|
||
operationId: ccConfigGetAgents
|
||
parameters:
|
||
- name: scope
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
- all
|
||
default: all
|
||
description: 'Discovery scope: `user`, `project`, or `all` (default). Unrecognized values fall back to `all`.'
|
||
example: all
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Override the working directory used to resolve the project root and project .claude dir. Defaults to the dashboard server's own cwd.
|
||
example: /repo
|
||
responses:
|
||
'200':
|
||
description: Agents list.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigAgentsResponse'
|
||
example:
|
||
items:
|
||
- scope: project
|
||
name: backend-reviewer
|
||
file: /repo/.claude/agents/backend-reviewer.md
|
||
size: 1536
|
||
mtime: 1718900000000
|
||
truncated: false
|
||
frontmatter:
|
||
name: backend-reviewer
|
||
model: sonnet
|
||
preview: Review backend route and hook logic for regressions...
|
||
/api/cc-config/commands:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: List slash commands
|
||
description: Read-only. Lists slash-command definitions (<root>/commands/*.md) under the user and/or project roots, with parsed frontmatter and a 320-char preview. Truncated above 256 KiB; degrades to empty on errors.
|
||
operationId: ccConfigGetCommands
|
||
parameters:
|
||
- name: scope
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
- all
|
||
default: all
|
||
description: 'Discovery scope: `user`, `project`, or `all` (default). Unrecognized values fall back to `all`.'
|
||
example: all
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Override the working directory used to resolve the project root and project .claude dir. Defaults to the dashboard server's own cwd.
|
||
example: /repo
|
||
responses:
|
||
'200':
|
||
description: Commands list.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigCommandsResponse'
|
||
example:
|
||
items:
|
||
- scope: user
|
||
name: commit
|
||
file: /Users/son/.claude/commands/commit.md
|
||
size: 800
|
||
mtime: 1718900000000
|
||
truncated: false
|
||
frontmatter:
|
||
description: Create a commit
|
||
preview: Commit the staged changes with a descriptive message...
|
||
/api/cc-config/output-styles:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: List output styles
|
||
description: Read-only. Lists output-style definitions (<root>/output-styles/*.md) under the user and/or project roots, with parsed frontmatter and a 320-char preview. Truncated above 256 KiB; degrades to empty on errors.
|
||
operationId: ccConfigGetOutputStyles
|
||
parameters:
|
||
- name: scope
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
- all
|
||
default: all
|
||
description: 'Discovery scope: `user`, `project`, or `all` (default). Unrecognized values fall back to `all`.'
|
||
example: all
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Override the working directory used to resolve the project root and project .claude dir. Defaults to the dashboard server's own cwd.
|
||
example: /repo
|
||
responses:
|
||
'200':
|
||
description: Output styles list.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigOutputStylesResponse'
|
||
example:
|
||
items:
|
||
- scope: user
|
||
name: concise
|
||
file: /Users/son/.claude/output-styles/concise.md
|
||
size: 420
|
||
mtime: 1718900000000
|
||
truncated: false
|
||
frontmatter:
|
||
name: concise
|
||
preview: Respond tersely, no preamble...
|
||
/api/cc-config/plugins:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: List installed plugins
|
||
description: 'Read-only. Reads the user-scope plugins manifest (~/.claude/plugins/installed_plugins.json), resolves each instance''s on-disk contributions, and reports its tri-state enabled flag from settings.json. Read-only by design: plugins are written concurrently by the running Claude Code CLI. No scope/cwd parameters. Degrades to an empty plugin list when the manifest is missing.'
|
||
operationId: ccConfigGetPlugins
|
||
responses:
|
||
'200':
|
||
description: Plugins manifest summary and list.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigPluginsResponse'
|
||
example:
|
||
manifestPath: /Users/son/.claude/plugins/installed_plugins.json
|
||
manifestExists: true
|
||
plugins:
|
||
- key: superpowers@obra
|
||
name: superpowers
|
||
marketplace: obra
|
||
scope: user
|
||
version: 1.2.0
|
||
installPath: /Users/son/.claude/plugins/superpowers
|
||
installedAt: '2026-05-01T12:00:00.000Z'
|
||
lastUpdated: '2026-06-01T09:30:00.000Z'
|
||
gitCommitSha: a1b2c3d4e5f6
|
||
installPathExists: true
|
||
enabled: true
|
||
contributes:
|
||
skills: 3
|
||
agents: 2
|
||
commands: 5
|
||
outputStyles: 0
|
||
hooks: 1
|
||
pluginJson:
|
||
name: superpowers
|
||
version: 1.2.0
|
||
/api/cc-config/mcp:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: List MCP servers
|
||
description: Read-only. Discovers MCP servers from ~/.claude.json (top-level and projects[<root>]) and ~/.claude/settings.json, split into `user` and `projectScoped`. Header and env VALUES are never returned — only their key NAMES. Read-only by design (the CLI writes these files concurrently). Degrades to empty arrays on errors.
|
||
operationId: ccConfigGetMcp
|
||
parameters:
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Override the working directory used to resolve the project root and project .claude dir. Defaults to the dashboard server's own cwd.
|
||
example: /repo
|
||
responses:
|
||
'200':
|
||
description: MCP servers grouped by scope.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigMcpResponse'
|
||
example:
|
||
user:
|
||
- name: github
|
||
source: ~/.claude.json (top-level)
|
||
kind: stdio
|
||
command: npx
|
||
args:
|
||
- '-y'
|
||
- '@modelcontextprotocol/server-github'
|
||
envNames:
|
||
- GITHUB_TOKEN
|
||
projectScoped:
|
||
- name: internal
|
||
source: ~/.claude.json (projects[/repo])
|
||
kind: http
|
||
url: https://mcp.example.com/sse
|
||
headers:
|
||
- Authorization
|
||
/api/cc-config/hooks:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: List configured hooks
|
||
description: Read-only. Reads hooks from the user, project, and project-local settings files. Known event types (SessionStart, SessionEnd, UserPromptSubmit, PreToolUse, PostToolUse, Stop, SubagentStop, Notification, PreCompact) are flattened into matcher/type/command/timeout entries; unknown events are passed through verbatim. Hooks in settings are read-only here. Degrades to per-file `exists:false` on errors.
|
||
operationId: ccConfigGetHooks
|
||
parameters:
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Override the working directory used to resolve the project root and project .claude dir. Defaults to the dashboard server's own cwd.
|
||
example: /repo
|
||
responses:
|
||
'200':
|
||
description: Hook sources by scope.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigHooksResponse'
|
||
example:
|
||
items:
|
||
- scope: user
|
||
file: /Users/son/.claude/settings.json
|
||
exists: true
|
||
hooks:
|
||
PostToolUse:
|
||
- matcher: '*'
|
||
type: command
|
||
command: node ~/.claude/hooks/post-tool-use.js
|
||
timeout: null
|
||
- scope: project
|
||
file: /repo/.claude/settings.json
|
||
exists: false
|
||
hooks: {}
|
||
/api/cc-config/settings:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: List settings files
|
||
description: Read-only. Returns the user, project, and project-local settings.json contents with secret-like keys redacted to the literal `<redacted>` (keys matching /token|secret|password|api[_-]?key|auth/i with string values). Missing files report `exists:false`. Settings files are read-only here (concurrent CLI writes).
|
||
operationId: ccConfigGetSettings
|
||
parameters:
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Override the working directory used to resolve the project root and project .claude dir. Defaults to the dashboard server's own cwd.
|
||
example: /repo
|
||
responses:
|
||
'200':
|
||
description: Settings sources by scope (secrets redacted).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigSettingsResponse'
|
||
example:
|
||
items:
|
||
- scope: user
|
||
file: /Users/son/.claude/settings.json
|
||
exists: true
|
||
data:
|
||
model: sonnet
|
||
apiKey: <redacted>
|
||
raw_size: 412
|
||
- scope: project
|
||
file: /repo/.claude/settings.json
|
||
exists: false
|
||
- scope: project-local
|
||
file: /repo/.claude/settings.local.json
|
||
exists: false
|
||
/api/cc-config/memory:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: List memory files
|
||
description: Read-only. Returns the two primary CLAUDE.md files (scopes `user`/`project`) plus every per-project file-based auto-memory markdown file under ~/.claude/projects/<slug>/memory/ (scope `auto-memory`, sorted index files first). Previews are 480 chars; files over 256 KiB are truncated. Degrades to fewer files on errors.
|
||
operationId: ccConfigGetMemory
|
||
parameters:
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Override the working directory used to resolve the project root and project .claude dir. Defaults to the dashboard server's own cwd.
|
||
example: /repo
|
||
responses:
|
||
'200':
|
||
description: Memory items.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigMemoryResponse'
|
||
example:
|
||
items:
|
||
- scope: user
|
||
file: /Users/son/.claude/CLAUDE.md
|
||
size: 1200
|
||
mtime: 1718900000000
|
||
truncated: false
|
||
preview: '# Workspace & Productivity System...'
|
||
- scope: auto-memory
|
||
project: '-Users-son-repo'
|
||
name: MEMORY.md
|
||
isIndex: true
|
||
file: /Users/son/.claude/projects/-Users-son-repo/memory/MEMORY.md
|
||
size: 980
|
||
mtime: 1718900000000
|
||
truncated: false
|
||
frontmatter: {}
|
||
preview: '## Persistent facts\n- Never run destructive ops without confirmation...'
|
||
/api/cc-config/marketplaces:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: List plugin marketplaces
|
||
description: Read-only. Reads ~/.claude/plugins/known_marketplaces.json and, best-effort, each marketplace's .claude-plugin/marketplace.json for plugin count and metadata. No scope/cwd parameters. Degrades to an empty list when the file is missing.
|
||
operationId: ccConfigGetMarketplaces
|
||
responses:
|
||
'200':
|
||
description: Known marketplaces summary and list.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigMarketplacesResponse'
|
||
example:
|
||
knownPath: /Users/son/.claude/plugins/known_marketplaces.json
|
||
knownExists: true
|
||
items:
|
||
- name: obra
|
||
source:
|
||
source: github
|
||
repo: obra/superpowers-marketplace
|
||
installLocation: /Users/son/.claude/plugins/marketplaces/obra
|
||
lastUpdated: '2026-06-10T00:00:00.000Z'
|
||
pluginCount: 12
|
||
marketplaceName: Superpowers
|
||
marketplaceDescription: Curated agent skills
|
||
marketplaceOwner:
|
||
name: obra
|
||
/api/cc-config/keybindings:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: Get keybindings
|
||
description: Read-only. Parses ~/.claude/keybindings.json into context-scoped groups of key → action bindings. When the file is absent, returns only `{ file, exists:false }`. No scope/cwd parameters.
|
||
operationId: ccConfigGetKeybindings
|
||
responses:
|
||
'200':
|
||
description: Parsed keybindings (or exists:false).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigKeybindingsResponse'
|
||
example:
|
||
file: /Users/son/.claude/keybindings.json
|
||
exists: true
|
||
schema: null
|
||
docs: null
|
||
groups:
|
||
- context: editor
|
||
bindings:
|
||
- key: ctrl+s
|
||
action: submit
|
||
put:
|
||
tags:
|
||
- CcConfig
|
||
summary: Overwrite keybindings
|
||
description: 'Mutating. Overwrites ~/.claude/keybindings.json from a structured list of context groups (`{ context, bindings: [{ key, action }] }`); on disk the bindings become an object keyed by `key`. The existing file is backed up first (under cc-config-backups/keybindings/) and any top-level metadata (`$schema`, `$docs`, unknown keys) is preserved — only the `bindings` array is replaced. Rejects duplicate contexts and duplicate keys within a context. Writes are atomic. Unlike settings.json, keybindings.json is not rewritten mid-session by the live CLI, so this edit is safe. Emits a `cc_config_changed` websocket event on success.'
|
||
operationId: ccConfigPutKeybindings
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- groups
|
||
properties:
|
||
groups:
|
||
type: array
|
||
description: Full set of context-scoped keybinding groups to persist.
|
||
items:
|
||
type: object
|
||
required:
|
||
- context
|
||
- bindings
|
||
properties:
|
||
context:
|
||
type: string
|
||
example: Global
|
||
bindings:
|
||
type: array
|
||
items:
|
||
type: object
|
||
required:
|
||
- key
|
||
- action
|
||
properties:
|
||
key:
|
||
type: string
|
||
example: ctrl+t
|
||
action:
|
||
type: string
|
||
example: toggleTodos
|
||
example:
|
||
groups:
|
||
- context: Global
|
||
bindings:
|
||
- key: ctrl+t
|
||
action: toggleTodos
|
||
- context: Chat
|
||
bindings:
|
||
- key: escape
|
||
action: cancel
|
||
responses:
|
||
'200':
|
||
description: keybindings.json written (backup taken when it already existed).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigFileWriteResponse'
|
||
example:
|
||
ok: true
|
||
file: /Users/son/.claude/keybindings.json
|
||
target: /Users/son/.claude/keybindings.json
|
||
backupPath: /Users/son/.claude/cc-config-backups/keybindings/keybindings.json.2026-06-25T12-00-00.000Z.bak
|
||
created: false
|
||
'400':
|
||
description: Bad request. `EBADREQ` — `groups` is missing or not an array. `EBADCONTENT` — a group/binding is malformed, a context is empty, or there is a duplicate context or duplicate key within a context.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EBADCONTENT
|
||
message: duplicate key "ctrl+t" in context Global
|
||
'413':
|
||
description: '`ETOOLARGE` — the serialized keybindings exceed the 256 KiB limit.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: ETOOLARGE
|
||
message: content exceeds 262144 bytes
|
||
/api/cc-config/statusline:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: Get statusline config and scripts
|
||
description: Read-only. Returns the `statusLine` block from ~/.claude/settings.json plus any statusline scripts (statusline.py, statusline-command.sh) with a 4000-char preview. Scripts over 256 KiB are truncated. No scope/cwd parameters.
|
||
operationId: ccConfigGetStatusline
|
||
responses:
|
||
'200':
|
||
description: Statusline config and scripts.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigStatuslineResponse'
|
||
example:
|
||
config:
|
||
type: command
|
||
command: python3 ~/.claude/statusline.py
|
||
scripts:
|
||
- file: /Users/son/.claude/statusline.py
|
||
size: 1280
|
||
mtime: 1718900000000
|
||
truncated: false
|
||
preview: '#!/usr/bin/env python3\nimport json, sys\n...'
|
||
/api/cc-config/hook-scripts:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: List hook scripts
|
||
description: Read-only. Lists files in the ~/.claude/hooks/ directory (name, path, size, mtime), sorted by name. Returns metadata only — no file contents. Use GET /file to read an individual script. No scope/cwd parameters.
|
||
operationId: ccConfigGetHookScripts
|
||
responses:
|
||
'200':
|
||
description: Hook scripts directory listing.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigHookScriptsResponse'
|
||
example:
|
||
dir: /Users/son/.claude/hooks
|
||
items:
|
||
- name: post-tool-use.js
|
||
file: /Users/son/.claude/hooks/post-tool-use.js
|
||
size: 640
|
||
mtime: 1718900000000
|
||
/api/cc-config/file:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: Read a single file body
|
||
description: 'Read-only. Returns the body of one file. Strict path containment: the resolved absolute path MUST live under the Claude home, the project .claude dir, or (only for a file literally named CLAUDE.md) the project root. Bodies over 256 KiB are truncated. NOTE: there is no 404 path — a missing, unreadable, or out-of-root file all return 400.'
|
||
operationId: ccConfigGetFile
|
||
parameters:
|
||
- name: path
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: Absolute path to read. Must resolve under an allowed root; under the project root only CLAUDE.md is permitted.
|
||
example: /Users/son/.claude/skills/code-reviewer/SKILL.md
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Override the working directory used to resolve the project root and project .claude dir. Defaults to the dashboard server's own cwd.
|
||
example: /repo
|
||
responses:
|
||
'200':
|
||
description: File body with metadata.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigFileReadResponse'
|
||
example:
|
||
ok: true
|
||
file: /Users/son/.claude/skills/code-reviewer/SKILL.md
|
||
truncated: false
|
||
size: 2048
|
||
text: '---\nname: code-reviewer\n---\n# Code Reviewer\n...'
|
||
mtime: 1718900000000
|
||
'400':
|
||
description: Bad or denied path. `BAD_PATH` — `path` query is missing or empty. `READ_DENIED` — path is outside the allowed roots, only CLAUDE.md is readable from the project root, or the file is missing/unreadable (there is no 404).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: READ_DENIED
|
||
message: path is outside allowed roots
|
||
put:
|
||
tags:
|
||
- CcConfig
|
||
summary: Create or overwrite a text artifact
|
||
description: Mutating. Creates or overwrites a low-risk text artifact (skills, agents, commands, output-styles, memory, auto-memory). Before overwriting an existing artifact a timestamped backup is created under a cc-config-backups directory (well outside the dirs Claude Code scans); fresh creates have no backup (backupPath:null). Writes are atomic (temp file + rename). Names are validated against a strict allowlist and the resolved path is re-checked to be inside its containment root. Content must be a string ≤ 256 KiB (UTF-8). Plugins, MCP servers, hooks-in-settings, and settings.json are intentionally NOT writable. Emits a `cc_config_changed` websocket event on success.
|
||
operationId: ccConfigPutFile
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigFileWriteRequest'
|
||
example:
|
||
scope: user
|
||
type: agents
|
||
name: my-reviewer
|
||
content: '---\nname: my-reviewer\n---\n# My Reviewer\nReview the diff...'
|
||
parameters:
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Override the working directory used to resolve the project root and project .claude dir. Defaults to the dashboard server's own cwd.
|
||
example: /repo
|
||
responses:
|
||
'200':
|
||
description: Artifact created or overwritten.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigFileWriteResponse'
|
||
example:
|
||
ok: true
|
||
file: /Users/son/.claude/agents/my-reviewer.md
|
||
target: /Users/son/.claude/agents/my-reviewer.md
|
||
backupPath: null
|
||
created: true
|
||
'400':
|
||
description: Bad request. `EBADREQ` — scope/type missing or not strings. `EBADTYPE` — unknown type. `EBADSCOPE` — scope not user/project. `EBADNAME` — name fails the allowlist (or auto-memory name is not a flat *.md). `EBADPROJECT` — invalid auto-memory project slug. `EBADCONTENT` — content is not a string. `EOUTOFROOT` — resolved path escapes its containment root.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EBADNAME
|
||
message: name must match /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/
|
||
'413':
|
||
description: '`ETOOLARGE` — content exceeds the 256 KiB (262144-byte) limit.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: ETOOLARGE
|
||
message: content exceeds 262144 bytes
|
||
'500':
|
||
description: '`EINTERNAL` (or any unmapped error code) — unexpected filesystem error.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EINTERNAL
|
||
message: 'EACCES: permission denied'
|
||
delete:
|
||
tags:
|
||
- CcConfig
|
||
summary: Delete a text artifact
|
||
description: Mutating. Deletes a low-risk text artifact (same type/scope/name/project semantics as PUT, no content). A mandatory backup is created BEFORE deletion — if the backup fails the original is left intact. Skill deletes remove the whole skill directory. Emits a `cc_config_changed` websocket event on success. Plugins, MCP servers, hooks-in-settings, and settings.json are NOT deletable.
|
||
operationId: ccConfigDeleteFile
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigFileDeleteRequest'
|
||
example:
|
||
scope: user
|
||
type: agents
|
||
name: my-reviewer
|
||
parameters:
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Override the working directory used to resolve the project root and project .claude dir. Defaults to the dashboard server's own cwd.
|
||
example: /repo
|
||
responses:
|
||
'200':
|
||
description: Artifact deleted (backup taken first).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigFileDeleteResponse'
|
||
example:
|
||
ok: true
|
||
file: /Users/son/.claude/agents/my-reviewer.md
|
||
target: /Users/son/.claude/agents/my-reviewer.md
|
||
backupPath: /Users/son/.claude/cc-config-backups/agents/my-reviewer.md.2026-06-25T12-00-00.000Z.bak
|
||
'400':
|
||
description: Bad request. `EBADREQ` — scope/type missing or not strings. `EBADTYPE` — unknown type. `EBADSCOPE` — scope not user/project. `EBADNAME` — invalid name. `EBADPROJECT` — invalid auto-memory project slug. `EOUTOFROOT` — resolved path escapes its containment root.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EBADTYPE
|
||
message: 'unknown type: plugins'
|
||
'404':
|
||
description: '`ENOTFOUND` — the target artifact does not exist.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: ENOTFOUND
|
||
message: agents/my-reviewer does not exist
|
||
'500':
|
||
description: '`EINTERNAL` (or any unmapped error code) — unexpected filesystem error.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EINTERNAL
|
||
message: 'EACCES: permission denied'
|
||
/api/cc-config/backups:
|
||
get:
|
||
tags:
|
||
- CcConfig
|
||
summary: List artifact backups
|
||
description: 'Read-only. Lists backups taken by the mutation endpoints, across the user and project roots plus per-project auto-memory backup dirs. Optional `scope`/`type` narrow the search. Results are sorted newest first. Best-effort: unreadable backup dirs are skipped, never erroring.'
|
||
operationId: ccConfigGetBackups
|
||
parameters:
|
||
- name: scope
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
enum:
|
||
- user
|
||
- project
|
||
description: Narrow to a single root scope. Only `user` or `project` are honored; any other value is ignored (both scopes scanned).
|
||
example: user
|
||
- name: type
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
enum:
|
||
- skills
|
||
- agents
|
||
- commands
|
||
- output-styles
|
||
- memory
|
||
- auto-memory
|
||
description: Narrow to a single artifact type. When omitted, all types are scanned.
|
||
example: agents
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Override the working directory used to resolve the project root and project .claude dir. Defaults to the dashboard server's own cwd.
|
||
example: /repo
|
||
responses:
|
||
'200':
|
||
description: Backups sorted newest first.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CcConfigBackupsResponse'
|
||
example:
|
||
items:
|
||
- scope: user
|
||
type: agents
|
||
name: my-reviewer.md.2026-06-25T12-00-00.000Z.bak
|
||
backupPath: /Users/son/.claude/cc-config-backups/agents/my-reviewer.md.2026-06-25T12-00-00.000Z.bak
|
||
isDir: false
|
||
mtime: 1718900000000
|
||
size: 2048
|
||
/api/run:
|
||
get:
|
||
tags:
|
||
- Run
|
||
summary: List live + recently-exited runs
|
||
description: Returns every run handle currently held in memory (newest first) plus concurrency telemetry (`maxConcurrent`, `activeCount`). Handles are reaped 5 minutes after the process exits, so terminal runs disappear from here but remain in GET /api/run/history. Read-only — no process is spawned. The loopback same-origin guard applies.
|
||
operationId: runList
|
||
responses:
|
||
'200':
|
||
description: Tracked runs and concurrency telemetry
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RunListResponse'
|
||
example:
|
||
items:
|
||
- id: 3f2c9a1e-7b4d-4e21-9b6a-1d2e3f4a5b6c
|
||
pid: 48213
|
||
mode: conversation
|
||
cwd: /Users/dev/projects/my-app
|
||
model: claude-opus-4-8
|
||
permissionMode: acceptEdits
|
||
effort: high
|
||
prompt: Refactor the auth module and add tests.
|
||
argv:
|
||
- '--output-format'
|
||
- stream-json
|
||
- '--verbose'
|
||
- '--include-partial-messages'
|
||
- '--permission-mode'
|
||
- acceptEdits
|
||
- '--input-format'
|
||
- stream-json
|
||
resumeSessionId: null
|
||
status: running
|
||
startedAt: 1718000000000
|
||
endedAt: null
|
||
exitCode: null
|
||
signal: null
|
||
error: null
|
||
sessionId: a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d
|
||
envelopeCount: 12
|
||
stdoutTail: |
|
||
{"type":"assistant",...}
|
||
stderrTail: ''
|
||
maxConcurrent: 10000
|
||
activeCount: 1
|
||
'403':
|
||
description: 'Cross-origin rejected (EBADORIGIN). Enforced by the router-level loopback same-origin guard on every /api/run route: a browser request carrying an Origin/Referer whose host is not localhost / 127.0.0.1 / ::1 / 0.0.0.0 is refused. Requests without an Origin header (e.g. curl) are allowed.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EBADORIGIN
|
||
message: cross-origin requests are not allowed
|
||
post:
|
||
tags:
|
||
- Run
|
||
summary: Spawn a new run
|
||
description: Spawns a real `claude` Code subprocess in the sanitised `cwd`. In `headless` mode the prompt is passed via argv and stdin is closed (one turn, then exit); in `conversation` mode stdin stays open for follow-ups via POST /api/run/{id}/message, and an existing session may be resumed with `resumeSessionId`. The child is always run with `--output-format stream-json --verbose --include-partial-messages`; parsed envelopes are broadcast as `run_stream` WebSocket messages and lifecycle transitions as `run_status`. A row is persisted to `dashboard_runs`, and the in-memory handle is reaped 5 minutes after exit. Concurrency is capped (ECONCURRENCY -> 429). The loopback same-origin guard applies. Returns the freshly-created RunHandle.
|
||
operationId: runSpawn
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RunSpawnRequest'
|
||
example:
|
||
prompt: Refactor the auth module and add tests.
|
||
mode: conversation
|
||
cwd: /Users/dev/projects/my-app
|
||
model: claude-opus-4-8
|
||
effort: high
|
||
permissionMode: acceptEdits
|
||
responses:
|
||
'201':
|
||
description: Run spawned; returns the new run handle (status `spawning`).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RunHandle'
|
||
example:
|
||
id: 3f2c9a1e-7b4d-4e21-9b6a-1d2e3f4a5b6c
|
||
pid: 48213
|
||
mode: conversation
|
||
cwd: /Users/dev/projects/my-app
|
||
model: claude-opus-4-8
|
||
permissionMode: acceptEdits
|
||
effort: high
|
||
prompt: Refactor the auth module and add tests.
|
||
argv:
|
||
- '--output-format'
|
||
- stream-json
|
||
- '--verbose'
|
||
- '--include-partial-messages'
|
||
- '--permission-mode'
|
||
- acceptEdits
|
||
- '--input-format'
|
||
- stream-json
|
||
- '--model'
|
||
- claude-opus-4-8
|
||
- '--effort'
|
||
- high
|
||
resumeSessionId: null
|
||
status: spawning
|
||
startedAt: 1718000000000
|
||
endedAt: null
|
||
exitCode: null
|
||
signal: null
|
||
error: null
|
||
sessionId: null
|
||
envelopeCount: 0
|
||
stdoutTail: ''
|
||
stderrTail: ''
|
||
'400':
|
||
description: Invalid spawn request — EBADPROMPT (prompt required), EBADCWD (cwd not an existing absolute directory), EBADMODE (bad mode, or resumeSessionId outside conversation mode), EBADEFFORT (effort not low/medium/high/xhigh/max), or EBADSESSION (resumeSessionId not a valid session id).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
examples:
|
||
badPrompt:
|
||
value:
|
||
error:
|
||
code: EBADPROMPT
|
||
message: prompt is required
|
||
badCwd:
|
||
value:
|
||
error:
|
||
code: EBADCWD
|
||
message: cwd must be an absolute path
|
||
badMode:
|
||
value:
|
||
error:
|
||
code: EBADMODE
|
||
message: mode must be "headless" or "conversation"
|
||
badEffort:
|
||
value:
|
||
error:
|
||
code: EBADEFFORT
|
||
message: 'effort must be one of: low, medium, high, xhigh, max'
|
||
badSession:
|
||
value:
|
||
error:
|
||
code: EBADSESSION
|
||
message: resumeSessionId is not a valid session id
|
||
'403':
|
||
description: 'Cross-origin rejected (EBADORIGIN). Enforced by the router-level loopback same-origin guard on every /api/run route: a browser request carrying an Origin/Referer whose host is not localhost / 127.0.0.1 / ::1 / 0.0.0.0 is refused. Requests without an Origin header (e.g. curl) are allowed.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EBADORIGIN
|
||
message: cross-origin requests are not allowed
|
||
'429':
|
||
description: Concurrency cap reached (ECONCURRENCY). The body additionally carries a top-level `running` array listing the runs currently holding the cap.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RunSpawnConcurrencyResponse'
|
||
example:
|
||
error:
|
||
code: ECONCURRENCY
|
||
message: concurrency limit 10000 reached
|
||
running:
|
||
- id: 3f2c9a1e-7b4d-4e21-9b6a-1d2e3f4a5b6c
|
||
pid: 48213
|
||
startedAt: 1718000000000
|
||
mode: conversation
|
||
'500':
|
||
description: Unexpected spawn failure (EINTERNAL).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EINTERNAL
|
||
message: spawn claude ENOENT
|
||
/api/run/history:
|
||
get:
|
||
tags:
|
||
- Run
|
||
summary: List persisted run history
|
||
description: 'Returns the persistent history of runs spawned via the dashboard, sourced from the `dashboard_runs` sqlite table (newest first). Unlike GET /api/run, this survives the 5-minute in-memory reap so past runs stay visible and resumable for days. Each item is cross-referenced against live handles to set `isLive`. Returns `{ items: [] }` if the persistence DB is unavailable. Read-only — no process is spawned. The loopback same-origin guard applies.'
|
||
operationId: runHistory
|
||
parameters:
|
||
- name: limit
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
maximum: 500
|
||
default: 50
|
||
description: Maximum number of history rows to return (default 50, clamped to 1–500).
|
||
example: 50
|
||
- name: laneId
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
description: Return only the runs started through this lane (POST /api/lanes/{id}/start). Omit for every run; runs spawned from POST /api/run carry no lane and are excluded whenever this is set.
|
||
example: 5
|
||
responses:
|
||
'200':
|
||
description: Run history, most recent first
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RunHistoryResponse'
|
||
example:
|
||
items:
|
||
- id: 3f2c9a1e-7b4d-4e21-9b6a-1d2e3f4a5b6c
|
||
session_id: a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d
|
||
mode: conversation
|
||
cwd: /Users/dev/projects/my-app
|
||
model: claude-opus-4-8
|
||
permission_mode: acceptEdits
|
||
effort: high
|
||
resume_session_id: null
|
||
prompt_preview: Refactor the auth module and add tests.
|
||
status: completed
|
||
exit_code: 0
|
||
started_at: '2026-06-25T17:00:00.000Z'
|
||
ended_at: '2026-06-25T17:01:42.500Z'
|
||
isLive: false
|
||
lane_id: null
|
||
'403':
|
||
description: 'Cross-origin rejected (EBADORIGIN). Enforced by the router-level loopback same-origin guard on every /api/run route: a browser request carrying an Origin/Referer whose host is not localhost / 127.0.0.1 / ::1 / 0.0.0.0 is refused. Requests without an Origin header (e.g. curl) are allowed.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EBADORIGIN
|
||
message: cross-origin requests are not allowed
|
||
/api/run/cwds:
|
||
get:
|
||
tags:
|
||
- Run
|
||
summary: Suggest working directories
|
||
description: 'Suggests plausible working directories for the Run launcher: the dashboard server''s cwd (always first), $HOME, and distinct recent cwds Claude Code has been used in (from the sessions table). Only directories that still exist on disk are returned; the DB lookup is best-effort. Read-only — no process is spawned. The loopback same-origin guard applies.'
|
||
operationId: runCwds
|
||
parameters:
|
||
- name: q
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Optional case-insensitive substring filter (also applied client-side).
|
||
example: my-app
|
||
responses:
|
||
'200':
|
||
description: Working-directory suggestions
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RunCwdsResponse'
|
||
example:
|
||
items:
|
||
- kind: dashboard
|
||
path: /Users/dev/Claude-Code-Agent-Monitor
|
||
label: Dashboard server
|
||
- kind: home
|
||
path: /Users/dev
|
||
label: Home
|
||
- kind: recent
|
||
path: /Users/dev/projects/my-app
|
||
label: my-app
|
||
'403':
|
||
description: 'Cross-origin rejected (EBADORIGIN). Enforced by the router-level loopback same-origin guard on every /api/run route: a browser request carrying an Origin/Referer whose host is not localhost / 127.0.0.1 / ::1 / 0.0.0.0 is refused. Requests without an Origin header (e.g. curl) are allowed.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EBADORIGIN
|
||
message: cross-origin requests are not allowed
|
||
/api/run/files:
|
||
get:
|
||
tags:
|
||
- Run
|
||
summary: Autocomplete files within a cwd
|
||
description: Walks the given `cwd` and returns up to 40 file paths (relative to that cwd, shortest first) for the prompt editor's `@` references. The cwd is validated via the same sanitiser as spawning (must be an existing absolute directory). Dotfiles (except .env/.gitignore) and heavy build dirs (node_modules, .git, dist, build, out, .next, coverage, target, .venv, __pycache__, etc.) are skipped; the walk is bounded (≤5000 entries visited). Read-only — no process is spawned. The loopback same-origin guard applies.
|
||
operationId: runFiles
|
||
parameters:
|
||
- name: cwd
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Absolute directory to walk. Must exist; defaults to the dashboard server's cwd when omitted. Invalid values yield 400 EBADCWD.
|
||
example: /Users/dev/projects/my-app
|
||
- name: q
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Optional case-insensitive substring filter applied to the relative path.
|
||
example: route
|
||
responses:
|
||
'200':
|
||
description: Matching file paths relative to cwd
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RunFilesResponse'
|
||
example:
|
||
items:
|
||
- package.json
|
||
- src/index.ts
|
||
- server/routes/run.js
|
||
'400':
|
||
description: 'Invalid cwd (EBADCWD): not a string, not absolute, or does not exist.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EBADCWD
|
||
message: 'cwd does not exist: /no/such/dir'
|
||
'403':
|
||
description: 'Cross-origin rejected (EBADORIGIN). Enforced by the router-level loopback same-origin guard on every /api/run route: a browser request carrying an Origin/Referer whose host is not localhost / 127.0.0.1 / ::1 / 0.0.0.0 is refused. Requests without an Origin header (e.g. curl) are allowed.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EBADORIGIN
|
||
message: cross-origin requests are not allowed
|
||
/api/run/binary:
|
||
get:
|
||
tags:
|
||
- Run
|
||
summary: Check whether the `claude` binary is on PATH
|
||
description: Probes PATH (via which/where) for the `claude` binary so the UI can warn before the user clicks Run. The binary is NOT invoked — only resolved. Read-only — no process is spawned beyond the lookup. The loopback same-origin guard applies.
|
||
operationId: runBinary
|
||
responses:
|
||
'200':
|
||
description: Binary resolution result
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RunBinaryResponse'
|
||
example:
|
||
found: true
|
||
path: /usr/local/bin/claude
|
||
'403':
|
||
description: 'Cross-origin rejected (EBADORIGIN). Enforced by the router-level loopback same-origin guard on every /api/run route: a browser request carrying an Origin/Referer whose host is not localhost / 127.0.0.1 / ::1 / 0.0.0.0 is refused. Requests without an Origin header (e.g. curl) are allowed.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EBADORIGIN
|
||
message: cross-origin requests are not allowed
|
||
/api/run/{id}/message:
|
||
post:
|
||
tags:
|
||
- Run
|
||
summary: Send a follow-up turn to a conversation run
|
||
description: 'Writes a stream-json user envelope to a running conversation''s stdin and broadcasts a `run_input_ack` WebSocket message. Only valid for `conversation`-mode runs that are still `running`/`spawning` with writable stdin. SIDE EFFECT: the child resumes processing the new turn and emits further `run_stream`/`run_status` messages. The loopback same-origin guard applies.'
|
||
operationId: runSendMessage
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
description: Run id (RunHandle.id).
|
||
example: 3f2c9a1e-7b4d-4e21-9b6a-1d2e3f4a5b6c
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RunMessageRequest'
|
||
example:
|
||
text: Also update the README to document the new flags.
|
||
responses:
|
||
'200':
|
||
description: Turn written to stdin
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RunMessageResponse'
|
||
example:
|
||
messageId: 9c0d1e2f-3a4b-5c6d-7e8f-9a0b1c2d3e4f
|
||
'400':
|
||
description: Cannot deliver input — EBADINPUT (text required), EWRONGMODE (run is not conversation mode), ENOTRUNNING (run is not running/spawning), or ESTDINCLOSED (child stdin not writable).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
examples:
|
||
badInput:
|
||
value:
|
||
error:
|
||
code: EBADINPUT
|
||
message: text is required
|
||
wrongMode:
|
||
value:
|
||
error:
|
||
code: EWRONGMODE
|
||
message: only conversation mode accepts follow-up input
|
||
notRunning:
|
||
value:
|
||
error:
|
||
code: ENOTRUNNING
|
||
message: run is completed
|
||
stdinClosed:
|
||
value:
|
||
error:
|
||
code: ESTDINCLOSED
|
||
message: stdin is not writable
|
||
'403':
|
||
description: 'Cross-origin rejected (EBADORIGIN). Enforced by the router-level loopback same-origin guard on every /api/run route: a browser request carrying an Origin/Referer whose host is not localhost / 127.0.0.1 / ::1 / 0.0.0.0 is refused. Requests without an Origin header (e.g. curl) are allowed.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EBADORIGIN
|
||
message: cross-origin requests are not allowed
|
||
'404':
|
||
description: No run with this id (ENOTFOUND) — it never existed or was reaped.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: ENOTFOUND
|
||
message: run not found
|
||
/api/run/{id}:
|
||
get:
|
||
tags:
|
||
- Run
|
||
summary: Get a single run
|
||
description: Returns the in-memory handle for one run. Pass `?envelopes=1` to additionally include the bounded (≤500) stream-json envelope replay buffer so a client can re-attach to an in-flight run and see what it missed. Available only while the handle is live or within the 5-minute post-exit reap window — afterwards use GET /api/run/history. Read-only — no process is spawned. The loopback same-origin guard applies.
|
||
operationId: runGet
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
description: Run id (RunHandle.id).
|
||
example: 3f2c9a1e-7b4d-4e21-9b6a-1d2e3f4a5b6c
|
||
- name: envelopes
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
enum:
|
||
- '1'
|
||
description: Set to `1` to include the `envelopes` replay buffer in the response.
|
||
example: '1'
|
||
responses:
|
||
'200':
|
||
description: The run handle (with `envelopes` appended when `?envelopes=1`).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
oneOf:
|
||
- $ref: '#/components/schemas/RunHandle'
|
||
- $ref: '#/components/schemas/RunHandleWithEnvelopes'
|
||
example:
|
||
id: 3f2c9a1e-7b4d-4e21-9b6a-1d2e3f4a5b6c
|
||
pid: 48213
|
||
mode: conversation
|
||
cwd: /Users/dev/projects/my-app
|
||
model: claude-opus-4-8
|
||
permissionMode: acceptEdits
|
||
effort: high
|
||
prompt: Refactor the auth module and add tests.
|
||
argv:
|
||
- '--output-format'
|
||
- stream-json
|
||
- '--verbose'
|
||
- '--include-partial-messages'
|
||
resumeSessionId: null
|
||
status: running
|
||
startedAt: 1718000000000
|
||
endedAt: null
|
||
exitCode: null
|
||
signal: null
|
||
error: null
|
||
sessionId: a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d
|
||
envelopeCount: 12
|
||
stdoutTail: |
|
||
{"type":"assistant",...}
|
||
stderrTail: ''
|
||
envelopes:
|
||
- type: system
|
||
subtype: init
|
||
session_id: a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d
|
||
- type: assistant
|
||
message:
|
||
role: assistant
|
||
content:
|
||
- type: text
|
||
text: Working on it...
|
||
'403':
|
||
description: 'Cross-origin rejected (EBADORIGIN). Enforced by the router-level loopback same-origin guard on every /api/run route: a browser request carrying an Origin/Referer whose host is not localhost / 127.0.0.1 / ::1 / 0.0.0.0 is refused. Requests without an Origin header (e.g. curl) are allowed.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EBADORIGIN
|
||
message: cross-origin requests are not allowed
|
||
'404':
|
||
description: No run with this id (ENOTFOUND) — it never existed or was reaped.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: ENOTFOUND
|
||
message: run not found
|
||
delete:
|
||
tags:
|
||
- Run
|
||
summary: Kill a run
|
||
description: 'Terminates a live run: sends SIGTERM (escalating to SIGKILL after ~5s if needed), sets the handle status to `killed`, broadcasts a `run_status` WebSocket message, persists the status to `dashboard_runs`, and schedules the handle for the 5-minute reap. Idempotent — returns `{ ok: true }` even if the run had already terminated. The loopback same-origin guard applies.'
|
||
operationId: runKill
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
description: Run id (RunHandle.id).
|
||
example: 3f2c9a1e-7b4d-4e21-9b6a-1d2e3f4a5b6c
|
||
responses:
|
||
'200':
|
||
description: Kill issued (or run already terminated).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RunKillResponse'
|
||
example:
|
||
ok: true
|
||
'403':
|
||
description: 'Cross-origin rejected (EBADORIGIN). Enforced by the router-level loopback same-origin guard on every /api/run route: a browser request carrying an Origin/Referer whose host is not localhost / 127.0.0.1 / ::1 / 0.0.0.0 is refused. Requests without an Origin header (e.g. curl) are allowed.'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: EBADORIGIN
|
||
message: cross-origin requests are not allowed
|
||
'404':
|
||
description: No run with this id (ENOTFOUND) — it never existed or was reaped.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: ENOTFOUND
|
||
message: run not found
|
||
/api/lanes/ensure:
|
||
post:
|
||
tags:
|
||
- Lanes
|
||
summary: Find or adopt the lane owning a working directory
|
||
description: 'Idempotent: returns the lane whose cwd is an exact match or the longest path-boundary parent of `cwd` with `created: false` (200), otherwise creates an `adopted` lane and returns it with `created: true` (201). The Workspace page opens on a directory rather than a lane id, so this is how it gets exactly one lane for that directory. Concurrent calls for the same path resolve to ONE lane: the `lanes.cwd` UNIQUE constraint decides, and the loser re-reads and returns the winner''s lane.'
|
||
operationId: ensureLane
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/LaneEnsureRequest'
|
||
responses:
|
||
'200':
|
||
description: An existing lane already owns that cwd.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- lane
|
||
- created
|
||
properties:
|
||
lane:
|
||
type: object
|
||
additionalProperties: true
|
||
created:
|
||
type: boolean
|
||
enum:
|
||
- false
|
||
'201':
|
||
description: No lane owned that cwd, so an adopted one was created.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- lane
|
||
- created
|
||
properties:
|
||
lane:
|
||
type: object
|
||
additionalProperties: true
|
||
created:
|
||
type: boolean
|
||
enum:
|
||
- true
|
||
'400':
|
||
description: cwd is missing or not an absolute path (EBADCWD).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
'403':
|
||
description: The browser request was not same-origin/loopback.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
/api/lanes/worktree:
|
||
post:
|
||
tags:
|
||
- Lanes
|
||
summary: Provision a managed git worktree lane
|
||
description: Validates the absolute source repository, creates a managed lane in `provisioning` state, and returns immediately. Worktree creation continues under the lane lock; the existing `lane_update` broadcast reports either `idle` or `failed` with git stderr in `notes`.
|
||
operationId: createLaneWorktree
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/LaneWorktreeCreateRequest'
|
||
responses:
|
||
'202':
|
||
description: Managed lane accepted for background provisioning.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- lane
|
||
properties:
|
||
lane:
|
||
type: object
|
||
additionalProperties: true
|
||
'400':
|
||
description: sourceRepo is relative, missing, or not a git repository.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
'403':
|
||
description: The browser request was not same-origin/loopback.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
'409':
|
||
description: The computed worktree directory already belongs to a lane, or no unique directory was available after 50 attempts.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
/api/lanes/{id}:
|
||
patch:
|
||
tags:
|
||
- Lanes
|
||
summary: Partially update a lane
|
||
description: Updates lane fields, including run_id; browser requests must pass the loopback same-origin guard. The provisioning-time facts kind, source_repo, slug and base_branch are NOT patchable — kind is check 1 of the destroy guard — and are silently ignored here.
|
||
operationId: updateLane
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
responses:
|
||
'200':
|
||
description: Updated lane.
|
||
'400':
|
||
description: kind was not one of adopted|managed (EBADKIND).
|
||
'403':
|
||
description: The browser request was not same-origin/loopback.
|
||
'404':
|
||
description: Lane not found.
|
||
/api/lanes/{id}/preflight:
|
||
get:
|
||
tags:
|
||
- Lanes
|
||
summary: Count facts before a destructive lane action
|
||
operationId: preflightLaneAction
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
- name: action
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: string
|
||
enum:
|
||
- reset
|
||
- remove
|
||
- purge
|
||
responses:
|
||
'200':
|
||
description: 'Current counted facts for the selected action. reset/remove additionally return blocked[] (hard blockers: adopted, missing, unreadable, unpushed-commits — the only one force overrides) and warnings[] (informational only, e.g. no-remote).'
|
||
'400':
|
||
description: Unknown action.
|
||
'404':
|
||
description: Lane not found.
|
||
/api/lanes/{id}/git:
|
||
get:
|
||
tags:
|
||
- Lanes
|
||
summary: A lane's working-copy facts
|
||
description: Branch, short HEAD, that commit's subject, and the uncommitted counts for the lane's cwd. Read-only, so no same-origin guard. Kept out of GET /api/lanes because it shells out to git three times and that payload is polled and re-broadcast on every lane_update. A cwd that is missing, is not a git repository, or makes git fail returns available:false with HTTP 200 — a lane pointing at a plain directory is a normal state, not a fault.
|
||
operationId: getLaneGitFacts
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: available:true with {branch, head, subject, dirty, untracked}, or available:false alone.
|
||
'404':
|
||
description: Lane not found.
|
||
/api/lanes/branches:
|
||
get:
|
||
tags:
|
||
- Lanes
|
||
summary: A candidate source repo's local branches
|
||
description: 'Feeds the Add-lane picker: given a repo path, returns its local branches (not origin/* refs — those aren''t checkout-able into a new worktree without a fetch first) plus which one is currently checked out. Same repo validation as POST /api/lanes/worktree; a repo neither endpoint can resolve can''t be provisioned from either. Read-only, no same-origin guard.'
|
||
operationId: listLaneBranches
|
||
parameters:
|
||
- name: repo
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: Absolute path to an existing git repository.
|
||
responses:
|
||
'200':
|
||
description: '{branches: string[], current: string | null}.'
|
||
'400':
|
||
description: repo is missing, relative, does not exist, or is not a git repo.
|
||
/api/lanes/{id}/{action}:
|
||
post:
|
||
tags:
|
||
- Lanes
|
||
summary: Confirm a reset, managed-worktree removal, or session purge
|
||
description: Actions run under the lane lock after waiting for the lane child's actual exit. A failed spawn is already exited because no child started. Reset requires a live managed worktree; remove tears down a managed worktree, prunes git's stale record when the directory was deleted by hand, or only forgets an adopted-lane row without touching its directory. Reset/remove require force when managed work has unpushed commits.
|
||
operationId: runLaneDestructiveAction
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
- name: action
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
enum:
|
||
- reset
|
||
- remove
|
||
- purge
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/LaneDestructiveActionRequest'
|
||
responses:
|
||
'200':
|
||
description: Action completed; purge includes its deleted-row counts.
|
||
'400':
|
||
description: Confirmation or complete expect facts missing, or the managed-worktree guard refused the target.
|
||
'403':
|
||
description: The browser request was not same-origin/loopback.
|
||
'409':
|
||
description: Preflight facts changed (ESTALE) or force is required (EUNPUSHED).
|
||
'500':
|
||
description: Git, run-exit timeout, or internal failure; git failures include error.stderr.
|
||
/api/push/vapid-public-key:
|
||
get:
|
||
tags:
|
||
- Push
|
||
summary: Get the VAPID public key
|
||
description: Returns the server's VAPID public application server key so a browser can register a Web Push subscription via `PushManager.subscribe({ applicationServerKey })`. The key pair is generated once and persisted in the shared data directory alongside the SQLite DB, so the web app and native apps reuse a single key pair across restarts. No authentication — this is a local-first dashboard. Safe to call repeatedly; always returns the same key.
|
||
operationId: pushVapidPublicKey
|
||
responses:
|
||
'200':
|
||
description: The VAPID public key
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PushVapidKeyResponse'
|
||
example:
|
||
publicKey: BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8
|
||
/api/push/subscribe:
|
||
post:
|
||
tags:
|
||
- Push
|
||
summary: Register a Web Push subscription
|
||
description: 'Stores a browser PushSubscription so future `/api/push/send` broadcasts reach this endpoint. Persisted with `INSERT OR REPLACE INTO push_subscriptions (endpoint, p256dh, auth)`, keyed on `endpoint` — so the operation is idempotent: re-subscribing the same endpoint overwrites its keys instead of creating a duplicate. No authentication (local-first). Requires `endpoint`, `keys.p256dh`, and `keys.auth`; any missing field returns 400.'
|
||
operationId: pushSubscribe
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PushSubscribeRequest'
|
||
example:
|
||
endpoint: https://fcm.googleapis.com/fcm/send/dGhpcy1pcy1hLWZha2UtZW5kcG9pbnQ
|
||
keys:
|
||
p256dh: BNcRdreALRFXTkOOUHK1EtK2wtaz5Ry4YfYCA_0QTpQtUbVlUls0VJXg7A8u-Ts1XbjhazAkj7I99e8QcYP7DkM
|
||
auth: tBHItJI5svbpez7KI4CCXg
|
||
responses:
|
||
'200':
|
||
description: Subscription stored (created or overwritten)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PushSubscribeResponse'
|
||
example:
|
||
ok: true
|
||
'400':
|
||
description: Missing required fields (one of `endpoint`, `keys.p256dh`, `keys.auth` was absent)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/MessageErrorResponse'
|
||
example:
|
||
error:
|
||
message: Missing required fields
|
||
delete:
|
||
tags:
|
||
- Push
|
||
summary: Remove a Web Push subscription
|
||
description: 'Deletes a stored subscription so it stops receiving broadcasts. The endpoint identifier is supplied in the request BODY (a DELETE with a JSON body), NOT as a query parameter. Idempotent — deleting an endpoint that is not stored still returns `{ ok: true }`. No authentication (local-first). A missing `endpoint` returns 400.'
|
||
operationId: pushUnsubscribe
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PushUnsubscribeRequest'
|
||
example:
|
||
endpoint: https://fcm.googleapis.com/fcm/send/dGhpcy1pcy1hLWZha2UtZW5kcG9pbnQ
|
||
responses:
|
||
'200':
|
||
description: Subscription removed (or no-op if it was not stored)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PushOkResponse'
|
||
example:
|
||
ok: true
|
||
'400':
|
||
description: Missing endpoint in the request body
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/MessageErrorResponse'
|
||
example:
|
||
error:
|
||
message: Missing endpoint
|
||
/api/push/send:
|
||
post:
|
||
tags:
|
||
- Push
|
||
summary: Broadcast a notification to all surfaces
|
||
description: 'Dispatches a notification to every reachable surface at once: it fires a native OS notification via Electron''s main-process Notification API when the server is hosted inside the desktop app, AND sends an encrypted Web Push delivery to every stored subscription. Both legs run unconditionally so whichever surface the user is on receives the alert — under `npm start` the native leg is a no-op, and under the desktop app the Web Push leg is typically a no-op (Electron has no FCM credentials, so `push_subscriptions` is empty). Subscriptions rejected with HTTP 410 (Gone) are pruned from `push_subscriptions` during the request. The response reports `{ native, pushed, failed }` so the caller can tell a real delivery from a silent no-op. No authentication (local-first). A missing `title` or `body` returns 400; an unexpected dispatch error returns 500.'
|
||
operationId: pushSend
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PushSendRequest'
|
||
example:
|
||
title: Session completed
|
||
body: Your Claude Code session finished with 3 subagents.
|
||
responses:
|
||
'200':
|
||
description: Dispatch ran; the body reports which surfaces fired and how many Web Push deliveries succeeded/failed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PushSendResponse'
|
||
example:
|
||
ok: true
|
||
native: false
|
||
pushed: 2
|
||
failed: 1
|
||
'400':
|
||
description: Missing title or body
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/MessageErrorResponse'
|
||
example:
|
||
error:
|
||
message: Missing title or body
|
||
'500':
|
||
description: Dispatch error while broadcasting the notification
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/MessageErrorResponse'
|
||
example:
|
||
error:
|
||
message: Push service unavailable
|
||
/api/sessions/facets:
|
||
get:
|
||
tags:
|
||
- Sessions
|
||
summary: List session facet values
|
||
description: 'Returns the distinct facet values for the Sessions page filters: the non-empty working directories (the `cwd` column, sorted ascending) in `cwds`, and the distinct data-source ids (the `sessions.source` column) in `sources`. `sources` always includes the built-in `local` history plus any configured remote SSH machines. Always returns a 200 with (possibly empty) arrays.'
|
||
operationId: listSessionFacets
|
||
responses:
|
||
'200':
|
||
description: Distinct session working directories and data-source ids
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SessionsFacetsResponse'
|
||
example:
|
||
cwds:
|
||
- /Users/son/WebstormProjects/Claude-Code-Agent-Monitor
|
||
- /Users/son/code/another-project
|
||
sources:
|
||
- local
|
||
- 4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
/api/remote-sources:
|
||
get:
|
||
tags:
|
||
- Remote Sources
|
||
summary: List remote data sources
|
||
description: Returns every configured remote SSH source the dashboard pulls Claude Code history from. NO secrets are ever returned — these records store none (SSH auth defers to the host SSH stack). Each entry carries its last sync `status`, `last_error`, `last_sync_at`, and `last_sync_counts`. Read-only; always 200.
|
||
operationId: listRemoteSources
|
||
responses:
|
||
'200':
|
||
description: All configured remote sources
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RemoteSourceListResponse'
|
||
example:
|
||
sources:
|
||
- id: 4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
label: Work laptop
|
||
host: son@studio.local
|
||
ssh_port: 22
|
||
identity_file: ~/.ssh/id_ed25519
|
||
remote_home: ~/.claude
|
||
enabled: true
|
||
status: ok
|
||
last_error: null
|
||
last_sync_at: '2026-07-22T18:41:55.117Z'
|
||
last_sync_counts:
|
||
imported: 9
|
||
skipped: 41
|
||
backfilled: 0
|
||
errors: 0
|
||
sessions_seen: 50
|
||
sessions_tagged: 50
|
||
created_at: '2026-07-20T09:15:00.000Z'
|
||
updated_at: '2026-07-22T18:41:55.117Z'
|
||
post:
|
||
tags:
|
||
- Remote Sources
|
||
summary: Register a remote data source
|
||
description: 'Registers a remote SSH source. `label` and `host` are required; `host` is an SSH destination (`user@host`) or a `~/.ssh/config` alias. Optional `ssh_port`, `identity_file`, `remote_home`, and `enabled` fine-tune the connection. No credentials are accepted or stored — auth defers to the host SSH stack. Returns the created source (201). Validation failures return 400 `{ error: { code, message } }` with one of the codes INVALID_LABEL, INVALID_HOST, INVALID_PORT, INVALID_IDENTITY_FILE, INVALID_REMOTE_HOME.'
|
||
operationId: createRemoteSource
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RemoteSourceCreateRequest'
|
||
examples:
|
||
minimal:
|
||
summary: Minimal — label + SSH config alias
|
||
value:
|
||
label: Work laptop
|
||
host: studio
|
||
full:
|
||
summary: Full — explicit port, key, and remote home
|
||
value:
|
||
label: Work laptop
|
||
host: son@studio.local
|
||
ssh_port: 22
|
||
identity_file: ~/.ssh/id_ed25519
|
||
remote_home: ~/.claude
|
||
enabled: true
|
||
responses:
|
||
'201':
|
||
description: Remote source created
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RemoteSourceResponse'
|
||
example:
|
||
source:
|
||
id: 4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
label: Work laptop
|
||
host: son@studio.local
|
||
ssh_port: 22
|
||
identity_file: ~/.ssh/id_ed25519
|
||
remote_home: ~/.claude
|
||
enabled: true
|
||
status: idle
|
||
last_error: null
|
||
last_sync_at: null
|
||
last_sync_counts: null
|
||
created_at: '2026-07-22T18:41:55.117Z'
|
||
updated_at: '2026-07-22T18:41:55.117Z'
|
||
'400':
|
||
description: 'Validation error (codes: INVALID_LABEL, INVALID_HOST, INVALID_PORT, INVALID_IDENTITY_FILE, INVALID_REMOTE_HOME).'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
examples:
|
||
label:
|
||
summary: Missing/blank label
|
||
value:
|
||
error:
|
||
code: INVALID_LABEL
|
||
message: '`label` is required'
|
||
host:
|
||
summary: Missing/invalid host
|
||
value:
|
||
error:
|
||
code: INVALID_HOST
|
||
message: '`host` is required'
|
||
port:
|
||
summary: Port out of range
|
||
value:
|
||
error:
|
||
code: INVALID_PORT
|
||
message: '`ssh_port` must be 1–65535'
|
||
/api/remote-sources/{id}:
|
||
patch:
|
||
tags:
|
||
- Remote Sources
|
||
summary: Update a remote data source (partial)
|
||
description: Partially updates a remote source. Only the keys present in the body are changed; omitted keys are left as-is. The same validation as create applies to any field that is present. Returns the updated source, or 404 when the id is unknown.
|
||
operationId: updateRemoteSource
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: Remote source id.
|
||
example: 4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RemoteSourceUpdateRequest'
|
||
examples:
|
||
disable:
|
||
summary: Disable a source without touching anything else
|
||
value:
|
||
enabled: false
|
||
rename:
|
||
summary: Rename and change port
|
||
value:
|
||
label: Studio Mac
|
||
ssh_port: 2222
|
||
responses:
|
||
'200':
|
||
description: Updated remote source
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RemoteSourceResponse'
|
||
example:
|
||
source:
|
||
id: 4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
label: Studio Mac
|
||
host: son@studio.local
|
||
ssh_port: 2222
|
||
identity_file: ~/.ssh/id_ed25519
|
||
remote_home: ~/.claude
|
||
enabled: false
|
||
status: ok
|
||
last_error: null
|
||
last_sync_at: '2026-07-22T18:41:55.117Z'
|
||
last_sync_counts:
|
||
imported: 9
|
||
skipped: 41
|
||
backfilled: 0
|
||
errors: 0
|
||
sessions_seen: 50
|
||
sessions_tagged: 50
|
||
created_at: '2026-07-20T09:15:00.000Z'
|
||
updated_at: '2026-07-22T19:02:10.400Z'
|
||
'400':
|
||
description: 'Validation error (codes: INVALID_LABEL, INVALID_HOST, INVALID_PORT, INVALID_IDENTITY_FILE, INVALID_REMOTE_HOME).'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: INVALID_PORT
|
||
message: '`ssh_port` must be 1–65535'
|
||
'404':
|
||
description: Remote source not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Remote source not found
|
||
delete:
|
||
tags:
|
||
- Remote Sources
|
||
summary: Delete a remote data source
|
||
description: Deletes a remote source. By default its imported sessions are DETACHED — reassigned to the built-in `local` source — so history is preserved. Pass `?purge=true` to instead permanently DELETE that source's imported sessions along with the source. The response reports whether a purge occurred.
|
||
operationId: deleteRemoteSource
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: Remote source id.
|
||
example: 4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
- name: purge
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: boolean
|
||
default: false
|
||
description: When true, also delete this source's imported sessions. When false/omitted, those sessions are reattached to `local`.
|
||
example: true
|
||
responses:
|
||
'200':
|
||
description: Deleted (with the purge outcome)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- ok
|
||
- purged
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
example: true
|
||
purged:
|
||
type: boolean
|
||
description: True when the source's imported sessions were deleted (purge=true); false when they were detached to `local`.
|
||
example: false
|
||
examples:
|
||
detached:
|
||
summary: Default — sessions detached to local
|
||
value:
|
||
ok: true
|
||
purged: false
|
||
purged:
|
||
summary: purge=true — sessions deleted
|
||
value:
|
||
ok: true
|
||
purged: true
|
||
'404':
|
||
description: Remote source not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Remote source not found
|
||
/api/remote-sources/{id}/test:
|
||
post:
|
||
tags:
|
||
- Remote Sources
|
||
summary: Probe SSH connectivity to a remote source
|
||
description: Runs an SSH connectivity probe against the source and reports the outcome synchronously. The `ok` flag carries the probe result and `message` is a human-readable summary; on success `remoteProjects` may list the remote project directories discovered under the remote Claude home. This does not import anything — use POST /{id}/sync to pull.
|
||
operationId: testRemoteSource
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: Remote source id.
|
||
example: 4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
responses:
|
||
'200':
|
||
description: Probe result (ok flag carries the connectivity outcome)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RemoteSourceTestResponse'
|
||
examples:
|
||
success:
|
||
summary: Reachable
|
||
value:
|
||
ok: true
|
||
message: Connected; found 24 project directories under ~/.claude/projects.
|
||
remoteProjects:
|
||
- '-Users-son-code-foo'
|
||
- '-Users-son-code-bar'
|
||
failure:
|
||
summary: Unreachable / auth failed
|
||
value:
|
||
ok: false
|
||
message: 'ssh: connect to host studio.local port 22: Connection refused'
|
||
'404':
|
||
description: Remote source not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Remote source not found
|
||
/api/remote-sources/{id}/sync:
|
||
post:
|
||
tags:
|
||
- Remote Sources
|
||
summary: Pull Claude Code history from a remote source now
|
||
description: Triggers an immediate pull of Claude Code history from the remote source over SSH, importing new transcripts through the same idempotent, baseline-preserving pipeline used for local imports and tagging imported sessions with this source's id. The response reports the per-run counters. Sync progress/completion is also broadcast over the WebSocket as `remote_source.status` frames.
|
||
operationId: syncRemoteSource
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: Remote source id.
|
||
example: 4d1f0e2a-7b9c-4c33-8a21-9e0f7b6d4c11
|
||
responses:
|
||
'200':
|
||
description: Sync result
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/RemoteSourceSyncResponse'
|
||
example:
|
||
ok: true
|
||
imported: 9
|
||
skipped: 41
|
||
backfilled: 0
|
||
errors: 0
|
||
sessions_seen: 50
|
||
sessions_tagged: 50
|
||
'404':
|
||
description: Remote source not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: NOT_FOUND
|
||
message: Remote source not found
|
||
'500':
|
||
description: Sync failed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: SYNC_FAILED
|
||
message: ssh exited with code 255
|
||
/api/remote-sources/sync-all:
|
||
post:
|
||
tags:
|
||
- Remote Sources
|
||
summary: Sync all enabled remote sources now
|
||
description: Pulls Claude Code history from every enabled remote source over SSH, sequentially (one connection at a time). Per-source failures are isolated — one unreachable source never aborts the others — and each outcome is returned in `results`. Progress/completion is also broadcast over the WebSocket as `remote_source.status` frames. Always returns 200.
|
||
operationId: syncAllRemoteSources
|
||
responses:
|
||
'200':
|
||
description: Per-source sync outcomes
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
ok:
|
||
type: boolean
|
||
synced:
|
||
type: integer
|
||
description: Number of enabled sources that were attempted.
|
||
results:
|
||
type: array
|
||
items:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: string
|
||
ok:
|
||
type: boolean
|
||
error:
|
||
type: string
|
||
example:
|
||
ok: true
|
||
synced: 2
|
||
results:
|
||
- id: src_a
|
||
ok: true
|
||
/api/settings/claude-home:
|
||
get:
|
||
tags:
|
||
- Settings
|
||
summary: Get the active Claude Code home directory
|
||
description: Returns the Claude Code home directory the dashboard uses to locate transcripts and settings. Resolves to the CLAUDE_HOME environment variable when set, otherwise `<homedir>/.claude`. Always returns 200.
|
||
operationId: getClaudeHome
|
||
responses:
|
||
'200':
|
||
description: Current Claude Code home directory
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SettingsClaudeHomeResponse'
|
||
example:
|
||
claude_home: /Users/son/.claude
|
||
put:
|
||
tags:
|
||
- Settings
|
||
summary: Update the Claude Code home directory
|
||
description: Changes the Claude Code home directory used for transcript/settings discovery. A leading `~/` in `path` is expanded to the OS home directory; the resolved value must be an absolute path that exists and is a directory. On success the new value is applied to process.env immediately (so subsequent reads use it) and persisted to the project `.env` file. Returns 400 INVALID_PATH when `path` is missing/not a string, or when the resolved path is not absolute, does not exist, or is not a directory.
|
||
operationId: updateClaudeHome
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SettingsClaudeHomeUpdateRequest'
|
||
example:
|
||
path: ~/.codefuse/engine/cc
|
||
responses:
|
||
'200':
|
||
description: Claude Code home updated
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SettingsClaudeHomeUpdateResponse'
|
||
example:
|
||
ok: true
|
||
claude_home: /Users/son/.codefuse/engine/cc
|
||
'400':
|
||
description: Invalid path — `path` missing or not a string, or the resolved path is not absolute / does not exist / is not a directory (code INVALID_PATH).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: INVALID_PATH
|
||
message: 'Directory does not exist: /Users/son/.codefuse/engine/cc'
|
||
/api/workflows/runs:
|
||
get:
|
||
tags:
|
||
- Workflows
|
||
summary: List Workflow-tool runs
|
||
description: Returns a paginated list of Workflow-tool runs (fleets of sub-agents spawned by the Claude Code 'Workflow' tool / self-paced /loop), newest first. Filter by `status` (the literal `all` is treated as no filter) or by `session_id`; `session_id` takes precedence over `status` when both are supplied. `counts` is always the whole-table breakdown by status. JSON-blob columns (`phases`, `progress`) are parsed into arrays in each run.
|
||
operationId: listWorkflowRuns
|
||
parameters:
|
||
- name: limit
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
maximum: 1000
|
||
default: 50
|
||
description: Page size, clamped to 1–1000 (default 50).
|
||
- name: offset
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
minimum: 0
|
||
default: 0
|
||
description: Pagination offset (clamped to >= 0).
|
||
- name: status
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Filter by run status (open string, e.g. running | completed | error | failed). The literal value `all` is treated as no filter.
|
||
- name: session_id
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
description: Filter to runs launched by this session. Takes precedence over `status` when both are provided.
|
||
responses:
|
||
'200':
|
||
description: Paginated list of workflow runs with status counts
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/WorkflowRunsListResponse'
|
||
example:
|
||
runs:
|
||
- run_id: wf_a1b2c3d4
|
||
session_id: 5f3c0e2a-1b9d-4c77-8a21-9e0f7b6d4c11
|
||
task_id: ISSUE-167
|
||
name: Refactor pricing engine
|
||
status: completed
|
||
default_model: claude-opus-4-8
|
||
started_at: '2026-06-25T18:04:11.122Z'
|
||
ended_at: '2026-06-25T18:09:47.530Z'
|
||
duration_ms: 336408
|
||
agent_count: 6
|
||
total_tokens: 1284750
|
||
total_tool_calls: 412
|
||
phases:
|
||
- name: plan
|
||
status: completed
|
||
progress:
|
||
- step: 1
|
||
label: scaffold
|
||
done: true
|
||
script_path: null
|
||
journal_path: /Users/son/.claude/projects/-Users-son-code/5f3c0e2a/workflows/wf_a1b2c3d4.json
|
||
source: journal
|
||
created_at: '2026-06-25T18:09:48.001Z'
|
||
updated_at: '2026-06-25T18:09:48.001Z'
|
||
total: 42
|
||
counts:
|
||
completed: 30
|
||
error: 5
|
||
running: 7
|
||
limit: 50
|
||
offset: 0
|
||
'500':
|
||
description: Failed to list workflow runs (code WORKFLOW_LIST_FAILED).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: WORKFLOW_LIST_FAILED
|
||
message: 'no such table: workflows'
|
||
/api/workflows/runs/{runId}:
|
||
get:
|
||
tags:
|
||
- Workflows
|
||
summary: Get a Workflow-tool run with its agents and events
|
||
description: Returns one Workflow-tool run (by `run_id`) together with its linked inner agents and the events attributed to those agents (chronological, capped at 5000 rows). The run's JSON-blob columns (`phases`, `progress`) are parsed into arrays. Returns 404 WORKFLOW_NOT_FOUND when no run matches the id.
|
||
operationId: getWorkflowRun
|
||
parameters:
|
||
- name: runId
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: The workflow run id (workflows.run_id).
|
||
responses:
|
||
'200':
|
||
description: Workflow run with inner agents and their events
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/WorkflowRunDetailResponse'
|
||
example:
|
||
workflow:
|
||
run_id: wf_a1b2c3d4
|
||
session_id: 5f3c0e2a-1b9d-4c77-8a21-9e0f7b6d4c11
|
||
task_id: ISSUE-167
|
||
name: Refactor pricing engine
|
||
status: completed
|
||
default_model: claude-opus-4-8
|
||
started_at: '2026-06-25T18:04:11.122Z'
|
||
ended_at: '2026-06-25T18:09:47.530Z'
|
||
duration_ms: 336408
|
||
agent_count: 6
|
||
total_tokens: 1284750
|
||
total_tool_calls: 412
|
||
phases:
|
||
- name: plan
|
||
status: completed
|
||
progress:
|
||
- step: 1
|
||
label: scaffold
|
||
done: true
|
||
script_path: null
|
||
journal_path: /Users/son/.claude/projects/-Users-son-code/5f3c0e2a/workflows/wf_a1b2c3d4.json
|
||
source: journal
|
||
created_at: '2026-06-25T18:09:48.001Z'
|
||
updated_at: '2026-06-25T18:09:48.001Z'
|
||
agents:
|
||
- id: agent-7f1c
|
||
session_id: 5f3c0e2a-1b9d-4c77-8a21-9e0f7b6d4c11
|
||
name: implementer
|
||
type: subagent
|
||
subagent_type: general-purpose
|
||
status: completed
|
||
task: Implement pricing changes
|
||
current_tool: null
|
||
started_at: '2026-06-25T18:04:30.000Z'
|
||
ended_at: '2026-06-25T18:08:12.000Z'
|
||
parent_agent_id: null
|
||
metadata: null
|
||
updated_at: '2026-06-25T18:08:12.000Z'
|
||
awaiting_input_since: null
|
||
awaiting_reason: null
|
||
events:
|
||
- id: 90211
|
||
session_id: 5f3c0e2a-1b9d-4c77-8a21-9e0f7b6d4c11
|
||
agent_id: agent-7f1c
|
||
event_type: PostToolUse
|
||
tool_name: Edit
|
||
summary: Edited server/routes/pricing.js
|
||
data: null
|
||
created_at: '2026-06-25T18:05:02.144Z'
|
||
'404':
|
||
description: No workflow run matches the id (code WORKFLOW_NOT_FOUND).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: WORKFLOW_NOT_FOUND
|
||
message: Workflow run not found
|
||
'500':
|
||
description: Failed to load workflow run detail (code WORKFLOW_DETAIL_FAILED).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
error:
|
||
code: WORKFLOW_DETAIL_FAILED
|
||
message: database is locked
|
||
/api/settings/import:
|
||
post:
|
||
tags:
|
||
- Settings
|
||
summary: Restore (import) a previously exported data bundle
|
||
description: 'Restores a bundle produced by GET /api/settings/export. Supply it either as `multipart/form-data` with a single `file` field (browser upload) or as a JSON body `{ "path": "<absolute path>" }` (the server reads the file from disk — used by the `ccam import-data` CLI, and it also sidesteps the global 1 MB JSON body cap for large bundles). The restore is idempotent and NON-DESTRUCTIVE: it is session-atomic, so a session already present (matched by its UUID) is skipped whole together with its agents/events/token_usage/workflows, and independent config rows (dashboard_runs, alert_rules, model_pricing) are inserted only when absent. Nothing existing is overwritten — ideal for consolidating several machines into one dashboard. The response reports per-table counts.'
|
||
operationId: importData
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
multipart/form-data:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
file:
|
||
type: string
|
||
format: binary
|
||
description: The export .json file.
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- path
|
||
properties:
|
||
path:
|
||
type: string
|
||
description: Absolute path (server-side) to an export .json file. `~` is expanded.
|
||
example:
|
||
path: /Users/you/ccam-export-2026-06-26.json
|
||
responses:
|
||
'200':
|
||
description: Per-table restore counts
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ImportResponse'
|
||
example:
|
||
ok: true
|
||
source: agent-monitor-export-2026-06-26.json
|
||
format: ccam-export
|
||
sessions_imported: 42
|
||
sessions_skipped: 3
|
||
agents: 96
|
||
events: 5120
|
||
token_usage: 42
|
||
workflows: 4
|
||
dashboard_runs: 11
|
||
alert_rules: 2
|
||
model_pricing: 0
|
||
errors: 0
|
||
'400':
|
||
description: Missing file, invalid JSON, or unrecognized export format
|
||
x-issues-url: https://git.smartgift.io.vn/Smartgift-AI/Claude-Code-Monitor/issues
|