---
title: "CLAUDE.md"
description: "This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository."
type: skill
canonical_url: https://claudary.paisolsolutions.com/skills/claude-31
source: "Claudary"
difficulty: intermediate
author: "Claude Code Knowledge Pack"
date: 2026-07-10T11:13:43.877Z
license: CC-BY-4.0
attribution: "CLAUDE.md — Claudary (https://claudary.paisolsolutions.com/skills/claude-31)"
---

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

## Overview

# 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**: Vi

---

Source: [Claudary](https://claudary.paisolsolutions.com/skills/claude-31) · https://claudary.paisolsolutions.com
