Skip to content

Latest commit

 

History

History
310 lines (230 loc) · 15.3 KB

File metadata and controls

310 lines (230 loc) · 15.3 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Monorepo Structure

This is a monorepo containing multiple packages. For package-specific guidance, refer to the individual CLAUDE.md files:

  • Main CLI Package: @apps/ccusage/CLAUDE.md - Core ccusage CLI tool and library
  • Codex CLI Package: @apps/codex/CLAUDE.md - OpenAI Codex usage tracking CLI
  • OpenCode CLI Package: @apps/opencode/CLAUDE.md - OpenCode usage tracking CLI
  • MCP Server Package: @apps/mcp/CLAUDE.md - MCP server implementation for ccusage data
  • Documentation: @docs/CLAUDE.md - VitePress-based documentation website

Each package has its own development commands, dependencies, and specific guidelines. Always check the relevant package's CLAUDE.md when working within that package directory.

Apps Are Bundled

All projects under apps/ ship as bundled CLIs/binaries. Treat their runtime dependencies as bundled assets: list everything in each app's devDependencies (never dependencies) so the bundler owns the runtime payload.

Development Commands

Testing and Quality:

  • pnpm run test - Run all tests (using vitest via pnpm, watch mode disabled)
  • Lint code using ESLint MCP server (available via Claude Code tools)
  • pnpm run format - Format code with ESLint (writes changes)
  • pnpm typecheck - Type check with TypeScript

Build and Release:

  • pnpm run build - Build distribution files with tsdown
  • pnpm run release - Full release workflow (lint + typecheck + test + build + version bump)

Development Usage:

  • pnpm run start daily - Show daily usage report
  • pnpm run start monthly - Show monthly usage report
  • pnpm run start session - Show session-based usage report
  • pnpm run start blocks - Show 5-hour billing blocks usage report
  • pnpm run start statusline - Show compact status line (Beta)
  • pnpm run start daily --json - Show daily usage report in JSON format
  • pnpm run start monthly --json - Show monthly usage report in JSON format
  • pnpm run start session --json - Show session usage report in JSON format
  • pnpm run start blocks --json - Show blocks usage report in JSON format
  • pnpm run start daily --mode <mode> - Control cost calculation mode (auto/calculate/display)
  • pnpm run start monthly --mode <mode> - Control cost calculation mode (auto/calculate/display)
  • pnpm run start session --mode <mode> - Control cost calculation mode (auto/calculate/display)
  • pnpm run start blocks --mode <mode> - Control cost calculation mode (auto/calculate/display)
  • pnpm run start blocks --active - Show only active block with projections
  • pnpm run start blocks --recent - Show blocks from last 3 days (including active)
  • pnpm run start blocks --token-limit <limit> - Token limit for quota warnings (number or "max")
  • node ./src/index.ts - Direct execution for development

MCP Server Usage: (now provided by the @ccusage/mcp package)

  • pnpm dlx @ccusage/mcp@latest -- --help - Show available options
  • pnpm dlx @ccusage/mcp@latest -- --type http --port 8080 - Start HTTP transport

Cost Calculation Modes:

  • auto (default) - Use pre-calculated costUSD when available, otherwise calculate from tokens
  • calculate - Always calculate costs from token counts using model pricing, ignore costUSD
  • display - Always use pre-calculated costUSD values, show 0 for missing costs

Environment Variables:

  • LOG_LEVEL - Control logging verbosity (0=silent, 1=warn, 2=log, 3=info, 4=debug, 5=trace)
    • Example: LOG_LEVEL=0 pnpm run start daily for silent output
    • Useful for debugging or suppressing non-critical output

Multiple Claude Data Directories:

This tool supports multiple Claude data directories to handle different Claude Code installations:

  • Default Behavior: Automatically searches both ~/.config/claude/projects/ (new default) and ~/.claude/projects/ (old default)
  • Environment Variable: Set CLAUDE_CONFIG_DIR to specify custom path(s)
    • Single path: export CLAUDE_CONFIG_DIR="/path/to/claude"
    • Multiple paths: export CLAUDE_CONFIG_DIR="/path/to/claude1,/path/to/claude2"
  • Data Aggregation: Usage data from all valid directories is automatically combined
  • Backward Compatibility: Existing configurations continue to work without changes

This addresses the breaking change in Claude Code where logs moved from ~/.claude to ~/.config/claude.

Architecture Overview

This is a CLI tool that analyzes Claude Code usage data from local JSONL files stored in Claude data directories (supports both ~/.claude/projects/ and ~/.config/claude/projects/). The architecture follows a clear separation of concerns:

Core Data Flow:

  1. Data Loading (data-loader.ts) - Parses JSONL files from multiple Claude data directories, including pre-calculated costs
  2. Token Aggregation (calculate-cost.ts) - Utility functions for aggregating token counts and costs
  3. Command Execution (commands/) - CLI subcommands that orchestrate data loading and presentation
  4. CLI Entry (index.ts) - Gunshi-based CLI setup with subcommand routing

Output Formats:

  • Table format (default): Pretty-printed tables with colors for terminal display
  • JSON format (--json): Structured JSON output for programmatic consumption

Key Data Structures:

  • Raw usage data is parsed from JSONL with timestamp, token counts, and pre-calculated costs
  • Data is aggregated into daily summaries, monthly summaries, session summaries, or 5-hour billing blocks
  • Important Note on Naming: The term "session" in this codebase has two different meanings:
    1. Session Reports (pnpm run start session): Groups usage by project directories. What we call "sessionId" in these reports is actually derived from the directory structure (project/directory)
    2. True Session ID: The actual Claude Code session ID found in the sessionId field within JSONL entries and used as the filename ({sessionId}.jsonl)
  • File structure: projects/{project}/{sessionId}.jsonl where:
    • {project} is the project directory name (used for grouping)
    • {sessionId}.jsonl is the JSONL file named with the actual session ID from Claude Code
    • Each JSONL file contains all usage entries for a single Claude Code session
    • The sessionId in the filename matches the sessionId field inside the JSONL entries
  • 5-hour blocks group usage data by Claude's billing cycles with active block tracking

External Dependencies:

  • Uses local timezone for date formatting
  • CLI built with gunshi framework, tables with cli-table3
  • LiteLLM Integration: Cost calculations depend on LiteLLM's pricing database for model pricing data

MCP Integration:

  • Built-in MCP Server: Exposes usage data through MCP protocol with tools:
    • daily - Daily usage reports
    • session - Session-based usage reports
    • monthly - Monthly usage reports
    • blocks - 5-hour billing blocks usage reports
  • External MCP Servers Available:
    • ESLint MCP: Lint TypeScript/JavaScript files directly through Claude Code tools
    • Context7 MCP: Look up documentation for libraries and frameworks
  • Claude Code Skills Available:
    • use-gunshi-cli: Guide for using gunshi CLI framework (via @gunshi/docs)
    • byethrow: Guide for using @praha/byethrow Result type (via @praha/byethrow-docs)

Git Commit and PR Conventions

Commit Message Format:

Follow the Conventional Commits specification with package/area prefixes:

<type>(<scope>): <subject>

Scope Naming Rules:

  • Apps: Use the app directory name

    • feat(ccusage): - Changes to apps/ccusage
    • fix(mcp): - Fixes in apps/mcp
    • feat(codex): - Features for apps/codex (if exists)
  • Packages: Use the package directory name

    • feat(terminal): - Changes to packages/terminal
    • fix(ui): - Fixes in packages/ui
    • refactor(core): - Refactoring packages/core
  • Documentation: Use docs scope

    • docs: or docs(guide): - Documentation updates
    • docs(api): - API documentation changes
  • Root-level changes: No scope (preferred) or use root

    • chore: - Root config updates
    • ci: - CI/CD changes
    • feat: - Root-level features
    • docs: - Root documentation updates
    • build: or build(root): - Root build system changes

Type Prefixes:

  • feat: - New feature
  • fix: - Bug fix
  • docs: - Documentation only changes
  • style: - Code style changes (formatting, missing semi-colons, etc)
  • refactor: - Code change that neither fixes a bug nor adds a feature
  • perf: - Performance improvements
  • test: - Adding missing tests or correcting existing tests
  • chore: - Changes to the build process or auxiliary tools
  • ci: - CI/CD configuration changes
  • revert: - Reverting a previous commit

Examples:

feat(ccusage): add support for Claude 4.1 models
fix(mcp): resolve connection timeout issues
docs(guide): update installation instructions
refactor(ccusage): extract cost calculation to separate module
test(mcp): add integration tests for HTTP transport
chore: update dependencies

PR Title Convention:

PR titles should follow the same format as commit messages. When a PR contains multiple commits, the title should describe the main change:

feat(ccusage): implement session-based usage reports
fix(mcp): handle edge cases in data aggregation
docs: comprehensive API documentation update

Code Style Notes

  • Uses ESLint for linting and formatting with tab indentation and double quotes
  • TypeScript with strict mode and bundler module resolution
  • No console.log allowed except where explicitly disabled with eslint-disable
  • Error handling: silently skips malformed JSONL lines during parsing
  • File paths always use Node.js path utilities for cross-platform compatibility
  • Import conventions: Use .ts extensions for local file imports (e.g., import { foo } from './utils.ts')

Error Handling:

  • Prefer @praha/byethrow Result type over traditional try-catch for functional error handling
    • Documentation: Available via byethrow skill (use /byethrow or check .claude/skills/byethrow/)
  • Use Result.try() for wrapping operations that may throw (JSON parsing, etc.)
  • Use Result.isFailure() for checking errors (more readable than !Result.isSuccess())
  • Use early return pattern (if (Result.isFailure(result)) continue;) instead of ternary operators
  • For async operations: create wrapper function with Result.try() then call it
  • Keep traditional try-catch only for: file I/O with complex error handling, legacy code that's hard to refactor
  • Always use Result.isFailure() and Result.isSuccess() type guards for better code clarity

Naming Conventions:

  • Variables: start with lowercase (camelCase) - e.g., usageDataSchema, modelBreakdownSchema
  • Types: start with uppercase (PascalCase) - e.g., UsageData, ModelBreakdown
  • Constants: can use UPPER_SNAKE_CASE - e.g., DEFAULT_CLAUDE_CODE_PATH
  • Internal files: use underscore prefix - e.g., _types.ts, _utils.ts, _consts.ts

Export Rules:

  • IMPORTANT: Only export constants, functions, and types that are actually used by other modules
  • Internal/private constants that are only used within the same file should NOT be exported
  • Always check if a constant is used elsewhere before making it export const vs just const
  • This follows the principle of minimizing the public API surface area
  • Dependencies should always be added as devDependencies unless explicitly requested otherwise

Post-Code Change Workflow:

After making any code changes, ALWAYS run these commands in parallel:

  • pnpm run format - Auto-fix and format code with ESLint (includes linting)
  • pnpm typecheck - Type check with TypeScript
  • pnpm run test - Run all tests

This ensures code quality and catches issues immediately after changes.

Documentation Guidelines

Screenshot Usage:

  • Placement: Always place screenshots immediately after the main heading (H1) in documentation pages
  • Purpose: Provide immediate visual context to users before textual explanations
  • Guides with Screenshots:
    • /docs/guide/index.md (What is ccusage) - Main usage screenshot
    • /docs/guide/daily-reports.md - Daily report output screenshot
    • /docs/guide/live-monitoring.md - Live monitoring dashboard screenshot
    • /docs/guide/mcp-server.md - Claude Desktop integration screenshot
  • Image Path: Use relative paths like /screenshot.png for images stored in /docs/public/
  • Alt Text: Always include descriptive alt text for accessibility

Claude Models and Testing

Supported Claude 4 Models (as of 2025):

  • claude-sonnet-4-20250514 - Latest Claude 4 Sonnet model
  • claude-opus-4-20250514 - Latest Claude 4 Opus model

Model Naming Convention:

  • Pattern: claude-{model-type}-{generation}-{date}
  • Example: claude-sonnet-4-20250514 (NOT claude-4-sonnet-20250514)
  • The generation number comes AFTER the model type

Testing Guidelines:

  • In-Source Testing Pattern: This project uses in-source testing with if (import.meta.vitest != null) blocks
  • Tests are written directly in the same files as the source code, not in separate test files
  • Vitest globals (describe, it, expect) are available automatically without imports
  • IMPORTANT: DO NOT use await import() dynamic imports anywhere in the codebase - this causes tree-shaking issues and should be avoided entirely
  • ESPECIALLY: Never use dynamic imports in vitest test blocks - this is particularly problematic for test execution
  • Vitest globals are enabled: Use describe, it, expect directly without any imports since globals are configured
  • Mock data is created using fs-fixture with createFixture() for Claude data directory simulation
  • All test files must use current Claude 4 models, not outdated Claude 3 models
  • Test coverage should include both Sonnet and Opus models for comprehensive validation
  • Model names in tests must exactly match LiteLLM's pricing database entries
  • When adding new model tests, verify the model exists in LiteLLM before implementation
  • Tests depend on real pricing data from LiteLLM - failures may indicate model availability issues

LiteLLM Integration Notes:

  • Cost calculations require exact model name matches with LiteLLM's database
  • Test failures often indicate model names don't exist in LiteLLM's pricing data
  • Future model updates require checking LiteLLM compatibility first
  • The application cannot calculate costs for models not supported by LiteLLM

Tips for Claude Code

  • Context7 MCP server available for library documentation lookup
  • use-gunshi-cli skill available for gunshi CLI framework documentation
  • byethrow skill available for @praha/byethrow Result type documentation
  • do not use console.log. use logger.ts instead
  • CRITICAL VITEST REMINDER: Vitest globals are enabled - use describe, it, expect directly WITHOUT imports. NEVER use await import() dynamic imports anywhere, especially in test blocks.

important-instruction-reminders

Do what has been asked; nothing more, nothing less. NEVER create files unless they're absolutely necessary for achieving your goal. ALWAYS prefer editing an existing file to creating a new one. NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User. Dependencies should always be added as devDependencies unless explicitly requested otherwise.