Skip to content

Latest commit

 

History

History
102 lines (80 loc) · 5.89 KB

data-model.md

File metadata and controls

102 lines (80 loc) · 5.89 KB

Data Model

Reference for the entry summary objects broadcast from server to dashboard via SSE, and persisted to ~/.ccxray/logs/index.ndjson.

For the aggregated schema that ccxray usage --json derives from these entries, see usage.md.

Entry summary

Produced by server/sse-broadcast.js summarizeEntry(). The full request/response payloads are NOT included — they live on disk and are lazy-loaded when a turn is selected.

Core identity

Field Type Description
id string Turn ID, format YYYY-MM-DDTHH-MM-SS-mmm
ts number Unix ms, when proxy first received the request
receivedAt number | null Alias of ts retained for client-side gap timing
sessionId string Session ID (from request metadata.user_id, or inferred)
parentSessionId string | null Parent conversation for a distinct child session. Persisted when known so child attribution survives restart
sessionInferred boolean true if session was attributed by inference (no explicit ID)
method string HTTP method (always POST for /v1/messages)
url string Request path
cwd string | null Working dir extracted from system prompt
branch string | undefined Git branch checked out in cwd when the turn was recorded (live proxy: read from .git/HEAD, following a linked worktree's gitdir: file, cached per cwd for 5 s; import: the transcript's own branch field). Omitted outside a git checkout, for an unknown cwd, and on a detached HEAD. Never back-filled by rebuild-index
isSubagent boolean Provider-aware classification that this turn belongs to a subagent execution lane

Request shape

Field Type Description
model string | null Model ID from request body (e.g., claude-opus-4-6)
msgCount number Length of messages[]
toolCount number Length of tools[]
toolCalls object { toolName: count } — tool_use blocks across messages
skillCalls object { skillName: count } — Skill tool calls by invoked skill (Anthropic only; absent on older entries). Read by ccxray usage for per-skill stats

Response outcome

Field Type Description
status number HTTP status code
elapsed string Seconds as 1-decimal string (e.g., "4.3")
isSSE boolean true if upstream response was streaming
stopReason string API stop_reason (end_turn | tool_use | max_tokens | …)
title string | null Turn description. Cascade: response text → last user text → tool-result summary (↩ ToolA · ToolB) → subagent's first user text
thinkingDuration number | null Extended-thinking seconds if captured from SSE

Usage & cost

Field Type Description
usage object | null { input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens }
cost object | null { cost, inputCost, outputCost, cacheReadCost, cacheWriteCost }
maxContext number Model context window (200K / 1M based on [1m] suffix in system prompt)
tokens object | null { system, tools, messages, total, contextBreakdown, perMessage } — structural breakdown from tokenizeRequest

Risk signals

Field Type Description
toolFail boolean At least one tool_result in the request had is_error: true
duplicateToolCalls object | null { toolName: extraCount } — repeated tool_use with same input
hasCredential boolean | undefined Credential pattern (API key, SSH key, etc.) detected in response or messages
toolSources object | undefined { tool_use_id: 'network' | 'local' | 'local:sensitive' } — taint classification

Backward compatibility

Older index.ndjson entries may lack newer fields. Consumers SHOULD use nullish-coalescing defaults:

const toolFail = entry.toolFail ?? false;
const duplicateToolCalls = entry.duplicateToolCalls ?? null;
const hasCredential = entry.hasCredential ?? false;
const parentSessionId = entry.parentSessionId ?? null;
const branch = entry.branch ?? null;

Session index row (sessions.json, GET /_api/sessions)

Derived by server/session-index.js from the entries above; rebuildable from index.ndjson. Selected fields:

Field Type Description
cwd string | null Last non-empty entry cwd
branch string | undefined Branch of the latest-received turn that recorded one (a session may switch branches; per-turn branch is the exact record). A turn without a branch never clears it; an older turn fed later (rebuild/import order) never rolls it back. Absent when no turn recorded a branch
firstPrompt string | null First 200 chars of the first user prompt, with injected tags (<system-reminder>, …) stripped. Taken from the first user text block that is non-empty after stripping

Where fields are computed

Field Source file
usage, cost server/pricing.js
maxContext server/config.js getMaxContext()
title server/forward.js title cascade using server/helpers.js extractors
tokens server/helpers.js tokenizeRequest()
toolCalls, duplicateToolCalls server/helpers.js extractToolCalls() / extractDuplicateToolCalls()
skillCalls server/helpers.js extractSkillCalls()
toolFail server/helpers.js hasToolFail()
hasCredential server/helpers.js entryHasCredential()
toolSources server/helpers.js buildToolSources()
isSubagent, cwd, parentSessionId provider parsers plus server/store.js session attribution
branch server/git-branch.js resolveGitBranch() via the provider parsers; server/importer.js for imported turns