Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
1302 lines
71 KiB
Markdown
1302 lines
71 KiB
Markdown
# Roadmap — Chat Switchboard
|
||
|
||
**See also:**
|
||
- [ARCHITECTURE.md](ARCHITECTURE.md) — Core services design, store layer, scope model
|
||
- [EXTENSIONS.md](EXTENSIONS.md) — Extension system spec (Browser/Starlark/Sidecar tiers,
|
||
manifests, browser tool bridge, surfaces/modes, model roles)
|
||
- [CHANGELOG.md](../CHANGELOG.md) — Detailed release notes for all completed versions
|
||
|
||
**Versioning (pre-1.0):** `0.<major>.<minor>` — hotfixes use quad: `0.x.y.z`
|
||
No compatibility guarantees before 1.0.
|
||
|
||
---
|
||
|
||
## Dependency Graph
|
||
|
||
Features have real dependencies. This ordering respects them.
|
||
|
||
```
|
||
v0.9.x Stability + Quick UX Wins ✅
|
||
│
|
||
v0.9.3 Content Visibility & Block Controls ✅
|
||
│
|
||
v0.9.4 API Key Encryption + Vault ✅
|
||
│
|
||
v0.10.0 Model Roles (utility + embedding) ✅
|
||
+ Usage Tracking
|
||
│
|
||
v0.10.2 Summarize & Continue ✅
|
||
│
|
||
v0.10.3 Frontend Refactor ✅
|
||
│
|
||
v0.10.4 Model Type Pipeline + Role Fixes ✅
|
||
│
|
||
v0.10.5 UI Primitives + Extension Surfaces ✅
|
||
│
|
||
v0.11.0 Extension Foundation (browser tier) ✅
|
||
│
|
||
┌───────┴──────────────┐
|
||
│ │
|
||
v0.12.0 File Handling v0.13.0 Admin Panel
|
||
+ Vision ✅ Refactor (fullscreen) ✅
|
||
│ │
|
||
│ v0.13.1 Web Search
|
||
│ + url_fetch ✅
|
||
│ │
|
||
└───────┬──────────────┘
|
||
│
|
||
v0.14.0 Knowledge Bases ✅ (embedding role + file storage + pgvector)
|
||
│
|
||
v0.15.0 Compaction ✅ (utility role + background job)
|
||
│
|
||
v0.15.1 Context Recall Tools ✅ (attachment_recall, conversation_search)
|
||
│
|
||
┌───────┴──────────────┐
|
||
│ │
|
||
v0.16.0 User Groups v0.17.0 Persona-KB Binding
|
||
+ Resource Grants ✅ + Enterprise KB Mode
|
||
│ + QOL / UX Wins
|
||
└───────┬──────────────┘
|
||
│
|
||
┌───────┴──────────────┐
|
||
│ │
|
||
v0.17.1 SQLite Backend ✅ v0.17.2 CodeMirror 6 ✅
|
||
v0.17.3 Notes Graph + Wikilinks ✅
|
||
(dual DB) (editor bundle, chat
|
||
│ input, ext editor)
|
||
└───────┬──────────────┘
|
||
│
|
||
v0.18.0 Memory ✅ (user + persona scopes, review pipeline)
|
||
│
|
||
v0.18.1 Side Panel Architecture ✅ (single-slot, ctx.ui primitives, mermaid refactor)
|
||
│
|
||
v0.19.0 Projects / Workspaces ✅ (project groups, KB resolution, drag-drop sidebar)
|
||
│
|
||
v0.19.1 Active Project + System Prompt + Detail Panel ✅
|
||
│
|
||
v0.19.2 Project Persona Default + Archive + Reorder ✅
|
||
│
|
||
v0.20.0 Notifications + @mention Routing + Multi-model ✅
|
||
│
|
||
v0.21.0 Workspace Storage Primitive ✅
|
||
│
|
||
┌───────┴──────────────┐
|
||
│ │
|
||
v0.21.1 Workspace ✅ v0.21.3 Surface Infra ✅
|
||
Tools + Bindings + REPL (parallel)
|
||
│ │
|
||
v0.21.2 Workspace ✅ v0.21.5 Editor Surface ✅
|
||
Indexing + Search (Development Mode)
|
||
│ │
|
||
v0.21.4 Git ✅ v0.21.6 Editor Surface ✅
|
||
Integration + Document Output
|
||
└───────┬──────────────┘
|
||
│
|
||
v0.21.7 Bugfix: scanJSON driver buffer aliasing ✅
|
||
│
|
||
v0.22.0 Provider Health + Capability Overrides ✅
|
||
+ Workspace Pane Refactor (FE)
|
||
│
|
||
v0.22.1 Provider Extensions (declarative config) ✅
|
||
│
|
||
v0.22.2 Routing Policies + Fallback Chains ✅
|
||
│
|
||
v0.22.3 Provider Admin UI + Deferred Polish ✅
|
||
│
|
||
v0.22.4 Provider Health UX + Project Files + Export ✅
|
||
│
|
||
v0.22.5 Surfaces + Go Templates + Admin Bug Fixes ✅
|
||
│
|
||
v0.23.0 Multi-Participant Channels + Presence
|
||
│
|
||
v0.24.0 Auth Strategy (mTLS/OIDC) + Full RBAC + Group permissions
|
||
│
|
||
┌───────┴──────────────┐
|
||
│ │
|
||
v0.25.0 Workflow v0.26.0 Tasks /
|
||
Engine Autonomous Agents
|
||
(team-owned, (service channels,
|
||
staged processes, scheduler, unattended
|
||
human + AI collab) execution)
|
||
```
|
||
|
||
---
|
||
|
||
## Completed Releases
|
||
|
||
> Full details for all completed versions are in [CHANGELOG.md](../CHANGELOG.md).
|
||
|
||
### ✅ v0.9.0 — Schema Consolidation + BYOK
|
||
21 migrations → single schema, store layer abstraction, persona-as-trust-boundary,
|
||
BYOK with auto-fetch, composite model IDs, journey integration tests.
|
||
|
||
### ✅ v0.9.1 — Capability Architecture + Docs
|
||
Removed static known model table. Resolution chain: catalog → heuristic only.
|
||
Frontend relies solely on backend for capabilities. Docs rewrite.
|
||
|
||
### ✅ v0.9.2 — Quick UX Wins + Hardening
|
||
Collapsible code blocks, HTML preview, token counter, context warning, proxy
|
||
interception detection, environment injection, team admin audit scoping.
|
||
|
||
### ✅ v0.9.3 — Content Visibility & Block Controls
|
||
Button-driven code collapse, always-rendered thinking blocks, tool call
|
||
persistence in history, Notes panel → unified side panel, streaming refactor
|
||
(`streamWithToolLoop`), regenerate fix.
|
||
|
||
### ✅ v0.9.4 — API Key Encryption + Vault
|
||
Two-tier AES-256-GCM: env-var key for global/team, per-user UEK (Argon2id)
|
||
for personal BYOK. `server/crypto/` package. Migration 003. Startup backfill.
|
||
DOMPurify strict allowlist (XSS fix).
|
||
|
||
### ✅ v0.10.0 — Model Roles + Usage Tracking + Vault Debt
|
||
Named role slots (utility, embedding) with fallback. `Provider.Embed()` interface.
|
||
`usage_log` + `model_pricing` tables. Streaming token capture. Vault debt:
|
||
UEK re-wrap on password change, destruction on admin reset.
|
||
|
||
### ✅ v0.10.1 — Polish + UX
|
||
Admin system prompt injection, Personas tab, Team Management modal extraction,
|
||
preview pane enhancements, code download, personal usage scoped to BYOK.
|
||
|
||
### ✅ v0.10.2 — Summarize & Continue + Role Cleanup
|
||
User-triggered conversation compaction via utility role. Summary as tree node
|
||
with boundary metadata. BYOK role overrides (personal → team → global).
|
||
Utility rate limiting. Generation role removed.
|
||
|
||
### ✅ v0.10.3 — Frontend Refactor
|
||
2 monolith files → 13 domain-scoped files (~544 lines avg). Zero features,
|
||
no function renames. Vanilla JS, no build step.
|
||
See [REFACTOR-0.10.3.md](REFACTOR-0.10.3.md).
|
||
|
||
### ✅ v0.10.4 — Model Type Pipeline + Role Fixes
|
||
`model_type` (chat/embedding/image) captured end-to-end from provider API
|
||
through catalog to frontend. Role dropdowns filter by type.
|
||
|
||
### ✅ v0.10.5 — UI Primitives + Extension Surfaces
|
||
Shared `Providers`/`Roles` registries, 6 consolidated render primitives,
|
||
`showConfirm()` replacing native dialogs, `.popup-menu` CSS primitive.
|
||
Removed ~400 lines of duplication.
|
||
|
||
### ✅ v0.11.0 — Extension Foundation (Browser Tier)
|
||
Full extension lifecycle: manifest, loader, scoped `ctx.*` API, browser tool
|
||
bridge via WebSocket. Custom renderer pipeline. 2 server tools (calculator,
|
||
datetime), 6 built-in browser extensions (Mermaid, KaTeX, CSV, Diff, JS
|
||
Sandbox, Regex). See [EXTENSIONS.md](EXTENSIONS.md).
|
||
|
||
### ✅ v0.12.0 — File Handling + Vision
|
||
S3/PVC storage backend, image/file upload (📎, drag-drop, paste), multimodal
|
||
message assembly, text extraction pipeline (PDF/DOCX/XLSX/PPTX/ODT/RTF),
|
||
vault CLI (`rekey`/`status`), per-chat model persistence.
|
||
|
||
### ✅ v0.13.0 — Admin Panel Refactor
|
||
12-tab modal → fullscreen admin panel. 4 categories (People, AI, System,
|
||
Monitoring) × section sidebar. URL-based routing, responsive, banner-aware.
|
||
CSS design token cleanup.
|
||
|
||
### ✅ v0.13.1 — Web Search + URL Fetch
|
||
`web_search` + `url_fetch` tools. Search provider abstraction (DuckDuckGo,
|
||
SearXNG). Tool categories with per-tool toggle UI in chat bar.
|
||
|
||
### ✅ v0.14.0 — Knowledge Bases
|
||
RAG: upload → chunk → embed (pgvector) → `kb_search` tool. Channel KB toggle.
|
||
Team/personal KB scopes. Notes semantic search. Admin panel KB management.
|
||
See [DESIGN-0.14.0.md](DESIGN-0.14.0.md).
|
||
|
||
### ✅ v0.15.0 — Compaction
|
||
Background scanner with configurable thresholds. Automatic summarization via
|
||
utility role. Per-channel opt-in/out. Context budget guard rail (80% ceiling).
|
||
|
||
### ✅ v0.15.1 — Context Recall Tools
|
||
`attachment_recall` (list + read, channel-scoped), `conversation_search`
|
||
(full-text via `plainto_tsquery`). Token estimator attachment awareness.
|
||
|
||
### ✅ v0.16.0 — User Groups + Resource Grants
|
||
Groups (global/team-scoped ACLs) decoupled from team membership. Three-way
|
||
resource grants (team_only/global/groups) for Personas and KBs. Grant picker
|
||
UI. Schema consolidation: 9 migrations → single `001_v016_schema.sql`.
|
||
|
||
---
|
||
|
||
## v0.17.0 — Persona-KB Binding + Enterprise KB Mode + QOL ✅
|
||
|
||
Personas become **gateways** to knowledge. In enterprise deployments,
|
||
users don't interact with KBs directly — they talk to Personas that
|
||
have KBs attached. Plus quality-of-life improvements: chat rename,
|
||
token display, state persistence, utility model auto-naming.
|
||
|
||
Depends on: knowledge bases (v0.14.0), user groups (v0.16.0).
|
||
|
||
**Persona-KB Binding**
|
||
- [x] `persona_knowledge_bases` table: `persona_id`, `kb_id`, `auto_search` (bool — always search vs tool-only)
|
||
- [x] When a channel uses a Persona with bound KBs, `kb_search` is auto-scoped to those KBs
|
||
- [x] No user toggle needed — Persona carries its own KB context
|
||
- [x] Channel KB toggle becomes "additional KBs" on top of Persona-provided ones
|
||
- [x] Persona system prompt auto-includes KB listing hint (reuses `BuildKBHint` pattern)
|
||
- [x] Admin/team admin UI: KB picker on Persona create/edit form
|
||
|
||
**Enterprise KB Mode**
|
||
- [x] `discoverable` flag on knowledge_bases: `true` (default — appears in user's KB popup) or `false` (hidden, only accessible through Persona binding)
|
||
- [x] Hidden KBs don't appear in `GET /api/v1/knowledge-bases-discoverable` for non-admins
|
||
- [x] Hidden KBs still searchable by `kb_search` tool when accessed through a Persona
|
||
- [x] Admin panel: toggle discoverability per KB
|
||
- [x] Platform policy: `kb_direct_access` — when `false`, disables channel KB popup entirely (strict enterprise mode)
|
||
|
||
**Access Control Integration**
|
||
- [x] Persona grants (v0.16.0 groups) control who can *use* a Persona
|
||
- [x] KB grants control who can *manage* a KB (upload/delete docs)
|
||
- [x] Persona-KB binding grants implicit *search* access through the Persona
|
||
- [x] Users who can use a Persona can search its KBs, even if they can't see those KBs directly
|
||
|
||
**Team Admin Workflow**
|
||
- [x] Team admin creates KB → uploads documents → marks non-discoverable
|
||
- [x] Team admin creates Persona → binds KBs → sets access to Team Only or specific Groups
|
||
- [x] Team members see the Persona in their preset list, use it, get KB-powered answers
|
||
- [x] Team members never see or manage the underlying KBs
|
||
|
||
**Technical Debt (carried forward)**
|
||
- [x] **Security**: KB create handler authorization — team/global scope verified
|
||
- [x] **Test hygiene**: stripped DIAG diagnostics from `TestGroupBasedPersonaAccess`
|
||
- [x] **Architecture**: `KnowledgeBaseStore.UpdateDocumentStorageKey()` — moved to store layer
|
||
- [x] **UX**: Embedding dropdown fix — tolerant type filter, manual model ID fallback, auto-switch on empty _(already implemented in `ui-primitives.js`)_
|
||
- [x] **Minor**: Paste-to-file character threshold — synced from backend `PublicSettings` (`storage.paste_to_file_chars`), admin-configurable, default 2000
|
||
|
||
**Role Fallback Alerts** ([#69](https://git.gobha.me/xcaliber/chat-switchboard/issues/69))
|
||
- [x] Audit log entry on fallback fire: `action = "role.fallback"` with primary/fallback model IDs and error string
|
||
- [x] `role.fallback` WebSocket event via EventBus (`PublishAsync`, zero latency impact on completion path)
|
||
- [x] In-memory cooldown on `Resolver` (per-role, 5-minute TTL) to deduplicate repeated fallback alerts
|
||
- [x] Admin UI: persistent alert banner on `role.fallback` event (persists until dismissed)
|
||
- [x] Wire `*events.Bus` into `roles.NewResolver` via `.WithBus()` builder
|
||
|
||
**QOL / UX Wins**
|
||
- [x] **Chat rename**: inline edit on sidebar item — dblclick title → input → blur/Enter saves via `API.updateChannel(id, { title })`
|
||
- [x] **Chat token count**: display `Tokens.estimateConversation()` in model bar, update on `selectChat` and after each message
|
||
- [x] **State restore on refresh**: persist `App.currentChatId` to `sessionStorage` on select, restore on load
|
||
- [x] **Utility model auto-naming**: after first assistant response, background utility role request → `POST /channels/:id/generate-title` → re-render sidebar. Fallback to truncation when no utility model configured. Debounced via `_autoNamePending` set
|
||
- [x] **SW extension cache fix**: exclude `/extensions/` from service worker fetch handler
|
||
- [x] **Mermaid renderer**: promoted enhanced version (v2.0 — pan/zoom, SVG/PNG export, source copy) to `extensions/builtin/mermaid-renderer/`
|
||
|
||
---
|
||
|
||
## v0.17.1 — SQLite Backend ✅
|
||
|
||
Dual-database support. Every subsequent schema change is developed
|
||
against both Postgres and SQLite from day one — no retrofit. SQLite
|
||
enables single-binary deployment for dev, demo, edge, and single-user.
|
||
|
||
Depends on: v0.17.0 DB debt cleanup (store layer is sole DB interface).
|
||
|
||
**Store Layer**
|
||
- [x] 19 SQLite store implementations covering all domain interfaces
|
||
- [x] `DB_DRIVER` env var: `postgres` (default) | `sqlite`
|
||
- [x] Separate migration files per driver (`migrations/sqlite/`)
|
||
- [x] WAL mode + single-writer connection pooling for SQLite concurrency
|
||
- [x] CI matrix: full handler integration tests against both Postgres and SQLite
|
||
|
||
**Vector Search**
|
||
- [x] App-level cosine similarity in Go (pure Go, no CGO/sqlite-vec required)
|
||
- [x] Embeddings stored as JSON text in `kb_chunks.embedding` column
|
||
- [x] Full feature parity with pgvector: `SimilaritySearch`, `InsertChunks`
|
||
- [x] Graceful: adequate performance for SQLite-scale deployments (single-user, not millions of chunks)
|
||
|
||
**Schema Compatibility**
|
||
- [x] UUID generation: application-side `store.NewID()` (Go `uuid.New()`)
|
||
- [x] JSONB → JSON text columns with `ToJSON()`/`ScanJSON()` helpers
|
||
- [x] `UUID[]` arrays → JSON arrays with `ToJSONArray()`/`ScanJSONArray()`
|
||
- [x] `TIMESTAMPTZ` → SQLite `TEXT` with `datetime('now')`
|
||
- [x] `ON CONFLICT excluded.*` pattern (works in both dialects)
|
||
- [x] `INSERT RETURNING id` → separate query pattern for SQLite
|
||
|
||
**Test Infrastructure**
|
||
- [x] `dialectSQL()` converts `$N` → `?` and strips `::jsonb` at runtime
|
||
- [x] `database.PH(n)` returns dialect-appropriate placeholder
|
||
- [x] `database.TruncateAll()` dialect-aware (DELETE + PRAGMA vs TRUNCATE CASCADE)
|
||
- [x] Generic provider config: `PROVIDER`/`PROVIDER_KEY`/`PROVIDER_URL` (replaces `VENICE_API_KEY`)
|
||
- [x] Model selection prefers non-reasoning models in live tests
|
||
|
||
**What SQLite mode skips** (feature-gated, not broken):
|
||
- [x] `LISTEN/NOTIFY` — WebSocket event fan-out uses in-process EventBus (already works)
|
||
- [x] Full-text search `tsvector` — conversation_search uses LIKE fallback
|
||
|
||
---
|
||
|
||
## v0.17.2 — CodeMirror 6 Integration ✅
|
||
|
||
Rich editor infrastructure for the frontend. CM6 is ESM-native; the build
|
||
step runs in Docker (esbuild → single IIFE bundle). No change to dev
|
||
experience for non-editor code — the rest of `src/js/` stays vanilla.
|
||
|
||
Depends on: nothing (frontend-only). Prerequisite for: extension surfaces
|
||
(v0.21.5 editor surface). See [DESIGN-CM6.md](DESIGN-CM6.md) for full spec.
|
||
|
||
**Build Pipeline**
|
||
- [x] `src/editor/` directory: `package.json`, `build.mjs`, `index.mjs`, language/theme modules
|
||
- [x] `scripts/build-editor.sh`: shared build script for both Dockerfiles and local dev
|
||
- [x] New Docker stage (`cm6-build`): `npm ci` + `node build.mjs` → `vendor/codemirror/`
|
||
- [x] Both `Dockerfile.frontend` and `Dockerfile` (unified) use the shared build script
|
||
- [x] Bundle output: `codemirror.bundle.js` (~295KB min, ~90KB gzip)
|
||
- [x] Graceful degradation: all integration points check `window.CM` — falls back to `<textarea>` if bundle unavailable
|
||
|
||
**Languages (bundled)**
|
||
- [x] Markdown, JavaScript, JSON, SQL, HTML, CSS, YAML, Go, Python, Rust
|
||
- [x] Additional modes: one-line import + rebuild
|
||
|
||
**Phase 1: Extension Editor** (admin panel)
|
||
- [x] `CM.codeEditor()` factory: line numbers, bracket matching, auto-indent, search/replace
|
||
- [x] Replace manifest `<textarea>` → CM6 JSON mode
|
||
- [x] Replace script `<textarea>` → CM6 JavaScript mode
|
||
- [x] Remove manual Tab-key handler in `admin-handlers.js` (CM6 handles it)
|
||
- [x] Update `saveAdminExtension()` to use `.getValue()`
|
||
|
||
**Phase 2: Chat Input** (markdown mode)
|
||
- [x] `CM.chatInput()` factory: markdown highlighting, minimal chrome (no line numbers, no gutter)
|
||
- [x] Enter=send, Shift+Enter=newline keybindings
|
||
- [x] Auto-growing height, placeholder text
|
||
- [x] Wire `onChange` → `updateInputTokens()`
|
||
- [x] Update `chat.js`, `attachments.js`, `tokens.js` to use CM API
|
||
- [x] WYSIWYG fenced code block decorations (visual container matching claude.ai UX)
|
||
- [x] Inline code shortcut (Ctrl/Cmd+E)
|
||
|
||
**Phase 3: Polish**
|
||
- [x] Theme integration: CSS variable overrides (`--bg`, `--border`, `--accent`, etc.)
|
||
- [x] Dark/light/system mode toggle in appearance settings
|
||
- [x] Vim/Emacs keybinding preference in appearance settings (`@replit/codemirror-vim`, `@replit/codemirror-emacs`)
|
||
- [x] Vim/Emacs applies to code editor + extension editor only (never chat input)
|
||
- [x] SW cache: exclude `vendor/codemirror/` with version bust
|
||
- [x] Update `debug.js` snapshot to include CM6 version
|
||
- [x] Documentation in ARCHITECTURE.md
|
||
|
||
**CI/CD**
|
||
- [x] Path-based change detection gating (FE-only → skip BE tests, docs-only → skip all)
|
||
|
||
---
|
||
|
||
## v0.17.3 — Notes Graph + Wikilinks ✅
|
||
|
||
Knowledge graph and bi-directional linking for the notes system. Transforms
|
||
notes from flat documents into an interconnected knowledge base with
|
||
Obsidian-style `[[wikilinks]]`, backlinks, graph visualization, and
|
||
transclusion.
|
||
|
||
Depends on: CodeMirror 6 (v0.17.2), Notes CRUD (v0.13.x). See
|
||
[DESIGN-0.17.3.md](DESIGN-0.17.3.md) for full spec.
|
||
|
||
**Backend: Note Links**
|
||
- [x] `note_links` table (Postgres + SQLite migrations)
|
||
- [x] `NoteLinkStore` interface + both implementations
|
||
- [x] `ExtractWikilinks()` regex parser + tests
|
||
- [x] Link extraction on note create/update
|
||
- [x] Dangling link resolution on note create
|
||
- [x] `notes.source_message_id` column for chat-to-note provenance
|
||
|
||
**API Endpoints**
|
||
- [x] `GET /notes/:id/backlinks` — notes linking to this note
|
||
- [x] `GET /notes/search-titles?q=` — lightweight fuzzy search for autocomplete
|
||
- [x] `GET /notes/graph` — full graph topology (nodes + edges + unresolved)
|
||
|
||
**CM6 Note Editor**
|
||
- [x] `note-editor.mjs` factory: markdown live preview (heading sizes, blockquotes, code blocks)
|
||
- [x] `wikilink.mjs` CM6 extension: parse, decorate as clickable chips, autocomplete on `[[`
|
||
- [x] Textarea → CM6 swap in `notes.js` with graceful fallback
|
||
- [x] `noteEditorTheme` in `theme.mjs`
|
||
|
||
**Graph Visualization**
|
||
- [x] Canvas-based force-directed graph (~200 lines, no d3 dependency)
|
||
- [x] O(n²) Coulomb repulsion + Hooke spring + center gravity
|
||
- [x] Pan, zoom (0.15–4.0x), drag nodes, hover highlight, click to open
|
||
- [x] Node sizing by link_count, folder-based coloring
|
||
- [x] Ghost nodes for unresolved `[[links]]` with toggle
|
||
- [x] Energy-based pause (stop rAF below KE threshold)
|
||
- [x] ResizeObserver for responsive canvas
|
||
|
||
**Note-from-Selection + Daily Notes**
|
||
- [x] "Note" button in message action bar
|
||
- [x] Selection-aware capture (`window.getSelection()` within message)
|
||
- [x] Provenance tracking (`source_channel_id` + `source_message_id`)
|
||
- [x] "Today" button → find-or-create daily note in `/daily/`
|
||
|
||
**Read Mode**
|
||
- [x] `[[link]]` rendered as clickable wikilink chips
|
||
- [x] `![[embed]]` transclusion with async content fetch, recursion guard
|
||
- [x] Backlinks panel (collapsible, with count badge)
|
||
|
||
---
|
||
|
||
## v0.18.0 — Memory (User + Persona Scopes) ✅
|
||
|
||
Long-term memory across conversations, with scope-aware isolation.
|
||
Unlike KB (static documents) or compaction (within-conversation), this
|
||
captures facts and preferences that persist across channels.
|
||
|
||
**Key differentiator: Persona-scoped memory.** Each Persona can build
|
||
its own memory independently of user memory, preventing cross-context
|
||
contamination and enabling specialized knowledge accumulation.
|
||
|
||
Depends on: compaction (v0.15.0), knowledge bases (v0.14.0), persona-KB binding (v0.17.0), SQLite backend (v0.17.1).
|
||
|
||
See [DESIGN-0.18.0.md](DESIGN-0.18.0.md) for full spec.
|
||
|
||
**Memory Scopes**
|
||
- [x] `user` — personal facts/preferences, persists across all conversations (current industry standard)
|
||
- [x] `persona` — shared across all users of that Persona, accumulated from conversations (differentiator)
|
||
- [x] `persona+user` — per-user within a Persona context (e.g. tutoring progress per student)
|
||
- [x] Configurable per Persona: which scopes are active, whether user memory is passed through
|
||
|
||
**Data Model**
|
||
- [x] `memories` table: `id`, `scope` (user, persona, persona_user), `owner_id` (user_id or persona_id), `user_id` (nullable — for persona+user scope), `key`, `value`, `source_channel_id`, `confidence` (float), `status` (active, pending_review, archived), `created_at`, `updated_at`
|
||
- [x] Index on `(scope, owner_id, user_id)` for fast lookup
|
||
- [x] Embedding column (`vector(3072)`) for semantic memory search
|
||
|
||
**Tools**
|
||
- [x] `memory_save` tool: LLM explicitly stores a fact
|
||
- Scope-aware: saves to the active memory scope for the current Persona context
|
||
- Structured: `key` (short label) + `value` (detail) + `confidence`
|
||
- [x] `memory_recall` tool: LLM queries stored facts relevant to current context
|
||
- Merges results from applicable scopes (user + persona + persona+user)
|
||
- Semantic search via embeddings + keyword fallback
|
||
|
||
**Automatic Extraction**
|
||
- [x] Background job: post-conversation analysis identifies memorable facts (opt-in)
|
||
- [x] Configurable extraction prompt per Persona (e.g. "extract FAQ-worthy Q&A pairs")
|
||
- [x] Extracted memories start in `pending_review` status
|
||
|
||
**Review Pipeline**
|
||
- [x] Admin/team admin review queue: pending memories with approve/reject/edit
|
||
- [x] Persona memory review: team admins see what Personas are "learning"
|
||
- [x] User memory review: users see their own memories in Settings
|
||
|
||
**Memory Injection**
|
||
- [x] At completion time: inject relevant memories into system prompt
|
||
- [x] Context budget aware: limit injected memory tokens
|
||
- [x] Scope priority: persona+user > persona > user (most specific wins on conflicts)
|
||
|
||
**Use Cases**
|
||
- [x] Helpdesk Persona: builds FAQ from repeated questions, human-reviewable
|
||
- [x] Roleplay Persona: isolated memory prevents tone/context bleeding from user's other conversations
|
||
- [x] Tutoring Persona: tracks per-student progress, common misconceptions
|
||
- [x] Sales Persona: accumulates objection responses from real conversations
|
||
- [x] Onboarding Persona: learns what new hires commonly struggle with
|
||
|
||
**User Controls**
|
||
- [x] Settings → Memory: view, edit, delete personal memories
|
||
- [x] Per-Persona memory toggle: "Allow this persona to remember things about me"
|
||
- [x] Admin: enable/disable, retention policies, per-team scoping
|
||
- [x] Privacy: user memories never cross team boundaries; persona memories respect group access
|
||
|
||
---
|
||
|
||
## v0.18.1 — Side Panel Architecture ✅
|
||
|
||
Refactored the side panel from a shared-tab layout to independent
|
||
single-slot panels. Any action fills the slot, replacing whatever was
|
||
there — no tabs, no association between panel types. Extension UI
|
||
primitives give browser extensions safe access to host app features.
|
||
|
||
Depends on: Notes graph + wikilinks (v0.17.3). Prerequisite for: live
|
||
collaboration (v0.23.0) where multiple panels need simultaneous visibility.
|
||
|
||
**Panel System**
|
||
- [x] Panel registry: named panels with independent open/close state
|
||
- [x] Single-slot model: action-driven, each open replaces the previous
|
||
- [x] Dual-view mode: two panels side-by-side (configurable split ratio via drag divider)
|
||
- [x] Panel-persistent state: each panel remembers scroll position, open note, etc.
|
||
- [x] Header label shows active panel name (replaces tab bar)
|
||
- [x] Keyboard shortcut: Ctrl/Cmd+\ cycles panels, Ctrl/Cmd+Shift+\ toggles dual
|
||
|
||
**Preview Panel**
|
||
- [x] Dedicated preview panel (independent of Notes)
|
||
- [x] HTML/document preview with iframe sandbox
|
||
- [x] Code output preview (extension-rendered blocks via pop-out)
|
||
- [x] Live-updating during streaming responses (500ms debounce)
|
||
|
||
**Extension UI Primitives**
|
||
- [x] `ctx.ui.toast()` — toast notifications
|
||
- [x] `ctx.ui.openPreview()` — load HTML into side panel preview
|
||
- [x] `ctx.ui.isDark()` — theme detection
|
||
- [x] `ctx.ui.isMobile()` — viewport width check
|
||
- [x] `ctx.ui.isPanelOpen()` — side panel visibility
|
||
- [x] `ctx.ui.confirm()` — modal confirm dialog
|
||
- [x] Mermaid extension refactored to use primitives exclusively (zero direct globals)
|
||
- [x] Context-aware expand: single button, fullscreen or side panel pop-out
|
||
|
||
**Mobile**
|
||
- [x] Swipe navigation between panels
|
||
- [x] Tap-to-close overlay
|
||
- [x] Graceful collapse to single-panel on narrow viewports
|
||
- [x] Enlarged touch targets, fullscreen close button (40px desktop, 48px mobile)
|
||
|
||
---
|
||
|
||
## ✅ v0.19.0 — Projects / Workspaces
|
||
|
||
Organizational containers that group related conversations, KBs, and
|
||
notes into a single workspace with shared access controls.
|
||
|
||
Depends on: user groups (v0.16.0), knowledge bases (v0.14.0).
|
||
|
||
**Data Model**
|
||
- [x] `projects` table: `id`, `name`, `description`, `color`, `icon`, `scope` (personal/team/global), `owner_id`, `team_id`, `is_archived`, `settings` (JSONB)
|
||
- [x] `project_channels` junction: ordered membership with UNIQUE `channel_id`, denormalized FK on `channels.project_id`
|
||
- [x] `project_knowledge_bases` junction: with `auto_search` flag
|
||
- [x] `project_notes` junction
|
||
- [x] `resource_grants` CHECK extended to include `'project'`
|
||
|
||
**Features**
|
||
- [x] Channels can belong to a project (optional `project_id` FK)
|
||
- [x] KBs can belong to a project → auto-linked to all channels in the project (BuildKBHint + kbsearch)
|
||
- [x] Notes can belong to a project → auto-associated when created from project channel
|
||
- [x] KB resolution chain: Persona → Project → Channel → Personal
|
||
- [x] Project sidebar section: collapsible groups above time-based Recent section
|
||
|
||
**UI**
|
||
- [x] Sidebar: projects as collapsible groups with color dots, counts, options menu
|
||
- [x] Right-click context menu: move chat to project / remove / create-and-assign
|
||
- [x] Drag-and-drop channels between project groups and Recent
|
||
- [x] New Project button in split dropdown
|
||
- [x] Channel list `project_id` filter (`?project_id=uuid` or `?project_id=none`)
|
||
- [x] Collapse state persisted in localStorage
|
||
|
||
**Deferred to later versions:**
|
||
- Project creation dialog (name, description, default Persona, default KBs) — using prompt() for now
|
||
- ~~Project detail panel (KB + note management within a project)~~ → v0.19.1
|
||
- ~~Project-level Persona default~~ → v0.19.2
|
||
- Folders within projects
|
||
- Project templates
|
||
- Admin-level team/global project management
|
||
- Project-specific files (full project-level upload — deferred for proper architecture)
|
||
- Notifications (moved to v0.20.0)
|
||
|
||
---
|
||
|
||
## ✅ v0.19.1 — Active Project + Project System Prompt + Detail Panel
|
||
|
||
Quality-of-life improvements making projects usable for daily workflow.
|
||
No migrations.
|
||
|
||
Depends on: v0.19.0 Projects/Workspaces.
|
||
|
||
**Active Project**
|
||
- [x] Pin a project as active — new chats auto-assign via `addChannelToProject` after channel creation
|
||
- [x] `App.activeProjectId` persisted in `localStorage('cs-active-project')`
|
||
- [x] Visual indicator: `.project-group.active` accent border + 📌 icon
|
||
- [x] Toggle from project ⋯ menu ("Pin as active" / "Unpin project")
|
||
- [x] Cleared on project delete
|
||
|
||
**Project System Prompt**
|
||
- [x] Per-project instructions in `projects.settings` JSONB (`system_prompt` key)
|
||
- [x] Injected in `loadConversation` between persona/channel prompt and KB hint
|
||
- [x] Merge semantics on update: reads existing JSONB, overlays patch keys, writes back
|
||
- [x] Both Postgres and SQLite stores updated
|
||
|
||
**Project Detail Panel**
|
||
- [x] Registered with `PanelRegistry` (same pattern as Notes, Preview)
|
||
- [x] System prompt textarea with Save button
|
||
- [x] KB management: list with names (LEFT JOIN), [+ Add] picker dropdown, [✕] remove
|
||
- [x] Notes list with titles (LEFT JOIN), [✕] unbind
|
||
- [x] Accessible from project ⋯ menu → "Project settings"
|
||
|
||
**Bug Fixes**
|
||
- [x] `renderChatList` early return prevented project groups from rendering when zero chats
|
||
- [x] Recent section drop target: "Drop chats here to unassign" hint with `min-height: 40px`
|
||
|
||
---
|
||
|
||
## ✅ v0.19.2 — Project Persona Default + Archive + Channel Reorder
|
||
|
||
Completes the project management feature set. No migrations.
|
||
|
||
Depends on: v0.19.1.
|
||
|
||
**Project Persona Default**
|
||
- [x] Bind a persona to a project via detail panel dropdown
|
||
- [x] Stored in `projects.settings.persona_id`
|
||
- [x] Resolution chain: explicit `req.PresetID` → project persona → none
|
||
- [x] Inherits model, provider config, temperature, max tokens, system prompt as defaults
|
||
|
||
**Project Archive Toggle**
|
||
- [x] Checkbox in project detail panel
|
||
- [x] Archived projects hidden from sidebar by default
|
||
- [x] "▸ Show archived (N)" toggle button below project list
|
||
- [x] Chats in hidden-archived projects spill into Recent section (never vanish)
|
||
- [x] Dimmed + italic visual treatment for archived groups
|
||
|
||
**Channel Reorder**
|
||
- [x] `loadProjectChannelPositions()` fetches server-persisted positions on startup
|
||
- [x] `_getReorderedProjectChats()` sorts project chats by stored position
|
||
- [x] Right-click context menu: ↑ Move up / ↓ Move down (optimistic swap + API call)
|
||
- [x] Order maintained across add/remove/move operations
|
||
|
||
---
|
||
|
||
## v0.20.0 — Notifications + @mention Routing + Multi-model ✅
|
||
|
||
Notification infrastructure that makes collaboration real-time, plus
|
||
multi-model routing for channels. Three-phase delivery: notifications
|
||
core (in-app), @mention parsing + fan-out completions, email transport
|
||
+ per-user notification preferences.
|
||
|
||
_(Notifications shifted from v0.19.0; @mention routing shifted from v0.17.0)_
|
||
|
||
Depends on: v0.19.2 (Projects complete), EventBus + WebSocket hub (v0.9.x),
|
||
`channel_models` table (v0.16.0 schema). See
|
||
[DESIGN-0.20.0.md](DESIGN-0.20.0.md) for full spec.
|
||
|
||
**Phase 1 — Notifications Core (in-app)**
|
||
- [x] `notifications` table: `id`, `user_id`, `type`, `title`, `body`, `resource_type`, `resource_id`, `is_read`, `created_at` (Postgres + SQLite migrations)
|
||
- [x] `NotificationStore` interface + both implementations: Create, ListByUser (paginated), MarkRead, MarkAllRead, Delete, UnreadCount
|
||
- [x] `notifications.Service` with `Notify()` / `NotifyMany()` — centralized creation + WebSocket dispatch
|
||
- [x] EventBus routes: `notification.new`, `notification.read` (badge sync across tabs)
|
||
- [x] API endpoints: list, unread-count, mark-read, mark-all-read, delete (5 endpoints, all user-scoped)
|
||
- [x] Initial sources: `role.fallback` (EventBus subscription), `kb.ready`/`kb.error`, `grant.changed`
|
||
- [x] Frontend: bell icon + unread badge (capped 9+), notification dropdown (latest 10, click-to-navigate), full panel via PanelRegistry
|
||
- [x] WebSocket handler: real-time push + toast for high-priority types
|
||
- [x] Background cleanup goroutine (configurable retention, default 90 days)
|
||
|
||
**Phase 2 — @mention Parsing + Multi-model Routing**
|
||
- [x] `mentions.Parse()`: extract @mentions, resolve against channel model roster (case-insensitive, longest-match-first, trailing punctuation tolerant)
|
||
- [x] Parser tests: no mentions, unresolved, multiple, overlapping names, punctuation edge cases
|
||
- [x] Channel model CRUD handlers (4 endpoints: list, add, remove, update)
|
||
- [x] Completion handler: mention extraction → target resolution → sequential fan-out → N assistant messages
|
||
- [x] SSE streaming: model attribution in delta events (`model_display` field)
|
||
- [x] Frontend: model pills in chat header with add/remove UI
|
||
- [x] Frontend: @mention autocomplete via CM6 `mentionCompletion` extension (roster-backed)
|
||
- [x] Frontend: model attribution labels on multi-model assistant messages
|
||
- [x] Backward compat: channels with no extra `channel_models` rows work exactly as before
|
||
|
||
**Phase 3 — Email Transport + Notification Preferences**
|
||
- [x] `notification_preferences` table (Postgres + SQLite): per-user, per-type in_app/email toggles
|
||
- [x] Preference resolution chain: specific type → user wildcard `*` → system default (in_app=true, email=false)
|
||
- [x] `EmailTransport`: SMTP with implicit TLS (port 465) and STARTTLS (port 587), multipart MIME (HTML + plaintext)
|
||
- [x] Email templates: branded HTML + plaintext, domain-prefixed subjects, Go `html/template`
|
||
- [x] Preference CRUD endpoints (3: list, set with partial patch, delete)
|
||
- [x] Admin SMTP configuration: enable toggle, host/port/user/password/from/TLS fields, test email button
|
||
- [x] User notification preferences UI (Settings → Notifications tab, per-type checkboxes)
|
||
- [x] Notification service: preference check before dispatch, async email delivery (goroutine, 30s timeout)
|
||
- [x] Tests: preference resolution chain (7 tests), email templates (4 tests)
|
||
- [x] Deferred: digest mode (batched email), SMTP password vault encryption
|
||
|
||
**Hotfix (carried forward from v0.19.2 investigation)**
|
||
- [x] `user_model_settings` NULL scan fix: COALESCE on `hidden`/`sort_order` in SELECT + INSERT for both dialects
|
||
- [x] Gin release mode: auto-set `gin.ReleaseMode` when `ENVIRONMENT=production`, suppress health check log spam
|
||
|
||
---
|
||
|
||
## v0.21.x — Workspace Platform + Extension Surfaces
|
||
|
||
Seven-release series decomposing workspace storage, tools, indexing, git,
|
||
surface infrastructure, and editor/article modes. Full specification in
|
||
[DESIGN-0.21.0.md](DESIGN-0.21.0.md).
|
||
|
||
Depends on: file storage (v0.12.0), extension foundation (v0.11.0),
|
||
CodeMirror 6 (v0.17.2), knowledge base embedding pipeline (v0.14.0).
|
||
|
||
### v0.21.0 — Workspace Storage Primitive ✅
|
||
|
||
Pure backend foundation. Workspaces as a polymorphic platform primitive
|
||
owned by users, projects, channels, or teams. Dual-layer storage: PVC
|
||
filesystem (source of truth) + DB metadata index (queryable cache).
|
||
|
||
- [x] `workspaces` table: polymorphic owner (user/project/channel/team), root_path, max_bytes quota, status
|
||
- [x] `workspace_files` table: metadata index (path, MIME type, size, sha256, is_directory)
|
||
- [x] `WorkspaceStore` interface: CRUD, file index (upsert/delete/list/prefix), ownership lookup, stats
|
||
- [x] Postgres + SQLite store implementations with upsert-on-conflict for file index
|
||
- [x] `workspace.FS` package: read, write (atomic via temp+rename), delete, mkdir, stat, list, reconcile (FS→DB sync)
|
||
- [x] `workspace.Archive`: zip/tar.gz extract + create with archive bomb protection (10K file limit, 100MB single file, quota enforcement), common-prefix stripping
|
||
- [x] Content type detection: extension-based (40+ source code types) with http.DetectContentType fallback
|
||
- [x] SHA256 computed during write via tee reader (enables content-addressed skip in v0.21.2)
|
||
- [x] Path traversal guards: cleanPath + absPath validation, symlink rejection
|
||
- [x] 15 API endpoints: workspace CRUD, file CRUD, archive upload/download, reconcile, stats
|
||
- [x] Owner-based authorization: user=self, channel=owner, project=member, team=member
|
||
- [x] Unit tests: path cleaning, traversal detection, MIME detection, unsafe path filtering, write/read round-trip, delete, mkdir
|
||
|
||
### v0.21.1 — Workspace Tools + Channel/Project Binding ✅
|
||
|
||
Make workspaces useful in chat mode via tool calls.
|
||
|
||
- [x] Workspace tools (category: workspace): `workspace_ls`, `workspace_read` (50KB soft limit), `workspace_write` (auto-mkdir), `workspace_rm` (recursive guard), `workspace_mv`, `workspace_patch` (find/replace)
|
||
- [x] `channels.workspace_id` FK, `projects.workspace_id` FK
|
||
- [x] Workspace resolution: channel workspace → project workspace (override pattern)
|
||
- [x] Tool injection in completion handler when workspace bound
|
||
- [x] Frontend: deferred (channel settings workspace toggle, project Files tab, chat bar workspace indicator)
|
||
|
||
### v0.21.2 — Workspace Indexing + Semantic Search ✅
|
||
|
||
Embed text files for semantic search. Reuses `knowledge.SplitText` + `knowledge.Embedder`.
|
||
|
||
- [x] `workspace_chunks` table (Postgres + SQLite migrations)
|
||
- [x] `workspace_files` additions: `index_status`, `chunk_count` columns
|
||
- [x] `workspaces.indexing_enabled` boolean (default true)
|
||
- [x] Store methods: `InsertChunks`, `DeleteChunksByFile`, `SimilaritySearch`, `UpdateFileIndexStatus`
|
||
- [x] Indexable types: text MIME types + 40+ code extensions + special filenames (Makefile, Dockerfile, etc.)
|
||
- [x] Code-aware chunking: 1500-char chunks with function/class/type/sub boundary separators
|
||
- [x] Content-addressed skip: sha256 comparison before re-chunking/re-embedding
|
||
- [x] `workspace.Indexer`: background goroutine with configurable concurrency semaphore
|
||
- [x] Single-file indexing via `FS.WriteFile` hook (`SetIndexer`)
|
||
- [x] Batch indexing via `ExtractArchive` (sequential within one semaphore slot)
|
||
- [x] `workspace_search` tool: semantic search with optional glob filtering, top-K capped at 20
|
||
- [x] `GET /api/v1/workspaces/:id/index-status` endpoint (per-status file counts, total chunks)
|
||
- [x] Configuration: `WORKSPACE_INDEXING_ENABLED`, `WORKSPACE_INDEX_CONCURRENCY` env vars
|
||
- [x] Graceful degradation when no embedding role configured
|
||
- [x] Mock store updated for FS unit tests
|
||
|
||
### v0.21.3 — Surface Infrastructure + REPL ✅
|
||
|
||
Pure UI architecture. No workspace dependency (parallel development).
|
||
|
||
- [x] `data-surface-region` attributes on index.html containers (surface-header, surface-main, surface-footer, sidebar-content)
|
||
- [x] `surfaces.js` — SurfaceRegistry: register, activate, deactivate, getCurrent, list
|
||
- [x] `ctx.ui.replace()` / `ctx.ui.restore()` with DOM preservation (DocumentFragment-based)
|
||
- [x] `ctx.surfaces.register()` API for extensions
|
||
- [x] Mode selector component in sidebar (`#modeSelectorWrap`, auto-shown when ≥2 surfaces)
|
||
- [x] Chat as default surface (implicit, always registered)
|
||
- [x] `surface.activated` / `surface.deactivated` / `surface.registered` / `surface.unregistered` EventBus events
|
||
- [x] REPL tab: AsyncFunction wrapper, global injection (API, Events, Extensions, Surfaces, DebugLog, Panels, UI, $, $$, sleep)
|
||
- [x] REPL tab: pretty-print results (collapsible JSON, type-colored primitives, DOM element summaries)
|
||
- [x] REPL tab: command history (sessionStorage, ↑/↓ navigation)
|
||
- [x] REPL tab: tab-completion on object graphs, event labels, globals
|
||
- [x] REPL tab: event label hints (Events.on/emit completion)
|
||
- [x] REPL tab: admin gate (admin role OR ?debug=1 URL param)
|
||
- [x] REPL tab: toolbar (clear, copy, help)
|
||
- [x] CSS: mode selector + REPL styles
|
||
- [x] Documentation in EXTENSIONS.md §6 updated with implementation details
|
||
- [ ] Mobile: mode selector collapses to hamburger/bottom nav — moved to v0.22+
|
||
- [ ] Integration with extension loader (surfaces from manifest — moved to v0.22+)
|
||
|
||
### v0.21.4 — Git Integration ✅
|
||
|
||
Layer git operations onto workspaces.
|
||
|
||
- [x] `workspaces` additions: git_remote_url, git_branch, git_credential_id, git_last_sync
|
||
- [x] `git_credentials` table: auth_type (https_pat/https_basic/ssh_key), encrypted_data (AES-256-GCM)
|
||
- [x] Postgres migration (012_v0214_git.sql) + SQLite migration (011_v0214_git.sql)
|
||
- [x] `models.GitCredential`, `GitCredentialSummary`, `GitStatus`, `GitFileStatus`, `GitLogEntry`
|
||
- [x] `GitCredentialStore` interface + Postgres/SQLite implementations (Create, GetByID, ListByUser, Delete)
|
||
- [x] `workspace.GitOps` with exec-based git operations (9 operations)
|
||
- [x] Credential injection: temp `GIT_ASKPASS` (PAT), `.git-credentials` (basic), `GIT_SSH_COMMAND` (SSH)
|
||
- [x] Security: reject file:// URLs, sanitize error output, GIT_TERMINAL_PROMPT=0
|
||
- [x] Clone, Pull, Push, Status, Diff, Commit, Log, BranchList, Checkout
|
||
- [x] `SetGitLastSync` on WorkspaceStore interface + both implementations
|
||
- [x] Post-operation reconcile + re-index hook (clone, pull, checkout)
|
||
- [x] 5 git tools: git_status, git_diff, git_commit, git_log, git_branch
|
||
- [x] Git tools filtered out when no workspace bound (completion handler)
|
||
- [x] 9 git API endpoints on /api/v1/workspaces/:id/git/*
|
||
- [x] 3 credential CRUD endpoints on /api/v1/git-credentials
|
||
- [x] Wired in main.go: GitOps creation, tool registration, route registration
|
||
- [ ] Workspace settings UI: git config section — moved to v0.22+
|
||
- [ ] User Settings: git credentials management UI — moved to v0.22+
|
||
- [ ] Integration tests: clone, commit, push/pull cycle (requires git binary in CI)
|
||
- [ ] `.gitignore` respect in workspace indexing — moved to v0.22+
|
||
|
||
### v0.21.5 — Editor Surface (Development Mode) ✅
|
||
|
||
IDE-like experience. Browser-tier surface consuming workspace primitives.
|
||
|
||
- [x] Layout: file tree (sidebar), code editor (CM6, main), AI chat panel (resizable split), status bar
|
||
- [x] File tree: workspace_ls backed, context menu (open, delete), nested directory expansion, file icons
|
||
- [x] Code editor: CM6 codeEditor() factory with textarea fallback, language auto-detection (20+ languages), tab bar, Ctrl+S save
|
||
- [x] AI chat panel: same channel context via Surfaces DOM borrowing, live update via workspace.file.changed event
|
||
- [x] Keyboard shortcuts: Ctrl+P quick open, Ctrl+S save, Ctrl+W close tab
|
||
- [x] Split pane layout with draggable resize handle
|
||
- [x] Status bar: file path, language mode, git branch
|
||
- [x] Workspace API methods on frontend (8 methods)
|
||
- [x] Surfaces.getSavedFragment/putSavedFragment for cross-surface DOM sharing
|
||
- [x] workspace.file.changed event emission from stream_loop.go after tool calls
|
||
- [x] Event route table: workspace.file. → DirToClient
|
||
- [x] editor-mode.css: dark theme, mobile responsive (stacked at ≤768px)
|
||
- [x] Auto-registration: surface registers when channel/project has workspace binding
|
||
- [x] Workspace management UI: create, list, bind from project settings + chat context menu
|
||
- [x] GET /workspaces list endpoint, workspace_id in channel API (update, get, list)
|
||
- [x] Git status indicators in file tree (M/A/U badges + colors) — closed in v0.21.6
|
||
- [ ] Drag-drop file reorder — moved to v0.22+
|
||
- [x] Ctrl+Shift+F workspace search (maps to quick open) — closed in v0.21.6
|
||
- [x] Auto-save on tab/mode switch — closed in v0.21.6
|
||
|
||
### v0.21.6 — Article Surface + Document Output Pipeline ✅
|
||
|
||
Writing-focused surface. Document is artifact, conversation is secondary.
|
||
|
||
- [x] Layout: outline (sidebar top), AI assistant (sidebar bottom), rich text editor (CM6 markdown, main)
|
||
- [x] Outline: auto-generated from headings, click-to-scroll (navigates CM6 cursor)
|
||
- [x] Rich text editor: CM6 codeEditor() markdown mode, line wrapping, centered content (720px max), textarea fallback
|
||
- [x] AI assistant: chat panel embedded in sidebar via Surfaces DOM borrowing
|
||
- [x] Export dropdown: Download Markdown, Download HTML (via marked.js + DOMPurify), Copy to clipboard
|
||
- [x] Document picker: lists .md/.mdx/.txt files from workspace, create new document inline
|
||
- [x] Focus mode: dims non-active lines in editor (CM6 opacity-based, toggle button)
|
||
- [x] Word count + reading time in status bar (~230 wpm)
|
||
- [x] Auto-save: debounced (2s) on content change, save on tab switch / surface deactivate
|
||
- [x] Live update on workspace.file.changed event (reloads if file unmodified)
|
||
- [x] Surface registration: registers as "Article" with file-text icon when workspace bound
|
||
- [x] article-mode.css: outline styling, export menu, focus mode, mobile responsive
|
||
- [x] (from v0.21.5 deferred) Git status indicators in editor file tree (M/A/U badges + colors)
|
||
- [x] (from v0.21.5 deferred) Auto-save on tab/mode switch in editor surface
|
||
- [x] (from v0.21.5 deferred) Ctrl+Shift+F workspace search (maps to quick open)
|
||
- [ ] Article-specific AI tools (suggest_outline, expand_section, check_citations) — moved to v0.22+
|
||
- [ ] Drag-to-reorder outline sections — moved to v0.22+
|
||
- [ ] PDF export via pandoc — moved to v0.22+
|
||
|
||
#### Bugfixes & DX (added post-initial)
|
||
|
||
- [x] Hash Router (`router.js`): URL-driven direct-to-surface navigation (#/chat, #/editor, #/article). Bookmarkable, back/forward works. Precursor to Go `html/template` server-rendered pages (v0.25.0) for public/workflow entry points.
|
||
- [x] `openDirect(wsId)` on EditorMode + ArticleMode: bypass check(), register directly with workspace ID
|
||
- [x] Workspace picker overlay: shown when navigating to surface without workspace, auto-selects if only one
|
||
- [x] `SEED_PROVIDERS` env var: auto-creates global providers on startup (dev/test only, idempotent)
|
||
- [x] Mode selector labels: icon + text, labels hide when sidebar collapsed
|
||
- [x] `chat.switched` / `chat.created` events: wired into selectChat(), newChat(), sendMessage()
|
||
- [x] `workspace_id` in channel API responses: added to list/get/create for both SQLite and Postgres
|
||
- [x] Frontend chat + project objects: now carry `workspace_id` for Router and surface check() optimization
|
||
|
||
---
|
||
|
||
### v0.21.7 — Bugfix: scanJSON Driver Buffer Aliasing ✅
|
||
|
||
Critical fix for intermittent 500 errors on paginated list endpoints.
|
||
|
||
- [x] `scanJSON` []byte path: copy driver buffer instead of aliasing (`json.RawMessage(v)` → `make+copy`)
|
||
- [x] `CreateChannel` Postgres RETURNING path: use `scanJSON(&ch.Settings)` instead of bare `&ch.Settings`
|
||
- [x] `UpdateChannel` settings write: validate `json.Valid()` before JSONB merge, reject with 400
|
||
- [x] New tests: `TestScanJSON_ByteSliceNotAliased`, `TestScanJSON_ByteSliceIsolation_MultiRow`
|
||
|
||
**Root cause:** `json.RawMessage(v)` is a type conversion, not a copy — it aliases
|
||
the `[]byte` buffer owned by `database/sql`. Per the `Scanner` interface docs, `[]byte`
|
||
values are only valid until the next `rows.Scan()` call. In paginated list endpoints,
|
||
row N's Settings slice header pointed into memory that row N+1's scan overwrote,
|
||
producing corrupt JSON that passed `json.Valid()` at scan time but failed at marshal
|
||
time when `SafeJSON` serialized the full response.
|
||
|
||
---
|
||
|
||
## v0.22.0 — Provider Health + Capability Overrides ✅
|
||
|
||
Smallest shippable unit that unblocks routing. Track provider error rates
|
||
and latency, add admin override layer for model capabilities.
|
||
|
||
Depends on: usage tracking (v0.10.0), capabilities resolver (v0.9.1).
|
||
|
||
**Provider Health Tracking**
|
||
- [x] `provider_health` table: `provider_config_id` FK, `window_start` (hourly buckets), `request_count`, `error_count`, `timeout_count`, `total_latency_ms`, `max_latency_ms`, `last_error`, `last_error_at`
|
||
- [x] In-memory health accumulator: goroutine-safe counters per provider, flushed to DB on interval (60s)
|
||
- [x] `RecordSuccess`/`RecordError`/`RecordTimeout` called from completion handler after every provider call (sync + streaming)
|
||
- [x] Provider status derivation: `healthy` / `degraded` / `down` based on error rate thresholds (5% = degraded, 25% = down)
|
||
- [x] `GET /api/v1/admin/providers/:id/health` endpoint: current status + hourly windows (configurable hours param)
|
||
- [x] `GET /api/v1/admin/providers/health` endpoint: summary status for all providers
|
||
- [x] _(shipped v0.22.3)_ Health status included in `GET /api/v1/models/enabled` response (new `provider_status` field)
|
||
- [ ] _(deferred → v0.22.2)_ Auto-disable: optional policy to mark provider inactive when `down` for N consecutive windows
|
||
- [x] Background cleanup: prune health rows older than 7 days (6-hour cycle)
|
||
|
||
**Capability Admin Overrides**
|
||
- [x] `capability_overrides` table: `provider_config_id` (nullable for global), `model_id`, `field`, `value`, `set_by`, `created_at`
|
||
- [x] Three-tier resolution in `ResolveIntrinsic()`: catalog → heuristic → **admin override** (highest priority)
|
||
- [x] `PUT /api/v1/admin/models/:id/capabilities` endpoint: set individual capability overrides
|
||
- [x] `DELETE /api/v1/admin/models/:id/capabilities/:overrideId` endpoint: remove override
|
||
- [x] `GET /api/v1/admin/models/:id/capabilities` endpoint: show resolved caps with source annotation (catalog/heuristic/override)
|
||
- [x] `GET /api/v1/admin/capability-overrides` endpoint: list all overrides
|
||
- [x] Postgres + SQLite migrations (013_v0220_health.sql / sqlite 012_v0220_health.sql)
|
||
|
||
**Search Provider Health** _(deferred → v0.22.1)_
|
||
- [ ] `RecordOutcome` for web_search and url_fetch tool calls (search provider tracking)
|
||
- [ ] Rate limit tracking per provider config (requests/minute counter in health accumulator)
|
||
|
||
**Workspace Pane Refactor** (frontend)
|
||
- [x] `.workspace` flex container replaces `.chat-area` + `.side-panel` layout
|
||
- [x] `.workspace-primary` / `.workspace-secondary` independent pane model
|
||
- [x] `.workspace-handle` drag-resize between panes (replaces old side-panel-resize)
|
||
- [x] Surface layout declarations: `primary`, `secondary`, `secondaryOpts` per surface
|
||
- [x] Dual-view mode removed (was `_dualMode`, `_splitRatio`, `_secondary` in PanelRegistry)
|
||
- [x] Zoom selector updated for new class names
|
||
|
||
**Bugfix (v0.21.7)**
|
||
- [x] `scanJSON` driver buffer aliasing — copy `[]byte` from database driver instead of aliasing slice header
|
||
- [x] `CreateChannel` RETURNING path uses `scanJSON(&ch.Settings)` instead of bare scan
|
||
- [x] `UpdateChannel` validates `json.Valid()` on settings before JSONB merge
|
||
|
||
---
|
||
|
||
## v0.22.1 — Provider Extensions (Declarative Config) ✅
|
||
|
||
Replace hardcoded provider-specific behavior with data-driven configuration.
|
||
Same model, different provider → different parameters.
|
||
|
||
Depends on: provider health (v0.22.0).
|
||
|
||
**Provider Profiles**
|
||
- [x] Profile schema per provider type: defines available settings, types, defaults, validation, dependency rules (`providers/profile.go`)
|
||
- [x] Built-in profile schemas for: openai, anthropic, venice, openrouter (unknown types fall back to openai-compatible)
|
||
- [x] System prompt injection: `system_prompt_prefix` setting prepended to first system message (all providers)
|
||
- [x] Thinking mode toggle: Anthropic `extended_thinking` + `thinking_budget` → injects `thinking.type=enabled`; Venice `enable_thinking` → disables Venice system prompt
|
||
- [ ] _(not needed)_ `provider_profiles` JSONB column — existing `provider_configs.settings` JSONB already serves this purpose
|
||
|
||
**Request/Response Transforms**
|
||
- [x] `Hooks.PreRequest(cfg, req)` — decorate request before dispatch (system prompt prefix, ExtraBody injection)
|
||
- [x] `Hooks.PostStreamEvent(cfg, event)` — normalize provider-specific response fields (Venice thinking extraction)
|
||
- [x] Hook implementations: Venice web search + thinking, Anthropic extended thinking + beta header, OpenRouter routing preferences + require_parameters, OpenAI frequency/presence penalty
|
||
- [x] Preset-level overrides: `MergePresetSettings()` merges persona overrides onto provider settings, respecting `ProviderOnly` fields
|
||
- [x] `ProviderConfig.Settings` fully utilized: hooks read from config, not hardcoded switch statements
|
||
- [x] `CompletionRequest.ExtraBody` field + `mergeExtraBody()` for provider-specific wire fields
|
||
- [x] Anthropic extended thinking stream support: `thinking_delta` content blocks → `Reasoning` field
|
||
|
||
**Provider Type Registry**
|
||
- [x] `providers.Init()` uses `RegisterType()` with full metadata (name, description, default endpoint, profile schema)
|
||
- [x] `ProviderTypeMeta` struct: ID, name, description, default_endpoint, profile_schema
|
||
- [x] `GET /api/v1/admin/provider-types` endpoint: list available provider types with their profile schemas
|
||
- [ ] _(deferred → v0.23)_ New provider types registrable via config file (openai-compatible endpoint + custom profile schema)
|
||
|
||
**Search Provider Health** (carried from v0.22.0)
|
||
- [ ] _(deferred → v0.22.2)_ `RecordOutcome` for web_search and url_fetch tool calls
|
||
- [ ] _(deferred → v0.22.2)_ Rate limit tracking per provider config
|
||
|
||
---
|
||
|
||
## v0.22.2 — Routing Policies + Fallback Chains ✅
|
||
|
||
Rules-based routing engine — policy, not ML. Evaluated after `resolveConfig()`
|
||
between "what model was requested" and "which provider serves it."
|
||
|
||
Depends on: provider health (v0.22.0), provider extensions (v0.22.1).
|
||
|
||
**Routing Policies**
|
||
- [x] `routing_policies` table: `id`, `name`, `scope` (global/team), `team_id`, `priority` (lower wins), `policy_type`, `config` (JSONB), `is_active`
|
||
- [x] Policy types: `provider_prefer` (ordered fallback list), `team_route` (restrict team to providers), `cost_limit` (heuristic cost cap), `model_alias` (alias → provider+model rewrite)
|
||
- [x] Policy evaluator: takes requested model + user context → returns ranked list of `(providerConfigID, modelID)` candidates
|
||
- [x] Integration point: `evaluateRouting()` called after resolveConfig, before provider dispatch — reloads winning config credentials on switch
|
||
- [ ] _(deferred → v0.23)_ `capability_match` policy type ("cheapest model with tool_calling")
|
||
|
||
**Fallback Chains**
|
||
- [x] Fallback runner: `RunWithFallback()` tries candidates in order with configurable max retries
|
||
- [x] Health-aware: skip providers with status `down`, prefer `healthy` over `degraded`
|
||
- [x] All-down graceful degradation: keeps candidates rather than failing
|
||
- [ ] _(deferred → v0.23)_ Latency-aware preference: track response time percentiles, prefer faster providers
|
||
- [ ] _(deferred → v0.23)_ Cost-aware preference with budget ceiling per request
|
||
|
||
**Routing Metadata**
|
||
- [x] `X-Switchboard-Provider` response header: `providerID/configID` on every completion
|
||
- [x] `X-Switchboard-Route` header: policy name when routing is active
|
||
- [x] `routing_decision` JSONB column on `usage_log`
|
||
- [x] `POST /api/v1/admin/routing/test` endpoint: dry-run policy evaluation with live health status
|
||
- [x] Admin CRUD: GET/POST/PUT/DELETE `/api/v1/admin/routing/policies`
|
||
|
||
---
|
||
|
||
## v0.22.3 — Provider Admin UI + Deferred Polish ✅
|
||
|
||
Admin interfaces for v0.22.0–v0.22.2 features, plus deferred items from v0.21.x.
|
||
|
||
Depends on: routing policies (v0.22.2).
|
||
|
||
**Admin UI**
|
||
- [x] Provider health dashboard: status badges, error rate/latency/timeout metrics per provider, refresh button (`loadAdminHealth`)
|
||
- [x] Capability override editor: table listing all overrides with model, config, field, value; delete button per row (`loadAdminCapabilities`)
|
||
- [x] Routing policy builder: CRUD with name/priority/type/scope/team/config(JSON)/active toggle, dry-run test panel with candidate ranking and health status (`loadAdminRouting`, `_showRoutingForm`, `_runRoutingTest`)
|
||
- [x] New "Routing" admin category with Health, Routing, and Capabilities sections
|
||
- [x] Health status included in `GET /api/v1/models/enabled` response (`provider_status` field on UserModel)
|
||
- [ ] _(deferred → v0.23)_ Provider profile editor: key-value config per provider type, preview of effective settings
|
||
- [ ] _(deferred → v0.23)_ Fallback chain visualizer: drag-to-reorder provider priority per model family
|
||
|
||
**Deferred from v0.22.0–v0.22.2**
|
||
- [ ] _(deferred → v0.23)_ `capability_match` policy type ("cheapest model with tool_calling")
|
||
- [ ] _(deferred → v0.23)_ Latency-aware preference: track response time percentiles, prefer faster providers
|
||
- [ ] _(deferred → v0.23)_ Cost-aware preference with budget ceiling per request
|
||
- [ ] _(deferred → v0.23)_ New provider types registrable via config file (openai-compatible endpoint + custom profile schema)
|
||
|
||
**Deferred from v0.21.x**
|
||
- [ ] _(deferred → v0.23)_ Mobile: mode selector collapses to hamburger/bottom nav
|
||
- [ ] _(deferred → v0.23)_ Integration with extension loader (surfaces from manifest.json)
|
||
- [ ] _(deferred → v0.23)_ Workspace settings UI: git config section in channel/project settings
|
||
- [ ] _(deferred → v0.23)_ User Settings: git credentials management UI
|
||
- [ ] _(deferred → v0.23)_ `.gitignore` respect in workspace indexing
|
||
- [ ] _(deferred → v0.23)_ Drag-drop file reorder in editor file tree
|
||
- [ ] _(deferred → v0.23)_ Article tools: suggest_outline, expand_section, check_citations (AI-powered)
|
||
- [ ] _(deferred → v0.23)_ Drag-to-reorder outline sections in article mode
|
||
- [x] _(shipped v0.22.4)_ PDF/DOCX export via pandoc in article mode
|
||
- [x] _(shipped v0.22.4)_ Project-specific file uploads (full project-level upload architecture)
|
||
|
||
---
|
||
|
||
## v0.22.4 — Provider Health UX + Project Files + Export ✅
|
||
|
||
Closes remaining provider infrastructure gaps and delivers UX features
|
||
deferred from earlier releases.
|
||
|
||
**Provider Infrastructure:**
|
||
- [x] Rate limit tracking per provider config (HTTP 429 classified separately)
|
||
- [x] Tool health tracking (web_search, url_fetch → `tool_health` table)
|
||
- [x] Auto-disable policy (N consecutive "down" windows → deactivate provider)
|
||
- [x] Search provider health tracking via tool health pipeline
|
||
- [x] SQLite health store parity (rate_limit_count, tool health, auto-disable)
|
||
- [x] Config: `PROVIDER_AUTO_DISABLE_THRESHOLD` env var (default: 3)
|
||
|
||
**UX:**
|
||
- [x] Workspace settings UI: git config section in project panel (remote URL, branch, credential)
|
||
- [x] Project-specific file uploads (POST/GET endpoints, project panel UI)
|
||
- [x] PDF/DOCX export via pandoc (POST /api/v1/export, editor menu integration)
|
||
- [x] Admin health dashboard: rate limit count display with warning color
|
||
|
||
**Frontend:**
|
||
- [x] 5 new API client methods (projectUploadFile, projectListFiles, exportDocument, updateWorkspace, listGitCredentials)
|
||
- [x] Health cards show rate limit counts
|
||
- [x] Git settings section appears when workspace is bound
|
||
|
||
---
|
||
|
||
## v0.22.5 — Surfaces + Go Templates + Admin Bug Fixes ✅
|
||
|
||
Replaces monolithic client-side rendering with server-rendered Go
|
||
templates organized as composable surfaces. Each page route renders a
|
||
dedicated surface that owns its full layout below the classification
|
||
banner. Reusable template components (`model-select`, `team-select`,
|
||
`file-upload`) eliminate duplicated form-building logic and fix data
|
||
population bugs by construction.
|
||
|
||
**Template Engine:**
|
||
- [x] `html/template` with `//go:embed` for compiled-in templates
|
||
- [x] Custom `FuncMap` (roleFilterType, toJSON, hasPrefix, dict)
|
||
- [x] CSP nonce generation per request
|
||
- [x] Data loaders per surface (pre-fetch exactly what templates need)
|
||
- [x] Base template with banner system (top + bottom, CSS custom properties)
|
||
|
||
**Surfaces:**
|
||
- [x] Chat surface (`/`, `/chat/:chatID`) — bridge to existing JS
|
||
- [x] Editor surface (`/editor/:wsId`) — server-rendered layout shell, fixes bugs #4 + #5
|
||
- [x] Notes surface (`/notes/:noteId`) — standalone with assist pane
|
||
- [x] Settings surface (`/settings/:section`) — full-page replaces modal
|
||
- [x] Admin surface (`/admin/:section`) — 5 categories, 10+ sections
|
||
- [x] Login page (`/login`) — standalone, cookie-based auth
|
||
|
||
**Reusable Components:**
|
||
- [x] `model-select` — type-filtered model dropdown (fixes bug #1)
|
||
- [x] `team-select` — pre-populated team picker (fixes bug #2)
|
||
- [x] `file-upload` — drop zone + file picker
|
||
|
||
**Auth:**
|
||
- [x] `AuthOrRedirect` middleware — cookie JWT, redirect to `/login`
|
||
- [x] `RequireAdminPage()` — role gate for admin pages
|
||
- [x] `sb_token` cookie sync on every token save/refresh
|
||
|
||
**Editor File Upload (bug #3):**
|
||
- [x] Upload button in toolbar + drag-and-drop on file tree
|
||
- [x] `uploadWorkspaceFile()` API method (binary-safe, respects quota)
|
||
- [x] Auto-open single uploaded text files
|
||
|
||
**Cleanup:**
|
||
- [x] Removed `/legacy` SPA fallback route
|
||
- [x] nginx.conf: page route proxy blocks before SPA fallback
|
||
|
||
---
|
||
|
||
## v0.23.0 — Multi-Participant Channels + Presence
|
||
|
||
The channel foundation for workflows and real-time collaboration. Today
|
||
channels are single-user direct chats. This release makes channels a
|
||
shared space that multiple actors can inhabit.
|
||
|
||
Depends on: extension surfaces (v0.21.3), WebSocket infrastructure (already exists).
|
||
|
||
_(Shifted from v0.20.0 — no content changes)_
|
||
|
||
**Channel Participants**
|
||
- [ ] `channel_participants` table: `channel_id`, `participant_type` (user, session, persona), `participant_id`, `role` (owner, member, observer), `joined_at`
|
||
- [ ] Channel access queries rewritten: `WHERE user_id = $1` → participant-based lookup
|
||
- [ ] Backward compatible: existing single-user channels auto-have one participant (owner)
|
||
- [ ] Channel `type` column: `direct` (current), `group` (multi-user), `workflow` (staged)
|
||
|
||
**Presence + Real-time**
|
||
- [ ] Typing indicators and presence (who's online, who's in this channel)
|
||
- [ ] Participant join/leave events via WebSocket
|
||
- [ ] Co-editing for extension surfaces (editor mode, article mode)
|
||
- [ ] Cursor sharing, selection highlighting
|
||
|
||
**Channel-Scoped Notes**
|
||
- [ ] Optional `channel_id` FK on notes (NULL = personal notebook, set = channel-attached)
|
||
- [ ] Notes created by tool calls within a channel auto-attach to that channel
|
||
- [ ] Channel notes visible to all participants (not just creator)
|
||
|
||
---
|
||
|
||
## v0.24.0 — Auth Strategy (mTLS/OIDC) + Full RBAC
|
||
|
||
Enterprise auth modes on top of the teams + groups foundation.
|
||
Depends on: vault passphrase support from v0.9.3 (conditional unlock for
|
||
personal providers under external auth), user groups (v0.16.0).
|
||
|
||
_(Shifted from v0.21.0 — enhanced with group-based permissions)_
|
||
|
||
- [ ] `AUTH_MODE` env var: `builtin` | `mtls` | `oidc`
|
||
- [ ] All three resolve to the same internal user model
|
||
- [ ] `auth_source` + `external_id` columns on users table
|
||
- [ ] mTLS: header trust, auto-provision from cert DN
|
||
- [ ] OIDC: Keycloak/Okta token validation, claim extraction, role mapping
|
||
- [ ] Per-source auto-activate policy: auto_activate, default_team, default_role
|
||
- [ ] Vault passphrase prompt for mTLS/OIDC users (v0.9.3 conditional unlock)
|
||
- [ ] Fine-grained permissions: model access, KB write, task create, token budgets
|
||
- [ ] Group-based permission sets: assign permissions to groups, users inherit from membership
|
||
- [ ] OIDC claim → group mapping: external IdP groups auto-sync to internal groups
|
||
|
||
**Anonymous / Session Participants**
|
||
- [ ] Session-based identity for unauthenticated visitors (workflow intake)
|
||
- [ ] mTLS: cert CN/fingerprint as stable session identity (no `users` row required)
|
||
- [ ] Non-mTLS: ephemeral session token (cookie or URL token)
|
||
- [ ] Session participants can send messages and trigger tool calls within workflow channels
|
||
- [ ] Session identity visible to assigned team members (cert DN, display name, or "Anonymous #N")
|
||
|
||
---
|
||
|
||
## v0.25.0 — Workflow Engine
|
||
|
||
Team-owned, stage-based process execution. The channel is the runtime,
|
||
personas drive each stage, and the existing tool/notes infrastructure
|
||
handles structured data collection. See [ARCHITECTURE.md — Workflow
|
||
Architecture](ARCHITECTURE.md#workflow-architecture-future--v0210) for
|
||
the conceptual model.
|
||
|
||
Depends on: multi-participant channels (v0.23.0), anonymous identity (v0.24.0).
|
||
|
||
_(Shifted from v0.22.0 — no content changes, dependency refs updated)_
|
||
|
||
**Workflow Definitions**
|
||
- [ ] `workflows` table: `team_id` (owner), `name`, `description`, `is_active`, `entry_mode` (public_link, team_internal, api)
|
||
- [ ] `workflow_stages` table: `workflow_id`, `ordinal`, `persona_id`, `assignment_team_id`, `form_template` (JSONB, structured note schema), `transition_rules` (JSONB)
|
||
- [ ] Team-admin CRUD: create/edit/delete workflows and stages
|
||
- [ ] Workflow versioning: edits create new version, active instances continue on their version
|
||
|
||
**Workflow Instances (Channels)**
|
||
- [ ] Workflow-typed channels: `type='workflow'`, `workflow_id`, `current_stage`, `stage_version`
|
||
- [ ] Entry point: public link generates workflow channel, adds anonymous participant, binds stage 1 persona
|
||
- [ ] Stage transitions: triggered by AI (tool call), team member (button), or rule (form complete)
|
||
- [ ] On transition: swap active persona, notify assignment team, update channel metadata
|
||
|
||
**Go Template Pages (server-rendered entry points)**
|
||
|
||
Server-rendered HTML via Go `html/template` for pages that need SEO, OG tags,
|
||
pre-auth rendering, or standalone access outside the SPA shell. Same binary,
|
||
same auth middleware, same deployment — no second language runtime.
|
||
|
||
- [ ] Template engine: Go `html/template` with shared base layout, partials for nav/footer
|
||
- [ ] Route layer: `/w/:slug` for public workflow pages, `/p/:id` for shared project views
|
||
- [ ] Workflow landing page: branded intake form, persona avatar, description — rendered server-side
|
||
- [ ] Shared/embedded surface pages: `/s/editor/:wsId`, `/s/article/:wsId/:path` — server renders minimal shell, JS hydrates surface directly (replaces hash routing for public links)
|
||
- [ ] Template data: workflow metadata, branding, environment banner — injected server-side
|
||
- [ ] Auth gating: public pages skip auth, team pages require session, admin pages require role
|
||
- [ ] Precursor: hash router (v0.21.6) handles in-app navigation; Go templates handle external/public entry points
|
||
|
||
**AI Intake**
|
||
- [ ] Stage persona drives structured collection via system prompt
|
||
- [ ] Form template → persona system prompt injection ("collect these fields: ...")
|
||
- [ ] Tool calls create channel-scoped notes as form responses
|
||
- [ ] AI determines readiness: "I have everything needed" → trigger transition
|
||
|
||
**Assignment + Queue**
|
||
- [ ] Assignment queue: unassigned workflow channels visible to team members
|
||
- [ ] Claim model: team member claims channel (becomes participant with `member` role)
|
||
- [ ] Round-robin / rule-based auto-assignment (optional, per-stage config)
|
||
- [ ] Assignment notifications via WebSocket + optional webhook
|
||
|
||
**Team Member Collaboration**
|
||
- [ ] Assigned member sees full history (AI intake + artifacts + notes)
|
||
- [ ] Persona remains active — assists both visitor and team member
|
||
- [ ] Member can trigger stage transitions, add notes, invoke tools
|
||
- [ ] Member can reassign to different team member or escalate to different team
|
||
|
||
**Frontend**
|
||
- [ ] Workflow builder UI in team admin panel (stage list, persona picker, form template editor)
|
||
- [ ] Queue view: sidebar section showing unassigned workflow channels for user's teams
|
||
- [ ] Channel header: workflow stage indicator, transition controls
|
||
- [ ] Anonymous visitor view: minimal UI, persona-driven conversation (public link entry)
|
||
|
||
---
|
||
|
||
## v0.26.0 — Tasks / Autonomous Agents
|
||
|
||
Unattended execution — workflows without a human in the loop.
|
||
Depends on: workflow engine (v0.25.0).
|
||
|
||
_(Shifted from v0.23.0 — no content changes, dependency refs updated)_
|
||
|
||
- [ ] Scheduler + task runner (cron-like triggers for workflow instantiation)
|
||
- [ ] `task_create` tool (AI can spawn sub-workflows)
|
||
- [ ] `type: 'service'` channels: workflow instances with no human participants
|
||
- [ ] Execution budgets: max tokens, max tool calls, max wall-clock per stage
|
||
- [ ] Admin controls for resource limits and kill switches
|
||
- [ ] Completion webhooks (notify external systems when workflow completes)
|
||
|
||
---
|
||
|
||
## TBD (unscheduled — real features, no immediate need)
|
||
|
||
Items that are real but don't yet have a version assignment. Pull left
|
||
based on need.
|
||
|
||
**Extension System — Additional Extensions**
|
||
- Image generation tool (browser or sidecar, provider-agnostic)
|
||
- STT/TTS (browser extension, Web Speech API — personal use case)
|
||
- Code execution sandbox (server-side, container isolation)
|
||
|
||
**Extension System — Server Tiers**
|
||
- Starlark runtime integration (Tier 1 — server sandbox)
|
||
- Sidecar HTTP tool protocol (Tier 2 — container isolation)
|
||
- Server-side tool execution in completion handler
|
||
|
||
**Desktop + Mobile**
|
||
- Desktop app (Tauri)
|
||
- Full PWA with offline capability
|
||
- Mobile-optimized layouts (beyond current responsive)
|
||
|
||
**Data + Portability**
|
||
- Bulk export/import (account data, conversations, settings)
|
||
- ChatGPT/other tool import
|
||
- GDPR-style "download my data"
|
||
- Backup/restore CronJob manifests
|
||
|
||
**UX / Multi-Seat**
|
||
- "Group" scope badge on model selector / KB list: show access-source annotation so users see _why_ they have access (global, team, group grant). Requires backend to include `access_source` in list responses.
|
||
- Per-provider model preferences: `user_model_settings` unique key is `(user_id, model_id)` — same model from different providers shares one visibility toggle. Needs `provider_config_id` dimension in DB constraint, store, API, and frontend `hiddenModels` keying. Frontend composite key (`configId:modelId`) already exists in `App.models[].id`.
|
||
|
||
**Projects — Future**
|
||
- Project-specific files: full project-level upload (own endpoint, storage path, UI surface — not just channel attachment re-linking)
|
||
- Project templates: create new projects from predefined configurations (persona, KBs, system prompt)
|
||
- Project creation dialog: replace `prompt()` with proper modal (name, description, persona, KB picker)
|
||
- Admin-level project management: cross-instance visibility, reassign ownership, enforce team policies (scope: enterprise only, BYOK personal projects stay private)
|
||
- Sub-projects / nested hierarchy: child inherits parent KBs, system prompt, persona (deferred until usage patterns clarify need vs tags/labels)
|
||
|
||
**Knowledge Bases — Future**
|
||
- KB auto-injection: top-K chunk prepend to system prompt, context budget aware, per-channel toggle (latency budgeting required)
|
||
- Hybrid search: combine vector similarity with full-text `tsvector`, re-rank
|
||
- Semantic chunking: embedding-based boundary detection for smarter splits
|
||
- HNSW index: better query performance than IVFFlat for large datasets
|
||
- Web scraping source: ingest URLs as KB documents (extends url_fetch)
|
||
- Scheduled re-indexing: periodic rebuild when source documents update
|
||
- ~~Store cleanup: add `UpdateDocumentStorageKey()` to `KnowledgeBaseStore` interface~~ _(done in v0.17.0)_
|
||
(currently uses direct `database.DB.ExecContext` in handler — works but bypasses store layer)
|
||
|
||
**Memory — Future**
|
||
- Memory compaction: summarize old memories to save context tokens
|
||
- Memory confidence decay: reduce confidence over time, prune low-confidence entries
|
||
- Memory export/import: portable memory format across instances
|
||
- Cross-persona memory sharing (opt-in): e.g. "coding assistant" can read facts from "project manager"
|
||
- Memory analytics: dashboard showing what Personas are learning, memory growth trends
|
||
|
||
**Platform**
|
||
- Rate limiting per user/team/tier (token budgets)
|
||
- ~~Provider health monitoring~~ → v0.22.0 + key rotation
|
||
- Multi-tenant SaaS mode
|
||
- Plugin/extension marketplace
|
||
- Virtual scroll for long conversations
|
||
- ~~SQLite backend option (single-user / dev)~~ → v0.17.1
|
||
|
||
**Pane Architecture (Workspace Container)**
|
||
|
||
The main area to the right of the sidebar is a **workspace container** that holds 1+ panes.
|
||
Each pane is a self-contained unit (chat, editor, notes, preview, etc.) with its own lifecycle.
|
||
Panes compose side-by-side rather than replacing each other (current surface model).
|
||
|
||
- Default layout: Left nav + single Chat pane (what exists today, zero cognitive overhead)
|
||
- Power user: Left nav + Editor pane + Chat pane side by side. Or Editor + Notes. Or all three.
|
||
- Workflow mode: Left nav hidden. Team member gets Chat + History. Customer gets just Chat.
|
||
- User-resizable splits between panes, layout persists per-project or per-user preference
|
||
- The current surface system was a stepping stone — proved out the region/activate/deactivate lifecycle. Panes reuse that contract but drop the "only one active at a time" constraint.
|
||
- Sidebar tabs (Chats / Files) already decouple navigation from center content (v0.21.6)
|
||
|
||
**Surfaces as Extensions**
|
||
- Surfaces (future: panes) become first-class extension types alongside block renderers and tool bridges
|
||
- `Surfaces.register()` already defines the contract: name, regions, activate/deactivate callbacks — swap hardcoded JS modules for manifest + dynamically loaded bundles
|
||
- Admin-installable surfaces: upload or enable from extension registry, scoped to team or global
|
||
- Surface manifest in `manifest.json`: declares required regions, capabilities, dependencies
|
||
- Surface IDE: built-in surface for building surfaces — Go template editor for server-rendered shells, JS/CSS editor for client behavior, live preview in sandboxed region. Eats its own dog food.
|
||
- Surface marketplace: share custom surfaces across instances (presentation mode, kanban, form builder, dashboard, etc.)
|
||
- Project-bound surface/pane defaults: project config specifies which panes are available and default layout |