This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
TokenWatch is a cross-platform (Windows + macOS) tray/menu-bar Electron application that monitors Claude Code usage in real-time. The app uses the ccusage npm package API to fetch token usage data and displays it through a warm Claude-inspired React UI with tabbed navigation, analytics, notifications, and visualizations.
TokenWatch started as a Windows port of CCSeva (MIT), with a full UI redesign, frameless custom title bar, i18n, worker-thread parsing, and local ccusage performance patches.
npm run electron-dev # Start with hot reload (recommended for development)
npm run dev # Build frontend only in watch mode
npm start # Start built appnpm run build # Production build (webpack + tsc compilation)
npm run pack # Package app with electron-builder
npm run dist # Build and create distribution package
npm run dist:mac # Build for macOS specificallynpm run lint # Run Biome linter
npm run lint:fix # Fix linting issues automatically
npm run format # Format code with Biome
npm run format:check # Check code formatting
npm run check # Run linting and formatting checks
npm run check:fix # Fix linting and formatting issues
npm run type-check # TypeScript type checking without emitnpm install # Install all dependenciesThe app follows standard Electron patterns with clear separation:
- Main Process (
main.ts): Manages system tray, IPC, and background services - Renderer Process (
src/): React app handling UI and user interactions - Preload Script (
preload.ts): Secure bridge exposingelectronAPIto renderer
- CCUsageService: Uses the
ccusagenpm package data-loader API to fetch usage data, implementing a 30-second cache. Now supports plan configuration and actual session-based reset times. - SettingsService: Manages user preferences persistence to
~/.tokenwatch/settings.jsonincluding plan selection, custom token limits, timezone, and reset hour settings - NotificationService: Manages macOS notifications with cooldown periods and threshold detection
- ResetTimeService: Handles Claude usage reset time calculations and timezone management
- SessionTracker: Tracks user sessions and activity patterns for analytics
- Main process polls CCUsageService every 30 seconds
- Service imports
loadSessionBlockDataandloadDailyUsageDatafromccusage/data-loaderto fetch usage data - The returned JavaScript objects are mapped to typed interfaces (
UsageStats,MenuBarData) - Menu bar updates with percentage display, renderer receives data via IPC
- React app renders tabbed interface with dashboard, analytics, and live monitoring views
- NotificationService triggers alerts based on usage thresholds and patterns
App.tsx (main container with state management)
├── NavigationTabs (tabbed interface)
├── Dashboard (overview with stats cards)
├── LiveMonitoring (real-time usage tracking)
├── Analytics (charts and historical data)
├── TerminalView (command-line interface simulation)
├── SettingsPanel (user preferences)
├── LoadingScreen (app initialization)
├── ErrorBoundary (error handling)
├── NotificationSystem (toast notifications)
└── ui/ (Radix UI components)
├── Button, Card, Progress, Tabs
├── Alert, Badge, Tooltip, Switch
└── Avatar, Popover, Select, Slider
The build requires both Webpack (renderer) and TypeScript compiler (main/preload):
webpack --mode production && tsc main.ts preload.ts --outDir dist- ccusage npm package: Direct dependency providing data-loader API functions
- Tailwind CSS v3: PostCSS processing with custom gradient themes
- React 19: Uses new JSX transform (
react-jsx) - Radix UI: Component library for accessible UI primitives
- Biome: Fast linter and formatter replacing ESLint/Prettier
Main process exposes these handlers:
get-usage-stats: Returns full UsageStats objectrefresh-data: Forces cache refresh and returns fresh datausage-updated: Event emitted to renderer every 30 seconds
Renderer accesses via window.electronAPI (type-safe interface in preload.ts).
The app detects Claude plans automatically:
- Pro: ≤7,000 tokens
- Max5: ≤35,000 tokens
- Max20: ≤140,000 tokens
- Custom: >140,000 tokens
Calculates tokens/hour based on last 24 hours of usage data, used for depletion time predictions.
- CCUsageService returns default stats on ccusage command failures
- React components display error states with retry buttons
- Main process continues functioning even if data fetch fails
Uses strict mode with custom path aliases (@/* → src/*). Three separate tsconfig files:
tsconfig.json: Main renderer process configurationtsconfig.main.json: Main Electron process configurationtsconfig.preload.json: Preload script configuration
- Tailwind CSS v3: Custom color palette for Claude branding with glass morphism effects
- Radix UI Components: Accessible, unstyled primitives for complex components
- Sonner: Toast notification system for user feedback
- Lucide React: Icon library for consistent iconography
- Class Variance Authority: Type-safe component variant management
macOS-specific Tray API with text-only display (no icon). Features contextual menus and window positioning near menu bar with auto-hide behavior.
Implements intelligent notification logic:
- 5-minute cooldown between notifications
- Progressive alerts (70% warning → 90% critical)
- Only notifies when status worsens, not repeated warnings
- Toast notifications within app for immediate feedback
ccusagenpm package: This is a direct dependency managed inpackage.json.- Claude Code: Must be configured with valid credentials in
~/.claudedirectory containing JSONL usage files, which theccusagepackage uses as its data source. - macOS: Tray and notification APIs are platform-specific
The project uses Biome for linting and formatting with these key settings:
- Import organization: Automatically sorts and organizes imports
- Strict linting: Warns on
anytypes, enforces import types, security rules - Consistent formatting: 2-space indentation, single quotes for JS, double quotes for JSX
- Line width: 100 characters maximum
When using the ccusage package data-loader API:
- Use data-loader functions: Import
loadSessionBlockDataandloadDailyUsageDatafromccusage/data-loader - Handle structured data: The API returns typed JavaScript objects, no JSON parsing needed
- One pass over the JSONL corpus:
src/workers/blockLoader.tsreads session blocks incrementally (per-file entry cache, append-only tail reads) and daily usage is derived from those same entries — per-model attribution is exact, not approximated. Do not add a second full-corpus call such asloadDailyUsageDataon the hot path; it doubles I/O for data we already have. - Robust error handling: Implement
try/catchblocks around API calls to handle missing~/.claudeconfiguration - Caching strategy: Implement 30-second caching to avoid excessive file system reads
- Claude Plan Settings: Added comprehensive plan selection in SettingsPanel with Auto-detect, Pro, Max5, Max20, and Custom options
- Persistent Settings: Extended SettingsService to save plan preferences to
~/.tokenwatch/settings.jsonwith backward compatibility - Custom Token Limits: Custom plan option allows users to set non-standard token limits with validation
- Real-time Plan Display: TerminalView now shows selected plan settings instead of just auto-detected plans
- Settings UI Enhancement: Professional plan selection dropdown with token limit display and current plan detection
- Active Session Integration: Reset time now uses actual
activeBlock.endTimefrom session data instead of estimated monthly cycles - Real-time Countdown: SettingsPanel displays live countdown showing "X hours Y minutes left" updating every minute
- Simplified Logic: Removed complex fallback calculations, shows "No active session" when appropriate
- Dashboard Integration: Updated Dashboard to use actual session-based reset times consistently
- Enhanced Average Cost: Fixed Analytics average cost per 1000 tokens calculation with better edge case handling
- Data Validation: Added checks for both
totalTokens > 0 AND totalCost > 0to prevent division by zero - Accurate Pricing: Formula
(totalCost / totalTokens) * 1000now properly validated for real-world cost accuracy
- Switched from CLI to API: Refactored
CCUsageServiceto use theccusagenpm package directly, replacingchild_processcalls. - Simplified data fetching: API calls (
loadSessionBlockData,loadDailyUsageData) now return structured JS objects, removing the need for manual JSON parsing and field name mapping. - Improved reliability: Direct API integration is more robust and less prone to issues from shell environment differences.
- Dependency management:
ccusageis now a formal npm dependency inpackage.json, ensuring version consistency.
tokenwatch/
├── main.ts # Electron main process with tray management
├── preload.ts # Secure IPC bridge
├── src/
│ ├── App.tsx # Main React container with state management
│ ├── components/ # Modern UI components
│ │ ├── Dashboard.tsx # Overview with stats cards
│ │ ├── Analytics.tsx # Charts and historical data
│ │ ├── LiveMonitoring.tsx # Real-time usage tracking
│ │ ├── TerminalView.tsx # CLI simulation interface
│ │ ├── SettingsPanel.tsx # User preferences
│ │ ├── NavigationTabs.tsx # Tabbed interface
│ │ ├── NotificationSystem.tsx # Toast notifications
│ │ ├── LoadingScreen.tsx # App initialization
│ │ ├── ErrorBoundary.tsx # Error handling
│ │ └── ui/ # Radix UI components
│ ├── services/ # Business logic services
│ │ ├── ccusageService.ts # ccusage data-loader integration
│ │ ├── settingsService.ts # User preferences persistence
│ │ ├── notificationService.ts # macOS notification management
│ │ ├── resetTimeService.ts # Reset time calculations
│ │ └── sessionTracker.ts # Session tracking
│ ├── types/
│ │ ├── usage.ts # TypeScript interfaces
│ │ └── electron.d.ts # Electron API types
│ ├── lib/utils.ts # Utility functions
│ └── styles/index.css # Tailwind CSS with custom themes
├── biome.json # Biome linter/formatter config
├── components.json # Radix UI component config
├── electron-builder.json # App packaging configuration
├── webpack.config.js # Renderer build configuration
├── tsconfig*.json # TypeScript configurations (3 files)
├── tailwind.config.js # Tailwind CSS configuration
└── postcss.config.js # PostCSS configuration
- Initialized git repository with comprehensive .gitignore
- Two commits made:
- Initial commit with full feature set
- Refactor commit improving ccusage integration
- Clean working tree ready for development
Since there are no automated tests, manual verification checklist:
- Menu bar text display appears with usage percentage
- Click expands tabbed interface with multiple views
- Right-click shows context menu with refresh/quit options
- All tabs (Dashboard, Live, Analytics, Terminal, Settings) function correctly
- Data updates every 30 seconds across all views
- Error boundaries handle failures gracefully
- ccusage data-loader integration: Verify correct import and usage of data-loader functions
- Data consistency: Ensure displayed data matches
ccusageoutput - Actual reset time accuracy: Verify session-based reset times from active blocks
- Session tracking: Confirm session data persistence and analytics
- Settings persistence: Confirm plan and preference settings save to
~/.tokenwatch/settings.json
- Plan selection: Test Auto-detect, Pro, Max5, Max20, and Custom plan options in SettingsPanel
- Custom token limits: Verify custom plan allows setting and validation of non-standard limits
- Real-time updates: Confirm plan changes immediately update Dashboard and TerminalView displays
- Settings persistence: Verify settings survive app restarts and maintain backward compatibility
- Toast notifications: In-app notifications work properly
- macOS notifications: System alerts appear at thresholds
- Real-time countdown: SettingsPanel shows live "X hours Y minutes left" updating every minute
- Plan display consistency: TerminalView shows selected plan settings (not just auto-detected)
- Cost calculation accuracy: Analytics shows correct average cost per 1000 tokens
- Theme consistency: Tailwind styling renders correctly
- Responsive design: Interface adapts to different window sizes
- Component interactions: All Radix UI components function properly