Skip to content

feat(claude-code): local Claude Code connector with full agent traces - #25

Open
volod-vana wants to merge 1 commit into
mainfrom
volod/claude-code-trajectories
Open

feat(claude-code): local Claude Code connector with full agent traces#25
volod-vana wants to merge 1 commit into
mainfrom
volod/claude-code-trajectories

Conversation

@volod-vana

Copy link
Copy Markdown
Contributor

Why

A buyer conversation (Semo AI) asked for agent trajectories — the action-observation loop of real runs — not chat transcripts. Claude Code already writes exactly that to ~/.claude/projects/*.jsonl. This publishes the local Claude Code connector and adds the scope that carries it.

claude_code.sessions deliberately carries only the shape of a run (turn counts, models, timing). claude_code.trajectories carries the bodies.

Scopes

Scope What
claude_code.usage aggregate tokens, cost, day/hour activity
claude_code.sessions per-session metadata, no bodies; now also lists subagent runs linked to their parent
claude_code.prompts typed prompt history
claude_code.trajectories new — prompts, assistant reasoning and replies, every tool call with its input, every tool result with its output, in order

Tool calls and results are linked by callId, so a consumer can rebuild the loop without reparsing the transcript. Steps carry role, type, at, model, and sidechain.

Why a separate scope: these payloads contain source code, file paths and command output from the machine. Its own scope lets a user grant the cheap metadata without ever granting the transcript, and lets a host gate the two differently.

Safety rails on the trajectory scope

  • Redaction before export: Anthropic/OpenAI keys, GitHub tokens and PATs, Slack, AWS, Google, JWTs, bearer tokens, PEM private-key blocks, 0x+64-hex, and SECRET/TOKEN/PASSWORD-style assignments. The count is reported by type; the matched text never is.
  • Per-step cap CLAUDE_CODE_MAX_STEP_CHARS (default 8000), each cut body marks itself truncated with its original length.
  • Whole-scope budget CLAUDE_CODE_MAX_MB (default 24), newest sessions first.
  • Both caps surface as degraded honest-telemetry errors, so a capped export can never be mistaken for a complete one.

Redaction is best-effort pattern matching, not a de-identification pipeline. It is the floor, not the guarantee. Anything sold or shared still needs a real privacy pass.

Two fixes that came out of building it

  • Subagent traces were invisible. The old walk only looked at <project>/<sessionId>.jsonl and missed <session>/subagents/agent-*.jsonl. On my machine that was 144 of 310 traces. The walk now recurses and tags each transcript with kind and parentSessionId.
  • The result envelope was not conformant. It shipped no requestedScopes, no errors array, and a string exportSummary.details. Now it satisfies validate-honest-telemetry-conformance, and scopes are gated on requestedScopes so a host asking for metadata alone never pays to build traces.
  • schemas/scope-catalog.schema.json only accepted *-playwright.json in its provenance list. The manifest schema has always allowed runtime: vanilla, so the filename pattern was the stale half.

Verification (real run, this machine)

node run-connector.cjs connectors/anthropic/claude-code-local.js --runner-dir <desktop runner>

  • 310 sessions (166 main + 144 subagent), 26,036 trace steps, 10,354 tool calls
  • 1,539 redactions (secret_assignment 1077, hex_secret 429, bearer 16, jwt 10, anthropic_key 3, github_token 2, google_key 2)
  • 24 MB at the default budget; 217 older sessions skipped and 358 bodies truncated, both reported as degraded
  • classified partial, scopeSummary: {requested: 4, produced: 4, degraded: 1, omitted: 0}
  • tool mix: Bash 6674, Edit 970, Read 879, MCP browser 329, Write 193
  • all four payloads validate against their published schemas (ajv)

Checks: unit tests 15/15, claude-export-ingest 5/5, validate-manifests 20 manifests 0 errors, check-source-id-stability, scope-catalog:check, check-additive-schemas (51), check-page-api-additive all clean.

Known trade-off

hex_secret redacts any 0x + 64 hex, which also catches transaction hashes and data-point ids. It fires often on Vana work (429 hits here). I kept it fail-safe — a raw private key has the same shape — and the tally makes the cost visible. Easy to narrow to context-matched hits if reviewers prefer.

Not in this PR

  • No connector-index artifact or signing; this is the source change only.
  • No opencode connector yet. Same shape of work, different store — worth a follow-up if we want coverage across coding agents (that is also where GLM trajectories would come from, since GLM has no account to connect to).

https://claude.ai/code/session_012ZQPAhPHFaF3fmmxUNHma8

Publishes the local Claude Code connector (previously only on my machine)
and adds the scope this was built for: `claude_code.trajectories`, the
full step-by-step trace of each session.

Semo AI (and buyers like them) want agent trajectories, not chat: the
action-observation loop of a real run. Claude Code already writes exactly
that to ~/.claude/projects/*.jsonl. `claude_code.sessions` deliberately
carries only the shape of a run; the new scope carries the bodies.

Scopes
- claude_code.usage        aggregate tokens, cost, activity (unchanged)
- claude_code.sessions     per-session metadata, no bodies (unchanged shape,
                           now also lists subagent runs, linked to their parent)
- claude_code.prompts      typed prompt history (unchanged, now redacted)
- claude_code.trajectories NEW: prompts, assistant reasoning and replies,
                           every tool call with its input, every tool result
                           with its output, in order. Calls and results are
                           linked by callId so the loop can be rebuilt without
                           reparsing the transcript.

Why it is a separate scope: these payloads contain source code, file paths
and command output from the machine. Its own scope means a user can grant the
cheap metadata without ever granting the transcript, and a host can gate the
two differently.

Safety rails
- credential-shaped strings are redacted before export (Anthropic/OpenAI keys,
  GitHub tokens/PATs, Slack, AWS, Google, JWTs, bearer tokens, PEM blocks,
  0x64-hex, and SECRET/TOKEN/PASSWORD-style assignments); the count is
  reported by type, the matched text never is
- per-step bodies capped (CLAUDE_CODE_MAX_STEP_CHARS, default 8000)
- whole-scope payload budget (CLAUDE_CODE_MAX_MB, default 24), newest first
- both caps surface as `degraded` honest-telemetry errors, so a capped export
  can never be mistaken for a complete one
Redaction is best-effort pattern matching, not de-identification. It is the
floor, not the guarantee.

Also in this change
- subagent transcripts (`<session>/subagents/agent-*.jsonl`) were invisible to
  the old single-level walk. On my machine that was 144 of 310 traces. The walk
  now recurses and tags each transcript with `kind` and `parentSessionId`.
- the result envelope now satisfies the honest-telemetry contract it never did
  before: `requestedScopes`, an `errors` array, and an object-shaped
  `exportSummary.details`. Scopes are also gated on requestedScopes, so a host
  asking for metadata alone never pays to build traces.
- schemas/scope-catalog.schema.json only accepted `*-playwright.json`
  manifests in its provenance list. The manifest schema has always allowed
  `runtime: vanilla`, so the filename pattern was the stale half.

Verified end to end on this machine through the real runner
(`node run-connector.cjs connectors/anthropic/claude-code-local.js`):
310 sessions (166 main + 144 subagent), 26,036 trace steps, 10,354 tool calls,
1,539 redactions, 24 MB at the default budget, classified `partial` with the
budget and truncation reported as degraded. All four payloads validate against
their published schemas. Unit tests 15/15; manifest, source-id-stability,
scope-catalog, additive-schema and page-api checks clean.

Claude-Session: https://claude.ai/code/session_012ZQPAhPHFaF3fmmxUNHma8
@github-actions

Copy link
Copy Markdown

Schema Health Check — All Clear

All 54 scopes have consistent local schema files.

@volod-vana
volod-vana marked this pull request as ready for review July 31, 2026 05:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant