@steno-ai/mcp 0.1.10 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,6 +42,7 @@ That's it. Your data stays in YOUR Supabase project. Nothing is shared.
42
42
  | `steno_remember` | Stores facts, preferences, decisions, people, events |
43
43
  | `steno_recall` | Searches memory with 6-signal fusion (vector + keyword + graph + temporal + recency + salience) |
44
44
  | `steno_flush` | Forces extraction of buffered session messages |
45
+ | `steno_update_status` | Updates priority/roadmap item status (not_started, in_progress, done, blocked) |
45
46
  | `steno_feedback` | Rates whether a recalled memory was useful |
46
47
  | `steno_stats` | Shows memory statistics |
47
48
 
@@ -59,7 +60,16 @@ That's it. Your data stays in YOUR Supabase project. Nothing is shared.
59
60
  - Session buffering for cross-message context
60
61
  - Source chunk preservation for full-context answers
61
62
 
62
- ## Manual Setup (if you prefer)
63
+ ## Claude Code Setup
64
+
65
+ ```bash
66
+ claude mcp add steno-memory -- npx -y @steno-ai/mcp \
67
+ --env SUPABASE_URL=https://YOUR-PROJECT.supabase.co \
68
+ --env SUPABASE_SERVICE_ROLE_KEY=eyJ... \
69
+ --env OPENAI_API_KEY=sk-...
70
+ ```
71
+
72
+ ## Claude Desktop — Manual Setup
63
73
 
64
74
  Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
65
75
 
package/dist/cli.d.ts CHANGED
File without changes
package/dist/cli.d.ts.map CHANGED
File without changes
package/dist/cli.js.map CHANGED
File without changes
package/dist/index.d.ts CHANGED
File without changes
File without changes
package/dist/index.js CHANGED
File without changes
package/dist/index.js.map CHANGED
File without changes
package/dist/init.d.ts CHANGED
File without changes
File without changes
package/dist/init.js CHANGED
@@ -73,7 +73,7 @@ const MIGRATIONS = [
73
73
  input_size INTEGER,
74
74
  scope TEXT NOT NULL,
75
75
  scope_id TEXT NOT NULL,
76
- session_id UUID,
76
+ session_id TEXT,
77
77
  tier_used TEXT,
78
78
  llm_model TEXT,
79
79
  facts_created INTEGER NOT NULL DEFAULT 0,
@@ -96,7 +96,7 @@ const MIGRATIONS = [
96
96
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
97
97
  scope TEXT NOT NULL CHECK (scope IN ('user','agent','session','hive')),
98
98
  scope_id TEXT NOT NULL,
99
- session_id UUID REFERENCES sessions(id) ON DELETE SET NULL,
99
+ session_id TEXT,
100
100
  content TEXT NOT NULL,
101
101
  embedding VECTOR(2000),
102
102
  embedding_model TEXT,
@@ -276,6 +276,133 @@ const MIGRATIONS = [
276
276
  AND f.search_vector @@ plainto_tsquery('english', search_query)
277
277
  ORDER BY ts_rank(f.search_vector, plainto_tsquery('english', search_query)) DESC LIMIT match_count);
278
278
  END; $$;`,
279
+ // Usage records unique constraint (required by increment_usage)
280
+ `ALTER TABLE usage_records ADD CONSTRAINT IF NOT EXISTS usage_records_tenant_period_unique UNIQUE (tenant_id, period_start);`,
281
+ // Extraction hash unique index
282
+ `CREATE UNIQUE INDEX IF NOT EXISTS idx_extractions_hash ON extractions(tenant_id, input_hash);`,
283
+ // match_facts RPC
284
+ `CREATE OR REPLACE FUNCTION match_facts(
285
+ query_embedding TEXT, match_tenant_id UUID, match_scope TEXT,
286
+ match_scope_id TEXT, match_count INT, min_similarity FLOAT DEFAULT 0,
287
+ match_as_of TIMESTAMPTZ DEFAULT NULL
288
+ ) RETURNS TABLE (
289
+ id UUID, tenant_id UUID, scope TEXT, scope_id TEXT, session_id TEXT,
290
+ content TEXT, embedding_model TEXT, embedding_dim INT, version INT,
291
+ lineage_id UUID, valid_from TIMESTAMPTZ, valid_until TIMESTAMPTZ,
292
+ operation TEXT, parent_id UUID, importance NUMERIC, frequency INT,
293
+ last_accessed TIMESTAMPTZ, decay_score NUMERIC, contradiction_status TEXT,
294
+ contradicts_id UUID, source_type TEXT, source_ref JSONB, confidence NUMERIC,
295
+ original_content TEXT, extraction_id UUID, extraction_tier TEXT,
296
+ modality TEXT, tags TEXT[], metadata JSONB,
297
+ event_date TIMESTAMPTZ, document_date TIMESTAMPTZ, source_chunk TEXT,
298
+ created_at TIMESTAMPTZ, similarity FLOAT
299
+ ) LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT
300
+ f.id, f.tenant_id, f.scope, f.scope_id, f.session_id,
301
+ f.content, f.embedding_model, f.embedding_dim, f.version, f.lineage_id,
302
+ f.valid_from, f.valid_until, f.operation, f.parent_id, f.importance, f.frequency,
303
+ f.last_accessed, f.decay_score, f.contradiction_status, f.contradicts_id,
304
+ f.source_type, f.source_ref, f.confidence, f.original_content, f.extraction_id,
305
+ f.extraction_tier, f.modality, f.tags, f.metadata,
306
+ f.event_date, f.document_date, f.source_chunk, f.created_at,
307
+ (1 - (f.embedding <=> query_embedding::vector)) AS similarity
308
+ FROM facts f WHERE f.tenant_id = match_tenant_id AND f.scope = match_scope
309
+ AND f.scope_id = match_scope_id
310
+ AND (CASE WHEN match_as_of IS NOT NULL THEN f.valid_from <= match_as_of AND (f.valid_until IS NULL OR f.valid_until > match_as_of) ELSE f.valid_until IS NULL END)
311
+ AND (1 - (f.embedding <=> query_embedding::vector)) >= min_similarity
312
+ ORDER BY f.embedding <=> query_embedding::vector LIMIT match_count; END; $$;`,
313
+ // increment_usage RPC
314
+ `CREATE OR REPLACE FUNCTION increment_usage(p_tenant_id UUID, p_tokens INT, p_queries INT, p_extractions INT, p_cost_usd FLOAT)
315
+ RETURNS VOID LANGUAGE plpgsql AS $$ DECLARE p_start DATE := date_trunc('month', CURRENT_DATE)::date;
316
+ p_end DATE := (date_trunc('month', CURRENT_DATE) + interval '1 month' - interval '1 day')::date;
317
+ BEGIN INSERT INTO usage_records (id, tenant_id, period_start, period_end, tokens_used, queries_used, extractions_count, cost_usd)
318
+ VALUES (gen_random_uuid(), p_tenant_id, p_start, p_end, p_tokens, p_queries, p_extractions, p_cost_usd)
319
+ ON CONFLICT (tenant_id, period_start) DO UPDATE SET
320
+ tokens_used = usage_records.tokens_used + EXCLUDED.tokens_used,
321
+ queries_used = usage_records.queries_used + EXCLUDED.queries_used,
322
+ extractions_count = usage_records.extractions_count + EXCLUDED.extractions_count,
323
+ cost_usd = usage_records.cost_usd + EXCLUDED.cost_usd, updated_at = NOW(); END; $$;`,
324
+ // match_entities RPC
325
+ `CREATE OR REPLACE FUNCTION match_entities(query_embedding TEXT, match_tenant_id UUID, match_count INT DEFAULT 10, min_similarity FLOAT DEFAULT 0.3)
326
+ RETURNS TABLE (id UUID, tenant_id UUID, name TEXT, entity_type TEXT, canonical_name TEXT, properties JSONB,
327
+ embedding_model TEXT, embedding_dim INT, merge_target_id UUID, created_at TIMESTAMPTZ, updated_at TIMESTAMPTZ, similarity FLOAT)
328
+ LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT e.id, e.tenant_id, e.name, e.entity_type, e.canonical_name,
329
+ e.properties, e.embedding_model, e.embedding_dim, e.merge_target_id, e.created_at, e.updated_at,
330
+ (1 - (e.embedding <=> query_embedding::vector))::float AS similarity
331
+ FROM entities e WHERE e.tenant_id = match_tenant_id AND e.embedding IS NOT NULL
332
+ AND (1 - (e.embedding <=> query_embedding::vector)) >= min_similarity
333
+ ORDER BY e.embedding <=> query_embedding::vector LIMIT match_count; END; $$;`,
334
+ // graph_traverse RPC
335
+ `CREATE OR REPLACE FUNCTION graph_traverse(match_tenant_id UUID, seed_entity_ids UUID[], max_depth INT DEFAULT 3, max_entities INT DEFAULT 200, match_as_of TIMESTAMPTZ DEFAULT NULL)
336
+ RETURNS TABLE (entity_id UUID, entity_name TEXT, entity_type TEXT, canonical_name TEXT, properties JSONB, hop_depth INT,
337
+ edge_id UUID, edge_source_id UUID, edge_target_id UUID, edge_relation TEXT, edge_type TEXT, edge_weight FLOAT,
338
+ edge_valid_from TIMESTAMPTZ, edge_valid_until TIMESTAMPTZ, edge_confidence FLOAT)
339
+ LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY WITH RECURSIVE traversal AS (
340
+ SELECT e.id AS entity_id, e.name AS entity_name, e.entity_type, e.canonical_name, e.properties, 0 AS hop_depth,
341
+ NULL::UUID AS edge_id, NULL::UUID AS edge_source_id, NULL::UUID AS edge_target_id, NULL::TEXT AS edge_relation,
342
+ NULL::TEXT AS edge_type, NULL::FLOAT AS edge_weight, NULL::TIMESTAMPTZ AS edge_valid_from,
343
+ NULL::TIMESTAMPTZ AS edge_valid_until, NULL::FLOAT AS edge_confidence, ARRAY[e.id] AS visited_ids
344
+ FROM entities e WHERE e.id = ANY(seed_entity_ids) AND e.tenant_id = match_tenant_id
345
+ UNION ALL
346
+ SELECT e2.id, e2.name, e2.entity_type, e2.canonical_name, e2.properties, t.hop_depth + 1,
347
+ ed.id, ed.source_id, ed.target_id, ed.relation, ed.edge_type, ed.weight, ed.valid_from, ed.valid_until, ed.confidence,
348
+ t.visited_ids || e2.id
349
+ FROM traversal t JOIN edges ed ON (ed.source_id = t.entity_id OR ed.target_id = t.entity_id) AND ed.tenant_id = match_tenant_id
350
+ AND (CASE WHEN match_as_of IS NOT NULL THEN ed.valid_from <= match_as_of AND (ed.valid_until IS NULL OR ed.valid_until > match_as_of) ELSE ed.valid_until IS NULL END)
351
+ JOIN entities e2 ON e2.id = CASE WHEN ed.source_id = t.entity_id THEN ed.target_id ELSE ed.source_id END AND e2.tenant_id = match_tenant_id
352
+ WHERE t.hop_depth < max_depth AND e2.id != ALL(t.visited_ids)
353
+ ) SELECT traversal.entity_id, traversal.entity_name, traversal.entity_type, traversal.canonical_name, traversal.properties,
354
+ traversal.hop_depth, traversal.edge_id, traversal.edge_source_id, traversal.edge_target_id, traversal.edge_relation,
355
+ traversal.edge_type, traversal.edge_weight, traversal.edge_valid_from, traversal.edge_valid_until, traversal.edge_confidence
356
+ FROM traversal LIMIT max_entities; END; $$;`,
357
+ // get_facts_for_entities RPC
358
+ `CREATE OR REPLACE FUNCTION get_facts_for_entities(match_tenant_id UUID, entity_ids UUID[], per_entity_limit INT DEFAULT 20)
359
+ RETURNS TABLE (entity_id UUID, fact_id UUID, tenant_id UUID, scope TEXT, scope_id TEXT, session_id TEXT,
360
+ content TEXT, embedding_model TEXT, embedding_dim INTEGER, version INTEGER, lineage_id UUID,
361
+ valid_from TIMESTAMPTZ, valid_until TIMESTAMPTZ, operation TEXT, parent_id UUID,
362
+ importance NUMERIC, frequency INTEGER, last_accessed TIMESTAMPTZ, decay_score NUMERIC,
363
+ contradiction_status TEXT, contradicts_id UUID, source_type TEXT, source_ref JSONB, confidence NUMERIC,
364
+ original_content TEXT, extraction_id UUID, extraction_tier TEXT, modality TEXT, tags TEXT[], metadata JSONB,
365
+ event_date TIMESTAMPTZ, document_date TIMESTAMPTZ, source_chunk TEXT, created_at TIMESTAMPTZ)
366
+ LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT ranked.entity_id, ranked.fact_id, ranked.tenant_id, ranked.scope,
367
+ ranked.scope_id, ranked.session_id, ranked.content, ranked.embedding_model, ranked.embedding_dim, ranked.version,
368
+ ranked.lineage_id, ranked.valid_from, ranked.valid_until, ranked.operation, ranked.parent_id, ranked.importance,
369
+ ranked.frequency, ranked.last_accessed, ranked.decay_score, ranked.contradiction_status, ranked.contradicts_id,
370
+ ranked.source_type, ranked.source_ref, ranked.confidence, ranked.original_content, ranked.extraction_id,
371
+ ranked.extraction_tier, ranked.modality, ranked.tags, ranked.metadata,
372
+ ranked.event_date, ranked.document_date, ranked.source_chunk, ranked.created_at
373
+ FROM (SELECT fe.entity_id, f.id AS fact_id, f.tenant_id, f.scope, f.scope_id, f.session_id, f.content,
374
+ f.embedding_model, f.embedding_dim, f.version, f.lineage_id, f.valid_from, f.valid_until, f.operation,
375
+ f.parent_id, f.importance, f.frequency, f.last_accessed, f.decay_score, f.contradiction_status, f.contradicts_id,
376
+ f.source_type, f.source_ref, f.confidence, f.original_content, f.extraction_id, f.extraction_tier, f.modality,
377
+ f.tags, f.metadata, f.event_date, f.document_date, f.source_chunk, f.created_at,
378
+ ROW_NUMBER() OVER (PARTITION BY fe.entity_id ORDER BY f.importance DESC, f.created_at DESC) AS rn
379
+ FROM fact_entities fe JOIN facts f ON f.id = fe.fact_id WHERE fe.entity_id = ANY(entity_ids)
380
+ AND f.tenant_id = match_tenant_id AND f.valid_until IS NULL AND NOT ('raw_chunk' = ANY(f.tags))) ranked
381
+ WHERE ranked.rn <= per_entity_limit; END; $$;`,
382
+ // keyword_search_facts RPC
383
+ `CREATE OR REPLACE FUNCTION keyword_search_facts(search_query TEXT, match_tenant_id UUID, match_scope TEXT,
384
+ match_scope_id TEXT, match_count INT, match_as_of TIMESTAMPTZ DEFAULT NULL)
385
+ RETURNS TABLE (id UUID, tenant_id UUID, scope TEXT, scope_id TEXT, session_id TEXT,
386
+ content TEXT, embedding_model TEXT, embedding_dim INT, version INT, lineage_id UUID,
387
+ valid_from TIMESTAMPTZ, valid_until TIMESTAMPTZ, operation TEXT, parent_id UUID,
388
+ importance NUMERIC, frequency INT, last_accessed TIMESTAMPTZ, decay_score NUMERIC,
389
+ contradiction_status TEXT, contradicts_id UUID, source_type TEXT, source_ref JSONB, confidence NUMERIC,
390
+ original_content TEXT, extraction_id UUID, extraction_tier TEXT, modality TEXT, tags TEXT[], metadata JSONB,
391
+ event_date TIMESTAMPTZ, document_date TIMESTAMPTZ, source_chunk TEXT, created_at TIMESTAMPTZ, rank_score FLOAT)
392
+ LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT f.id, f.tenant_id, f.scope, f.scope_id, f.session_id,
393
+ f.content, f.embedding_model, f.embedding_dim, f.version, f.lineage_id, f.valid_from, f.valid_until,
394
+ f.operation, f.parent_id, f.importance, f.frequency, f.last_accessed, f.decay_score, f.contradiction_status,
395
+ f.contradicts_id, f.source_type, f.source_ref, f.confidence, f.original_content, f.extraction_id,
396
+ f.extraction_tier, f.modality, f.tags, f.metadata, f.event_date, f.document_date, f.source_chunk, f.created_at,
397
+ ts_rank(f.search_vector, plainto_tsquery('english', search_query)) AS rank_score
398
+ FROM facts f WHERE f.tenant_id = match_tenant_id AND f.scope = match_scope AND f.scope_id = match_scope_id
399
+ AND (CASE WHEN match_as_of IS NOT NULL THEN f.valid_from <= match_as_of AND (f.valid_until IS NULL OR f.valid_until > match_as_of) ELSE f.valid_until IS NULL END)
400
+ AND f.search_vector @@ plainto_tsquery('english', search_query)
401
+ ORDER BY rank_score DESC LIMIT match_count; END; $$;`,
402
+ // increment_trigger_fired RPC
403
+ `CREATE OR REPLACE FUNCTION increment_trigger_fired(p_tenant_id UUID, p_trigger_id UUID)
404
+ RETURNS VOID LANGUAGE plpgsql AS $$ BEGIN UPDATE triggers SET times_fired = times_fired + 1,
405
+ last_fired_at = NOW(), updated_at = NOW() WHERE tenant_id = p_tenant_id AND id = p_trigger_id; END; $$;`,
279
406
  // Default tenant
280
407
  `INSERT INTO tenants (id, name, slug, plan) VALUES ('00000000-0000-0000-0000-000000000001', 'Default', 'default', 'enterprise') ON CONFLICT DO NOTHING;`,
281
408
  ];
@@ -293,34 +420,38 @@ async function main() {
293
420
  // 2. Run migrations
294
421
  console.log('\n Running database migrations...');
295
422
  const supabase = createClient(supabaseUrl, supabaseKey);
296
- let success = 0;
297
- let skipped = 0;
298
- for (let i = 0; i < MIGRATIONS.length; i++) {
299
- try {
300
- const { error } = await supabase.rpc('exec_sql', { query: MIGRATIONS[i] }).catch(() => ({ error: { message: 'rpc not available' } }));
301
- if (error) {
302
- // Try direct REST approach
303
- const res = await fetch(`${supabaseUrl}/rest/v1/rpc/exec_sql`, {
304
- method: 'POST',
305
- headers: { 'apikey': supabaseKey, 'Authorization': `Bearer ${supabaseKey}`, 'Content-Type': 'application/json' },
306
- body: JSON.stringify({ query: MIGRATIONS[i] }),
307
- });
308
- if (res.ok) {
309
- success++;
310
- }
311
- else {
312
- skipped++;
313
- }
314
- }
315
- else {
316
- success++;
317
- }
318
- }
319
- catch {
320
- skipped++;
423
+ // Try running migrations via Supabase Management API (requires service role key)
424
+ // If that fails, write SQL to a file for manual execution
425
+ const allSql = MIGRATIONS.join('\n\n');
426
+ const sqlPath = path.join(process.cwd(), 'steno-migrations.sql');
427
+ // Attempt automatic migration via Supabase SQL endpoint
428
+ let autoMigrated = false;
429
+ try {
430
+ const res = await fetch(`${supabaseUrl}/rest/v1/rpc/exec_sql`, {
431
+ method: 'POST',
432
+ headers: { 'apikey': supabaseKey, 'Authorization': `Bearer ${supabaseKey}`, 'Content-Type': 'application/json' },
433
+ body: JSON.stringify({ query: allSql }),
434
+ });
435
+ if (res.ok) {
436
+ autoMigrated = true;
437
+ console.log(' ✓ All migrations applied automatically');
321
438
  }
322
439
  }
323
- console.log(` ✓ ${success} migrations applied, ${skipped} skipped (may already exist)`);
440
+ catch { /* RPC not available */ }
441
+ if (!autoMigrated) {
442
+ // Write SQL file for manual execution
443
+ fs.writeFileSync(sqlPath, allSql);
444
+ console.log(`
445
+ ⚠️ Could not run migrations automatically.
446
+
447
+ Please run the SQL manually:
448
+ 1. Open your Supabase dashboard → SQL Editor
449
+ 2. Paste the contents of: ${sqlPath}
450
+ 3. Click "Run"
451
+ 4. Come back here and press Enter to continue
452
+ `);
453
+ await ask(' Press Enter after running the SQL... ');
454
+ }
324
455
  // 3. Write Claude Desktop config
325
456
  const configDir = path.join(os.homedir(), 'Library', 'Application Support', 'Claude');
326
457
  const configPath = path.join(configDir, 'claude_desktop_config.json');
package/dist/init.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
File without changes
@@ -1 +1 @@
1
- {"version":3,"file":"local-server.d.ts","sourceRoot":"","sources":["../src/local-server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAErF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,cAAc,CAAC;IACxB,SAAS,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,EAAE,UAAU,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,kBAAkB,EAAE,gBAAgB,EAAE,CAAC;CACnE;AAkDD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,SAAS,CA+StE"}
1
+ {"version":3,"file":"local-server.d.ts","sourceRoot":"","sources":["../src/local-server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAErF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,cAAc,CAAC;IACxB,SAAS,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,EAAE,UAAU,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,kBAAkB,EAAE,gBAAgB,EAAE,CAAC;CACnE;AAkDD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,SAAS,CAsgBtE"}
@@ -46,6 +46,15 @@ export function createLocalServer(config) {
46
46
  const server = new McpServer({
47
47
  name: 'steno-local',
48
48
  version: '0.1.0',
49
+ ...{ instructions: `You have access to the user's persistent long-term memory via Steno.
50
+
51
+ CRITICAL RULES:
52
+ 1. ALWAYS call steno_recall BEFORE answering ANY question about the user, their life, work, projects, people they know, preferences, past events, companies, or decisions.
53
+ 2. When the user shares personal information, call steno_remember to store it, then ALWAYS call steno_flush immediately after to ensure extraction happens now.
54
+ 3. Before context compaction or session end, call steno_remember with a summary of key decisions and progress, then steno_flush.
55
+ 4. Never say "I don't have information about that" without first checking steno_recall.
56
+ 5. Steno memory persists across ALL conversations — it knows things from past sessions that your conversation history does not.
57
+ 6. Use steno_update_status to change priority/roadmap item status when the user starts, completes, or gets blocked on a task.` },
49
58
  });
50
59
  // Lazy import to avoid loading heavy modules at startup
51
60
  let _search = null;
@@ -224,8 +233,146 @@ export function createLocalServer(config) {
224
233
  if (results.results.length === 0) {
225
234
  return { content: [{ type: 'text', text: 'No memories found.' }] };
226
235
  }
227
- const text = results.results
228
- .map((r) => {
236
+ // Build priority label map: factId → "Priority #N (short name)"
237
+ // Query ALL facts with priority_order metadata — not just the ones in results
238
+ // This ensures labels resolve even for facts referenced by edges but not in recall
239
+ const priorityLabels = new Map();
240
+ try {
241
+ const { data: allPriorityFacts } = await config.storage.client
242
+ .from('facts')
243
+ .select('id, content, metadata')
244
+ .eq('tenant_id', config.tenantId)
245
+ .not('metadata->priority_order', 'is', null);
246
+ if (allPriorityFacts) {
247
+ for (const f of allPriorityFacts) {
248
+ const order = f.metadata?.priority_order;
249
+ if (order) {
250
+ const shortName = f.content.replace(/^User('s)?\s+(plans|added|believes|is planning|wants|Steno)\s+/i, '').slice(0, 35).replace(/\s+\S*$/, '');
251
+ priorityLabels.set(f.id, `Priority #${order} (${shortName})`);
252
+ }
253
+ }
254
+ }
255
+ }
256
+ catch { /* fallback to results-only labels */ }
257
+ // Also add labels from results (in case metadata query missed any)
258
+ for (const r of results.results) {
259
+ if (priorityLabels.has(r.fact.id))
260
+ continue;
261
+ const meta = r.fact.metadata;
262
+ const order = meta?.priority_order;
263
+ if (order) {
264
+ const shortName = r.fact.content.replace(/^User('s)?\s+(plans|added|believes|is planning|wants)\s+/i, '').slice(0, 35).replace(/\s+\S*$/, '');
265
+ priorityLabels.set(r.fact.id, `Priority #${order} (${shortName})`);
266
+ }
267
+ }
268
+ // Build dependency map — ONE batch query for ALL dependency edges in this tenant
269
+ const factIds = results.results.map(r => r.fact.id);
270
+ const depMap = new Map();
271
+ try {
272
+ // Query ALL precedes/depends_on/deadline edges — not just for these fact_ids
273
+ // because edges reference sourceFactId/targetFactId in metadata, not in fact_id column
274
+ const { data: depEdges } = await config.storage.client
275
+ .from('edges')
276
+ .select('relation, fact_id, metadata')
277
+ .eq('tenant_id', config.tenantId)
278
+ .in('relation', ['precedes', 'depends_on', 'deadline']);
279
+ if (depEdges) {
280
+ for (const edge of depEdges) {
281
+ const edgeMeta = edge.metadata;
282
+ const sourceFactId = edgeMeta?.sourceFactId || edge.fact_id;
283
+ const targetFactId = edgeMeta?.targetFactId;
284
+ // Only process edges involving facts in our result set
285
+ const sourceInResults = factIds.includes(sourceFactId);
286
+ const targetInResults = targetFactId ? factIds.includes(targetFactId) : false;
287
+ if (!sourceInResults && !targetInResults)
288
+ continue;
289
+ if (!depMap.has(sourceFactId))
290
+ depMap.set(sourceFactId, { blocks: [], blockedBy: [], deadlines: [] });
291
+ if (edge.relation === 'precedes' && targetFactId) {
292
+ const label = priorityLabels.get(targetFactId) || 'another priority';
293
+ depMap.get(sourceFactId).blocks.push(label);
294
+ }
295
+ if (edge.relation === 'depends_on' && targetFactId) {
296
+ const label = priorityLabels.get(targetFactId) || 'another priority';
297
+ depMap.get(sourceFactId).blockedBy.push(label);
298
+ }
299
+ if (edge.relation === 'deadline') {
300
+ const deadline = edgeMeta?.deadline;
301
+ if (deadline) {
302
+ depMap.get(sourceFactId).deadlines.push(deadline);
303
+ // Cascade deadline upstream: if X blocks Y and Y has deadline, X gets it too
304
+ for (const [fid, deps2] of depMap) {
305
+ if (deps2.blocks.some(b => b.includes(sourceFactId.slice(0, 8)) || priorityLabels.get(sourceFactId)?.includes(b.split('(')[1]?.slice(0, 10) || ''))) {
306
+ if (!deps2.deadlines.includes(deadline))
307
+ deps2.deadlines.push(deadline + ' (cascaded)');
308
+ }
309
+ }
310
+ }
311
+ }
312
+ }
313
+ // Second pass: cascade deadlines through depends_on chain
314
+ // If A depends_on B, and B has a deadline, A implicitly has that deadline
315
+ for (const [factId, deps] of depMap) {
316
+ if (deps.deadlines.length === 0) {
317
+ // Check if anything this blocks has a deadline
318
+ for (const blockLabel of deps.blocks) {
319
+ for (const [otherId, otherDeps] of depMap) {
320
+ if (priorityLabels.get(otherId) === blockLabel && otherDeps.deadlines.length > 0) {
321
+ for (const dl of otherDeps.deadlines) {
322
+ if (!dl.includes('cascaded') && !deps.deadlines.includes(dl)) {
323
+ deps.deadlines.push(dl + ' (implicit — blocks deadline item)');
324
+ }
325
+ }
326
+ }
327
+ }
328
+ }
329
+ }
330
+ }
331
+ }
332
+ }
333
+ catch { /* batch edge lookup failed */ }
334
+ // Inject missing priority facts that are referenced by edges but not in recall results
335
+ // This ensures Priority #1 (root node) always shows up when its children are recalled
336
+ const resultFactIds = new Set(results.results.map(r => r.fact.id));
337
+ try {
338
+ const { data: allPriorities } = await config.storage.client
339
+ .from('facts')
340
+ .select('*')
341
+ .eq('tenant_id', config.tenantId)
342
+ .not('metadata->priority_order', 'is', null);
343
+ if (allPriorities) {
344
+ for (const pf of allPriorities) {
345
+ if (!resultFactIds.has(pf.id) && (depMap.has(pf.id) || priorityLabels.has(pf.id))) {
346
+ // This priority is referenced but not in results — inject it
347
+ const camelFact = Object.fromEntries(Object.entries(pf).map(([k, v]) => [k.replace(/_([a-z])/g, (_, c) => c.toUpperCase()), v]));
348
+ results.results.push({
349
+ fact: camelFact,
350
+ score: 0.1, // Low score since it wasn't directly matched
351
+ signals: { vectorScore: 0, keywordScore: 0, graphScore: 0.5, recencyScore: 0, salienceScore: 0, temporalScore: 0 },
352
+ });
353
+ }
354
+ }
355
+ }
356
+ }
357
+ catch { /* injection failed */ }
358
+ // Sort results: priorities first (by priority_order), then regular memories
359
+ const sortedResults = [...results.results].sort((a, b) => {
360
+ const aOrder = a.fact.metadata?.priority_order;
361
+ const bOrder = b.fact.metadata?.priority_order;
362
+ if (aOrder && bOrder)
363
+ return aOrder - bOrder;
364
+ if (aOrder)
365
+ return -1;
366
+ if (bOrder)
367
+ return 1;
368
+ return b.score - a.score;
369
+ });
370
+ const enrichedLines = [];
371
+ for (const r of sortedResults) {
372
+ const meta = r.fact.metadata;
373
+ const status = meta?.status;
374
+ const priorityOrder = meta?.priority_order;
375
+ const deps = depMap.get(r.fact.id);
229
376
  const dateParts = [];
230
377
  if (r.fact.eventDate)
231
378
  dateParts.push(`event: ${new Date(r.fact.eventDate).toISOString().slice(0, 10)}`);
@@ -236,14 +383,34 @@ export function createLocalServer(config) {
236
383
  .filter(([, v]) => v > 0)
237
384
  .map(([k, v]) => `${k.replace('Score', '')}=${v.toFixed(2)}`)
238
385
  .join(', ');
239
- let line = `[Memory] ${r.fact.content} (score: ${r.score.toFixed(2)}${dateStr}${signals ? `, ${signals}` : ''})`;
240
- if (r.fact.sourceChunk) {
386
+ const isPriority = status || priorityOrder;
387
+ const blocks = deps?.blocks ?? [];
388
+ const blockedBy = deps?.blockedBy ?? [];
389
+ const deadlines = deps?.deadlines ?? [];
390
+ let line;
391
+ if (isPriority) {
392
+ line = `[Priority${priorityOrder ? ` #${priorityOrder}` : ''}] ${r.fact.content}`;
393
+ line += `\n status: ${status || 'unknown'}`;
394
+ if (blocks.length > 0)
395
+ line += `\n blocks: → ${blocks.join(', ')}`;
396
+ if (blockedBy.length > 0)
397
+ line += `\n blocked_by: ← ${blockedBy.join(', ')}`;
398
+ else if (status === 'not_started')
399
+ line += `\n blocked_by: none`;
400
+ if (deadlines.length > 0)
401
+ line += `\n deadline: ${deadlines.join(', ')}`;
402
+ line += `\n (score: ${r.score.toFixed(2)}${dateStr})`;
403
+ }
404
+ else {
405
+ line = `[Memory] ${r.fact.content} (score: ${r.score.toFixed(2)}${dateStr}${signals ? `, ${signals}` : ''})`;
406
+ }
407
+ if (r.fact.sourceChunk && !isPriority) {
241
408
  line += `\n[Source Context] ${r.fact.sourceChunk}`;
242
409
  }
243
410
  line += '\n---';
244
- return line;
245
- })
246
- .join('\n');
411
+ enrichedLines.push(line);
412
+ }
413
+ const text = enrichedLines.join('\n');
247
414
  return {
248
415
  content: [
249
416
  {
@@ -272,6 +439,45 @@ export function createLocalServer(config) {
272
439
  ],
273
440
  };
274
441
  });
442
+ // ─── UPDATE STATUS ───
443
+ server.tool('steno_update_status', 'Update the status of a priority/roadmap item. Use when a task changes state (e.g., started working on it, completed it, or it became blocked).', {
444
+ priority: z.number().describe('Priority number (1-6)'),
445
+ status: z.enum(['not_started', 'in_progress', 'done', 'blocked']).describe('New status'),
446
+ }, async ({ priority, status }) => {
447
+ try {
448
+ // Find the fact with this priority_order
449
+ const { data: facts, error: findError } = await config.storage.client
450
+ .from('facts')
451
+ .select('id, content, metadata')
452
+ .eq('tenant_id', config.tenantId)
453
+ .not('metadata->priority_order', 'is', null);
454
+ if (findError)
455
+ throw findError;
456
+ const fact = facts?.find((f) => f.metadata?.priority_order === priority);
457
+ if (!fact) {
458
+ return { content: [{ type: 'text', text: `No priority #${priority} found.` }] };
459
+ }
460
+ const oldStatus = fact.metadata?.status || 'unknown';
461
+ const newMetadata = { ...fact.metadata, status };
462
+ const { error: updateError } = await config.storage.client
463
+ .from('facts')
464
+ .update({ metadata: newMetadata })
465
+ .eq('id', fact.id)
466
+ .eq('tenant_id', config.tenantId);
467
+ if (updateError)
468
+ throw updateError;
469
+ const shortName = fact.content.replace(/^User('s)?\s+(plans|added|believes|is planning|wants|Steno)\s+/i, '').slice(0, 50);
470
+ return {
471
+ content: [{
472
+ type: 'text',
473
+ text: `Priority #${priority} (${shortName}): ${oldStatus} → ${status}`,
474
+ }],
475
+ };
476
+ }
477
+ catch (err) {
478
+ return { content: [{ type: 'text', text: `Error updating status: ${err?.message ?? err}` }] };
479
+ }
480
+ });
275
481
  // ─── STATS ───
276
482
  server.tool('steno_stats', 'Get memory statistics — how many facts, entities, and edges are stored.', {}, async () => {
277
483
  const facts = await config.storage.getFactsByScope(config.tenantId, config.scope, config.scopeId, { limit: 1 });
@@ -1 +1 @@
1
- {"version":3,"file":"local-server.js","sourceRoot":"","sources":["../src/local-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"local-server.js","sourceRoot":"","sources":["../src/local-server.ts"],"names":[],"mappings":"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"}
package/dist/local.d.ts CHANGED
File without changes
File without changes
package/dist/local.js CHANGED
File without changes
package/dist/local.js.map CHANGED
File without changes
package/dist/server.d.ts CHANGED
File without changes
File without changes
package/dist/server.js CHANGED
File without changes
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steno-ai/mcp",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "MCP server for Claude Code, Claude Desktop, and other MCP clients",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -9,7 +9,10 @@
9
9
  "directory": "packages/mcp-server"
10
10
  },
11
11
  "type": "module",
12
- "bin": "./dist/cli.js",
12
+ "bin": {
13
+ "steno-mcp": "./dist/cli.js",
14
+ "steno-mcp-init": "./dist/init.js"
15
+ },
13
16
  "exports": {
14
17
  ".": {
15
18
  "import": "./dist/index.js",
@@ -23,23 +26,23 @@
23
26
  "src",
24
27
  "README.md"
25
28
  ],
29
+ "scripts": {
30
+ "test": "vitest run",
31
+ "build": "tsc",
32
+ "typecheck": "tsc --noEmit"
33
+ },
26
34
  "dependencies": {
27
35
  "@modelcontextprotocol/sdk": "^1",
36
+ "@steno-ai/engine": "workspace:*",
37
+ "@steno-ai/openai-adapter": "workspace:*",
38
+ "@steno-ai/supabase-adapter": "workspace:*",
28
39
  "@supabase/supabase-js": "^2.49.0",
29
40
  "openai": "^4.0.0",
30
- "zod": "^3.25",
31
- "@steno-ai/engine": "0.1.7",
32
- "@steno-ai/openai-adapter": "0.1.2",
33
- "@steno-ai/supabase-adapter": "0.1.4"
41
+ "zod": "^3.25"
34
42
  },
35
43
  "devDependencies": {
36
44
  "@types/node": "^22",
37
45
  "typescript": "^5.7",
38
46
  "vitest": "^3"
39
- },
40
- "scripts": {
41
- "test": "vitest run",
42
- "build": "tsc",
43
- "typecheck": "tsc --noEmit"
44
47
  }
45
- }
48
+ }
package/src/cli.ts CHANGED
File without changes
package/src/index.ts CHANGED
File without changes
package/src/init.ts CHANGED
@@ -75,7 +75,7 @@ const MIGRATIONS = [
75
75
  input_size INTEGER,
76
76
  scope TEXT NOT NULL,
77
77
  scope_id TEXT NOT NULL,
78
- session_id UUID,
78
+ session_id TEXT,
79
79
  tier_used TEXT,
80
80
  llm_model TEXT,
81
81
  facts_created INTEGER NOT NULL DEFAULT 0,
@@ -98,7 +98,7 @@ const MIGRATIONS = [
98
98
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
99
99
  scope TEXT NOT NULL CHECK (scope IN ('user','agent','session','hive')),
100
100
  scope_id TEXT NOT NULL,
101
- session_id UUID REFERENCES sessions(id) ON DELETE SET NULL,
101
+ session_id TEXT,
102
102
  content TEXT NOT NULL,
103
103
  embedding VECTOR(2000),
104
104
  embedding_model TEXT,
@@ -278,6 +278,133 @@ const MIGRATIONS = [
278
278
  AND f.search_vector @@ plainto_tsquery('english', search_query)
279
279
  ORDER BY ts_rank(f.search_vector, plainto_tsquery('english', search_query)) DESC LIMIT match_count);
280
280
  END; $$;`,
281
+ // Usage records unique constraint (required by increment_usage)
282
+ `ALTER TABLE usage_records ADD CONSTRAINT IF NOT EXISTS usage_records_tenant_period_unique UNIQUE (tenant_id, period_start);`,
283
+ // Extraction hash unique index
284
+ `CREATE UNIQUE INDEX IF NOT EXISTS idx_extractions_hash ON extractions(tenant_id, input_hash);`,
285
+ // match_facts RPC
286
+ `CREATE OR REPLACE FUNCTION match_facts(
287
+ query_embedding TEXT, match_tenant_id UUID, match_scope TEXT,
288
+ match_scope_id TEXT, match_count INT, min_similarity FLOAT DEFAULT 0,
289
+ match_as_of TIMESTAMPTZ DEFAULT NULL
290
+ ) RETURNS TABLE (
291
+ id UUID, tenant_id UUID, scope TEXT, scope_id TEXT, session_id TEXT,
292
+ content TEXT, embedding_model TEXT, embedding_dim INT, version INT,
293
+ lineage_id UUID, valid_from TIMESTAMPTZ, valid_until TIMESTAMPTZ,
294
+ operation TEXT, parent_id UUID, importance NUMERIC, frequency INT,
295
+ last_accessed TIMESTAMPTZ, decay_score NUMERIC, contradiction_status TEXT,
296
+ contradicts_id UUID, source_type TEXT, source_ref JSONB, confidence NUMERIC,
297
+ original_content TEXT, extraction_id UUID, extraction_tier TEXT,
298
+ modality TEXT, tags TEXT[], metadata JSONB,
299
+ event_date TIMESTAMPTZ, document_date TIMESTAMPTZ, source_chunk TEXT,
300
+ created_at TIMESTAMPTZ, similarity FLOAT
301
+ ) LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT
302
+ f.id, f.tenant_id, f.scope, f.scope_id, f.session_id,
303
+ f.content, f.embedding_model, f.embedding_dim, f.version, f.lineage_id,
304
+ f.valid_from, f.valid_until, f.operation, f.parent_id, f.importance, f.frequency,
305
+ f.last_accessed, f.decay_score, f.contradiction_status, f.contradicts_id,
306
+ f.source_type, f.source_ref, f.confidence, f.original_content, f.extraction_id,
307
+ f.extraction_tier, f.modality, f.tags, f.metadata,
308
+ f.event_date, f.document_date, f.source_chunk, f.created_at,
309
+ (1 - (f.embedding <=> query_embedding::vector)) AS similarity
310
+ FROM facts f WHERE f.tenant_id = match_tenant_id AND f.scope = match_scope
311
+ AND f.scope_id = match_scope_id
312
+ AND (CASE WHEN match_as_of IS NOT NULL THEN f.valid_from <= match_as_of AND (f.valid_until IS NULL OR f.valid_until > match_as_of) ELSE f.valid_until IS NULL END)
313
+ AND (1 - (f.embedding <=> query_embedding::vector)) >= min_similarity
314
+ ORDER BY f.embedding <=> query_embedding::vector LIMIT match_count; END; $$;`,
315
+ // increment_usage RPC
316
+ `CREATE OR REPLACE FUNCTION increment_usage(p_tenant_id UUID, p_tokens INT, p_queries INT, p_extractions INT, p_cost_usd FLOAT)
317
+ RETURNS VOID LANGUAGE plpgsql AS $$ DECLARE p_start DATE := date_trunc('month', CURRENT_DATE)::date;
318
+ p_end DATE := (date_trunc('month', CURRENT_DATE) + interval '1 month' - interval '1 day')::date;
319
+ BEGIN INSERT INTO usage_records (id, tenant_id, period_start, period_end, tokens_used, queries_used, extractions_count, cost_usd)
320
+ VALUES (gen_random_uuid(), p_tenant_id, p_start, p_end, p_tokens, p_queries, p_extractions, p_cost_usd)
321
+ ON CONFLICT (tenant_id, period_start) DO UPDATE SET
322
+ tokens_used = usage_records.tokens_used + EXCLUDED.tokens_used,
323
+ queries_used = usage_records.queries_used + EXCLUDED.queries_used,
324
+ extractions_count = usage_records.extractions_count + EXCLUDED.extractions_count,
325
+ cost_usd = usage_records.cost_usd + EXCLUDED.cost_usd, updated_at = NOW(); END; $$;`,
326
+ // match_entities RPC
327
+ `CREATE OR REPLACE FUNCTION match_entities(query_embedding TEXT, match_tenant_id UUID, match_count INT DEFAULT 10, min_similarity FLOAT DEFAULT 0.3)
328
+ RETURNS TABLE (id UUID, tenant_id UUID, name TEXT, entity_type TEXT, canonical_name TEXT, properties JSONB,
329
+ embedding_model TEXT, embedding_dim INT, merge_target_id UUID, created_at TIMESTAMPTZ, updated_at TIMESTAMPTZ, similarity FLOAT)
330
+ LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT e.id, e.tenant_id, e.name, e.entity_type, e.canonical_name,
331
+ e.properties, e.embedding_model, e.embedding_dim, e.merge_target_id, e.created_at, e.updated_at,
332
+ (1 - (e.embedding <=> query_embedding::vector))::float AS similarity
333
+ FROM entities e WHERE e.tenant_id = match_tenant_id AND e.embedding IS NOT NULL
334
+ AND (1 - (e.embedding <=> query_embedding::vector)) >= min_similarity
335
+ ORDER BY e.embedding <=> query_embedding::vector LIMIT match_count; END; $$;`,
336
+ // graph_traverse RPC
337
+ `CREATE OR REPLACE FUNCTION graph_traverse(match_tenant_id UUID, seed_entity_ids UUID[], max_depth INT DEFAULT 3, max_entities INT DEFAULT 200, match_as_of TIMESTAMPTZ DEFAULT NULL)
338
+ RETURNS TABLE (entity_id UUID, entity_name TEXT, entity_type TEXT, canonical_name TEXT, properties JSONB, hop_depth INT,
339
+ edge_id UUID, edge_source_id UUID, edge_target_id UUID, edge_relation TEXT, edge_type TEXT, edge_weight FLOAT,
340
+ edge_valid_from TIMESTAMPTZ, edge_valid_until TIMESTAMPTZ, edge_confidence FLOAT)
341
+ LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY WITH RECURSIVE traversal AS (
342
+ SELECT e.id AS entity_id, e.name AS entity_name, e.entity_type, e.canonical_name, e.properties, 0 AS hop_depth,
343
+ NULL::UUID AS edge_id, NULL::UUID AS edge_source_id, NULL::UUID AS edge_target_id, NULL::TEXT AS edge_relation,
344
+ NULL::TEXT AS edge_type, NULL::FLOAT AS edge_weight, NULL::TIMESTAMPTZ AS edge_valid_from,
345
+ NULL::TIMESTAMPTZ AS edge_valid_until, NULL::FLOAT AS edge_confidence, ARRAY[e.id] AS visited_ids
346
+ FROM entities e WHERE e.id = ANY(seed_entity_ids) AND e.tenant_id = match_tenant_id
347
+ UNION ALL
348
+ SELECT e2.id, e2.name, e2.entity_type, e2.canonical_name, e2.properties, t.hop_depth + 1,
349
+ ed.id, ed.source_id, ed.target_id, ed.relation, ed.edge_type, ed.weight, ed.valid_from, ed.valid_until, ed.confidence,
350
+ t.visited_ids || e2.id
351
+ FROM traversal t JOIN edges ed ON (ed.source_id = t.entity_id OR ed.target_id = t.entity_id) AND ed.tenant_id = match_tenant_id
352
+ AND (CASE WHEN match_as_of IS NOT NULL THEN ed.valid_from <= match_as_of AND (ed.valid_until IS NULL OR ed.valid_until > match_as_of) ELSE ed.valid_until IS NULL END)
353
+ JOIN entities e2 ON e2.id = CASE WHEN ed.source_id = t.entity_id THEN ed.target_id ELSE ed.source_id END AND e2.tenant_id = match_tenant_id
354
+ WHERE t.hop_depth < max_depth AND e2.id != ALL(t.visited_ids)
355
+ ) SELECT traversal.entity_id, traversal.entity_name, traversal.entity_type, traversal.canonical_name, traversal.properties,
356
+ traversal.hop_depth, traversal.edge_id, traversal.edge_source_id, traversal.edge_target_id, traversal.edge_relation,
357
+ traversal.edge_type, traversal.edge_weight, traversal.edge_valid_from, traversal.edge_valid_until, traversal.edge_confidence
358
+ FROM traversal LIMIT max_entities; END; $$;`,
359
+ // get_facts_for_entities RPC
360
+ `CREATE OR REPLACE FUNCTION get_facts_for_entities(match_tenant_id UUID, entity_ids UUID[], per_entity_limit INT DEFAULT 20)
361
+ RETURNS TABLE (entity_id UUID, fact_id UUID, tenant_id UUID, scope TEXT, scope_id TEXT, session_id TEXT,
362
+ content TEXT, embedding_model TEXT, embedding_dim INTEGER, version INTEGER, lineage_id UUID,
363
+ valid_from TIMESTAMPTZ, valid_until TIMESTAMPTZ, operation TEXT, parent_id UUID,
364
+ importance NUMERIC, frequency INTEGER, last_accessed TIMESTAMPTZ, decay_score NUMERIC,
365
+ contradiction_status TEXT, contradicts_id UUID, source_type TEXT, source_ref JSONB, confidence NUMERIC,
366
+ original_content TEXT, extraction_id UUID, extraction_tier TEXT, modality TEXT, tags TEXT[], metadata JSONB,
367
+ event_date TIMESTAMPTZ, document_date TIMESTAMPTZ, source_chunk TEXT, created_at TIMESTAMPTZ)
368
+ LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT ranked.entity_id, ranked.fact_id, ranked.tenant_id, ranked.scope,
369
+ ranked.scope_id, ranked.session_id, ranked.content, ranked.embedding_model, ranked.embedding_dim, ranked.version,
370
+ ranked.lineage_id, ranked.valid_from, ranked.valid_until, ranked.operation, ranked.parent_id, ranked.importance,
371
+ ranked.frequency, ranked.last_accessed, ranked.decay_score, ranked.contradiction_status, ranked.contradicts_id,
372
+ ranked.source_type, ranked.source_ref, ranked.confidence, ranked.original_content, ranked.extraction_id,
373
+ ranked.extraction_tier, ranked.modality, ranked.tags, ranked.metadata,
374
+ ranked.event_date, ranked.document_date, ranked.source_chunk, ranked.created_at
375
+ FROM (SELECT fe.entity_id, f.id AS fact_id, f.tenant_id, f.scope, f.scope_id, f.session_id, f.content,
376
+ f.embedding_model, f.embedding_dim, f.version, f.lineage_id, f.valid_from, f.valid_until, f.operation,
377
+ f.parent_id, f.importance, f.frequency, f.last_accessed, f.decay_score, f.contradiction_status, f.contradicts_id,
378
+ f.source_type, f.source_ref, f.confidence, f.original_content, f.extraction_id, f.extraction_tier, f.modality,
379
+ f.tags, f.metadata, f.event_date, f.document_date, f.source_chunk, f.created_at,
380
+ ROW_NUMBER() OVER (PARTITION BY fe.entity_id ORDER BY f.importance DESC, f.created_at DESC) AS rn
381
+ FROM fact_entities fe JOIN facts f ON f.id = fe.fact_id WHERE fe.entity_id = ANY(entity_ids)
382
+ AND f.tenant_id = match_tenant_id AND f.valid_until IS NULL AND NOT ('raw_chunk' = ANY(f.tags))) ranked
383
+ WHERE ranked.rn <= per_entity_limit; END; $$;`,
384
+ // keyword_search_facts RPC
385
+ `CREATE OR REPLACE FUNCTION keyword_search_facts(search_query TEXT, match_tenant_id UUID, match_scope TEXT,
386
+ match_scope_id TEXT, match_count INT, match_as_of TIMESTAMPTZ DEFAULT NULL)
387
+ RETURNS TABLE (id UUID, tenant_id UUID, scope TEXT, scope_id TEXT, session_id TEXT,
388
+ content TEXT, embedding_model TEXT, embedding_dim INT, version INT, lineage_id UUID,
389
+ valid_from TIMESTAMPTZ, valid_until TIMESTAMPTZ, operation TEXT, parent_id UUID,
390
+ importance NUMERIC, frequency INT, last_accessed TIMESTAMPTZ, decay_score NUMERIC,
391
+ contradiction_status TEXT, contradicts_id UUID, source_type TEXT, source_ref JSONB, confidence NUMERIC,
392
+ original_content TEXT, extraction_id UUID, extraction_tier TEXT, modality TEXT, tags TEXT[], metadata JSONB,
393
+ event_date TIMESTAMPTZ, document_date TIMESTAMPTZ, source_chunk TEXT, created_at TIMESTAMPTZ, rank_score FLOAT)
394
+ LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT f.id, f.tenant_id, f.scope, f.scope_id, f.session_id,
395
+ f.content, f.embedding_model, f.embedding_dim, f.version, f.lineage_id, f.valid_from, f.valid_until,
396
+ f.operation, f.parent_id, f.importance, f.frequency, f.last_accessed, f.decay_score, f.contradiction_status,
397
+ f.contradicts_id, f.source_type, f.source_ref, f.confidence, f.original_content, f.extraction_id,
398
+ f.extraction_tier, f.modality, f.tags, f.metadata, f.event_date, f.document_date, f.source_chunk, f.created_at,
399
+ ts_rank(f.search_vector, plainto_tsquery('english', search_query)) AS rank_score
400
+ FROM facts f WHERE f.tenant_id = match_tenant_id AND f.scope = match_scope AND f.scope_id = match_scope_id
401
+ AND (CASE WHEN match_as_of IS NOT NULL THEN f.valid_from <= match_as_of AND (f.valid_until IS NULL OR f.valid_until > match_as_of) ELSE f.valid_until IS NULL END)
402
+ AND f.search_vector @@ plainto_tsquery('english', search_query)
403
+ ORDER BY rank_score DESC LIMIT match_count; END; $$;`,
404
+ // increment_trigger_fired RPC
405
+ `CREATE OR REPLACE FUNCTION increment_trigger_fired(p_tenant_id UUID, p_trigger_id UUID)
406
+ RETURNS VOID LANGUAGE plpgsql AS $$ BEGIN UPDATE triggers SET times_fired = times_fired + 1,
407
+ last_fired_at = NOW(), updated_at = NOW() WHERE tenant_id = p_tenant_id AND id = p_trigger_id; END; $$;`,
281
408
  // Default tenant
282
409
  `INSERT INTO tenants (id, name, slug, plan) VALUES ('00000000-0000-0000-0000-000000000001', 'Default', 'default', 'enterprise') ON CONFLICT DO NOTHING;`,
283
410
  ];
@@ -300,27 +427,39 @@ async function main() {
300
427
  console.log('\n Running database migrations...');
301
428
  const supabase = createClient(supabaseUrl, supabaseKey);
302
429
 
303
- let success = 0;
304
- let skipped = 0;
305
- for (let i = 0; i < MIGRATIONS.length; i++) {
306
- try {
307
- const { error } = await (supabase.rpc('exec_sql', { query: MIGRATIONS[i] }) as any).catch(() => ({ error: { message: 'rpc not available' } }));
308
- if (error) {
309
- // Try direct REST approach
310
- const res = await fetch(`${supabaseUrl}/rest/v1/rpc/exec_sql`, {
311
- method: 'POST',
312
- headers: { 'apikey': supabaseKey, 'Authorization': `Bearer ${supabaseKey}`, 'Content-Type': 'application/json' },
313
- body: JSON.stringify({ query: MIGRATIONS[i] }),
314
- });
315
- if (res.ok) { success++; } else { skipped++; }
316
- } else {
317
- success++;
318
- }
319
- } catch {
320
- skipped++;
430
+ // Try running migrations via Supabase Management API (requires service role key)
431
+ // If that fails, write SQL to a file for manual execution
432
+ const allSql = MIGRATIONS.join('\n\n');
433
+ const sqlPath = path.join(process.cwd(), 'steno-migrations.sql');
434
+
435
+ // Attempt automatic migration via Supabase SQL endpoint
436
+ let autoMigrated = false;
437
+ try {
438
+ const res = await fetch(`${supabaseUrl}/rest/v1/rpc/exec_sql`, {
439
+ method: 'POST',
440
+ headers: { 'apikey': supabaseKey, 'Authorization': `Bearer ${supabaseKey}`, 'Content-Type': 'application/json' },
441
+ body: JSON.stringify({ query: allSql }),
442
+ });
443
+ if (res.ok) {
444
+ autoMigrated = true;
445
+ console.log(' ✓ All migrations applied automatically');
321
446
  }
447
+ } catch { /* RPC not available */ }
448
+
449
+ if (!autoMigrated) {
450
+ // Write SQL file for manual execution
451
+ fs.writeFileSync(sqlPath, allSql);
452
+ console.log(`
453
+ ⚠️ Could not run migrations automatically.
454
+
455
+ Please run the SQL manually:
456
+ 1. Open your Supabase dashboard → SQL Editor
457
+ 2. Paste the contents of: ${sqlPath}
458
+ 3. Click "Run"
459
+ 4. Come back here and press Enter to continue
460
+ `);
461
+ await ask(' Press Enter after running the SQL... ');
322
462
  }
323
- console.log(` ✓ ${success} migrations applied, ${skipped} skipped (may already exist)`);
324
463
 
325
464
  // 3. Write Claude Desktop config
326
465
  const configDir = path.join(os.homedir(), 'Library', 'Application Support', 'Claude');
@@ -70,6 +70,15 @@ export function createLocalServer(config: LocalServerConfig): McpServer {
70
70
  const server = new McpServer({
71
71
  name: 'steno-local',
72
72
  version: '0.1.0',
73
+ ...({ instructions: `You have access to the user's persistent long-term memory via Steno.
74
+
75
+ CRITICAL RULES:
76
+ 1. ALWAYS call steno_recall BEFORE answering ANY question about the user, their life, work, projects, people they know, preferences, past events, companies, or decisions.
77
+ 2. When the user shares personal information, call steno_remember to store it, then ALWAYS call steno_flush immediately after to ensure extraction happens now.
78
+ 3. Before context compaction or session end, call steno_remember with a summary of key decisions and progress, then steno_flush.
79
+ 4. Never say "I don't have information about that" without first checking steno_recall.
80
+ 5. Steno memory persists across ALL conversations — it knows things from past sessions that your conversation history does not.
81
+ 6. Use steno_update_status to change priority/roadmap item status when the user starts, completes, or gets blocked on a task.` } as any),
73
82
  });
74
83
 
75
84
  // Lazy import to avoid loading heavy modules at startup
@@ -291,24 +300,182 @@ export function createLocalServer(config: LocalServerConfig): McpServer {
291
300
  return { content: [{ type: 'text' as const, text: 'No memories found.' }] };
292
301
  }
293
302
 
294
- const text = results.results
295
- .map((r) => {
296
- const dateParts: string[] = [];
297
- if (r.fact.eventDate) dateParts.push(`event: ${new Date(r.fact.eventDate).toISOString().slice(0, 10)}`);
298
- if (r.fact.documentDate) dateParts.push(`doc: ${new Date(r.fact.documentDate).toISOString().slice(0, 10)}`);
299
- const dateStr = dateParts.length > 0 ? `, ${dateParts.join(', ')}` : '';
300
- const signals = Object.entries(r.signals)
301
- .filter(([, v]) => v > 0)
302
- .map(([k, v]) => `${k.replace('Score', '')}=${(v as number).toFixed(2)}`)
303
- .join(', ');
304
- let line = `[Memory] ${r.fact.content} (score: ${r.score.toFixed(2)}${dateStr}${signals ? `, ${signals}` : ''})`;
305
- if (r.fact.sourceChunk) {
306
- line += `\n[Source Context] ${r.fact.sourceChunk}`;
303
+ // Build priority label map: factId → "Priority #N (short name)"
304
+ // Query ALL facts with priority_order metadata — not just the ones in results
305
+ // This ensures labels resolve even for facts referenced by edges but not in recall
306
+ const priorityLabels = new Map<string, string>();
307
+ try {
308
+ const { data: allPriorityFacts } = await (config.storage as any).client
309
+ .from('facts')
310
+ .select('id, content, metadata')
311
+ .eq('tenant_id', config.tenantId)
312
+ .not('metadata->priority_order', 'is', null);
313
+ if (allPriorityFacts) {
314
+ for (const f of allPriorityFacts) {
315
+ const order = f.metadata?.priority_order;
316
+ if (order) {
317
+ const shortName = f.content.replace(/^User('s)?\s+(plans|added|believes|is planning|wants|Steno)\s+/i, '').slice(0, 35).replace(/\s+\S*$/, '');
318
+ priorityLabels.set(f.id, `Priority #${order} (${shortName})`);
319
+ }
307
320
  }
308
- line += '\n---';
309
- return line;
310
- })
311
- .join('\n');
321
+ }
322
+ } catch { /* fallback to results-only labels */ }
323
+ // Also add labels from results (in case metadata query missed any)
324
+ for (const r of results.results) {
325
+ if (priorityLabels.has(r.fact.id)) continue;
326
+ const meta = r.fact.metadata as Record<string, unknown> | undefined;
327
+ const order = meta?.priority_order as number | undefined;
328
+ if (order) {
329
+ const shortName = r.fact.content.replace(/^User('s)?\s+(plans|added|believes|is planning|wants)\s+/i, '').slice(0, 35).replace(/\s+\S*$/, '');
330
+ priorityLabels.set(r.fact.id, `Priority #${order} (${shortName})`);
331
+ }
332
+ }
333
+
334
+ // Build dependency map — ONE batch query for ALL dependency edges in this tenant
335
+ const factIds = results.results.map(r => r.fact.id);
336
+ const depMap = new Map<string, { blocks: string[]; blockedBy: string[]; deadlines: string[] }>();
337
+
338
+ try {
339
+ // Query ALL precedes/depends_on/deadline edges — not just for these fact_ids
340
+ // because edges reference sourceFactId/targetFactId in metadata, not in fact_id column
341
+ const { data: depEdges } = await (config.storage as any).client
342
+ .from('edges')
343
+ .select('relation, fact_id, metadata')
344
+ .eq('tenant_id', config.tenantId)
345
+ .in('relation', ['precedes', 'depends_on', 'deadline']);
346
+
347
+ if (depEdges) {
348
+ for (const edge of depEdges) {
349
+ const edgeMeta = edge.metadata as Record<string, unknown> | undefined;
350
+ const sourceFactId = (edgeMeta?.sourceFactId as string) || edge.fact_id;
351
+ const targetFactId = edgeMeta?.targetFactId as string | undefined;
352
+
353
+ // Only process edges involving facts in our result set
354
+ const sourceInResults = factIds.includes(sourceFactId);
355
+ const targetInResults = targetFactId ? factIds.includes(targetFactId) : false;
356
+ if (!sourceInResults && !targetInResults) continue;
357
+
358
+ if (!depMap.has(sourceFactId)) depMap.set(sourceFactId, { blocks: [], blockedBy: [], deadlines: [] });
359
+
360
+ if (edge.relation === 'precedes' && targetFactId) {
361
+ const label = priorityLabels.get(targetFactId) || 'another priority';
362
+ depMap.get(sourceFactId)!.blocks.push(label);
363
+ }
364
+ if (edge.relation === 'depends_on' && targetFactId) {
365
+ const label = priorityLabels.get(targetFactId) || 'another priority';
366
+ depMap.get(sourceFactId)!.blockedBy.push(label);
367
+ }
368
+ if (edge.relation === 'deadline') {
369
+ const deadline = edgeMeta?.deadline as string | undefined;
370
+ if (deadline) {
371
+ depMap.get(sourceFactId)!.deadlines.push(deadline);
372
+ // Cascade deadline upstream: if X blocks Y and Y has deadline, X gets it too
373
+ for (const [fid, deps2] of depMap) {
374
+ if (deps2.blocks.some(b => b.includes(sourceFactId.slice(0, 8)) || priorityLabels.get(sourceFactId)?.includes(b.split('(')[1]?.slice(0, 10) || ''))) {
375
+ if (!deps2.deadlines.includes(deadline)) deps2.deadlines.push(deadline + ' (cascaded)');
376
+ }
377
+ }
378
+ }
379
+ }
380
+ }
381
+
382
+ // Second pass: cascade deadlines through depends_on chain
383
+ // If A depends_on B, and B has a deadline, A implicitly has that deadline
384
+ for (const [factId, deps] of depMap) {
385
+ if (deps.deadlines.length === 0) {
386
+ // Check if anything this blocks has a deadline
387
+ for (const blockLabel of deps.blocks) {
388
+ for (const [otherId, otherDeps] of depMap) {
389
+ if (priorityLabels.get(otherId) === blockLabel && otherDeps.deadlines.length > 0) {
390
+ for (const dl of otherDeps.deadlines) {
391
+ if (!dl.includes('cascaded') && !deps.deadlines.includes(dl)) {
392
+ deps.deadlines.push(dl + ' (implicit — blocks deadline item)');
393
+ }
394
+ }
395
+ }
396
+ }
397
+ }
398
+ }
399
+ }
400
+ }
401
+ } catch { /* batch edge lookup failed */ }
402
+
403
+ // Inject missing priority facts that are referenced by edges but not in recall results
404
+ // This ensures Priority #1 (root node) always shows up when its children are recalled
405
+ const resultFactIds = new Set(results.results.map(r => r.fact.id));
406
+ try {
407
+ const { data: allPriorities } = await (config.storage as any).client
408
+ .from('facts')
409
+ .select('*')
410
+ .eq('tenant_id', config.tenantId)
411
+ .not('metadata->priority_order', 'is', null);
412
+ if (allPriorities) {
413
+ for (const pf of allPriorities) {
414
+ if (!resultFactIds.has(pf.id) && (depMap.has(pf.id) || priorityLabels.has(pf.id))) {
415
+ // This priority is referenced but not in results — inject it
416
+ const camelFact = Object.fromEntries(
417
+ Object.entries(pf).map(([k, v]) => [k.replace(/_([a-z])/g, (_, c: string) => c.toUpperCase()), v])
418
+ );
419
+ results.results.push({
420
+ fact: camelFact as any,
421
+ score: 0.1, // Low score since it wasn't directly matched
422
+ signals: { vectorScore: 0, keywordScore: 0, graphScore: 0.5, recencyScore: 0, salienceScore: 0, temporalScore: 0 },
423
+ });
424
+ }
425
+ }
426
+ }
427
+ } catch { /* injection failed */ }
428
+
429
+ // Sort results: priorities first (by priority_order), then regular memories
430
+ const sortedResults = [...results.results].sort((a, b) => {
431
+ const aOrder = (a.fact.metadata as any)?.priority_order as number | undefined;
432
+ const bOrder = (b.fact.metadata as any)?.priority_order as number | undefined;
433
+ if (aOrder && bOrder) return aOrder - bOrder;
434
+ if (aOrder) return -1;
435
+ if (bOrder) return 1;
436
+ return b.score - a.score;
437
+ });
438
+
439
+ const enrichedLines: string[] = [];
440
+ for (const r of sortedResults) {
441
+ const meta = r.fact.metadata as Record<string, unknown> | undefined;
442
+ const status = meta?.status as string | undefined;
443
+ const priorityOrder = meta?.priority_order as number | undefined;
444
+ const deps = depMap.get(r.fact.id);
445
+
446
+ const dateParts: string[] = [];
447
+ if (r.fact.eventDate) dateParts.push(`event: ${new Date(r.fact.eventDate).toISOString().slice(0, 10)}`);
448
+ if (r.fact.documentDate) dateParts.push(`doc: ${new Date(r.fact.documentDate).toISOString().slice(0, 10)}`);
449
+ const dateStr = dateParts.length > 0 ? `, ${dateParts.join(', ')}` : '';
450
+ const signals = Object.entries(r.signals)
451
+ .filter(([, v]) => v > 0)
452
+ .map(([k, v]) => `${k.replace('Score', '')}=${(v as number).toFixed(2)}`)
453
+ .join(', ');
454
+
455
+ const isPriority = status || priorityOrder;
456
+ const blocks = deps?.blocks ?? [];
457
+ const blockedBy = deps?.blockedBy ?? [];
458
+ const deadlines = deps?.deadlines ?? [];
459
+ let line: string;
460
+ if (isPriority) {
461
+ line = `[Priority${priorityOrder ? ` #${priorityOrder}` : ''}] ${r.fact.content}`;
462
+ line += `\n status: ${status || 'unknown'}`;
463
+ if (blocks.length > 0) line += `\n blocks: → ${blocks.join(', ')}`;
464
+ if (blockedBy.length > 0) line += `\n blocked_by: ← ${blockedBy.join(', ')}`;
465
+ else if (status === 'not_started') line += `\n blocked_by: none`;
466
+ if (deadlines.length > 0) line += `\n deadline: ${deadlines.join(', ')}`;
467
+ line += `\n (score: ${r.score.toFixed(2)}${dateStr})`;
468
+ } else {
469
+ line = `[Memory] ${r.fact.content} (score: ${r.score.toFixed(2)}${dateStr}${signals ? `, ${signals}` : ''})`;
470
+ }
471
+ if (r.fact.sourceChunk && !isPriority) {
472
+ line += `\n[Source Context] ${r.fact.sourceChunk}`;
473
+ }
474
+ line += '\n---';
475
+ enrichedLines.push(line);
476
+ }
477
+
478
+ const text = enrichedLines.join('\n');
312
479
 
313
480
  return {
314
481
  content: [
@@ -346,6 +513,54 @@ export function createLocalServer(config: LocalServerConfig): McpServer {
346
513
  },
347
514
  );
348
515
 
516
+ // ─── UPDATE STATUS ───
517
+ server.tool(
518
+ 'steno_update_status',
519
+ 'Update the status of a priority/roadmap item. Use when a task changes state (e.g., started working on it, completed it, or it became blocked).',
520
+ {
521
+ priority: z.number().describe('Priority number (1-6)'),
522
+ status: z.enum(['not_started', 'in_progress', 'done', 'blocked']).describe('New status'),
523
+ },
524
+ async ({ priority, status }) => {
525
+ try {
526
+ // Find the fact with this priority_order
527
+ const { data: facts, error: findError } = await (config.storage as any).client
528
+ .from('facts')
529
+ .select('id, content, metadata')
530
+ .eq('tenant_id', config.tenantId)
531
+ .not('metadata->priority_order', 'is', null);
532
+
533
+ if (findError) throw findError;
534
+
535
+ const fact = facts?.find((f: any) => f.metadata?.priority_order === priority);
536
+ if (!fact) {
537
+ return { content: [{ type: 'text' as const, text: `No priority #${priority} found.` }] };
538
+ }
539
+
540
+ const oldStatus = fact.metadata?.status || 'unknown';
541
+ const newMetadata = { ...fact.metadata, status };
542
+
543
+ const { error: updateError } = await (config.storage as any).client
544
+ .from('facts')
545
+ .update({ metadata: newMetadata })
546
+ .eq('id', fact.id)
547
+ .eq('tenant_id', config.tenantId);
548
+
549
+ if (updateError) throw updateError;
550
+
551
+ const shortName = fact.content.replace(/^User('s)?\s+(plans|added|believes|is planning|wants|Steno)\s+/i, '').slice(0, 50);
552
+ return {
553
+ content: [{
554
+ type: 'text' as const,
555
+ text: `Priority #${priority} (${shortName}): ${oldStatus} → ${status}`,
556
+ }],
557
+ };
558
+ } catch (err: any) {
559
+ return { content: [{ type: 'text' as const, text: `Error updating status: ${err?.message ?? err}` }] };
560
+ }
561
+ },
562
+ );
563
+
349
564
  // ─── STATS ───
350
565
  server.tool(
351
566
  'steno_stats',
package/src/local.ts CHANGED
File without changes
package/src/server.ts CHANGED
File without changes