Skip to content

feat: Implement history capture system (JSONL + Obsidian routing) #4

Description

@krishagel

Summary

Implement automatic session capture that stores raw conversation data (JSONL) and creates human-readable summaries (Obsidian markdown) routed by content type. This enables searchable history and pattern detection for preference learning.

Inspiration: PAI v2.0 kai-history-system

User Story

As a user of Geoffrey, I want all sessions automatically documented so that I can search past conversations and Geoffrey can learn from patterns over time.

Requirements

Dual Storage Architecture

JSONL (Raw Data):

  • Machine-readable event logs
  • Enables future ML/pattern detection
  • Stored in: ~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/history/raw/

Obsidian (Human-Readable):

  • Markdown summaries
  • Searchable via Dataview
  • Content-based routing to folders

Routing Rules

Content Type Keywords Obsidian Folder
Research "research", "analyze", "investigate" Research/[topic]/
Decisions "decide", "choose", "approach" Decisions/
Code/Tasks Everything else Daily-Logs/

Acceptance Criteria

  • SessionEnd hook captures transcript to JSONL
  • JSONL stored in ~/Library/.../Geoffrey/history/raw/YYYY-MM/session-{timestamp}.jsonl
  • Obsidian summary created with metadata frontmatter
  • Content analysis routes to appropriate folder
  • Daily logs use format: Daily-Logs/YYYY-MM-DD.md
  • Research logs use format: Research/{topic}/YYYY-MM-DD-{title}.md
  • Decision logs use format: Decisions/YYYY-MM-DD-{title}.md

Technical Implementation

Files to Create/Modify

hooks/
├── session-end/
│   ├── capture-history.ts       # NEW: Store raw JSONL
│   └── route-to-obsidian.ts     # NEW: Create Obsidian summary
└── shared/
    ├── content-analyzer.ts      # NEW: Classify conversation type
    └── obsidian-utils.ts        # NEW: Vault operations

JSONL Format (Raw Storage)

{"timestamp":"2025-12-29T10:30:00Z","event":"user_message","content":"Help me research credit cards"}
{"timestamp":"2025-12-29T10:30:15Z","event":"tool_use","tool":"WebSearch","query":"best credit cards 2025"}
{"timestamp":"2025-12-29T10:30:45Z","event":"assistant_message","content":"Here's what I found..."}

Obsidian Markdown Format

Frontmatter (all files):

---
session_id: abc123
date: 2025-12-29
type: research | decision | daily
topics: [credit-cards, travel]
files_modified: []
---

Daily Log Example:

---
session_id: abc123
date: 2025-12-29
type: daily
topics: [omnifocus, tasks]
---

# 2025-12-29 Session Summary

## Tasks Completed
- Created 3 OmniFocus tasks
- Updated project priorities

## Key Decisions
None

## Files Modified
- None

Research Example:

---
session_id: def456
date: 2025-12-29
type: research
topics: [credit-cards, travel, rewards]
---

# Credit Card Research: Travel Rewards Comparison

## Summary
Analyzed 5 travel credit cards for international spend optimization.

## Key Findings
- Chase Sapphire Reserve: 3x on travel/dining
- Capital One Venture X: 2x on everything

## Sources
- [NerdWallet 2025 Guide](...)
- [The Points Guy](...)

Decision Example:

---
session_id: ghi789
date: 2025-12-29
type: decision
topics: [architecture, hooks]
---

# Decision: Hook System Architecture

## Context
Implementing PAI v2.0-style hooks for Geoffrey

## Options Considered
1. JSONL for raw + Obsidian for summaries
2. Obsidian markdown only
3. JSONL only

## Decision
Option 1: Hybrid approach

## Rationale
- JSONL enables future ML
- Obsidian provides human searchability
- Best of both worlds

Content Analysis Logic

interface ContentClassification {
  type: 'research' | 'decision' | 'daily';
  topics: string[];
  title?: string;
}

function classifyContent(transcript: Message[]): ContentClassification {
  const allText = transcript.map(m => m.content).join(' ').toLowerCase();
  
  // Research indicators
  if (allText.includes('research') || allText.includes('analyze') || 
      allText.includes('compare') || allText.includes('investigate')) {
    return { type: 'research', topics: extractTopics(allText) };
  }
  
  // Decision indicators
  if (allText.includes('decide') || allText.includes('choose') || 
      allText.includes('should i') || allText.includes('approach')) {
    return { type: 'decision', topics: extractTopics(allText) };
  }
  
  // Default to daily log
  return { type: 'daily', topics: extractTopics(allText) };
}

Directory Structure

~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/
├── history/
│   └── raw/
│       └── 2025-12/
│           ├── session-20251229-103000.jsonl
│           └── session-20251229-140000.jsonl
└── Obsidian/
    ├── Daily-Logs/
    │   └── 2025-12-29.md
    ├── Research/
    │   ├── credit-cards/
    │   │   └── 2025-12-29-travel-rewards.md
    │   └── ai-tools/
    │       └── 2025-12-28-claude-api.md
    └── Decisions/
        ├── 2025-12-29-hook-architecture.md
        └── 2025-12-28-skill-structure.md

Testing Plan

  • Unit tests: Content classification, topic extraction
  • Integration tests: JSONL write, Obsidian file creation
  • Manual tests: Various conversation types, verify routing

Research Findings

PAI v2.0 History Architecture

Five Layers:

  1. Event capture (all Claude Code events)
  2. Raw storage (JSONL format)
  3. Content analysis (keyword detection)
  4. Agent routing (metadata-based dispatch)
  5. Organized storage (timestamped directories)

Key Patterns:

  • Monthly directories: YYYY-MM/
  • Timestamped sessions: session-{timestamp}.jsonl
  • Automatic categorization based on keywords
  • Metadata-rich frontmatter for Dataview queries

Obsidian Integration Considerations

Dynamic Vault Path:

  • Already implemented in docs/obsidian-integration.md
  • Path: ~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/

Existing Folders:

  • Daily-Logs/ ✅ exists
  • Research/ ✅ exists
  • Decisions/ ✅ exists

Dataview Compatibility:

  • Frontmatter enables queries like: LIST WHERE type = "research" AND contains(topics, "credit-cards")

Dependencies

References

  • PAI v2.0: kai-history-system.md
  • Geoffrey: docs/obsidian-integration.md for vault structure
  • Current Obsidian setup: Mission Control dashboard with Dataview

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions