Skip to content

feat: local observability — token capture + cost tracking#618

Merged
kokevidaurre merged 1 commit intodevelopfrom
feat/observability
Mar 26, 2026
Merged

feat: local observability — token capture + cost tracking#618
kokevidaurre merged 1 commit intodevelopfrom
feat/observability

Conversation

@kokevidaurre
Copy link
Contributor

Summary

Every squads run now logs execution data with real token/cost capture:

  • Token capture — parses Claude Code's session JSONL files after each run to get actual input/output/cache tokens
  • Cost calculation — model-aware pricing (Opus, Sonnet, Haiku rates)
  • JSONL log — appends to .agents/observability/executions.jsonl
  • Commandssquads obs history and squads obs cost

Tested

squads obs history
  pass  company/company-lead    2m  4,709 tok  $0.386  claude-sonnet-4-6
  pass  research/research-scanner  5m  5,976 tok  $0.503  claude-sonnet-4-6

squads obs cost --period today
  Total: $0.89 across 2 runs
  By Squad: research $0.50, company $0.39
  By Model: claude-sonnet-4-6 $0.89

Test plan

  • Token capture works (verified with real run)
  • Cost calculation matches model pricing
  • obs history shows records with filters
  • obs cost shows per-squad and per-model breakdowns
  • Build passes CI

🤖 Generated with Claude Code

Every squads run now logs to .agents/observability/executions.jsonl:
- Tokens (input, output, cache read, cache write)
- Cost in USD (calculated from model pricing table)
- Duration, status, squad, agent, model, trigger

Token capture: after each run, parses Claude Code's session JSONL
files (~/.claude/projects/) to extract actual usage data. No API
calls, no external dependencies.

New commands:
- squads obs history — execution history with tokens and cost
- squads obs cost — spend summary by squad, model, time period

Tested: research-scanner run captured 5,976 tokens, $0.503 on
claude-sonnet-4-6. Cost summary shows per-squad breakdown.

Co-Authored-By: Claude <noreply@anthropic.com>
@kokevidaurre kokevidaurre merged commit 4fb4245 into develop Mar 26, 2026
11 checks passed
@kokevidaurre kokevidaurre deleted the feat/observability branch March 26, 2026 17:09
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a local observability system that logs execution history and token costs to a JSONL file. It includes new CLI commands for viewing history and cost summaries, as well as logic to capture usage data from Claude Code session files. The review feedback highlights several areas for improvement: using a more robust method for retrieving the user's home directory to ensure cross-platform compatibility, reducing code duplication when logging observability records, and avoiding empty catch blocks that swallow errors and hinder debugging.

* Claude Code writes sessions to ~/.claude/projects/<hash>/*.jsonl
*/
function findRecentSessionFile(afterTimestamp: number): string | null {
const home = process.env.HOME || '';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

process.env.HOME is not a reliable way to get the user's home directory, especially on Windows. Please use os.homedir() for cross-platform compatibility.

You will need to add import { homedir } from 'os'; at the top of the file.

Suggested change
const home = process.env.HOME || '';
const home = homedir();

Comment on lines +514 to +527
logObservability({
ts: new Date().toISOString(),
id: config.execContext.executionId,
squad: config.squadName,
agent: config.agentName,
provider: config.provider || 'anthropic',
model: 'unknown',
trigger: (config.execContext.trigger || 'manual') as ObservabilityRecord['trigger'],
status: 'failed',
duration_ms: durationMs,
input_tokens: 0, output_tokens: 0, cache_read_tokens: 0, cache_write_tokens: 0,
cost_usd: 0, context_tokens: 0,
error: String(err),
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There's significant code duplication between this on('error') handler and the on('close') handler (lines 467-484) for creating the ObservabilityRecord. This can make maintenance harder, as changes might need to be applied in two places.

Consider creating a helper function to construct and log the ObservabilityRecord. This function could take parameters like status, error, and session usage to handle both success and failure cases, reducing duplication and centralizing the logic.

} catch { continue; }
}
}
} catch { /* projects dir read error */ }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This empty catch block silently swallows all errors that might occur when reading the projects directory (e.g., permission errors). This can make debugging very difficult.

Consider logging the error, at least as a warning, to provide visibility into potential issues with the environment setup. This also applies to the other empty catch blocks in this function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant