Skip to main content

Session & Tool-Usage Tracker

Understanding how the MCP ADR Analysis Server tracks project-local session intents, tool usage, and ADR registrations with keyword-scored retrieval.


๐ŸŽฏ Overviewโ€‹

This component stores project-local workflow state (intents, tool executions, ADR registrations, todo sync, score trends) and supports keyword retrieval. It tracks relationships between architectural decisions, code patterns, and project evolution over time within project-local JSON snapshots.

Key Conceptsโ€‹

  • Session Intent Tracking - Records human requests and AI tool executions per session
  • Temporal Evolution - How decisions and patterns change over time
  • Project-Local State - Stores intents, tool results, ADR registrations, and score trends in JSON snapshots
  • Keyword-Scored Retrieval - Finds relevant entries by keyword matching over stored snapshots
  • TODO Synchronization - Keeps task state in sync with project TODO files

๐Ÿ—๏ธ Architecture and Designโ€‹

Tracker Structureโ€‹

Entity Typesโ€‹

Core Entities:

interface Entity {
id: string;
type: EntityType;
properties: Record<string, any>;
createdAt: Date;
updatedAt: Date;
confidence: number;
}

enum EntityType {
// Code Entities
CLASS = 'class',
FUNCTION = 'function',
MODULE = 'module',
INTERFACE = 'interface',

// Architectural Entities
COMPONENT = 'component',
SERVICE = 'service',
DATABASE = 'database',
API = 'api',

// Decision Entities
ADR = 'adr',
PATTERN = 'pattern',
CONSTRAINT = 'constraint',

// Project Entities
FEATURE = 'feature',
REQUIREMENT = 'requirement',
DEPENDENCY = 'dependency',
}

Relationship Types:

interface Relationship {
id: string;
source: string; // Entity ID
target: string; // Entity ID
type: RelationshipType;
weight: number; // Strength of relationship
context: string; // Context of the relationship
}

enum RelationshipType {
// Code Relationships
IMPLEMENTS = 'implements',
EXTENDS = 'extends',
DEPENDS_ON = 'depends_on',
CALLS = 'calls',

// Architectural Relationships
CONTAINS = 'contains',
CONNECTS_TO = 'connects_to',
USES = 'uses',
PROVIDES = 'provides',

// Decision Relationships
DECIDES = 'decides',
CONSTRAINS = 'constrains',
INFLUENCES = 'influences',
REPLACES = 'replaces',

// Temporal Relationships
EVOLVES_FROM = 'evolves_from',
SUPERSEDES = 'supersedes',
PREVIOUS_VERSION = 'previous_version',
}

๐Ÿ”„ How It Worksโ€‹

Graph Construction Pipelineโ€‹

Phase 1: Entity Extraction

class EntityExtractor {
async extractEntities(projectPath: string): Promise<Entity[]> {
const entities: Entity[] = [];

// 1. Extract code entities
const codeEntities = await this.extractCodeEntities(projectPath);
entities.push(...codeEntities);

// 2. Extract architectural entities
const archEntities = await this.extractArchitecturalEntities(projectPath);
entities.push(...archEntities);

// 3. Extract decision entities
const decisionEntities = await this.extractDecisionEntities(projectPath);
entities.push(...decisionEntities);

// 4. Extract temporal entities
const temporalEntities = await this.extractTemporalEntities(projectPath);
entities.push(...temporalEntities);

return entities;
}

private async extractCodeEntities(projectPath: string): Promise<Entity[]> {
const files = await this.scanCodeFiles(projectPath);
const entities: Entity[] = [];

for (const file of files) {
const ast = await this.parseFile(file);
const fileEntities = this.extractFromAST(ast, file);
entities.push(...fileEntities);
}

return entities;
}
}

Phase 2: Relationship Mapping

class RelationshipMapper {
async mapRelationships(entities: Entity[]): Promise<Relationship[]> {
const relationships: Relationship[] = [];

// 1. Code relationships
const codeRelations = await this.mapCodeRelationships(entities);
relationships.push(...codeRelations);

// 2. Architectural relationships
const archRelations = await this.mapArchitecturalRelationships(entities);
relationships.push(...archRelations);

// 3. Decision relationships
const decisionRelations = await this.mapDecisionRelationships(entities);
relationships.push(...decisionRelations);

// 4. Temporal relationships
const temporalRelations = await this.mapTemporalRelationships(entities);
relationships.push(...temporalRelations);

return relationships;
}

private async mapCodeRelationships(entities: Entity[]): Promise<Relationship[]> {
const relationships: Relationship[] = [];
const codeEntities = entities.filter(e => this.isCodeEntity(e));

for (const entity of codeEntities) {
// Find imports and dependencies
const dependencies = await this.findDependencies(entity, codeEntities);

for (const dep of dependencies) {
relationships.push({
id: `${entity.id}-depends_on-${dep.id}`,
source: entity.id,
target: dep.id,
type: RelationshipType.DEPENDS_ON,
weight: this.calculateDependencyWeight(entity, dep),
context: 'code_dependency',
});
}

// Find usage patterns
const usages = await this.findUsages(entity, codeEntities);
for (const usage of usages) {
relationships.push({
id: `${usage.id}-uses-${entity.id}`,
source: usage.id,
target: entity.id,
type: RelationshipType.USES,
weight: this.calculateUsageWeight(entity, usage),
context: 'code_usage',
});
}
}

return relationships;
}
}

Phase 3: Graph Query and Inference

class GraphQueryEngine {
async queryGraph(query: GraphQuery): Promise<QueryResult> {
switch (query.type) {
case 'find_related':
return this.findRelatedEntities(query);
case 'trace_influence':
return this.traceInfluence(query);
case 'find_patterns':
return this.findPatterns(query);
case 'predict_impact':
return this.predictImpact(query);
default:
throw new Error(`Unknown query type: ${query.type}`);
}
}

private async findRelatedEntities(query: FindRelatedQuery): Promise<QueryResult> {
const entity = await this.getEntity(query.entityId);
const relationships = await this.getRelationships(entity.id);

// Find entities within specified degrees of separation
const related = await this.traverseGraph(entity, query.maxDepth);

// Rank by relevance
const ranked = this.rankByRelevance(related, query.context);

return {
entities: ranked,
relationships: relationships,
confidence: this.calculateConfidence(ranked),
};
}

private async traceInfluence(query: TraceInfluenceQuery): Promise<QueryResult> {
const source = await this.getEntity(query.sourceId);
const target = await this.getEntity(query.targetId);

// Find paths between source and target
const paths = await this.findPaths(source, target, query.maxPathLength);

// Calculate influence strength
const influence = this.calculateInfluence(paths);

return {
paths: paths,
influence: influence,
confidence: this.calculatePathConfidence(paths),
};
}
}

Learning and Adaptationโ€‹

Pattern Recognition:

class PatternRecognizer {
async identifyPatterns(entities: Entity[], relationships: Relationship[]): Promise<Pattern[]> {
const patterns: Pattern[] = [];

// 1. Structural patterns
const structuralPatterns = await this.identifyStructuralPatterns(entities, relationships);
patterns.push(...structuralPatterns);

// 2. Behavioral patterns
const behavioralPatterns = await this.identifyBehavioralPatterns(entities, relationships);
patterns.push(...behavioralPatterns);

// 3. Architectural patterns
const archPatterns = await this.identifyArchitecturalPatterns(entities, relationships);
patterns.push(...archPatterns);

// 4. Evolution patterns
const evolutionPatterns = await this.identifyEvolutionPatterns(entities, relationships);
patterns.push(...evolutionPatterns);

return patterns;
}

private async identifyStructuralPatterns(
entities: Entity[],
relationships: Relationship[]
): Promise<Pattern[]> {
const patterns: Pattern[] = [];

// Find common structural motifs
const motifs = await this.findStructuralMotifs(entities, relationships);

for (const motif of motifs) {
if (motif.frequency > 3 && motif.confidence > 0.7) {
patterns.push({
id: `structural_${motif.name}`,
type: PatternType.STRUCTURAL,
name: motif.name,
description: this.generatePatternDescription(motif),
entities: motif.entities,
relationships: motif.relationships,
confidence: motif.confidence,
frequency: motif.frequency,
});
}
}

return patterns;
}
}

๐Ÿ’ก Design Decisionsโ€‹

Decision 1: JSON-Snapshot-Based State Trackingโ€‹

Problem: Need a lightweight way to persist session state and architectural relationships without external dependencies
Solution: Use project-local JSON snapshots with keyword-scored retrieval
Trade-offs:

  • โœ… Pros: No external database required, simple file-based persistence, easy to inspect and debug
  • โŒ Cons: Limited query expressiveness compared to a full database, linear scan for keyword matching

Decision 2: Multi-Layer Graph Storageโ€‹

Problem: Graph queries need to be fast but also persistent across sessions
Solution: Implement in-memory graph for speed with persistent storage for durability
Trade-offs:

  • โœ… Pros: Fast queries, data persistence, memory efficiency
  • โŒ Cons: Complexity in synchronization, potential consistency issues

Decision 3: Confidence-Weighted Relationshipsโ€‹

Problem: Not all relationships are equally strong or reliable
Solution: Assign confidence weights to relationships based on evidence strength
Trade-offs:

  • โœ… Pros: More nuanced analysis, better handling of uncertainty
  • โŒ Cons: Increased complexity, need for confidence calculation algorithms

Decision 4: Temporal Graph Evolutionโ€‹

Problem: Architectural knowledge changes over time and needs to be tracked
Solution: Maintain temporal relationships and track evolution patterns
Trade-offs:

  • โœ… Pros: Historical analysis, trend identification, evolution understanding
  • โŒ Cons: Increased storage requirements, complexity in temporal queries

๐Ÿ“Š Session & Tool-Usage Tracker Metricsโ€‹

Current Performanceโ€‹

MetricCurrent ValueTarget
Entity Count50,000+100,000+
Relationship Count200,000+500,000+
Query Response Time150ms<100ms
Pattern Recognition Accuracy85%90%+
Graph Update FrequencyReal-timeReal-time

Learning Effectivenessโ€‹

  • Pattern Discovery: 15+ architectural patterns identified
  • Relationship Accuracy: 92% confidence in identified relationships
  • Prediction Success: 78% accuracy in impact predictions
  • Knowledge Retention: 95% of learned patterns retained


๐Ÿ“š Further Readingโ€‹


Questions about the session tracker? โ†’ Open an Issue