This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/docs/ROADMAP.md
2026-03-14 22:51:50 +00:00

41 KiB
Raw Blame History

Roadmap — Chat Switchboard

See also:

  • ARCHITECTURE.md — Core services design, store layer, scope model
  • EXTENSIONS.md — Extension system spec (Browser/Starlark/Sidecar tiers, manifests, browser tool bridge, surfaces/modes, model roles)
  • EXTENSION-SURFACES.md — Extension surface authoring guide (manifest format, platform API, CSS properties, install workflow)
  • 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.xv0.27.5  Foundation → Extensions → Surfaces → Auth     ✅
                 → Workflows → Tasks → Team Tasks
                 (see CHANGELOG.md for full history)
                        │
                v0.28.0 Platform Polish
                  ├─ v0.28.1  Surfaces ICD audit        ✅
                  ├─ v0.28.2  ICD audit — all domains   ✅
                  ├─ v0.28.3  ICD close-out + FE decomp   ✅
                  ├─ v0.28.4  Security tier (red team)    ✅
                  ├─ v0.28.5  Frontend SDK + Pipes      ✅
                  │   (switchboard-sdk.js, pipe/filter
                  │    pipeline, component mounting)
                  ├─ v0.28.6  Infrastructure
                  │   (virtual scroll, Helm, task webhook
                  │    UI, system tasks, model prefs)
                  └─ v0.28.7  Unified Packaging + Task RBAC
                      (.pkg archive, manifest.type,
                       task permission gate pre-Starlark)
                        │
                v0.29.0 Starlark Sandbox
                  (eval loop, permissions, admin UI
                   — adds starlark capability to .pkg)
                        │
                v0.29.1 API Extensions
                  (Starlark route handlers,
                   outbound HTTP, requires_provider)
                        │
                v0.29.2 DB Extensions
                  (namespaced tables, scoped db module,
                   declarative schema in manifest)
                        │
                v0.29.3 Workflow Forms
                  (form_template → real UI, LLM optional,
                   .star validation, structured data)
                        │
                v0.30.0 Package Lifecycle
                  (schema versioning, migrations,
                   settings extension point,
                   export/import, marketplace)
                        │
                v0.30.1 SDK Adoption
                  (sw.notes factory, core surface
                   migration, fix-once-fix-everywhere)
                        │
                v0.30.2 Workflow Packages
                  (stage surfaces, custom UI per stage,
                   team admin workflow builder)
                        │
                v0.31.0 Editor Package
                  (E2E proof: rebuild editor as
                   installable .pkg, zero
                   platform special-casing)

v0.28.0 — Platform Polish

Audit arc, frontend decomposition, security, and infrastructure improvements.

v0.28.1 — Surfaces ICD Audit

  • ICD surfaces.md corrected (6 discrepancies: field name, archive format, response shape)
  • Surface ID slug validation + extractableRelPath install hardening
  • 19 E2E surface CRUD tests in ICD runner (install, enable/disable, delete, error paths)
  • 22 handler-level tests + 14 store-level tests (PG + SQLite)
  • CI timeout 8m → 12m for PG integration tests

v0.28.2 — ICD Audit: All Domains

Full audit of every ICD document against code. Goal: ICD becomes the single source of truth. After this version, the workflow is ICD-first — update the contract before changing code.

Methodology: Read ICD → grep all source → trace route → handler → store (PG + SQLite) → tests → enforce {"data": [...]} envelope convention → fix ICD → fix code → fix runner → CI green. Final pass picks up straggling failures across all domains.

Final score: 469/469 (100%)

Completed audits:

Notifications (cs0):

  • Notifications ICD audit: object shape, query params, response envelopes, WS events
  • Notification type enum sync: remove aspirational types, add implemented types (kb.ready, kb.error, grant.changed, task.budget_exceeded)
  • Implement memory.extracted notification (hook in memory extractor)
  • Implement user.mentioned persisted notification (was WS-only)
  • Implement workflow.claimed persisted notification (was WS-only)
  • Remove dead NotifTypeProjectInvite constant
  • GET /notifications/preferences — envelope fix (missing key "preferences")

Knowledge (cs1cs4):

  • knowledge.md corrected: KB object shape (6 field mismatches), search envelope (data not results), search result fields, status progression (extracting step), file type support (text-only, not binary), auth annotations
  • Test harness: add RequirePermission on POST /knowledge-bases and POST /:id/documents, add missing GET /:id/documents/:docId/status and DELETE /:id/documents/:docId routes
  • New tests: document status polling, document delete, update-empty-body 400, permission denial for non-privileged user
  • P0 fix: SetDiscoverable authorization — loadAndAuthorize + owner/admin check, audit log, cross-user security tests (cs2)
  • ListDiscoverableKBs response normalization — use toKBResponse(), shape assertion test (cs3)
  • Dead code removal: ListGlobal/ListForTeam on KnowledgeBaseStore — interface + PG + SQLite (cs4)
  • Move CreateKB team role check from raw database.DB.QueryRow to stores.Teams.IsTeamAdmin; remove database import (cs4)
  • Team-scoped KB creation test: member denied, team admin succeeds (cs4)

Profile (cs5):

  • profile.md corrected: avatar API (was multipart/form-data, actually JSON base64), response shapes for all 7 endpoints, auth annotations, field table
  • P0 fix: GET /settings returns bare object → wrapped in {"settings": {...}}
  • profileResponse shape: add last_login_at field + dialect-safe time scan (database.ST() / database.SNT()), COALESCE guard on settings column
  • Integration test harness: register all 7 profile/settings routes (was only GET /profile), remove stale /avatar route aliases
  • New profile_test.go: GET profile shape, PUT profile (display_name, email, duplicate email 409), GET/PUT settings envelope, password change (success, wrong current 401, too short 400), avatar delete

Workspaces (cs6):

  • workspaces.md corrected: workspace object shape (added indexing_enabled, git_* fields, total_bytes not storage_bytes, owner_type full enum), file entry shape (is_directory/size_bytes not is_dir/size), git status full shape, git log envelope ({"data": [...]}), git commit request (paths not files), archive format query param, auth annotations, all response shapes
  • P0 fix: GET /workspaces returns bare array → {"data": [...]}
  • P0 fix: GET /git-credentials returns bare array → {"data": [...]}
  • Fix: GET .../git/log returns bare array → {"data": [...]} + nil slice guard
  • New workspace_test.go: List empty envelope, list with data + shape, root_path not exposed, user isolation, GET by ID shape, not found 404, forbidden 403, git-credentials empty envelope, auth required (11 tests)

Projects (cs7):

  • projects.md full rewrite: 6 categories of drift (ghost fields, missing fields, request shapes, association objects, omitempty on computed counts)
  • 14 new Go tests: CRUD shapes, 201 status, envelope, admin list, auth, isolation
  • P0 nil guard: ListByProject files null[]
  • P0: ListTeamProviderModels missing Type field — Venice 400 fix
  • ICD runner projects rewritten 9 → 19 tests
  • ICD runner tier-providers: SSE parser, model exclusion, ID fallback fixes

v0.28.3 — ICD Close-out + Frontend Decomposition Prep

ICD straggler sweep (rolled in from v0.28.2 tail) and frontend decomposition groundwork.

ICD close-out (cs0):

  • websocket.md full rewrite: event envelope field (event not type), payload shapes for 11 event types, routing table from code, room model documented as planned-not-implemented
  • auth.md corrected: login response shape (added token_type/expires_in, removed phantom fields), register admin-approval path
  • enums.md corrected: added missing queued task run status
  • Presence status gap documented (DB allows away, runtime emits only online/offline)
  • VERSION, CHANGELOG, ROADMAP updated

WebSocket delivery fix (cs1):

  • workflow.claimed, workflow.advanced, workflow.completed use room-scoped Bus.Publish() but rooms are never joined — events never reach WebSocket clients. Convert to SendToUser() per channel participant (same pattern as message.created, workflow.assigned).

Frontend decomposition:

  • JS dependency audit: docs/JS-DEPENDENCY-AUDIT.md — full map of 47 files, 431 globals, cross-file call graph, script load order per surface
  • IIFE extraction: all 47 JS files wrapped, ~168 functions privatized, zero implicit globals remain. Explicit window.* exports on every file.
  • Cross-file coupling fix: events.js no longer reads _storageKey from api.js — uses API.accessToken instead
  • ICD runner gains test tiers: crud, envelope, security, sdk
  • Runner coverage target: 100% of ICD-documented endpoints have at least one test
  • Phase 2: onclick → addEventListener migration (143 dynamic → 5 unconvertible, 163 data-action delegated via _uiDispatch on document.body)
  • Phase 3: Action registry (sb.js) — 248 window.* exports replaced with sb.register()/sb.ns(). sb.resolve() centralized dispatch. sb.call() template bridge ready for Go template migration.
  • Phase 3b: Go template onclick → sb.call() migration (72 handlers across 10 templates, 4 unconvertible inline DOM ops, 3 standalone pages excluded)
  • Phase 4: ES module conversion — IIFE wrappers removed from all 47 files, <script type="module"> across all templates. sb.js + vendor stay classic. CI test harness fixed (sb.js in VM context).
  • Phase 5 (future): import/export statements, remove window[name] dual-write from sb.register()/sb.ns()

v0.28.4 — Security Tier (ICD Runner Red Team)

New security tier in ICD test runner. 58 tests, 529/531 pass. 5 bugs found and fixed. surfaces/ directory added with build script.

Auth boundary:

  • JWT revocation: disable user → existing token rejected immediately. Real bug found + fixedUserStatusCache (30 s TTL) added to auth middleware; is_active checked on every request.
  • Token reuse after POST /auth/logout — revoked refresh token fails
  • Expired token rejection (tampered JWT, alg=none — both rejected)
  • Role escalation: modified JWT claims → 401. Real bug found + fixed — role now resolved from DB, not JWT claims.
  • User ID substitution: user_id in request bodies ignored by handlers

Cross-tenant data access:

  • User A's token → GET user B's notes, memories, workspaces, BYOK configs, tasks — all 404/403
  • Team member → access other team's providers, personas, tasks — all 403
  • Non-participant → read channel messages, files — 403/404

Input validation:

  • Path traversal in surface install — rejected (400)
  • SQL injection in search endpoints (notes, users, channels) — 7 payloads, all parameterized
  • XSS payloads in channel titles, note content, persona names — stored safely, frontend sanitizes
  • Oversized request bodies, malformed JSON — handled (400)
  • Null byte in path params → 500 fixedValidatePathParams() middleware (400)
  • Oversized path params → 500 fixed — same middleware (400)

Session security:

  • Visitor session → access channels outside bound workflow — 401
  • Visitor → escalate to authenticated user via crafted headers — 401
  • Cross-visitor isolation: enforced by session_auth.go channel binding, but no E2E test (requires public_link workflow setup — defer to visitor E2E milestone)

Infrastructure:

  • CORS_ALLOWED_ORIGINS env var — production restricts, dev allows *
  • surfaces/ directory with build.shdist/<n>.surface
  • hello-dashboard.surface unpacked into surfaces/hello-dashboard/

v0.28.5 — Frontend SDK + Pipes

switchboard-sdk.js — composition layer over existing globals. Surface authors consume a single coherent API instead of hunting through 15 JS files. Pipe/filter pipeline formalizes the extension hook model into composable, priority-ordered transform stages.

SDK core:

  • Switchboard.init({ mount }) — idempotent boot: tokens, profile, theme, events, user menu
  • sw.user, sw.isAdmin — resolved identity
  • sw.api.get() / sw.api.post() — authenticated REST, no token/base-path management
  • sw.on(event, fn) — WebSocket subscription (no Events global knowledge)
  • sw.chat(container, opts) — drop-in ChatPane (wraps ChatPane.create())
  • sw.notes(container, opts) — stub shipped (warns); notes component needs factory refactor before clean mounting (v0.30.1 SDK Adoption)
  • sw.toast(), sw.confirm() — UI primitives
  • sw.theme.current, sw.theme.on('change', fn) — theme queries
  • Absorbs cs15 UserMenu band-aid — universal hydration moves into init()

Pipe/filter pipeline:

Three stages, each a priority-ordered chain of transform functions. Filters receive typed context, return (possibly modified) context. Pipeline wires filters in priority order; any filter can halt the chain.

  • sw.pipe.pre(priority, fn)pre-send: transform user message before LLM request. Context: { message, channel, attachments, metadata }. Runs on both sendMessage() and regenerateMessage() with regenerate flag.
  • sw.pipe.stream(priority, fn)post-receive: transform LLM response stream chunks as they arrive (sync-only). Context: { chunk, accumulated, channel, model }.
  • sw.pipe.render(priority, fn)post-render: transform rendered HTML/markdown after DOMPurify. Context: { element, message, channel }. Replaces runExtensionPostRender() with compat shim for existing ctx.renderers.register() extensions.
  • Pipeline execution engine: ordered dispatch, error isolation (one filter throws → skip it, continue chain), timing telemetry per filter
  • sw.pipe.list() — introspection: list registered filters by stage with priority, source, scope, and timing stats
  • Filter scoping: { scope: { channelType: [...] } } restricts execution to specific channel types with zero-overhead skip
  • Manifest "pipes" key: declarative filter registration — deferred to v0.28.7 (unified packaging, where manifest keys are extended)

Testing:

  • ICD runner gains sdk test tier: 36 tests — boot, identity, REST, events, theme, pipe registration, execution, scoping, halt, error isolation, compat shim, introspection
  • Pipe filter tests: priority ordering, halt semantics, error isolation, scoped/unscoped execution

v0.28.6 — Infrastructure

  • Virtual scroll for long conversations (prerequisite for heavy task output channels)
  • KB auto-injection: platform-registered pre-send pipe filter (_kb-auto-inject, priority 5), top-K chunk prepend to ctx.metadata.kb_context, context budget aware, per-channel toggle. First real validation of the v0.28.5 pipeline architecture.
  • Helm chart (replaces raw k8s manifests, helm install switchboard ./chart)
  • Per-provider model preferences — finalize: make provider_config_id required on PUT /models/preferences (fixes NULL-in-UNIQUE dedup bug), migrate /models/enabled and /models/preferences to {"data": [...]} envelope, add integration test coverage
  • Git credentials settings UI: vault-encrypted per-user credentials, SSH key management, per-workspace remote config. Table exists (git_credentials), vault pattern exists — needs settings section and CRUD handler.
  • system.announcement notification type: admin broadcast endpoint (POST /admin/notifications/broadcast), fan-out to all active users via NotifyMany, admin UI for composing announcements
  • Task webhook trigger UI: schedule selector gains webhook option, trigger URL displayed + copy button, outbound webhook_url + webhook_secret fields in create/edit form, task-to-task chaining documentation in admin UI. Backend fully implemented — this is pure admin UI work.
  • System task type: task_type: "system" — built-in Go function registry (retention_sweep, memory_compact, session_cleanup, staleness_check). Admin creates task, picks function from dropdown, sets cron schedule. Executor calls registered Go function instead of LLM completion. Replaces the current goroutine-based background jobs with visible, configurable, auditable tasks. Existing goroutines kept as fallback until system tasks are validated. Permanent track — Go registry is not replaced by Starlark (v0.29.0). Core platform ops must not break from bad user code. Admin-only by design (no RBAC needed — hardcoded to admin role).

v0.28.7 — Unified Packaging + Task RBAC

Single .pkg archive format for both surfaces and extensions. Manifest "type" field (surface, extension, full) drives install behavior. Format first, capabilities later — v0.29.x adds Starlark/DB/API capabilities into packages that already install cleanly.

Task permission model gates task creation by type and scope. Retroactively locks down action tasks (webhook relay = data exfiltration risk) and pre-positions for starlark tasks in v0.29.0.

Depends on: v0.28.5 (SDK — pipe/filter registration is part of manifest contract).

Archive format:

  • .pkg archive: zip containing manifest.json + assets (JS, CSS, templates, icons). Same structure as .surface archives, extended manifest schema
  • manifest.type field: surface (routes + templates + data loader), extension (hooks + tools + pipes, no own route), full (both). Absent type defaults to surface for backward compat
  • manifest.pipes key: declarative pipe filter registration (pre-send, post-receive, post-render) with priority and entry function reference. Wired by SDK on extension load
  • manifest.tools key: LLM-callable tool declarations (existing schema, now part of unified manifest)
  • manifest.hooks key: EventBus subscriptions (existing schema from EXTENSIONS.md, carried forward)

Install infrastructure:

  • POST /admin/packages/install — unified install endpoint. Reads manifest.type, validates type-specific requirements, wires subsystems. Replaces POST /admin/surfaces/install (old route kept as alias)
  • Validation branches by type: surface requires routes/template, extension requires at least one of hooks/tools/pipes, full requires both sets
  • Admin UI: merge Surfaces + Extensions into single "Packages" section. Type badge on each entry. Filter by type. Enable/disable granular for full packages (disable hooks independently of routes)
  • packages table (or rename surfacespackages with migration): adds type column, retains all existing surface columns

Migration:

  • Existing .surface archives install unchanged (type defaults to surface). No re-install required
  • Existing extensions table rows (loose-JS browser extensions) get synthetic package wrappers: migration generates manifest.json from existing DB fields, archives JS entry file into .pkg format
  • build.sh in surfaces/ updated to produce .pkg files. Directory optionally renamed to packages/
  • ICD runner surface install tests updated to use new endpoint (or alias)

Task RBAC:

Permission gate on task creation by task_type and scope. Must ship before Starlark (v0.29.0) — cannot allow server-side code execution without a permission model. Also retroactively locks down action tasks.

  • task_permissions table (or extend extension_permissions pattern): maps (user_id | team_id | role) → task_type → allowed. Default permissions seeded on migration: - Admin: all types, all scopes - Team admin: prompt, workflow (team scope). action denied by default - User: prompt, workflow (personal scope). action denied by default - system always admin-only (hardcoded, not in permissions table)
  • Create/update task handlers check permission before accepting task_type. Existing action tasks grandfathered (can run, cannot be cloned or created without permission). Migration adds warning notification to owners of existing action tasks
  • Admin UI: task permission management — per-user and per-team overrides. "Allow action tasks for Team X" toggle. Pre-positions starlark permission type (hidden until v0.29.0 enables it)
  • POST /api/v1/tasks and PATCH /api/v1/tasks/:id validate task_type against caller's permissions. 403 on denied type
  • ICD tests: permission-denied task creation, team admin boundaries, admin override

ICD + docs:

  • packages.md ICD: install, list, enable/disable, delete, type filtering
  • EXTENSIONS.md updated: packaging section references .pkg format, loose-JS model documented as legacy
  • tasks.md ICD updated: permission model, per-type RBAC
  • ICD runner gains packaging test tier: install surface-type, install extension-type, install full-type, type validation, backward compat

Tier 2 — Medium value (pull into any v0.28.x):

  • User-installable extension packages: RBAC-gated POST /packages/install (non-admin), team-scoped or personal scope, permission review flow. Depends on v0.28.7 packaging.
  • Memory compaction: summarize old memories, confidence decay, prune low-confidence
  • capability_match routing policy ("cheapest model with tool_calling")
  • New provider types registrable via config file (OpenAI-compatible + custom schema)

v0.29.0 — Starlark Sandbox + Permission Model

Server-side extension runtime. Prove the eval loop, permission pipeline, and admin UI before adding capabilities.

Depends on: v0.28.0 (platform polish — specifically v0.28.7 unified packaging), extension infrastructure (v0.11.0).

  • go.starlark.net integration (eval loop, timeout, memory ceiling)

  • Permission model: manifest declarations, admin grant/revoke, DB schema (extension_permissions table: extension_id, permission, granted, granted_by)

  • Runtime enforcement: sandbox loader checks granted permissions, injects only approved modules. Denied permissions → clean error, not silent no-op.

  • Admin UI: permission review on install, per-extension grant/revoke toggle, audit log of permission changes

  • Extension lifecycle states: install → pending_review → approved → active

  • Initial modules: secrets (vault-backed per-extension), notifications (emit to users)

  • Migration: extension_permissions table

  • ICD: update extensions.md with Starlark-specific endpoints

  • task_type: "starlark": task executor gains Starlark code path. Task references a .star script (inline or from a .pkg), executor runs it in the sandbox with task context (trigger payload, schedule info, previous run data). No LLM, no webhook relay — actual computation. RBAC gate from v0.28.7 enforced: task.starlark permission enabled in task_permissions (hidden until this version). Admin-grantable to team admins on a per-team basis.

    **Two-track execution model (permanent):**
    - `system` (v0.28.6): Go function registry — core platform ops
      (`retention_sweep`, `memory_compact`, etc.). Cannot break from
      bad user code. Admin-only, not editable, not versionable.
    - `starlark`: custom admin/team admin tasks — nightly reports,
      data quality checks, integration sync, cleanup scripts. Editable,
      versionable, sandbox-isolated, permission-gated.
    

v0.29.1 — API Extensions

Starlark route handlers. Surfaces can serve custom JSON endpoints.

Depends on: v0.29.0 (sandbox + permissions).

  • api_routes manifest key: [{"method": "GET", "path": "/data", "handler": "handlers.list"}]
  • Routes mounted at /s/{surface_id}/api/..., auth context injected
  • Starlark request/response primitives (headers, body, status)
  • http outbound module: allowlist/blocklist per extension
  • requires_provider manifest key: extensions declare provider capability needs (e.g. "image_generation"). Platform resolves via existing provider chain (BYOK → team → global → routing policy). Starlark provider module makes calls on behalf of extension — raw API keys never exposed to sandbox.
  • Server-side tool execution in completion handler (Starlark tools run server-side, browser tools run client-side — unified tool schema)
  • Multi-file asset routing: ServeExtensionAsset path-based lookup (replaces inline _script for all requests)
  • Deduplicate tool schema extraction: unify ListBrowserToolSchemas and ListTools into shared helper handling both browser and server-side tools

v0.29.2 — DB Extensions

Namespaced tables for extension data. Create-only (no migrations yet).

Depends on: v0.29.1 (API extensions — handlers need somewhere to persist).

  • Namespaced tables: ext_{surface_id}_* prefix enforced by platform
  • Declarative schema in manifest: "tables": [{"name": "items", "columns": [...]}] Platform generates dialect-correct DDL (PG + SQLite)
  • db Starlark module: query(), exec() scoped to extension tables + declared views
  • Views as read contract: extension declares views over platform tables with explicit column allowlist — never direct access to platform tables
  • SQL validation: db module rejects references to tables outside namespace
  • Schema creation on install, drop on uninstall

v0.29.3 — Workflow Forms

form_template renders as real UI. The LLM moves to the corner — present if configured, but not required for data collection. Workflows become structured processes, not guided conversations.

Depends on: v0.29.2 (DB extensions — structured form data persists in ext_workflow_* tables, not just stage_data JSON blob), v0.29.0 (Starlark — .star validators run on form submission).

Form rendering:

  • form_template schema: typed field definitions (text, email, select, number, date, textarea, checkbox, file). Validation rules per field (required, pattern, min/max). Current freeform JSON → structured schema with backward compat (old JSON treated as textarea field prompts for the LLM)
  • Stage renders as form when form_template has typed fields. HTML form generation from schema, client-side validation, styled with platform CSS custom properties
  • Form submission → stage_data merge (same MergeWorkflowStageData path as chat-based data collection, but from structured fields instead of LLM extraction)
  • Stage advance on form submit: if auto_transition: true and all required fields pass validation, advance without human operator or LLM involvement

LLM-optional stages:

  • Stage without persona_id renders form only — no chat pane, no completion endpoint, pure data collection
  • Stage with persona_id + form_template renders form + chat side-by-side: user fills form, LLM assists (auto-fill suggestions, field explanations, validation help)
  • Stage with persona_id + no form_template — current behavior (pure chat-based collection, no change)

Starlark validation:

  • validate Starlark hook: manifest declares .star validator per stage. Runs on form submit before advance. Returns field errors or approval. Uses db module for cross-reference validation (e.g., "is this email already in the system?")
  • on_submit Starlark hook: post-validation side effects (create records, send notifications, call APIs via http module)

Visitor form entry:

  • Visitor entry point renders form for non-chat stages (branded page with form, no chat widget). Session-scoped same as current visitor auth model
  • Progressive: visitor sees form → submits → next stage (may be form or chat or operator review)

Team admin UX:

  • Form builder: visual field editor in workflow admin (drag fields, set types/validation, preview). Replaces raw JSON textarea for form_template. Admin-only initially, team admin in v0.30.2.

v0.30.0 — Package Lifecycle

Lifecycle sophistication for the .pkg format established in v0.28.7. Schema management, settings integration, and ecosystem features.

Depends on: v0.29.2 (DB extensions — schema declarations must exist before versioning and migrations make sense).

  • Install creates schema + mounts routes + serves assets in one operation (extends v0.28.7 install with v0.29.2 schema support)
  • Schema versioning: "schema_version": N in manifest
  • Schema migrations: "migrations": [{"from": 1, "to": 2, "sql": "..."}]
  • Settings extension point: packages declare settings sections in manifest, platform settings surface renders them alongside core sections
  • Export/import format for sharing packages across instances
  • Package marketplace (discovery, not hosting — instances pull from URLs)

v0.30.1 — SDK Adoption

Migrate core surfaces to consume the SDK instead of raw globals. Prerequisite for the Editor Package — if the platform's own surfaces don't use sw.*, the SDK isn't validated for real.

The goal: a bug fix in sw.notes() or sw.chat() propagates to every surface automatically. No more duplicated wiring, no more "fixed on chat but broken on editor" class of bugs.

Depends on: v0.28.5 (SDK exists), v0.30.0 (package lifecycle — settings extension point needed for surface-specific config).

Component factories:

  • sw.notes(container, opts) — real factory: creates NoteEditor, note list, graph panel. Extracted from notes.js monolith into self-contained mountable component. opts: { projectId, channelId, onLink, standalone }. Returns instance with destroy().
  • sw.chat(container, opts) — extend existing wrapper with pipe integration (stream/render filters auto-wired), model selector binding, file upload, typing indicator. Currently thin wrapper around ChatPane.create() — needs to become the canonical path.
  • sw.panels(container, opts) — PaneContainer composition via SDK. Resize, tab management, drag handles. Fixes the "scaling bug lives in two places" problem — one implementation, one fix.

Core surface migration:

  • Chat surface (app.js, chat.js): boot via sw = Switchboard.init(), replace direct API.* / Events.* / UI.* calls with sw.* in new code paths. Existing code keeps working (globals still exist). Progressive — not a rewrite, just new code uses the SDK.
  • Editor surface (editor-surface.js): mount chat pane via sw.chat(), mount notes via sw.notes(), consume sw.theme.on('change') for CM6 theme sync. Removes duplicated panel resize/scale wiring.
  • Notes surface: mount via sw.notes(), share implementation with chat sidebar notes panel.
  • Settings surface: consume sw.api.* and sw.theme.*.

Validation:

  • Existing ICD runner tests still pass (surfaces behave identically)
  • ICD runner sdk tier extended with component mount/destroy tests
  • Manual: chat, editor, notes surfaces all function after migration
  • Bug fix propagation test: fix applied to sw.notes() visible on both chat sidebar and notes surface simultaneously

v0.30.2 — Workflow Packages

Workflows become packageable. Each stage can serve its own surface — form, dashboard, chat, or custom UI. Team admins build and manage workflows through a visual builder, not JSON editing.

Depends on: v0.29.3 (workflow forms — form rendering exists), v0.30.0 (package lifecycle — schema versioning, settings extension point), v0.30.1 (SDK adoption — stage surfaces consume sw.*).

Stage surfaces:

  • A workflow stage can reference a surface (built-in or from a .pkg). Stage config gains surface_id field — platform mounts that surface when the stage is active, with stage data injected as context
  • Built-in stage surfaces: form (v0.29.3 form renderer), chat (current behavior), review (operator sees collected data + approve/reject)
  • Custom stage surfaces: a .pkg with type: "workflow-stage" provides a surface that receives stage data and emits advance/reject signals via sw.workflow.advance(data) / sw.workflow.reject(reason) SDK calls
  • Stage transitions respect surface completion — surface signals "done" with structured data, workflow engine merges and advances

Workflow-as-package:

  • .pkg with type: "workflow": bundles workflow definition, stage surfaces, Starlark handlers, and assets in one installable archive. POST /admin/packages/install creates the workflow + stages + surfaces
  • Manifest "workflow" key: stages, transitions, form schemas, surface refs, on_complete hooks. Replaces manual workflow creation via admin API
  • Version pinning: installed workflow package tracks its package version. Upgrade re-publishes with new version number

Team admin workflow builder:

  • Visual stage editor: drag-to-reorder stages, per-stage config panel (surface type, persona, form fields, transition rules, assignment)
  • Form builder integrated per stage (extends v0.29.3 admin form builder)
  • Preview: team admin can walk through the workflow as a visitor would, seeing each stage surface in sequence
  • Publish/version from the builder UI — no JSON, no API calls
  • Team admin permission: workflow.manage — team admins can create, edit, publish workflows for their team. Global admin can create global workflows. Regular users can only enter workflows, not build them

SDK extensions:

  • sw.workflow namespace: advance(data), reject(reason), getData(), getStage(), onTransition(fn) — stage surfaces interact with the workflow engine through the SDK, not raw API calls

v0.31.0 — Editor Package

Rebuild the editor as an installable .pkg package. Zero platform special-casing — same POST /admin/packages/install, same manifest, same /s/:slug route as any third-party package. If pages.go or main.go need changes to support it, the platform abstraction is wrong, not the editor.

Validates the full v0.28.7v0.30.2 stack E2E: unified packaging, Starlark handlers, DB extensions, package lifecycle, SDK adoption, and workflow packages all exercised by one real-world package.

Depends on: v0.30.2 (workflow packages — editor validates the full stack including workflow stage surfaces).

Platform primitives consumed (not owned):

  • CM6 (core UI primitive — chat input, notes, code blocks all use it)
  • Workspace tools (workspace_ls, workspace_read, workspace_write)
  • Git tools + credentials (v0.28.0 — core settings, vault-encrypted)
  • Provider resolution via requires_provider (v0.29.1)

Package delivers:

  • Editor .pkg archive (type: full): manifest, JS, CSS, Starlark handlers
  • Built separately, installed via admin API — follows exact same patterns as any other package
  • Editor settings section (via v0.30.0 settings extension point): keybindings (vim/emacs/standard), font size, editor theme
  • Editor state persistence via ext_editor_* tables: open tabs, cursor positions, split layout, per-workspace config
  • File tree, tab bar, multi-pane layout — all via package JS, consuming platform CSS custom properties
  • Markdown preview (improved renderer, shared with notes surface)
  • Remove editor from core: delete surface-editor template, "editor" manifest in pages.go, "editor" data loader, editor-surface.js

TBD (unscheduled — real features, no immediate need)

Items that are real but don't yet have a version assignment. Pull left based on need.

Surfaces + Editor

  • Article drag-to-reorder outline sections
  • Article-specific AI tools: suggest_outline, expand_section, check_citations
  • Mobile: mode selector collapses to hamburger/bottom nav
  • Surface IDE: built-in surface for building surfaces (Go template editor, JS/CSS editor, live preview in sandboxed region)
  • Project-bound surface/pane defaults: project config specifies which panes are available and default layout

Workspace + Git

  • Integration tests: clone, commit, push/pull cycle (requires git binary in CI)

Provider Health + Routing

  • Latency-aware routing: track response time percentiles, prefer faster providers
  • Cost-aware routing with budget ceiling per request
  • Provider profile editor: key-value config per provider type, preview of effective settings
  • Fallback chain visualizer: drag-to-reorder provider priority per model family

Extensions

  • Image generation tool (browser or sidecar, provider-agnostic)
  • STT/TTS (browser extension, Web Speech API)
  • Code execution sandbox (server-side, container isolation)
  • Sidecar HTTP tool protocol (Tier 2 — container isolation)

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
  • Admin settings team/user export (user export blocked by vault-encrypted BYOK keys; team export needs merge-vs-replace semantics)

UX / Multi-Seat

  • "Group" scope badge on model selector / KB list: access-source annotation so users see why they have access (global, team, group grant)
  • Multi-tenant SaaS mode
  • Plugin/extension marketplace

Projects

  • /p/:id — shared project view
  • Project-specific files: full project-level upload (own endpoint, storage path)
  • Project templates: create from predefined configurations
  • Project creation dialog: replace prompt() with proper modal
  • Admin-level project management: cross-instance visibility, ownership reassign
  • Sub-projects / nested hierarchy

Knowledge Bases

  • 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

Memory

  • Memory export/import: portable memory format across instances
  • Cross-persona memory sharing (opt-in)
  • Memory analytics: dashboard showing what Personas are learning, growth trends

Platform

  • Rate limiting per user/team/tier (token budgets beyond current group budgets)

Pre-1.0 — Code Quality Sweeps

Codebase-wide refactors required before 1.0. Not tied to a feature version — pull left when touching the affected code, or schedule a dedicated pass.

SELECT * → Explicit Column Lists All store implementations use SELECT * FROM <table> with positional rows.Scan(). If a migration adds a column, every scan breaks silently at runtime (wrong column mapped to wrong field). Every scanOne/scanMany helper needs explicit column lists. Scope: every store file in store/postgres/ and store/sqlite/.

Raw SQL Hunt Several handlers execute raw SQL via database.DB.Exec / database.TestDB.Exec instead of going through the store interface. These bypass the dialect abstraction and are a source of PG/SQLite divergence bugs. Known instances:

  • handlers/channels.go — inline channel queries with pq.Array
  • handlers/workflows.go — inline unique constraint string matching
  • handlers/participants.goisDuplicateErr string matching (should use database.IsUniqueViolation)
  • knowledge/ handlers — direct database.DB.ExecContext for storage key updates Full sweep: grep for database.DB.Exec, database.TestDB.Exec, DB.QueryRow outside of store/ packages. Move to store methods or use existing dialect-safe helpers.