Skip to main content

performance-metrics

Log task completion data to .claude/metrics/. Use at the end of every task to record tokens, cost, agents used, rework cycles, and hallucination events. Also use for periodic reporting to identify efficiency and quality trends.

Source facts

Repository
bdfinst/agentic-dev-team
Last source activity
August 24, 2026 at 16:39
Detected SKILL.md language
English
Stars
299
Forks
36

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
performance-metrics
description
Log task completion data to .claude/metrics/. Use at the end of every task to record tokens, cost, agents used, rework cycles, and hallucination events. Also use for periodic reporting to identify efficiency and quality trends.
role
worker
user-invocable
true
# Performance Metrics ## Overview Schema and procedures for capturing performance data in `.claude/metrics/`. Metrics enable evidence-based evaluation of agent effectiveness, cost efficiency, and quality outcomes. ## Constraints - Never log credentials, API keys, or PII in metric entries - Log entries are append-only; do not modify or delete existing JSONL records - Log at task completion, not mid-task; mid-task state belongs in `.claude/memory/` progress files - Use the defined JSONL schema; do not invent new top-level fields without updating the reference ## Metric Categories > **Targets discipline.** Per CLAUDE.md → "Claims discipline", a numeric target > may only ship if an instrument measures it. The instrumented metrics below cite > their sensor; the rest read "Aspirational — no sensor yet" until one exists > (tracked by #102 cost metering and #106 telemetry). Do not reintroduce bare > numeric targets — `tests/docs/prose_honesty_test.bats` enforces this across all > shipped prose. ### Efficiency Metrics | Metric | Description | Target | | --- | --- | --- | | Task completion time | Wall-clock time from request to delivery | Track trend, no fixed target | | Token usage per task | Total input + output tokens consumed | Minimize for comparable quality | | Agent loading overhead | Tokens spent on agent/skill file reads | Aspirational — no sensor yet | | Context summarization frequency | How often summarization triggers per task | Aspirational — no sensor yet | ### Quality Metrics | Metric | Description | Target | | --- | --- | --- | | First-pass acceptance rate | Tasks accepted without rework | Aspirational — no sensor yet | | Rework count | Number of revision cycles per task | Aspirational — no sensor yet | | Hallucination incidents | Outputs containing fabricated information | Aspirational — no sensor yet | | Accuracy score | Correctness of structured data extraction | Aspirational — no sensor yet | | Test coverage | Percentage of code covered by generated tests | Track per project | ### Cost Metrics | Metric | Description | Target | | --- | --- | --- | | Cost per task | Total API cost (input + output tokens at rate) | Track trend | | LLM routing ratio | Percentage of tasks routed to each LLM | Track distribution | | Selective loading savings | Tokens saved vs. loading all agents | Aspirational — no sensor yet | ## Log Format Metrics are stored in `.claude/metrics/` as JSONL files (one JSON object per line). ### File Naming ``` .claude/metrics/{date}-task-log.jsonl ``` Example: `.claude/metrics/2026-02-20-task-log.jsonl` ### Task Completion Entry Logged at the end of each task: ```json { "timestamp": "2026-02-20T14:30:00Z", "task_id": "unique-id", "task_type": "implementation", "task_description": "Build REST API for user authentication", "agents_used": ["software-engineer", "architect"], "skills_used": ["hexagonal-architecture"], "tokens": { "input": 12500, "output": 3200, "total": 15700 }, "cost_usd": 0.043, "llm": "opus", "handoffs": 0, "phases": 2, "rework_cycles": 1, "accepted": true, "hallucination_detected": false, "duration_seconds": 180 } ``` ### Field Reference | Field | Type | Description | | --- | --- | --- | | `timestamp` | string | ISO 8601 completion time | | `task_id` | string | Unique identifier for this task | | `task_type` | string | `implementation`, `design`, `bugfix`, `testing`, `documentation`, `analysis` | | `task_description` | string | Brief description of the task | | `agents_used` | string[] | Agent names that were loaded | | `skills_used` | string[] | Skill names that were loaded | | `tokens.input` | number | Input tokens from API usage field | | `tokens.output` | number | Output tokens from API usage field | | `tokens.total` | number | Sum of input + output | | `cost_usd` | number | Estimated cost based on token rates | | `llm` | string | Model ID used | | `handoffs` | number | Times the handoff skill was triggered (either mode) | | `phases` | number | Number of loading phases | | `rework_cycles` | number | Number of revision cycles | | `accepted` | boolean | Whether the user accepted the output | | `hallucination_detected` | boolean | Whether a hallucination was flagged | | `duration_seconds` | number | Wall-clock seconds from start to delivery | ### Cost Metering Entry (#102, #1094) The `Stop`/`SubagentStop` hook (`hooks/cost_meter.py` → `hooks/lib/cost_meter.py record`) appends one entry per fire to `.claude/metrics/cost-metering.jsonl` — the running per-session token/cost summary parsed from the transcript. Full schema reference: `knowledge/telemetry-schema.md`. ```json { "timestamp": "2026-07-18T14:30:00Z", "transcript": "session.jsonl", "total": {"input_tokens": 18000, "output_tokens": 3500, "cost_usd": 0.16, "messages": 12}, "by_model": {"<model-id>": {"cost_usd": 0.16, "input_tokens": 18000, "output_tokens": 3500}}, "by_thread": {"main": {"cost_usd": 0.10, "input_tokens": 10000, "output_tokens": 2000}, "subagent": {"cost_usd": 0.06, "input_tokens": 8000, "output_tokens": 1500}}, "by_agent_type": {"main": {"cost_usd": 0.10, "input_tokens": 10000, "output_tokens": 2000}, "security-review": {"cost_usd": 0.06, "input_tokens": 8000, "output_tokens": 1500}} } ``` | Field | Type | Description | | --- | --- | --- | | `total` | object | Session-cumulative token counts, `cost_usd`, `messages` | | `by_model` | object | Per-model slim breakdown (`cost_usd`, `input_tokens`, `output_tokens`) | | `by_thread` | object | `main` vs `subagent`, from the native `isSidechain` flag | | `by_agent_type` | object | `main` for main-loop turns; sidechain turns keyed by subagent type via the harness-recorded `attributionAgent` field or the Task-dispatch `subagent_type`/`agentId` join; unmappable sidechain spend lands in `unattributed` (#1094) | **Privacy:** token counts, dollar amounts, model identifiers, and thread/ agent-type identifiers only — never prompt text, code, file paths, or tool payloads. Attribution reads only fields the Claude Code harness itself writes to the transcript; the meter never guesses (see #170 for the buckets removed because the harness records no signal for them). Disable with `DEV_TEAM_COST_METER=off`. Report it with `/cost-report`. ### Review Value Entry (#348) `/build` appends one entry per **inline review checkpoint** to `.claude/metrics/review-value.jsonl` so the pipeline's review overhead becomes *measurable* — distinguishing a build where review caught and fixed a real defect from one where every loop passed no-op. This is the sensor that lets the plan/step tiering (the `/plan` plan-tier and `/build` per-step complexity routing) be right-sized with evidence rather than guessed. ```json { "timestamp": "2026-06-22T14:30:00Z", "plan": "plans/add-auth.md", "slice": "2", "step": "all", "checkpoint": "slice", "complexity": "standard", "source": "build-checkpoint", "agents_run": ["spec-compliance-review", "security-review"], "issues_found": 1, "severity_breakdown": {"errors": 1, "warnings": 0, "suggestions": 0}, "issues_fixed": 1, "fix_iterations": 1, "outcome": "fixed" } ``` | Field | Type | Description | | --- | --- | --- | | `checkpoint` | string | `step` (per-step `complex` review), `slice` (batched slice-boundary review), or `backstop` (the Step-6 backstop pass, #1962) | | `source` | string | Row provenance — `build-checkpoint` (fix-applying `/build` inline checkpoint, the default when absent), `build-backstop` (fix-applying `/build` Step-6 backstop, #1962), or `code-review` (read-only standalone review). `/harness-audit` Step 4 excludes `code-review` rows from fix-rate drop-candidate logic (#1257); `build-backstop` rows are fix-applying and stay in it, and additionally drive the backstop-redundancy readout that gates `--backstop-review=skip` | | `outcome` | string | `no-op`, `fixed`, `escalated`, or — backstop rows only — `skipped` when `--backstop-review=skip` suppressed the pass. A `skipped` row records the suppression and is excluded from every rate (#1962) | | `diff_shape` | string | `test-only` or `mixed`, from `change_shape.py`'s `isTestOnly` (never eyeballed). Splits per-lens outcomes by diff shape so a test-only lens gate can be justified by measurement rather than intuition (#1964) | | `step` | string | `N.M` for a per-step checkpoint; `all` for a batched slice checkpoint | | `agents_run` | string[] | Review agents and static-analysis lane tools run at this checkpoint | | `issues_found` | number | Actionable issues the checkpoint surfaced (semantic review + static lanes) | | `severity_breakdown` | object | `{errors, warnings, suggestions}` counts (same enum as `/code-review`); the three sum to `issues_found`. Lets `/harness-audit` Step 3 flag low-value (mostly-minor) lenses (#1256) | | `issues_fixed` | number | Of those, how many were auto-fixed | | `fix_iterations` | number | Review-fix and static self-heal fix-loop iterations consumed | | `outcome` | string | `no-op` (passed clean), `fixed` (found + fixed), `escalated` (a fix loop didn't converge — including a static lane capping out) | **Privacy:** counts and outcomes only — never prompt text, code, or file content, consistent with the cost meter's privacy boundary. Disable with `DEV_TEAM_REVIEW_VALUE=off`. Report it with `/cost-report` (its "review value" section). ### Verify Log Entry (#727) `/build` appends one entry per **slice with a runtime surface** to `metrics/verify-log.jsonl` (sub-step 4.9) — evidence that the project's own test/verification tooling actually exercised the change end-to-end before the slice was marked done, or was explicitly skipped because the diff had no runtime surface to drive. This is the sensor that closes the gap the #727 investigation found: a "done" feature that fails the first time it's really run means runtime verification was either skipped or never mandated in the first place. ```json { "timestamp": "2026-07-02T14:30:00Z", "plan": "plans/add-auth.md", "slice": "2", "branch": "feat/add-auth", "files": ["src/api/auth.py"], "outcome": "ran", "reason": null } ``` | Field | Type | Description | | --- | --- | --- | | `branch` | string | Current branch name — `${CLAUDE_PLUGIN_ROOT}/scripts/progress_guardian.py --pre-pr` matches on this | | `files` | string[] | The slice's changed runtime files the verification was scoped to | | `outcome` | string | `ran` (the verification ran and passed), `skipped` (no runtime surface — see `reason`), or `failed-then-fixed` (the verification failed at least once before the fix landed) | | `reason` | string \| null | Required when `outcome` is `skipped` (e.g. `"tests-only"`, `"docs-only"`); `null` otherwise | **Not disableable.** Unlike Review Value logging (`DEV_TEAM_REVIEW_VALUE=off`), there is no env var to turn this off — `${CLAUDE_PLUGIN_ROOT}/scripts/progress_guardian.py --pre-pr` fails closed on a branch with runtime-surface changes and no matching entry, and that gate is a correctness control, not a metrics-collection nicety. ## When to Log > **Task completion entries are written automatically** by `hooks/task_completion_metrics.py` > on every `Stop` / `SubagentStop` event — skills no longer need a manual > "log this on completion" step. To surface task-specific values (task type, > agents used, hallucination flag, rework count, defect count, or a config > change), populate `.claude/session-metrics.json` before the session ends; the > hook reads and clears it. Leave the file absent for a minimal heartbeat entry. | Event | Action | | --- | --- | | Task completed | Logged automatically by `hooks/task_completion_metrics.py` (no manual step needed) | | `/build` inline review checkpoint | Append a Review Value entry to `.claude/metrics/review-value.jsonl` (#348) | | `/build` slice with a runtime surface | Append a Verify Log entry to `metrics/verify-log.jsonl` (#727) | | Configuration change | Add `config_change` to `.claude/session-metrics.json`; hook writes `.claude/metrics/config-changelog.jsonl` | | Hallucination detected | Set `hallucination_detected: true` in `.claude/session-metrics.json` | | Context summarization triggered | Increment counter in current task entry | ## Output JSONL log entries written to `.claude/metrics/` and/or a summary report of metric trends. Be concise — report anomalies and trend signals; omit entries within normal range. ## Reporting Periodically review metrics to identify patterns: 1. **Weekly**: Review task completion entries for rework trends and hallucination rate 2. **Monthly**: Aggregate cost metrics and LLM routing distribution 3. **Per-project**: Compare first-pass acceptance rate across task types Summaries can be written to `.dev-team-reports/` for historical reference.
View on GitHub