Session State Detection System Architecture: ProcessDetector and StateCalculator in Claude Code Templates

The session state detection system combines ProcessDetector to scan the OS for running Claude CLI processes with StateCalculator to derive human-readable conversation states from message history, file timestamps, and process metadata, enabling real-time analytics entirely in-process.

The davila7/claude-code-templates repository provides an analytics dashboard that monitors Claude Code conversation activity in real-time. At its core, a sophisticated session state detection system determines whether conversations are active, idle, or awaiting responses by chaining two specialized services. This architecture eliminates external dependencies while providing sub-second state updates through intelligent caching and heuristic calculations.

Core Components of the Session State Detection System

The system relies on two tightly coupled classes that operate sequentially to produce accurate state information.

ProcessDetector: OS-Level Process Discovery

The ProcessDetector class (cli-tool/src/analytics/core/ProcessDetector.js) handles system-level process interrogation. Its primary method, detectRunningClaudeProcesses() (lines 23-41), executes shell commands to identify running Claude CLI instances and extracts metadata including pid, command, and workingDir.

Key capabilities include:

  • Result caching: Process scans are cached for approximately 500ms to prevent excessive shell calls
  • Conversation matching: The matchProcessToConversation() method (lines 38-55) correlates running processes to specific conversations using working directory or project name heuristics
  • Data enrichment: enrichWithRunningProcesses() (lines 99-166) attaches runningProcess objects to conversation records

StateCalculator: Conversation State Logic

The StateCalculator class (cli-tool/src/analytics/core/StateCalculator.js) transforms raw conversation data into human-readable status strings. It operates in two distinct modes:

  • Full calculation via determineConversationState() (lines 20-66): Analyzes complete message lists, file modification timestamps, and attached process data to classify states as "Claude Code working...", "Awaiting response...", "Idle", or "Inactive"
  • Quick calculation via quickStateCalculation() (lines 12-33): Applies lightweight heuristics based on recent file activity when a running process is already attached, optimizing for performance during high-frequency polling

Data Flow Architecture

The session state detection system follows a four-stage pipeline that keeps the analytics dashboard synchronized with actual CLI activity.

  1. Process discovery: ProcessDetector.detectRunningClaudeProcesses() executes ps aux commands and builds an array of process objects. Results remain cached for ~500ms to minimize system overhead.
  2. Conversation enrichment: ConversationAnalyzer.loadInitialData() instantiates ProcessDetector and invokes enrichWithRunningProcesses(conversations, claudeDir, stateCalculator). For each conversation, it finds matching processes and recalculates states using StateCalculator.determineConversationState().
  3. State calculation: The system chooses between full calculation (when loading initial data) or quick calculation (during rapid updates), depending on whether process information is already attached.
  4. API exposure: Endpoints in cli-tool/src/analytics.js expose computed states via HTTP, while WebSocketServer.js pushes real-time updates to connected clients.

Implementation Details and Code Examples

Detecting Running Claude Processes

To use ProcessDetector in a standalone Node.js script:

const ProcessDetector = require('./cli-tool/src/analytics/core/ProcessDetector');

(async () => {
  const pd = new ProcessDetector();
  
  // Scan for running Claude processes
  const processes = await pd.detectRunningClaudeProcesses();
  console.log('Running processes:', processes);
  
  // Each process object contains pid, command, and workingDir
})();

The method returns structured data that enables correlation between system processes and conversation files stored in the Claude configuration directory.

Calculating Conversation States

StateCalculator accepts message arrays and file statistics to determine activity status:

const StateCalculator = require('./cli-tool/src/analytics/core/StateCalculator');
const fs = require('fs-extra');

(async () => {
  const sc = new StateCalculator();
  
  // Load conversation messages from JSONL file
  const path = '/Users/me/.claude/projects/my-project/conversation.jsonl';
  const raw = await fs.readFile(path, 'utf8');
  const messages = raw.trim().split('\n').map(line => JSON.parse(line));
  
  // Get file modification time
  const fileStat = await fs.stat(path);
  
  // Determine state without process attachment
  const state = sc.determineConversationState(messages, fileStat.mtime);
  console.log('Current state:', state); // "Idle", "Awaiting response...", etc.
})();

Real-Time API Endpoints

The session state detection system exposes REST endpoints for dashboard integration. Query the current state of all conversations:

curl -s http://localhost:3333/api/conversation-state \
  | jq '.activeStates["my-conversation-id"]'

Trigger a targeted update for active conversations only:

curl -s http://localhost:3333/api/fast-update \
  | jq '.conversations[] | {id, conversationState}'

The /api/fast-update endpoint specifically invokes stateCalculator.quickStateCalculation() for conversations with attached processes, while falling back to time-based heuristics for inactive sessions.

Summary

  • ProcessDetector (cli-tool/src/analytics/core/ProcessDetector.js) handles OS-level process discovery with 500ms caching to identify running Claude CLI instances.
  • StateCalculator (cli-tool/src/analytics/core/StateCalculator.js) provides dual-mode state determination: full analysis for initial loads and quick heuristics for rapid updates.
  • The enrichment pipeline in ConversationAnalyzer bridges these components by attaching process data to conversation objects before state calculation.
  • All operations occur in-process without external services, enabling high-frequency polling through the /api/conversation-state and /api/fast-update endpoints.
  • The architecture supports real-time updates via WebSocket while maintaining performance through intelligent caching and targeted recalculation.

Frequently Asked Questions

How does ProcessDetector identify which processes belong to specific Claude Code conversations?

ProcessDetector uses matchProcessToConversation() (lines 38-55) to correlate running processes with conversation records by comparing the process working directory against the conversation's project path. When a match is found, it attaches a runningProcess field to the conversation object, enabling StateCalculator to factor active CLI sessions into its determination logic.

What is the difference between determineConversationState() and quickStateCalculation()?

determineConversationState() performs a comprehensive analysis of the complete message history, file modification timestamps, and optional process data to classify conversations into precise states like "Claude Code working..." or "Awaiting response...". In contrast, quickStateCalculation() (lines 12-33) uses lightweight heuristics based solely on recent file activity when a running process is already known, optimizing for the high-frequency polling required by the /api/fast-update endpoint.

How often does the system refresh process information to avoid performance penalties?

ProcessDetector implements a 500ms cache on detectRunningClaudeProcesses() results to prevent excessive shell calls during rapid dashboard refreshes. This caching strategy allows the analytics dashboard to update dozens of times per minute while maintaining sub-second response times and minimizing system resource consumption.

Can the session state detection system operate without external databases or services?

Yes, the entire architecture runs in-process within the Node.js application. As implemented in davila7/claude-code-templates, the system relies on filesystem access for conversation JSONL files, shell commands for process detection, and in-memory caching for state management. No external databases, message queues, or network services are required for core functionality.

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 →