Add session documentation system (migration + MCP tools)

Phase 1-2 complete: Database schema + 9 MCP tools for session docs

Database Changes (migration 016):
- session_notes table (accomplishments, decisions, gotchas, etc.)
- session_plans table (plan mode plans with lifecycle tracking)
- project_documentation table (persistent project docs)
- sessions.documentation column (auto-generated markdown)
- HNSW indexes for semantic search across all doc types

MCP Tools Added (session-docs.ts):
1. session_note_add - Add structured notes to session
2. session_notes_list - List notes by type
3. session_plan_save - Save plan with embedding
4. session_plan_update_status - Track plan lifecycle
5. session_plan_list - List session plans
6. project_doc_upsert - Create/update project docs
7. project_doc_get - Get specific doc by type
8. project_doc_list - List all project docs
9. session_documentation_generate - Auto-generate markdown

Replaces: CLAUDE.md files, ~/.claude/plans/ directory

Next: Update session-start/end scripts for temp file management

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Christian Gick
2026-01-19 10:13:57 +02:00
parent afce0bd3e5
commit 3745a13eaf
5 changed files with 926 additions and 0 deletions

View File

@@ -0,0 +1,211 @@
-- Migration 016: Session Documentation System
-- Purpose: Migrate from file-based documentation (CLAUDE.md, plan files) to database
-- Dependencies: 010_sessions.sql (sessions table), 001_base_schema.sql (pgvector)
-- ============================================================================
-- SESSION NOTES: Structured notes within sessions
-- ============================================================================
CREATE TABLE IF NOT EXISTS session_notes (
id SERIAL PRIMARY KEY,
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
note_type TEXT NOT NULL CHECK (note_type IN (
'accomplishment',
'decision',
'gotcha',
'next_steps',
'context'
)),
content TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
embedding vector(1024) -- For semantic search of notes
);
-- Indexes for efficient querying
CREATE INDEX idx_session_notes_session ON session_notes(session_id);
CREATE INDEX idx_session_notes_type ON session_notes(note_type);
CREATE INDEX idx_session_notes_created ON session_notes(created_at DESC);
-- HNSW index for semantic similarity search
CREATE INDEX idx_session_notes_embedding ON session_notes
USING hnsw (embedding vector_cosine_ops);
COMMENT ON TABLE session_notes IS 'Structured notes within sessions (replaces ad-hoc note files)';
COMMENT ON COLUMN session_notes.note_type IS 'Category of note: accomplishment, decision, gotcha, next_steps, context';
COMMENT ON COLUMN session_notes.embedding IS 'Vector embedding for semantic search across notes';
-- ============================================================================
-- SESSION PLANS: Plan mode plans with lifecycle tracking
-- ============================================================================
CREATE TABLE IF NOT EXISTS session_plans (
id SERIAL PRIMARY KEY,
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
plan_file_name TEXT, -- Original filename (e.g., "transient-forging-reddy.md")
plan_content TEXT NOT NULL,
status TEXT DEFAULT 'draft' CHECK (status IN (
'draft',
'approved',
'executed',
'abandoned'
)),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
approved_at TIMESTAMP WITH TIME ZONE,
completed_at TIMESTAMP WITH TIME ZONE,
embedding vector(1024) -- For semantic search of plans
);
-- Indexes for efficient querying
CREATE INDEX idx_session_plans_session ON session_plans(session_id);
CREATE INDEX idx_session_plans_status ON session_plans(status);
CREATE INDEX idx_session_plans_created ON session_plans(created_at DESC);
-- HNSW index for semantic similarity search
CREATE INDEX idx_session_plans_embedding ON session_plans
USING hnsw (embedding vector_cosine_ops);
COMMENT ON TABLE session_plans IS 'Plan mode plans with lifecycle tracking (replaces ~/.claude/plans/)';
COMMENT ON COLUMN session_plans.plan_file_name IS 'Original filename from plan mode (e.g., eloquent-yellow-cat.md)';
COMMENT ON COLUMN session_plans.status IS 'Plan lifecycle: draft → approved → executed/abandoned';
COMMENT ON COLUMN session_plans.embedding IS 'Vector embedding for semantic search across plans';
-- ============================================================================
-- PROJECT DOCUMENTATION: Persistent project-level docs
-- ============================================================================
CREATE TABLE IF NOT EXISTS project_documentation (
id SERIAL PRIMARY KEY,
project TEXT NOT NULL REFERENCES projects(key) ON DELETE CASCADE,
doc_type TEXT NOT NULL CHECK (doc_type IN (
'overview',
'architecture',
'guidelines',
'history'
)),
title TEXT NOT NULL,
content TEXT NOT NULL,
last_updated_session TEXT REFERENCES sessions(id) ON DELETE SET NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(project, doc_type) -- One doc of each type per project
);
-- Indexes for efficient querying
CREATE INDEX idx_project_docs_project ON project_documentation(project);
CREATE INDEX idx_project_docs_type ON project_documentation(doc_type);
CREATE INDEX idx_project_docs_updated ON project_documentation(updated_at DESC);
COMMENT ON TABLE project_documentation IS 'Persistent project documentation (replaces CLAUDE.md sections)';
COMMENT ON COLUMN project_documentation.doc_type IS 'Type of documentation: overview, architecture, guidelines, history';
COMMENT ON COLUMN project_documentation.last_updated_session IS 'Session that last updated this documentation';
-- ============================================================================
-- SESSIONS TABLE ENHANCEMENTS
-- ============================================================================
-- Add documentation column for full markdown documentation
ALTER TABLE sessions
ADD COLUMN IF NOT EXISTS documentation TEXT;
-- Add migration flag to track CLAUDE.md migration status
ALTER TABLE sessions
ADD COLUMN IF NOT EXISTS claude_md_migrated BOOLEAN DEFAULT FALSE;
COMMENT ON COLUMN sessions.documentation IS 'Full markdown documentation for session (auto-generated at end)';
COMMENT ON COLUMN sessions.claude_md_migrated IS 'Flag indicating this session migrated from CLAUDE.md file';
-- ============================================================================
-- HELPER VIEWS
-- ============================================================================
-- View: Session with note counts
CREATE OR REPLACE VIEW session_documentation_summary AS
SELECT
s.id,
s.project,
s.session_number,
s.started_at,
s.ended_at,
s.status,
s.summary,
COUNT(DISTINCT sn.id) as note_count,
COUNT(DISTINCT sp.id) as plan_count,
ARRAY_AGG(DISTINCT sn.note_type) FILTER (WHERE sn.note_type IS NOT NULL) as note_types,
MAX(sn.created_at) as last_note_at,
MAX(sp.created_at) as last_plan_at
FROM sessions s
LEFT JOIN session_notes sn ON s.id = sn.session_id
LEFT JOIN session_plans sp ON s.id = sp.session_id
GROUP BY s.id, s.project, s.session_number, s.started_at, s.ended_at, s.status, s.summary;
COMMENT ON VIEW session_documentation_summary IS 'Sessions with note and plan counts for quick overview';
-- View: Latest project documentation
CREATE OR REPLACE VIEW latest_project_docs AS
SELECT
pd.project,
pd.doc_type,
pd.title,
LEFT(pd.content, 200) as content_preview,
pd.updated_at,
s.session_number as last_updated_session_number,
s.started_at as last_updated_session_date
FROM project_documentation pd
LEFT JOIN sessions s ON pd.last_updated_session = s.id
ORDER BY pd.project, pd.doc_type;
COMMENT ON VIEW latest_project_docs IS 'Latest project documentation with session context';
-- ============================================================================
-- MAINTENANCE FUNCTIONS
-- ============================================================================
-- Function to clean up old session notes (optional retention policy)
CREATE OR REPLACE FUNCTION cleanup_old_session_notes(retention_days INTEGER DEFAULT 180)
RETURNS INTEGER AS $$
DECLARE
deleted_count INTEGER;
BEGIN
DELETE FROM session_notes
WHERE created_at < NOW() - (retention_days || ' days')::INTERVAL
AND session_id IN (
SELECT id FROM sessions WHERE status = 'completed'
);
GET DIAGNOSTICS deleted_count = ROW_COUNT;
RETURN deleted_count;
END;
$$ LANGUAGE plpgsql;
COMMENT ON FUNCTION cleanup_old_session_notes IS 'Clean up notes from completed sessions older than retention period (default 180 days)';
-- Function to generate session documentation stats
CREATE OR REPLACE FUNCTION session_documentation_stats(p_project TEXT DEFAULT NULL)
RETURNS TABLE(
total_sessions BIGINT,
sessions_with_notes BIGINT,
sessions_with_plans BIGINT,
total_notes BIGINT,
total_plans BIGINT,
avg_notes_per_session NUMERIC,
avg_plans_per_session NUMERIC
) AS $$
BEGIN
RETURN QUERY
SELECT
COUNT(DISTINCT s.id) as total_sessions,
COUNT(DISTINCT CASE WHEN sn.id IS NOT NULL THEN s.id END) as sessions_with_notes,
COUNT(DISTINCT CASE WHEN sp.id IS NOT NULL THEN s.id END) as sessions_with_plans,
COUNT(sn.id) as total_notes,
COUNT(sp.id) as total_plans,
ROUND(COUNT(sn.id)::NUMERIC / NULLIF(COUNT(DISTINCT s.id), 0), 2) as avg_notes_per_session,
ROUND(COUNT(sp.id)::NUMERIC / NULLIF(COUNT(DISTINCT s.id), 0), 2) as avg_plans_per_session
FROM sessions s
LEFT JOIN session_notes sn ON s.id = sn.session_id
LEFT JOIN session_plans sp ON s.id = sp.session_id
WHERE (p_project IS NULL OR s.project = p_project)
AND s.status = 'completed';
END;
$$ LANGUAGE plpgsql;
COMMENT ON FUNCTION session_documentation_stats IS 'Generate statistics about session documentation usage';