How the Year in Review 2025 Feature Calculates Claude Session Statistics: A Deep Dive into the Analytics Engine

The Year in Review 2025 feature calculates Claude session statistics by filtering local conversation logs to the 2025 calendar year and applying deterministic aggregation methods in cli-tool/src/analytics/core/YearInReview2025.js to derive metrics including token usage, model distribution, activity streaks, and tool utilization without external API calls.

The davila7/claude-code-templates repository includes a comprehensive analytics engine that powers the Year in Review 2025 dashboard. This feature processes raw conversation data stored locally in the user's .claude directory to generate detailed statistics about coding sessions, productivity patterns, and AI model utilization. Every metric is computed through pure local analysis of JSON conversation logs, ensuring complete data privacy and offline functionality.

Entry Point and Core Architecture

The analytics pipeline centers on the YearInReview2025 class defined in cli-tool/src/analytics/core/YearInReview2025.js. When the CLI receives the --2025 flag, it instantiates this class and invokes the generateYearInReview() method, passing the complete array of conversation records and the path to the user's .claude configuration directory.

The constructor initializes the analyzer, and the primary method orchestrates the entire computation workflow. It receives conversation data from the analytics engine and returns a comprehensive statistics object that powers both the terminal summary and the static HTML visualization.

Data Filtering and Preparation

Before calculating statistics, the engine performs two critical preparation steps:

  • filterConversations2025() parses the lastModified timestamp of each conversation, retaining only those falling between 2025-01-01 and 2025-12-31. This creates the working dataset for all subsequent calculations.
  • detectInstalledComponents() scans the ~/.claude/local directory to identify installed MCPs (Model Context Protocols) and enabled plugins, providing metadata for the component installation visualization used by tools like Gource.

Statistical Computation Methods

The analyzer derives every dashboard metric through deterministic aggregation functions operating on the filtered 2025 conversation array.

Conversation Volume and Model Distribution

The foundation of the statistics starts with simple array operations:

  • totalConversations is calculated as conversations2025.length, providing the raw count of sessions in the target year.
  • analyzeModelUsage() iterates through the conversation array, counting occurrences of each primary model name. It formats model identifiers (e.g., converting internal codes to "Claude 3.5 Sonnet") and returns the top three most frequently used models with their respective percentages.

Token Usage Calculations

The calculateTokenUsage() method performs granular token accounting:

// Sums tokenUsage or falls back to conv.tokens
const totalTokens = conversations2025.reduce((sum, conv) => {
  return sum + (conv.tokenUsage || conv.tokens || 0);
}, 0);

// Breaks into input, output, and cache categories
// Returns formatted strings like "1.2B" or "450M"

This method aggregates tokenUsage objects (or falls back to flat tokens values) across all conversations, categorizing consumption into input, output, and cached tokens. The results are formatted into human-readable billions or millions for display.

Activity Streaks and Heatmaps

Activity tracking relies on date mathematics:

  • calculateStreak() constructs a Set of distinct activity dates from conversation timestamps, sorts them chronologically, then walks the array to identify consecutive day sequences. It tracks both the longest historical streak and the current active streak ending on the analysis date.
  • generateActivityHeatmap() creates a GitHub-style 52-week visualization grid. For each day, it records conversation count, token sums, tool usage statistics, and model breakdowns. It assigns intensity levels 0 through 4 based on daily conversation volume, producing the color-coded annual activity map.

Tool, Agent, and MCP Metrics

The analyzer tracks component utilization through specialized counters:

  • countTools(), countAgents(), and countMCPs() return simple aggregations with formatted string outputs (e.g., "1.2K" for large numbers).
  • analyzeToolUsage() performs deeper analysis by totaling totalToolCalls across conversations and aggregating per-tool statistics from conv.toolUsage.toolStats. It returns the grand total alongside the five most frequently invoked tools.

Temporal and Project Analysis

Time-based patterns emerge through bucketing algorithms:

  • analyzeTimeOfDay() extracts the hour from each conversation's lastModified timestamp, buckets sessions into 24 hourly slots, and identifies the peak activity hour.
  • analyzeTopProjects() groups conversations by the conv.project field (defaulting to "Unknown" for untagged sessions). It counts conversations and sums tokens per project, returning the five most active projects ranked by engagement volume.

Insights and Local Component History

Additional context comes from filesystem analysis:

  • generateInsights() calculates overall message counts, averages messages per conversation, and identifies the single most productive day (the date with the highest conversation count).
  • analyzeCommands(), analyzeSkills(), analyzeMCPs(), and analyzeSubagents() operate as asynchronous helpers that read history files from the .claude directory. These methods parse command logs, skill invocations, MCP interactions, and subagent spawns, returning usage counts and timestamped event arrays.

Parallel Processing and Result Assembly

The computation workflow maximizes efficiency through parallelization:

  1. Async Component Analysis: Commands, skills, MCPs, and subagent data are fetched concurrently using Promise.all(), preventing filesystem I/O from blocking the main thread.
  2. Synchronous Aggregation: Core conversation statistics (tokens, streaks, time-of-day) compute synchronously on the filtered array.
  3. Final Assembly: All results merge into a single stats object containing keys for totalConversations, models, tokens, streak, activityHeatmap, topProjects, toolUsage, and component-specific data.

The assembled statistics object returns to the CLI entry point in cli-tool/src/index.js, which writes the JSON output and generates the static HTML report using the template in cli-tool/src/analytics-web/2025.html.

Example: Invoking the Analyzer

const YearInReview2025 = require('./analytics/core/YearInReview2025');
const analyzer = new YearInReview2025();

(async () => {
  const allConvs = await analytics.getAllConversations();
  const stats = await analyzer.generateYearInReview(allConvs, '/home/user/.claude');
  
  console.log(`Analyzed ${stats.totalConversations} conversations`);
  console.log('Top model:', stats.models[0].name);
})();

Example: Streak Calculation Logic

const sortedDays = Array.from(activeDays).sort();
let longest = 1, current = 1;

for (let i = 1; i < sortedDays.length; i++) {
  const diff = (new Date(sortedDays[i]) - new Date(sortedDays[i-1])) / (1000*60*60*24);
  if (diff === 1) { 
    current++; 
    longest = Math.max(longest, current); 
  } else { 
    current = 1; 
  }
}

Summary

  • The Year in Review 2025 feature operates entirely on local conversation logs, requiring no external API connectivity or cloud services.
  • All calculations occur in cli-tool/src/analytics/core/YearInReview2025.js, with entry point generateYearInReview() orchestrating the analysis pipeline.
  • The engine filters conversations to the 2025 calendar year using filterConversations2025() before applying deterministic aggregation methods.
  • Statistics range from simple counts (totalConversations) to complex temporal analysis (calculateStreak(), analyzeTimeOfDay()).
  • Parallel async operations fetch command history, skill usage, and MCP data from the local .claude directory while synchronous methods process conversation arrays.
  • Output feeds a static HTML template to render the visual dashboard, with all data formatted for human readability (e.g., "1.2B tokens", "1.2K tools").

Frequently Asked Questions

Where does the Year in Review 2025 feature get its data?

The feature reads from local conversation logs stored in the user's .claude directory. It accesses JSON conversation files, history logs, and local component manifests to build a complete picture of activity without transmitting data to external servers.

Can the statistics calculation work offline?

Yes. Since the analyzer in cli-tool/src/analytics/core/YearInReview2025.js processes only local files and conversation arrays, it functions completely offline. The deterministic calculations require no network access once the conversation data resides on the filesystem.

How does the feature determine the "most productive day"?

The generateInsights() method creates a histogram of conversation counts by date, then identifies the date with the maximum value. This single day represents the highest volume of Claude interactions during the 2025 calendar year.

What distinguishes the token calculation from simple message counting?

The calculateTokenUsage() method accesses granular token metadata within each conversation record, distinguishing between input tokens, output tokens, and cache hits. This provides accurate resource consumption metrics rather than approximating based on message length or conversation count.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →