AgentSkillsCN

cost-impact

计算一段时间内 Claude Code 的成本影响报告,按仓库分组并提供每次会话的详细信息。Opus 4.6 / Sonnet 4.6 / Haiku 4.5 的单价按每次使用、每种模型列出,包含子代理代币,输出为 Markdown 格式,带有可点击的 PR 链接和可折叠的每仓库部分。适用于用户问“这周我在 Claude 上花了多少钱”、“成本报告”、“/cost-impact”或希望对 Claude 使用情况进行每周回顾时。

SKILL.md
--- frontmatter
name: cost-impact
description: Compute a Claude Code cost-impact report across a time window, grouped by repo with per-session detail. Prices per-turn per-model at Opus 4.6 / Sonnet 4.6 / Haiku 4.5 list rates, includes subagent tokens, outputs markdown with clickable PR links and collapsible per-repo sections. Use when user asks "how much did I spend on Claude this week", "cost report", "/cost-impact", or wants a weekly retrospective on Claude usage.
allowed-tools: Bash, Read

Cost Impact

Generate a markdown report of your Claude Code spend over the last N days, grouped by repo, with clickable links to PRs shipped during each session.

Announce at start: "I'm using the cost-impact skill to compute your Claude spend for the last N days."

When to use

  • User asks: "how much did I spend on Claude this week?", "Claude cost report", "weekly Claude retro", "/cost-impact"
  • User wants to investigate a specific day's unusual spend
  • End-of-week debrief on where the Claude budget went

Inputs

One optional positional argument: number of days back (integer, default 7).

code
/cost-impact        # last 7 days (default)
/cost-impact 1      # just today
/cost-impact 14     # last 2 weeks

If the user names a specific day ("yesterday", "last Friday"), compute the integer offset from today and pass that — the underlying script is window-based, not date-based.

Default flow: save locally, then offer the gist

Always save locally first. Local save is the unconditional default — the user's own disk is not a publication surface and needs no approval gate. After the local save lands, ask whether they also want to publish a public gist. If yes, run the privacy guard (see below) and only publish if it passes.

Sequence:

  1. Run _impl.py (writes /tmp/cost-impact.md)
  2. Copy to ~/tmp/cost-impact-YYYY-MM-DD.md and report the absolute path
  3. Ask: "Want me to also publish this as a public gist?"
  4. If yes → run the privacy guard, then gh gist create if it passes
  5. If no → done

Do not ask about destination up front. That order forces the user to context-switch before the script's output exists; asking after the local save lets them glance at the file (or its summary) before deciding to share.

If the user has an existing cost-impact gist they want updated in place, treat the in-place edit as a publish for privacy-guard purposes — see "Updating an existing gist" below.

How to run

bash
python3 ~/gits/chop-conventions/skills/cost-impact/_impl.py <days>

The script:

  1. Scans ~/.claude/projects/*/*.jsonl (main sessions) and ~/.claude/projects/*/*/subagents/agent-*.jsonl (subagent transcripts)
  2. Filters to turns whose timestamp (converted to local TZ) falls in the requested window
  3. Bills each turn at its model's published list price — pricing table in _impl.py::PRICING tracks Opus 4.6/4.5, Sonnet 4.6/4.5/4, Haiku 4.5/3.5, and older tiers
  4. Rolls subagent costs into the parent session so per-session totals reflect all work done on behalf of that session
  5. Groups results by project, then by parent-session UUID, then by day
  6. Writes /tmp/cost-impact.md and prints a one-line summary to stdout

Expected stdout shape:

code
Wrote /tmp/cost-impact.md (16,936 bytes, 64 session-days)
Actual: $1,244.92 | no-cache ref: $6,933.49 | savings: 82%
Repos: 11, top 3: activation-energy-game, settings, blog4

If you see Actual: $0.00 the window is probably wrong — check that date shows today and that session JSONLs have fresh timestamps.

Routing the output

After _impl.py writes /tmp/cost-impact.md:

Step 1 — Save locally (always, no questions):

bash
mkdir -p ~/tmp
cp /tmp/cost-impact.md ~/tmp/cost-impact-$(date +%Y-%m-%d).md

Relay the absolute path back.

Step 2 — Ask if they want a public gist as well. Only if yes, run the privacy guard (see below). If the guard passes, publish:

bash
gh gist create --public \
  -d "Claude cost impact YYYY-MM-DD (N-day window)" \
  /tmp/cost-impact.md

Relay the gist URL back. If they decline the gist or the guard refuses, the local save from Step 1 is the final artifact — no further action.

Updating an existing gist

If the user already has a cost-impact gist and the new report supersedes it, prefer gh gist edit <id> /tmp/cost-impact.md to update in place so shared links don't break. Ask which gist to update if you don't know the ID. Run the privacy guard before editing — an in-place edit to a public gist is a publish.

Privacy guard (gist destinations only)

Before running gh gist create or gh gist edit against a public gist, read /tmp/cost-impact.md and judge whether the content would leak information the user wouldn't want public. This is assistant judgment, not a mechanical check. Look for:

  • Repo names that identify private, client, or unreleased projects (anything not already visible on the user's public GitHub profile)
  • PR URLs pointing at private repos
  • Session UUIDs that could correlate with private incidents if cross-referenced
  • Session titles or PR titles that reference secrets, credentials, internal codenames, or people by name
  • Hostnames that reveal internal network naming conventions beyond the user's already-public setup

If the report looks sensitive: STOP the gist upload. Do NOT publish. Tell the user what specifically looked sensitive (cite the repo name, PR URL, or line), and offer the local-save path instead:

"Holding off on the gist — I see <specific thing> in the report which looks like it'd expose a private project. Saving locally to ~/tmp/cost-impact-YYYY-MM-DD.md instead, or want to scrub and retry?"

Local save is always allowed regardless of sensitivity — the user's own disk is not a publication surface.

When in doubt, prefer refusing the gist. A false-positive refusal costs the user one prompt ("go ahead, it's fine") — a false-negative publish can't be unsent once the gist URL is indexed.

What the report contains

  1. Summary table — total $, total duration, total turns (main/sub/total), sessions in window, host (from socket.gethostname() — load-bearing provenance when the report is shared out of context), cost breakdown (input/output/cache writes/reads), without-cache reference, cache savings %
  2. Cost by model — each model's share of the total
  3. Per day — actual $, sessions, main+sub turns, no-cache reference, plus a separate daily details table splitting input, output, 1h cache writes, 5m cache writes, and cache reads
  4. Per repo summary table — sessions, actual $, share %
  5. Sessions grouped by repo — collapsible <details> sections, one per repo, each showing its sessions sorted by actual $ descending. Per-session row: day, duration, session UUID prefix, turns main/sub, costs split out, clickable PR links (from gh pr create commands found in the session)
  6. Footnotes — methodology notes, known caveats, links to relevant Anthropic docs and GitHub issues

Knobs in _impl.py

Edit these constants at the top of the file if your setup differs:

ConstantPurposeDefault
PRICINGPer-model price table (input/output/cache-write-1h/5m/cache-read per MTok)Opus 4.6 $5/$25, Sonnet 4.6 $3/$15, Haiku 4.5 $1/$5
MAX_PLAN_MONTHLYUsed only for the subsidy footnote200.00

Pricing is sourced from platform.claude.com/docs/en/about-claude/pricing. Update the table if Anthropic changes published rates.

Hard rules

  • Do NOT modify _impl.py to bake in a specific user's values (repo list, gist ID, plan cost, hostname). Keep it generic — the hostname comes from socket.gethostname() at runtime, not a constant.
  • Do NOT post the report to a gist without running the privacy guard (see "Privacy guard" above). The report contains session names, PR URLs, and repo paths that may identify private projects.
  • Do NOT run this on a machine that isn't the user's — it reads ~/.claude/projects/ which contains conversation history.
  • Ask before updating an existing gist in place — the previous version of the report may have been shared with someone, and editing it in place will change what they see next time they load it. In-place edits are subject to the same privacy guard as new publishes.

Known caveats (surfaced in the report's footnotes)

  • Fast mode invisible: usage field in JSONL doesn't flag fast mode turns, so if the user hit /fast those are undercounted by 6×. No current way to detect.
  • Peak-hours quota burn (weekday 5–11am PT) affects how quickly Max plan session quota gets consumed, not the $ per token. The report prices at list; peak vs off-peak is not reflected in the dollar column.
  • Opus 4.6 / Sonnet 4.6 flat pricing: no 200k threshold — older 4 / 4.1 tiers had 2× above 200k, but 4.5+ bill flat across the full 1M context window.
  • TTL bug (anthropics/claude-code#45381): if DISABLE_TELEMETRY or CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC is set, sessions silently fall from 1h to 5m cache tier, costing more. The report footnote measures ephemeral_5m_input_tokens directly and reports whether you were hit.
  • Unknown / unpriced models: turns with a model ID not in PRICING are excluded from totals and surfaced as a stderr warning at run time + an ⚠ Unpriced models line in the report's footnotes. Update the PRICING table in _impl.py when a new model ships.

Related