The Event Store is Auto-Skill’s persistent storage layer. It captures every tool invocation from your coding agent sessions and stores them in a SQLite database for pattern analysis.
CREATE TABLE IF NOT EXISTS events ( id TEXT PRIMARY KEY, -- ULID session_id TEXT NOT NULL, -- Groups related events project_path TEXT NOT NULL, -- For project-specific patterns tool_name TEXT NOT NULL, -- Read, Write, Edit, Bash, etc. tool_input TEXT NOT NULL, -- JSON-serialized parameters tool_response TEXT, -- Truncated response (max 1000 chars) success INTEGER NOT NULL, -- 1 or 0 timestamp TEXT NOT NULL, -- ISO-8601 agent_id TEXT -- claude-code, cursor, etc.);-- Indexes for fast queriesCREATE INDEX IF NOT EXISTS idx_session_id ON events(session_id);CREATE INDEX IF NOT EXISTS idx_project_path ON events(project_path);CREATE INDEX IF NOT EXISTS idx_timestamp ON events(timestamp);CREATE INDEX IF NOT EXISTS idx_tool_name ON events(tool_name);
The schema is created automatically when you first use the EventStore. From event-store.ts:70-96
// From event-store.ts:148-161getSessionEvents(sessionId: string): ToolEvent[] { const rows = this.db .prepare( `SELECT * FROM events WHERE session_id = ? ORDER BY timestamp ASC` ) .all(sessionId) as Record<string, unknown>[]; return rows.map(rowToEvent);}
Retrieve full event objects (including inputs) grouped by session:
// From event-store.ts:222-274getEventsWithInputs( projectPath?: string, lookbackDays: number = 7,): ToolEvent[][] { const cutoff = new Date( Date.now() - lookbackDays * 24 * 60 * 60 * 1000 ).toISOString(); let sql = ` SELECT * FROM events WHERE timestamp > ? `; const params: unknown[] = [cutoff]; if (projectPath) { sql += " AND project_path = ?"; params.push(projectPath); } sql += " ORDER BY session_id, timestamp ASC"; const rows = this.db.prepare(sql).all(...params) as Record<string, unknown>[]; // Group by session const sessions: ToolEvent[][] = []; let currentSession: string | null = null; let currentEvents: ToolEvent[] = []; for (const row of rows) { const event = rowToEvent(row); if (event.sessionId !== currentSession) { if (currentEvents.length > 0) { sessions.push(currentEvents); } currentSession = event.sessionId; currentEvents = []; } currentEvents.push(event); } if (currentEvents.length > 0) { sessions.push(currentEvents); } return sessions;}
getEventsWithInputs() returns full event objects including tool inputs and responses. Use this when you need detailed context for pattern matching, not just tool names.
// From event-store.ts:276-314getStats(): EventStoreStats { const totalEvents = ( this.db.prepare("SELECT COUNT(*) AS cnt FROM events").get() as { cnt: number } ).cnt; const uniqueSessions = ( this.db .prepare("SELECT COUNT(DISTINCT session_id) AS cnt FROM events") .get() as { cnt: number } ).cnt; const uniqueProjects = ( this.db .prepare("SELECT COUNT(DISTINCT project_path) AS cnt FROM events") .get() as { cnt: number } ).cnt; const toolRows = this.db .prepare( `SELECT tool_name, COUNT(*) AS count FROM events GROUP BY tool_name ORDER BY count DESC LIMIT 10` ) .all() as Array<{ tool_name: string; count: number }>; return { totalEvents, uniqueSessions, uniqueProjects, topTools: toolRows.map((r) => ({ tool: r.tool_name, count: r.count })), };}
// From event-store.ts:316-332cleanupOldEvents(days: number = 30): number { const cutoff = new Date( Date.now() - days * 24 * 60 * 60 * 1000 ).toISOString(); const result = this.db .prepare("DELETE FROM events WHERE timestamp < ?") .run(cutoff); return result.changes; // Number of deleted rows}
Cleanup is manual — Auto-Skill doesn’t automatically delete old events. Run cleanupOldEvents() periodically or via CLI command.
The database is opened with optimal settings for concurrent access:
// From db.ts:32-64export function openDatabase(dbPath: string): Database { // Ensure parent directory exists with secure permissions const dir = path.dirname(dbPath); fs.mkdirSync(dir, { recursive: true, mode: 0o700 }); let db: Database; // Support both Node (better-sqlite3) and Bun (bun:sqlite) if (typeof Bun !== "undefined") { const { Database: BunDB } = require("bun:sqlite"); db = new BunDB(dbPath) as unknown as Database; } else { const BetterSqlite3 = require("better-sqlite3"); db = new BetterSqlite3(dbPath) as Database; } // Enable WAL mode for better concurrency db.pragma("journal_mode = WAL"); // Enable foreign key constraints db.pragma("foreign_keys = ON"); return db;}
WAL Mode
Write-Ahead Logging for concurrent reads during writesBetter performance for event capture
Foreign Keys
Constraint enforcement for data integrityPrevents orphaned records