Per-turn LLM token and dollar cost ledger attributed by repository, branch, and model. Appends JSONL records and provides /ledger summary.

The complete skill library that Cure Consulting Group uses to build apps, platforms, and products. These skills encode our standards, frameworks, and processes — so every project ships with the same level of rigor.
Now available as a Claude Code Plugin — install once, get auto-updates across all projects.
ProductEngineeringSkills/
├── .claude-plugin/ # Plugin manifest
│ └── plugin.json
├── skills/{domain}/ # 80 skills, organized by domain (engineering/platform/product/business/marketing/security/legal)
│ ├── sdlc/
│ ├── android-feature-scaffold/
│ ├── incident-response/ # NEW
│ ├── accessibility-audit/ # NEW
│ ├── performance-review/ # NEW
│ ├── database-architect/ # NEW
│ ├── infrastructure-scaffold/ # NEW
│ ├── project-bootstrap/
│ ├── e2e-testing/
│ ├── test-accounts/
│ ├── uat/
│ ├── compliance-architect/
│ ├── data-migration/
│ ├── feature-flags/
│ ├── release-management/
│ ├── observability/
│ ├── client-handoff/
│ ├── llmops/
│ ├── disaster-recovery/
│ ├── dora-metrics/
│ ├── design-system/
│ ├── client-communication/
│ ├── i18n/
│ ├── notification-architect/
│ ├── offline-first/
│ ├── chaos-engineering/
│ ├── edge-computing/
│ ├── finops/
│ ├── micro-frontends/
│ ├── growth-engineering/
│ ├── green-software/
│ ├── proposal-generator/
│ ├── api-gateway/
│ ├── ... (75 total — see docs/OVERVIEW.md for full inventory)
│ └── legal-doc-scaffold/
├── agents/ # 35 custom subagent definitions
├── personas/ # 4 cross-domain engagement archetypes
│ ├── code-reviewer.md # Security + quality review agent
│ ├── project-bootstrapper.md # New project setup agent
│ ├── test-runner.md # Execute test suites, report coverage
│ ├── pr-reviewer.md # Automated PR diff review
│ ├── refactor-assistant.md # Safe refactoring with test validation
│ ├── ci-debugger.md # Diagnose failed CI/CD runs
│ ├── release-coordinator.md # Version bump, changelog, deploy validation
│ ├── doc-generator.md # API docs, ADRs, changelogs from code
│ ├── codebase-explainer.md # Onboarding — explain architecture, trace flows
│ ├── migration-validator.md # Database migration safety checks
│ ├── deployment-validator.md # Pre-deployment checklist validation
│ ├── dependency-auditor.md # Vulnerability and outdated package audit
│ ├── api-validator.md # OpenAPI spec and contract validation
│ ├── product-analyst.md # Feature adoption, analytics instrumentation
│ ├── ux-researcher.md # Usability analysis, friction mapping
│ ├── roadmap-strategist.md # RICE scoring, dependency mapping, roadmaps
│ ├── competitive-intel.md # Feature matrices, positioning, moat analysis
│ ├── content-strategist.md # Editorial calendars, SEO, content briefs
│ ├── campaign-analyst.md # Attribution, funnel analysis, channel ROI
│ ├── brand-guardian.md # Voice/tone, visual identity, microcopy audit
│ ├── growth-analyst.md # Activation, retention, viral mechanics
│ ├── financial-analyst.md # Revenue forecasts, unit economics, scenarios
│ ├── market-intelligence.md # TAM/SAM/SOM, trends, market timing
│ ├── investor-relations.md # Board updates, KPIs, fundraising narratives
│ ├── contract-reviewer.md # SOW/contract risk, terms, IP review
│ ├── data-analyst.md # Schema exploration, queries, data quality
│ ├── metrics-dashboard.md # KPI definitions, SLOs, dashboard wireframes
│ ├── ab-test-analyst.md # Experiment design, statistical analysis
│ ├── qa-engineer.md # Test planning, edge cases, regression, quality gates
│ ├── accessibility-checker.md # WCAG 2.2 automated compliance
│ └── firebase-security-auditor.md # Firestore rules and Functions audit
├── hooks/ # Multi-layer automated enforcement
│ └── hooks.json # Command + Prompt hooks (9 event types)
├── rules/ # 11 path-specific coding standards
│ ├── android.md # Loads for *.kt files
│ ├── ios.md # Loads for *.swift files
│ ├── web.md # Loads for *.ts/*.tsx files
│ ├── firebase.md # Loads for functions/**
│ ├── python.md # Loads for *.py files
│ ├── go.md # Loads for *.go files
│ ├── rust.md # Loads for *.rs files
│ ├── sql.md # Loads for *.sql, migrations/**
│ ├── docker.md # Loads for Dockerfile, *.dockerfile
│ ├── terraform.md # Loads for *.tf, *.tfvars
│ └── cicd.md # Loads for .github/workflows/**
├── output-styles/ # 9 custom output formatting styles
│ ├── prd/ # Product docs (PRDs, GTM, research)
│ ├── code-generation/ # Code scaffolds and implementations
│ ├── financial-analysis/ # Cost models, SaaS metrics
│ ├── audit-report/ # Audits, reviews, compliance
│ ├── api-specification/ # OpenAPI specs, endpoint docs
│ ├── architecture-decision/ # ADRs, RFCs, trade-off matrices
│ ├── runbook/ # Incident runbooks, DR procedures
│ ├── test-plan/ # Test plans, coverage reports
│ └── monitoring-alert/ # Alert definitions, thresholds
├── .mcp.json # MCP server configs (GitHub, Sentry, Firestore, PostgreSQL)
├── .lsp.json # LSP server configs (TypeScript, Python/Pyright)
├── marketplace.json # Plugin marketplace manifest
├── settings.json # Default permission rules
├── claude-commands/ # Legacy format (backwards compat, 64 files)
├── gemini skills/ # Google Gemini skills (.skill ZIP)
├── CLAUDE.md # Project instructions (Claude)
├── GEMINI.md # Project instructions (Gemini CLI)
├── AGENT-GUIDE.md # How to structure prompts for agents & skills
├── setup.sh # Setup script for Antigravity & other projects
└── README.md
Install the plugin as an npm package from GitHub Packages. This is the easiest way to keep all your projects up to date.
1. Authenticate with GitHub Packages (one-time setup):
# Create a Personal Access Token (PAT) with read:packages scope at
# https://github.com/settings/tokens, then:
npm login --scope=@cure-consulting-group --registry=https://npm.pkg.github.com
Or add to your project's .npmrc:
@cure-consulting-group:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
2. Install in your project:
npm install @cure-consulting-group/product-engineering-skills
The postinstall script automatically:
~/.claude/plugins/ProductEngineeringSkills~/.claude/settings.jsonAll 80 skills, 39 agents, 4 personas, hooks, rules, and output styles are immediately available.
3. Enable auto-updates with Dependabot (recommended):
Add .github/dependabot.yml to your project (or run setup.sh which does this automatically):
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
allow:
- dependency-name: "@cure-consulting-group/product-engineering-skills"
labels:
- "dependencies"
- "skills-update"
commit-message:
prefix: "chore"
include: "scope"
Dependabot will open a PR in your project whenever a new version is published. Merge it and every agent on that project gets the updated skills.
4. Manual update:
npm update @cure-consulting-group/product-engineering-skills
# Load the plugin during a session
claude --plugin-dir /path/to/ProductEngineeringSkills
# Or for development/testing
claude --plugin-dir ./ProductEngineeringSkills
Once loaded, all skills are available as namespaced commands:
/cure-product-engineering:sdlc
/cure-product-engineering:feature-audit
/cure-product-engineering:android-feature-scaffold
/cure-product-engineering:incident-response
/cure-product-engineering:accessibility-audit
Hooks, agents, rules, output styles, and MCP servers are all included automatically.
The fastest way to onboard any project:
# From the target project directory
/path/to/ProductEngineeringSkills/setup.sh
# Or specify the project path
/path/to/ProductEngineeringSkills/setup.sh /path/to/antigravity-app
# Install globally for ALL projects
/path/to/ProductEngineeringSkills/setup.sh --global
# Legacy mode (just copy skills, no hooks/agents)
/path/to/ProductEngineeringSkills/setup.sh --legacy
The setup script will:
~/.claude/plugins/.claude/settings.local.json to .gitignore# Add the Cure Consulting marketplace
claude marketplace add https://github.com/Cure-Consulting-Group/ProductEngineeringSkills/marketplace.json
# Install the plugin
claude plugin install cure-product-engineering
Copy the claude-commands/ files into your project's .claude/commands/ directory:
cp claude-commands/*.md /path/to/your/project/.claude/commands/
Then use them as slash commands:
/sdlc — Generate SDLC artifacts
/android-feature-scaffold — Scaffold an Android feature module
/feature-audit — Audit a completed feature
Import the .skill files from gemini skills/ into your Gemini workspace. Each .skill file is a ZIP archive containing:
SKILL.md — The main skill definitionreferences/ — Supporting documents and templates| Skill | What It Does | Auto-Invoked? |
|---|---|---|
| product-manager | OKRs, roadmaps, RICE prioritization, feature briefs | Yes |
| product-design | Apple HIG, Material Design 3, design tokens, accessibility-first | Yes |
| market-research | TAM/SAM/SOM, competitive analysis, ICP definition (read-only) | Yes |
| go-to-market | GTM plans, launch strategy, channel selection, growth playbooks | Yes |
| product-marketing | Brand strategy, messaging frameworks, campaigns | Yes |
| customer-onboarding | Activation flows, empty states, email sequences, retention | Yes |
| seo-content-engine | Technical SEO, structured data, content strategy | Yes |
| Skill | What It Does | Auto-Invoked? |
|---|---|---|
| sdlc | PRDs, ADRs, RFCs, Epics, Stories, Task specs — full SDLC | Yes |
| android-feature-scaffold | Clean Architecture Android scaffolding (MVI, Compose, Hilt) | Yes |
| ios-architect | Swift/SwiftUI Clean Architecture, MVVM, structured concurrency | Yes |
| nextjs-feature-scaffold | App Router, Server/Client components, Tailwind patterns | Yes |
| firebase-architect | Firestore schema, security rules, Cloud Functions | Yes |
| api-architect | REST/GraphQL design, versioning, auth, rate limiting | Yes |
| api-gateway | API gateway and BFF layers, rate limiting, GraphQL federation | Yes |
| stripe-integration | Stripe payments + subscriptions via Firebase Functions | Yes |
| ai-feature-builder | LLM integration, RAG pipelines, prompt engineering | Yes |
| llmops | LLM operationalization — prompt versioning, eval pipelines, cost optimization, guardrails | Yes |
| database-architect | Schema design, migrations, indexing for Firestore/PostgreSQL/SQLite | Yes |
| data-migration | ETL pipelines, zero-downtime cutover, validation, rollback strategies | Yes |
| infrastructure-scaffold | Cloud infra configs for Firebase, GCP, Vercel, Docker | Yes |
| edge-computing | Edge functions, CDN strategies, cache invalidation, edge middleware | Yes |
| micro-frontends | Module federation, monorepo management, independent deployments | Yes |
| offline-first | Offline-first architecture, sync strategies, conflict resolution, optimistic UI | Yes |
| i18n | Internationalization — string extraction, RTL, locale-aware formatting, translation workflows | Yes |
| notification-architect | Push (FCM/APNs), in-app messaging, email, preference management | Yes |
| Skill | What It Does | Auto-Invoked? |
|---|---|---|
| feature-audit | 5-phase post-completion audit with scored gap report | Yes (read-only, forked) |
| testing-strategy | Testing pyramid, platform standards, coverage rules | Yes |
| e2e-testing | E2E test suites with page objects, visual regression, CI integration | Yes |
| test-accounts | Test user personas, seed data scripts, environment credentials | Yes |
| uat | UAT plans, acceptance criteria checklists, go/no-go release gates | Yes |
| security-review | OWASP checklist, auth/data/API/mobile/web security | Yes (read-only, forked) |
| compliance-architect | HIPAA, COPPA, GDPR, PCI compliance frameworks, consent flows, audit trails | Yes |
| accessibility-audit | WCAG 2.2 compliance, screen readers, inclusive design | Yes (read-only, forked) |
| performance-review | Performance budgets, load testing, optimization strategies | Yes |
| chaos-engineering | Resilience testing, failure injection, graceful degradation, game days | Yes |
| green-software | Sustainable software practices, carbon-aware computing, energy efficiency | Yes |
| Skill | What It Does | Auto-Invoked? |
|---|---|---|
| project-bootstrap | Bootstrap repo with CLAUDE.md + STATE.md via codebase inspection and developer interview | Yes |
| project-manager | Sprint planning, RACI, risk registers, retrospectives | Yes |
| ci-cd-pipeline | GitHub Actions, build/test/deploy, environments, secrets | Yes |
| release-management | App store submissions, staged rollouts, versioning, ASO, changelogs | Yes |
| feature-flags | Progressive rollouts, A/B testing, kill switches, experimentation frameworks | Yes |
| observability | Structured logging, distributed tracing, alerting, SLO/SLI, dashboards | Yes |
| dora-metrics | DORA and SPACE metrics — deployment frequency, lead time, MTTR, developer experience | Yes |
| analytics-implementation | Event taxonomy, tracking plans, funnels, dashboards | Yes |
| incident-response | Runbooks, severity classification, post-mortems, escalation | Yes |
| disaster-recovery | DR and business continuity — RTO/RPO, backup strategies, failover, DR testing | Yes |
| growth-engineering | Activation funnels, referral programs, lifecycle automation, PLG patterns | Yes |
| design-system | Design tokens, component libraries, Storybook/Catalog, cross-platform consistency | Yes |
| Skill | What It Does | Auto-Invoked? |
|---|---|---|
| engineering-cost-model | Project estimates, infrastructure costs, build vs buy | Yes (read-only) |
| saas-financial-model | Unit economics, MRR/ARR, pricing tiers, break-even | Yes (read-only) |
| finops | Cloud cost optimization, budget alerts, resource right-sizing, FinOps practices | Yes |
| investor-reporting | Investor updates, board decks, portfolio financials, cap table, runway modeling | Yes |
| fundraising-materials | Pitch decks, data rooms, investor updates, cap table scenarios, fundraising pipeline | Yes |
| burn-rate-tracker | Burn rates, runway scenarios, break-even analysis, cash flow projections | Yes |
| legal-doc-scaffold | ToS, Privacy Policy, SOW, NDA scaffolds | No (manual only) |
| Skill | What It Does | Auto-Invoked? |
|---|---|---|
| portfolio-registry | Product portfolio registry — single source of truth for all products, stacks, teams, stages | Yes |
| technology-radar | ThoughtWorks-style technology radar — Adopt/Trial/Assess/Hold across the portfolio | Yes |
| Skill | What It Does | Auto-Invoked? |
|---|---|---|
| client-handoff | Handoff packages, runbooks, credential transfers, maintenance SLAs, knowledge transfer | Yes |
| client-communication | Sprint demo scripts, stakeholder updates, risk escalation, executive summaries | Yes |
| proposal-generator | Consulting proposals, SOWs, milestone pricing, engagement structure | No (manual only) |
| Skill | What It Does | Auto-Invoked? |
|---|---|---|
| android-design-expert | Material Design 3 — dynamic color, component tokens, adaptive layouts, motion, Compose patterns | Yes |
| ios-design-expert | Apple HIG — SF Symbols, Dynamic Type, navigation patterns, SwiftUI components | Yes |
| web-design-expert | Responsive design, CSS architecture, design tokens, container queries, accessibility-first, Tailwind | Yes |
| stitch-design | AI-native UI design via Stitch MCP — vibe design, mockups, screen generation, design tokens, component export | Yes |
The library ships a standard maintenance loop (self-provisioned to .claude/loop.md on first session start — run bare /loop to use it), Recurring Mode sections in the goal-shaped skills (finops, burn-rate-tracker, investor-reporting, security-review, and others), and copy-paste cloud-routine recipes in docs/AUTOMATION.md. Library upkeep cadence: docs/MAINTENANCE.md. Mechanism selection and unattended-run guardrails: /cure-product-engineering:engagement-automation.
The plugin ships command and prompt hooks across 9 event types: SessionStart, PreCompact, PostCompact, ConfigChange, PostToolUseFailure, UserPromptSubmit, PreToolUse, Stop, SubagentStop. Highlights: a Stop-hook quality gate (blocks "done" without verification), a PreToolUse static security guard on skill/agent/persona files, and a ConfigChange audit trigger when skill files change mid-session.
New in v4.0: Hooks now suggest and auto-trigger agents based on context. Every code edit, test run, deployment, and PR action recommends the most relevant agent(s).
| Hook | Event | What It Does | Agent Integration |
|---|---|---|---|
| Welcome | SessionStart | Confirms plugin loaded with counts; full inventory stays in docs/OVERVIEW.md | Points to inventory |
| Git status | SessionStart | Reports current branch, uncommitted changes, last commit | — |
| Dependency check | SessionStart | Detects outdated packages | Suggests dependency-auditor |
| Code edit advisor | PostToolUse (Edit/Write) | Context-aware suggestions based on file type (.kt, .swift, .ts, .sql, .tf, etc.) | Suggests code-reviewer, test-runner, brand-guardian, migration-validator |
| Command advisor | PostToolUse (Bash) | Post-action guidance for tests, installs, deploys, PRs, releases | Suggests ci-debugger, dependency-auditor, pr-reviewer, release-coordinator |
| Failure recovery | PostToolUseFailure | Diagnoses failure type and suggests fix approach | Auto-suggests ci-debugger, deployment-validator, dependency-auditor |
| Destructive prompt guard | UserPromptSubmit | Detects destructive operations in prompts | Blocks and confirms |
| Protected files | PreToolUse (Edit/Write) | Blocks edits to .env, lock files, credentials, tfstate | — |
| Dangerous commands | PreToolUse (Bash) | Blocks force push, destructive rm, DROP TABLE, prod deploys | — |
| Context re-injection | PreCompact | Re-injects all 80 skills, 39 agents, 4 personas, and Cure standards | Full inventory preserved |
| Post-compact restore | PostCompact | Confirms context restored with agent availability | — |
| Subagent start banner | SubagentStart | Announces agent with role, standards, and companion agents | Lists companion agents |
| Subagent completion | SubagentStop | Suggests follow-up agents (test-runner, code-reviewer, pr-reviewer) | Agent chaining |
| Task quality check | TaskCompleted | Validates tests, security, docs, brand consistency | Suggests test-runner, code-reviewer, doc-generator, brand-guardian |
| Hook | Event | What It Does | Agent Integration |
|---|---|---|---|
| Code quality gate | PreToolUse (Edit/Write) | Haiku validates: no secrets, no debug logs, no disabled tests, no any types | — |
| Deployment safety | PreToolUse (Bash) | Haiku validates: blocks production deployments outside CI/CD | — |
| Intent classifier | UserPromptSubmit | Haiku classifies prompt intent and suggests the most relevant agent(s) from all 30 | Maps prompts → agents with confidence scores |
| Hook | Event | What It Does | Agent Integration |
|---|---|---|---|
| Completion validator | Stop | Validates: tests for new code, security review for sensitive changes, rollback for migrations, docs for features, brand consistency for UI, analytics for events, API contracts | Suggests specific agents for each gap found |
Pre-configured MCP servers in .mcp.json:
| Server | Type | What It Does |
|---|---|---|
| GitHub | HTTP | PR management, issue tracking, code search |
| Sentry | HTTP | Error monitoring, issue tracking, release health |
| Firestore | stdio | Direct database queries, schema inspection |
| PostgreSQL | stdio | Database queries, schema inspection, migrations |
Pre-configured LSP servers in .lsp.json:
| Server | Language | What It Provides |
|---|---|---|
| TypeScript | .ts, .tsx, .js | Type checking, auto-imports, refactoring, go-to-definition |
| Python (Pyright) | *.py | Static type analysis, import resolution, error diagnostics |
Custom output formatting for different artifact types:
| Style | Used By | Key Rules |
|---|---|---|
| prd | Product skills (PRDs, GTM, research) | Numbered sections, decision matrices, executive summaries |
| code-generation | Engineering skills (scaffolds) | File tree first, dependency order, complete runnable code |
| financial-analysis | Business skills (costs, models) | ASCII tables, explicit assumptions, sensitivity analysis |
| audit-report | Quality skills (audits, reviews) | Severity scoring, checklists, remediation with effort estimates |
| api-specification | API design skills | OpenAPI 3.0 blocks, endpoint tables, request/response examples |
| architecture-decision | ADR and RFC skills | Context/decision/consequences format, trade-off matrices |
| runbook | Incident response, disaster recovery | Numbered steps, command blocks, decision trees, escalation paths |
| test-plan | Testing strategy, QA skills | Coverage tables, test case templates, pass/fail criteria |
| monitoring-alert | Observability, incident response | Alert definition tables, threshold rationale, runbook links |
| Agent | Purpose | Tools | Auto-Triggered By |
|---|---|---|---|
| code-reviewer | Security + quality review against Cure standards | Read-only | Stop hook, SubagentStop |
| project-bootstrapper | Set up new projects with correct architecture |
hooks/register.ts 77 lines1import type { On } from 'claude-code'
2
3import {
4 calculateCost,
5 createLedgerEntry,
6 formatLedgerSummary,
7 type SessionTotals,
8 type UsageCounts,
9} from './ledger'
10
11const LEDGER_STATE_KEY = 'cure-llm-ledger-totals'
12
13export function register(on: On) {
14 on('session.start', async ($, e, next) => {
15 await $.command.register({
16 name: 'ledger',
17 description: 'Show LLM token usage and estimated dollar cost breakdown for this session',
18 })
19 return next(e)
20 })
21
22 on('command.run', { command: 'ledger' }, async $ => {
23 const totals = ((await $.store.get(LEDGER_STATE_KEY)) as SessionTotals | undefined) ?? {
24 totalCostUsd: 0,
25 totalInput: 0,
26 totalCacheWrite: 0,
27 totalCacheRead: 0,
28 totalOutput: 0,
29 byModel: {},
30 }
31 return { text: formatLedgerSummary(totals) }
32 })
33
34 on('turn.step', async function* ($, e, next) {
35 const result = yield* next(e)
36 const usage = result?.usage
37
38 if (usage) {
39 const counts: UsageCounts = {
40 inputTokens: Number(usage.input_tokens || 0),
41 cacheWriteTokens: Number(usage.cache_creation_input_tokens || 0),
42 cacheReadTokens: Number(usage.cache_read_input_tokens || 0),
43 outputTokens: Number(usage.output_tokens || 0),
44 }
45
46 const model = String(result.model || e.model || 'claude-3-5-sonnet')
47 const turnCost = calculateCost(model, counts)
48
49 // Update store
50 const totals = ((await $.store.get(LEDGER_STATE_KEY)) as SessionTotals | undefined) ?? {
51 totalCostUsd: 0,
52 totalInput: 0,
53 totalCacheWrite: 0,
54 totalCacheRead: 0,
55 totalOutput: 0,
56 byModel: {},
57 }
58
59 totals.totalCostUsd = Math.round((totals.totalCostUsd + turnCost) * 10_000) / 10_000
60 totals.totalInput += counts.inputTokens
61 totals.totalCacheWrite += counts.cacheWriteTokens
62 totals.totalCacheRead += counts.cacheReadTokens
63 totals.totalOutput += counts.outputTokens
64
65 const modelStats = totals.byModel[model] ?? { turns: 0, costUsd: 0, tokens: 0 }
66 modelStats.turns += 1
67 modelStats.costUsd = Math.round((modelStats.costUsd + turnCost) * 10_000) / 10_000
68 modelStats.tokens += counts.inputTokens + counts.cacheWriteTokens + counts.cacheReadTokens + counts.outputTokens
69 totals.byModel[model] = modelStats
70
71 await $.store.set(LEDGER_STATE_KEY, totals)
72 }
73
74 return result
75 })
76}
77hooks/ledger.ts 122 lines1/**
2 * Pure functions for calculating LLM token costs and formatting ledger records.
3 */
4
5export type ModelPricing = {
6 inputPerM: number
7 cacheWritePerM: number
8 cacheReadPerM: number
9 outputPerM: number
10}
11
12export const PRICING_TABLE: Record<string, ModelPricing> = {
13 opus: {
14 inputPerM: 15.0,
15 cacheWritePerM: 18.75,
16 cacheReadPerM: 1.5,
17 outputPerM: 75.0,
18 },
19 sonnet: {
20 inputPerM: 3.0,
21 cacheWritePerM: 3.75,
22 cacheReadPerM: 0.3,
23 outputPerM: 15.0,
24 },
25 haiku: {
26 inputPerM: 0.8,
27 cacheWritePerM: 1.0,
28 cacheReadPerM: 0.08,
29 outputPerM: 4.0,
30 },
31}
32
33export function resolvePricing(modelName?: string): ModelPricing {
34 const model = (modelName || '').toLowerCase()
35 if (model.includes('opus')) return PRICING_TABLE.opus
36 if (model.includes('haiku')) return PRICING_TABLE.haiku
37 return PRICING_TABLE.sonnet
38}
39
40export type UsageCounts = {
41 inputTokens: number
42 cacheWriteTokens: number
43 cacheReadTokens: number
44 outputTokens: number
45}
46
47export function calculateCost(model: string, usage: UsageCounts): number {
48 const pricing = resolvePricing(model)
49 const cost =
50 (usage.inputTokens / 1_000_000) * pricing.inputPerM +
51 (usage.cacheWriteTokens / 1_000_000) * pricing.cacheWritePerM +
52 (usage.cacheReadTokens / 1_000_000) * pricing.cacheReadPerM +
53 (usage.outputTokens / 1_000_000) * pricing.outputPerM
54
55 return Math.round(cost * 10_000) / 10_000
56}
57
58export type LedgerEntry = {
59 timestamp: string
60 repo: string
61 branch: string
62 model: string
63 input_tokens: number
64 cache_write_tokens: number
65 cache_read_tokens: number
66 output_tokens: number
67 cost_usd: number
68}
69
70export function createLedgerEntry(params: {
71 timestamp: string
72 repo: string
73 branch: string
74 model: string
75 usage: UsageCounts
76}): LedgerEntry {
77 const cost_usd = calculateCost(params.model, params.usage)
78 return {
79 timestamp: params.timestamp,
80 repo: params.repo,
81 branch: params.branch,
82 model: params.model,
83 input_tokens: params.usage.inputTokens,
84 cache_write_tokens: params.usage.cacheWriteTokens,
85 cache_read_tokens: params.usage.cacheReadTokens,
86 output_tokens: params.usage.outputTokens,
87 cost_usd,
88 }
89}
90
91export type SessionTotals = {
92 totalCostUsd: number
93 totalInput: number
94 totalCacheWrite: number
95 totalCacheRead: number
96 totalOutput: number
97 byModel: Record<string, { turns: number; costUsd: number; tokens: number }>
98}
99
100export function formatLedgerSummary(totals: SessionTotals): string {
101 if (totals.totalCostUsd === 0 && totals.totalInput === 0 && totals.totalOutput === 0) {
102 return 'cure-llm-ledger: No model usage recorded in this session yet.'
103 }
104
105 const lines = [
106 `cure-llm-ledger: Session Spend $${totals.totalCostUsd.toFixed(4)}`,
107 ` Tokens: ${totals.totalInput.toLocaleString()} in · ${totals.totalCacheRead.toLocaleString()} cache read · ${totals.totalCacheWrite.toLocaleString()} cache write · ${totals.totalOutput.toLocaleString()} out`,
108 ]
109
110 const models = Object.entries(totals.byModel)
111 if (models.length > 0) {
112 lines.push(' By model:')
113 for (const [model, stats] of models) {
114 lines.push(
115 ` • ${model}: $${stats.costUsd.toFixed(4)} (${stats.turns} turns, ${stats.tokens.toLocaleString()} tokens)`,
116 )
117 }
118 }
119
120 return lines.join('\n')
121}
122