ctx0 Implementation Index
This document guides Claude Code (or any implementing agent) through the ctx0 implementation process. Read this first to understand what to build and in what order.
Documentation Map
Before implementing, read the documentation in this order:
| Order | Document | Purpose |
|---|---|---|
| 1 | ctx0-supabase-data-architecture.md | Database schema, tables, RLS, functions |
| 2 | ctx0-vault-structure.md | Locked folders, file organization |
| 3 | ctx0-agents.md | Agent system (AGENT.md + config.json) |
| 4 | ctx0-skills.md | DB-as-skill pattern for sync tables |
| 5 | ctx0-sessions.md | Session/conversation storage |
Implementation Phases
Phase 1: Database Schema
Goal: Set up Supabase tables, indexes, RLS, and functions.
Tasks:
- Create all ctx0_* tables (see ctx0-supabase-data-architecture.md)
- Create indexes for performance
- Create RLS policies for user isolation
- Create helper functions (ctx0_query, ctx0_semantic_search)
- Create storage bucket (ctx0-vault)
Files to create:
packages/ctx0/
├── migrations/
│ ├── 001_ctx0_schema.sql # All tables, indexes, RLS
│ └── manifest.json # Migration metadata
└── src/
└── migrations.ts # Export SQL as strings
Verification:
- All 9 tables created
- Indexes created
- RLS enabled on all tables
- User isolation policies work
- Service role bypass works
- ctx0_query function blocks mutations
- Storage bucket created
Phase 2: Vault Structure
Goal: Initialize vault with locked folders and default content.
Tasks:
- Create initialization function that sets up vault structure
- Create locked folders (.ctx0/, agents/, skills/, tools/, mcp/)
- Create default agents (ctx0, curator)
- Create default tools documentation
- Create _index.md files
Files to modify:
packages/daemon/src/
├── ctx0/
│ ├── init.ts # Vault initialization
│ ├── entries.ts # Entry CRUD operations
│ └── storage.ts # Storage bucket operations
Default content to create:
/agents/ctx0/AGENT.md+config.json/agents/curator/AGENT.md+config.json/tools/ctx0_remember/TOOL.md/tools/ctx0_retrieve/TOOL.md/tools/ctx0_sql/TOOL.md/agents/_index.md/skills/_index.md/tools/_index.md/mcp/_index.md
Verification:
- Locked folders created with is_locked=true
- Default agents created with is_system=true
- Default tools documented
- User cannot delete locked folders
- User can add custom agents/skills/tools
Phase 3: ctx0 Tools
Goal: Implement the core ctx0 tools for agents to use.
Tasks:
- Implement ctx0_remember tool
- Implement ctx0_retrieve tool (semantic search)
- Implement ctx0_sql tool (DB-as-skill queries)
- Implement ctx0_browse tool (list entries)
- Implement ctx0_read tool (read entry content)
Files to create:
packages/daemon/src/tools/
├── ctx0-remember.ts
├── ctx0-retrieve.ts
├── ctx0-sql.ts
├── ctx0-browse.ts
└── ctx0-read.ts
Verification:
- ctx0_remember creates entries in vault
- ctx0_retrieve returns semantically similar entries
- ctx0_sql only allows SELECT queries
- ctx0_sql blocks dangerous keywords
- ctx0_browse lists entries in a path
- ctx0_read returns full entry content
Phase 4: Session Storage
Goal: Store and retrieve conversation history.
Tasks:
- Implement session creation/update
- Implement message logging
- Implement compaction tracking
- Implement session resumption
Files to create:
packages/daemon/src/ctx0/
├── sessions.ts # Session CRUD
└── messages.ts # Message logging
Verification:
- Sessions created with correct metadata
- Messages stored with correct sequence
- Tool calls logged with params and results
- Compaction points marked correctly
- Compaction summary stored in message
- Sessions can be resumed from compaction point
Phase 5: Agent System
Goal: Load and invoke agents from vault.
Tasks:
- Parse AGENT.md files (frontmatter + markdown)
- Load config.json for structured config
- Build agent context with tools, skills, permissions
- Implement subagent invocation
- Implement skill preloading
Files to create:
packages/daemon/src/ctx0/
├── agents.ts # Agent loading and invocation
└── parser.ts # AGENT.md/SKILL.md parsing
Verification:
- AGENT.md parsed correctly (frontmatter + body)
- Agent tools filtered correctly
- Subagent invocation works
- Skills preloaded into agent context
- Custom agents loadable from vault
Phase 6: Tracker Script
Goal: Import conversations from external AI tools.
Tasks:
- Watch Claude Code conversation files
- Parse .jsonl format
- Insert into ctx0_sessions + ctx0_session_messages
- Track compaction events
- Store source_path for linking back
Files to create:
packages/daemon/src/tracker/
├── index.ts # Main tracker
├── claude-code.ts # Claude Code parser
└── watchers.ts # File watching
Verification:
- Tracker detects new Claude Code conversations
- Messages parsed correctly
- Tool calls extracted
- Compaction events detected
- Sessions linked to source files
Package Structure
packages/
├── ctx0/ # Shared migrations and types
│ ├── package.json # @bot0/ctx0
│ ├── migrations/
│ │ ├── 001_ctx0_schema.sql
│ │ └── manifest.json
│ └── src/
│ ├── index.ts
│ ├── migrations.ts
│ └── types.ts
│
└── daemon/ # Core implementation
└── src/
├── ctx0/
│ ├── init.ts # Vault initialization
│ ├── entries.ts # Entry operations
│ ├── sessions.ts # Session operations
│ ├── agents.ts # Agent system
│ └── storage.ts # Storage bucket
├── tools/
│ ├── ctx0-remember.ts
│ ├── ctx0-retrieve.ts
│ ├── ctx0-sql.ts
│ ├── ctx0-browse.ts
│ └── ctx0-read.ts
└── tracker/
├── index.ts
└── claude-code.ts
Key Implementation Details
Entry Path Handling
Paths always start with / and use forward slashes:
// Good const path = '/contacts/sarah-chen.md'; const folder = '/agents/ctx0/'; // Bad const path = 'contacts/sarah-chen.md'; const folder = 'agents\\ctx0\\';
Locked Folder Enforcement
Before any entry modification:
const LOCKED_FOLDERS = ['.ctx0', 'agents', 'skills', 'tools', 'mcp']; function isLockedPath(path: string): boolean { const parts = path.split('/').filter(Boolean); return LOCKED_FOLDERS.includes(parts[0]); } function canModifyEntry(entry: Entry, operation: 'update' | 'delete'): boolean { if (entry.is_locked) return false; if (entry.is_system && operation === 'delete') return false; return true; }
AGENT.md Parsing
import matter from 'gray-matter'; interface AgentConfig { name: string; description: string; tools?: string[]; disallowedTools?: string[]; model?: string; skills?: string[]; subagents?: string[]; } function parseAgentMd(content: string): { config: AgentConfig; prompt: string } { const { data, content: body } = matter(content); return { config: data as AgentConfig, prompt: body.trim() }; }
ctx0_sql Security
const FORBIDDEN_PATTERNS = [ /\bDROP\b/i, /\bDELETE\b/i, /\bTRUNCATE\b/i, /\bINSERT\b/i, /\bUPDATE\b/i, /\bALTER\b/i, /\bCREATE\b/i, /\bGRANT\b/i, /\bREVOKE\b/i, ]; function validateQuery(sql: string): void { if (!/^\s*SELECT\b/i.test(sql)) { throw new Error('Only SELECT queries allowed'); } for (const pattern of FORBIDDEN_PATTERNS) { if (pattern.test(sql)) { throw new Error('Query contains forbidden keyword'); } } }
Compaction Tracking
When inserting a compaction marker:
await supabase.from('ctx0_session_messages').insert({ session_id: sessionId, user_id: userId, message_sequence: nextSequence(), role: 'system', content: '[Context compacted]', is_compaction_point: true, compaction_summary: summary, context_tokens_before: tokenCount }); await supabase.from('ctx0_sessions') .update({ compaction_count: sql`compaction_count + 1` }) .eq('id', sessionId);
Testing Checklist
Database
- Tables create without errors
- RLS blocks cross-user access
- Service role bypasses RLS
- ctx0_query rejects mutations
- Indexes improve query performance
Vault
- Initialization creates all folders
- Default agents are loadable
- Custom agents can be added
- Locked folders protected
- Entry CRUD works
Tools
- ctx0_remember creates entries
- ctx0_retrieve returns relevant results
- ctx0_sql executes safe queries
- ctx0_sql blocks unsafe queries
- ctx0_browse lists correctly
- ctx0_read returns content
Sessions
- Sessions track all agents
- Messages preserve order
- Tool calls logged
- Compaction tracked
- Resumption works
Agents
- AGENT.md parsing works
- Tool filtering works
- Subagent invocation works
- Skill preloading works
Common Pitfalls
- UUID generation: Use
gen_random_uuid()in SQL, not client-side - Path normalization: Always use
/prefix, no trailing slash for files - RLS context: Ensure user_id is set correctly for RLS to work
- Compaction timing: Store summary BEFORE clearing context
- Locked folder checks: Check BEFORE the operation, not after