# Changelog All notable changes to Chat Switchboard. ## [0.18.0] — 2026-02-28 ### Added - **Memory system.** Long-term memory across conversations with scope-aware isolation. Three memory scopes: `user` (personal facts/preferences), `persona` (shared across all users of a Persona), and `persona_user` (per-user within a Persona context, e.g. tutoring progress per student). Memories persist across channels and are injected into the system prompt at completion time with scope priority (persona_user > persona > user). - **Memory tools.** Two new LLM-callable tools: - `memory_save` — LLM explicitly stores a fact with key/value/confidence. Scope-aware: saves to the active scope for the current Persona context. - `memory_recall` — LLM queries stored facts relevant to current context. Merges results from applicable scopes with semantic search via embeddings and keyword fallback. - **Automatic memory extraction.** Background scanner finds conversations with sufficient new activity, sends them to the utility model role for fact extraction, and stores results as `pending_review` memories. Configurable extraction prompt per Persona (e.g. "extract FAQ-worthy Q&A pairs"). Scanner runs on a configurable interval with concurrency control. Global kill switch via admin settings. - **Memory review pipeline.** Extracted memories start in `pending_review` status. Admin panel shows pending review queue with bulk approve. Users can approve/reject/edit their own pending memories from the Settings → Memory tab. - **User memory management.** Settings → Memory tab shows active/pending memory counts, filterable/searchable memory list with inline edit and delete. Status filter (active, pending_review, archived). Approve All button for batch operations on pending memories. - **Admin memory controls.** Admin panel → Memory section shows system-wide pending review queue. Memory extraction toggle in admin Settings panel (`memory_extraction_enabled`). Bulk approve endpoint for batch review. - **Hybrid semantic recall.** Memory recall supports both keyword search and vector similarity (cosine distance). Postgres uses `<=>` operator with pgvector; SQLite computes cosine similarity in Go with app-level vector loading. Results are merged and deduplicated. - **Memory injection at completion time.** `BuildMemoryHint()` loads relevant memories and formats them as a system prompt section, injected after the knowledge base hint. Context-budget aware with configurable character limit. Supports embedding-based relevance filtering when the user's latest message is available. - **Persona memory configuration.** Personas gain `memory_enabled` (bool) and `memory_extraction_prompt` (text) fields. When memory is enabled on a Persona, conversations with that Persona contribute to persona-scoped memory extraction. Custom extraction prompts allow specialization (e.g. helpdesk FAQ extraction vs. tutoring progress tracking). - **Database migrations.** Four new migration files (Postgres + SQLite): - `004_v0180_memories.sql` / `sqlite/003_v0180_memories.sql` — `memories` table with composite unique index, full-text search index (GIN/keyword), `memory_extraction_log` tracking table. - `005_v0180_memory_phase2.sql` / `sqlite/004_v0180_memory_phase2.sql` — Persona memory columns, extraction log unique constraint. - **API endpoints.** Eight new authenticated endpoints: - `GET /memories` — list user's memories (filterable by status/query) - `GET /memories/count` — active + pending counts - `PUT /memories/:id` — edit a memory's key/value/confidence - `DELETE /memories/:id` — delete a memory - `POST /memories/:id/approve` — approve a pending memory - `POST /memories/:id/reject` — reject (archive) a pending memory - `GET /admin/memories/pending` — admin pending review queue - `POST /admin/memories/bulk-approve` — admin bulk approve ### Changed - `CompletionHandler` now accepts an `*knowledge.Embedder` parameter for memory injection with semantic relevance filtering. - Persona create/update forms include memory configuration fields (enabled toggle, extraction prompt textarea). - Admin settings save handler includes `memory_extraction` and `memory_extraction_enabled` keys. - `store.Stores` struct includes `Memories MemoryStore` field. - Admin panel sections include Memory with pending review loader. ### Technical Notes - Memory embeddings use `vector(3072)` matching the existing KB/notes schema. HNSW index is not used (pgvector limits HNSW to 2000 dims); filtered sequential scans are performant for per-user memory tables. IVFFlat or dimension reduction available as future optimizations. - SQLite hybrid recall loads embeddings into Go and computes cosine similarity at the application level, reusing the existing `cosineSimilarity()` function from the knowledge base store. - Memory tools use late registration (like KB search and note tools) because they require stores and embedder dependencies initialized in main.go. ## [0.17.3] — 2026-02-28 ### Added - **Wikilink bi-directional linking.** Notes support `[[Title]]` and `[[Title|display text]]` syntax. Links are extracted on save via regex, resolved to target note IDs by case-insensitive title match, and stored in a `note_links` junction table. Dangling links (references to notes that don't exist yet) are preserved and automatically resolved when a matching note is created later. - **Transclusion embeds.** `![[Title]]` syntax renders embedded note content inline in read mode. Content is fetched asynchronously with a recursion guard (max depth 1 — nested transclusions render as plain text references). Transclusion links are visually distinct in both the editor (border-left, italic) and the graph (dashed edges). - **Backlinks panel.** Read mode shows a collapsible "Linked mentions" panel below the note content listing all notes that link to the current note. Each backlink is clickable to navigate directly. Count badge updates on every note open. - **Knowledge graph visualization.** Canvas-based force-directed graph with no external dependencies (~480 lines). Physics: O(n²) Coulomb repulsion, Hooke spring attraction on edges, center gravity. Interaction: pan, zoom (0.15–4.0x toward cursor), drag nodes, hover highlights node + neighbors. Click opens note editor. Nodes sized by √(link_count), colored by folder path (10-color palette). Ghost nodes for unresolved `[[links]]` with toggle button. Energy-based pause (stops rAF when total kinetic energy falls below threshold). ResizeObserver for responsive canvas sizing. - **CM6 note editor.** New `CM.noteEditor()` factory function with live markdown preview (heading sizes for h1–h3, blockquote styling, fenced code block decorations), `[[wikilink]]` autocomplete triggered by `[[` with async title search, and clickable wikilink chip rendering. Falls back to plain `