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

> Explore the session state detection system architecture, using ProcessDetector and StateCalculator for real-time, in-process analytics of Claude conversations. Understand process scanning and state derivation.

- Repository: [Daniel Avila/claude-code-templates](https://github.com/davila7/claude-code-templates)
- Tags: architecture
- Published: 2026-04-26

---

**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`](https://github.com/davila7/claude-code-templates/blob/main/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`](https://github.com/davila7/claude-code-templates/blob/main/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`](https://github.com/davila7/claude-code-templates/blob/main/cli-tool/src/analytics.js) expose computed states via HTTP, while [`WebSocketServer.js`](https://github.com/davila7/claude-code-templates/blob/main/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:

```javascript
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:

```javascript
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:

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

```

Trigger a targeted update for active conversations only:

```bash
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`](https://github.com/davila7/claude-code-templates/blob/main/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`](https://github.com/davila7/claude-code-templates/blob/main/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.