Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 201 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1 +1,201 @@
- DO NOT directly change the scripts or settings in .claude or ~/.claude. only update the source code that modifies these files.
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Common Commands

### Development
```bash
# Start dashboard development server (http://localhost:3000)
npm run dev:dashboard

# Watch hooks tests during development
npm run dev:hooks

# Run both dashboard and hooks development
npm run dev # Runs dashboard by default
```

### Testing
```bash
# Run all tests
npm test

# Run with coverage
npm run test:coverage

# Test specific component
npm run test:dashboard
npm run test:hooks

# Run single test file in hooks (using UV)
cd apps/hooks && uv run python -m pytest tests/test_post_tool_use.py -v

# Run specific test
cd apps/hooks && uv run python -m pytest tests/test_post_tool_use.py::TestClassName::test_method -v

# Dashboard tests with watch mode
cd apps/dashboard && npm run test:watch
```

### Code Quality
```bash
# Run linters
npm run lint

# Full validation (lint + test + coverage check)
npm run validate

# Check coverage thresholds
npm run coverage:check

# Generate coverage reports
npm run coverage:report
npm run coverage:badges
```

### Build & Production
```bash
# Build everything
npm run build

# Dashboard production build
cd apps/dashboard && npm run build:production

# Validate environment configuration
cd apps/dashboard && npm run validate:env

# Health check
./scripts/health-check.sh
```

### Installation & Setup
```bash
# Quick start (automated setup)
./scripts/quick-start.sh

# Install hooks system
cd apps/hooks && python scripts/install.py

# Validate installation
cd apps/hooks && python scripts/install.py --validate-only

# Setup database schema
cd apps/hooks && python scripts/setup_schema.py
```

## High-Level Architecture

### System Overview
Chronicle is an observability system for Claude Code agent activities, capturing tool usage, interactions, and performance metrics. It consists of two main components that communicate through a shared database:

1. **Hooks System (Python)**: Intercepts Claude Code events and stores them in database
2. **Dashboard (Next.js)**: Real-time visualization of captured events

### Data Flow Architecture
```
Claude Code Agent
Hook Scripts (Python)
Database Layer (Supabase/SQLite)
Real-time Subscriptions
Dashboard (Next.js)
```

### Database Architecture
The system uses a dual-database approach:
- **Primary**: Supabase (PostgreSQL) for production with real-time capabilities
- **Fallback**: SQLite for local development or when Supabase is unavailable

Key tables:
- `events`: Core event storage with tool usage, errors, and metadata
- `sessions`: Claude Code session tracking and lifecycle
- `tools`: Tool execution details and performance metrics

### Hook System Architecture (`apps/hooks/`)
The hooks system uses UV for dependency management and follows a modular pattern:

- **Entry Points** (`src/hooks/`): Individual hook scripts for each Claude Code event
- `session_start.py`: Initialize session tracking
- `pre_tool_use.py`: Capture tool invocations (pure observation, no blocking)
- `post_tool_use.py`: Record tool results and performance
- `user_prompt_submit.py`: Track user interactions
- `stop.py`: Clean session closure

- **Shared Library** (`src/lib/`):
- `base_hook.py`: Common hook functionality and event creation
- `database.py`: Database abstraction layer with connection pooling
- `utils.py`: MCP tool detection, sanitization, and utilities
- `security.py`: Data sanitization and PII filtering
- `performance.py`: Metrics collection and optimization

- **Configuration** (`config/`):
- `settings.py`: Environment and database configuration
- `models.py`: Pydantic models for type safety
- `database.py`: Database connection management

### Dashboard Architecture (`apps/dashboard/`)
Next.js 15 app with App Router and real-time updates:

- **Components** (`src/components/`):
- `EventDashboard.tsx`: Main dashboard container
- `EventFeed.tsx`: Real-time event stream display
- `EventCard.tsx`: Individual event visualization
- `ConnectionStatus.tsx`: Database connection monitoring

- **Hooks** (`src/hooks/`):
- `useSupabaseConnection.ts`: Manages database connection and reconnection
- `useEvents.ts`: Real-time event subscription and caching
- `useSessions.ts`: Session management and filtering

- **Libraries** (`src/lib/`):
- `supabase.ts`: Supabase client with real-time configuration
- `eventProcessor.ts`: Event transformation and filtering
- `config.ts`: Environment-aware configuration
- `security.ts`: Client-side data sanitization

### Key Design Patterns

1. **Environment Detection**: Both components auto-detect environment (development/staging/production) and adjust behavior accordingly

2. **Graceful Degradation**: Falls back to SQLite if Supabase unavailable, demo mode if no database

3. **Performance Optimization**:
- Connection pooling in hooks
- Event batching in dashboard
- Debounced real-time subscriptions
- 100ms target latency for hooks

4. **Security First**:
- Automatic PII filtering
- Configurable data sanitization
- Environment variable validation
- No authentication required for MVP (pure observability)

## Project Management

### Linear Integration
This project uses Linear for issue tracking and project management. The MCP Linear integration is available for:

- **Creating issues**: Use issue IDs like `CHR-1`, `CHR-2` for Chronicle-related tasks
- **Viewing project status**: Check current sprint progress and backlog items
- **Updating task states**: Move issues through workflow states
- **Adding comments**: Document progress and decisions on Linear issues
- **Linking PRs**: Reference Linear issues in commit messages and PR descriptions

When working on features or fixes:
1. Check Linear for existing issues before starting work
2. Reference Linear issue IDs in commits (e.g., `fix: resolve database connection issue [CHR-123]`)
3. Update issue status as work progresses
4. Add implementation notes as comments on the Linear issue

## Important Notes

- DO NOT directly change scripts or settings in `.claude` or `~/.claude` directories - only update source code that modifies these files
- The system is designed for pure observability - hooks should never block or modify Claude Code behavior
- All hook scripts use UV's single-file script format with inline dependencies
- Coverage thresholds: Dashboard 80%, Hooks 60%, Security modules 90%
- Real-time updates use Supabase's PostgreSQL LISTEN/NOTIFY under the hood
73 changes: 39 additions & 34 deletions apps/dashboard/__tests__/lib/security.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,47 @@ import {
} from '../../src/lib/security';

// Mock dependencies
const mockConfig = {
environment: 'test',
security: {
enableCSP: true,
enableSecurityHeaders: true,
rateLimiting: {
enabled: true,
windowMs: 15 * 60 * 1000, // 15 minutes
maxRequests: 100,
jest.mock('../../src/lib/config', () => {
const mockConfig = {
environment: 'test',
backend: {
mode: 'supabase',
supabase: {
url: 'https://test.supabase.co',
anonKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.key',
},
},
},
supabase: {
url: 'https://test.supabase.co',
anonKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.key',
},
monitoring: {
sentry: {
dsn: 'https://[email protected]/project',
security: {
enableCSP: true,
enableSecurityHeaders: true,
rateLimiting: {
enabled: true,
windowMs: 15 * 60 * 1000, // 15 minutes
maxRequests: 100,
},
},
},
debug: {
enabled: false,
showDevTools: false,
},
};

const mockConfigUtils = {
isDevelopment: jest.fn(() => false),
isProduction: jest.fn(() => true),
log: jest.fn(),
};

jest.mock('../../src/lib/config', () => ({
config: mockConfig,
configUtils: mockConfigUtils,
}));
monitoring: {
sentry: {
dsn: 'https://[email protected]/project',
},
},
debug: {
enabled: false,
showDevTools: false,
},
};

const mockConfigUtils = {
isDevelopment: jest.fn(() => false),
isProduction: jest.fn(() => true),
log: jest.fn(),
};

return {
config: mockConfig,
configUtils: mockConfigUtils,
};
});

jest.mock('../../src/lib/utils', () => ({
logger: {
Expand Down
8 changes: 4 additions & 4 deletions apps/dashboard/src/lib/supabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import { config, configUtils } from './config';
import { logger } from './utils';

// Get Supabase URL and key, prioritizing env vars for client-side
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || config.supabase.url || '';
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || config.supabase.anonKey || '';
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || config.backend.supabase?.url || '';
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || config.backend.supabase?.anonKey || '';

// Debug: Log what we're using
console.log('🔧 Supabase Client Initialization:', {
url: supabaseUrl,
keyPrefix: supabaseAnonKey ? supabaseAnonKey.substring(0, 20) + '...' : 'missing',
hasEnvUrl: !!process.env.NEXT_PUBLIC_SUPABASE_URL,
hasEnvKey: !!process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
hasConfigUrl: !!config.supabase.url,
hasConfigKey: !!config.supabase.anonKey,
hasConfigUrl: !!config.backend.supabase?.url,
hasConfigKey: !!config.backend.supabase?.anonKey,
});

// Validate we have required config before creating client
Expand Down
3 changes: 1 addition & 2 deletions apps/hooks/src/hooks/pre_tool_use.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,7 @@ def process_hook(self, input_data: Dict[str, Any]) -> Dict[str, Any]:



origin/dev


def _sanitize_tool_input(self, tool_input: Dict[str, Any]) -> Dict[str, Any]:
"""Sanitize tool input for logging."""
if not isinstance(tool_input, dict):
Expand Down
13 changes: 9 additions & 4 deletions apps/hooks/tests/uv_scripts/test_db_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,16 @@ class Style:

# Load environment and database manager
try:
from env_loader import load_chronicle_env, get_database_config
from database_manager import DatabaseManager
# Add src directory to path for imports
from pathlib import Path
src_dir = Path(__file__).parent.parent.parent / 'src'
sys.path.insert(0, str(src_dir))

from lib.database import DatabaseManager, get_database_config
from scripts.env_loader import load_chronicle_env
load_chronicle_env()
except ImportError:
print(f"{Fore.RED}Error: Cannot import env_loader or database_manager")
except ImportError as e:
print(f"{Fore.RED}Error: Cannot import required modules: {e}")
print("Make sure you're running from the correct directory")
sys.exit(1)

Expand Down
Loading