# Switchboard Core — Roadmap ## Current: v0.4.4 — Rich Editor + Import/Export Fork of chat-switchboard, gutted to a pure extension platform. All AI/chat features removed from the kernel. What remains is the minimum viable platform that extensions build on. ### Retained kernel capabilities - **Auth**: builtin (simple), mTLS, OIDC - **Identity**: users, teams, groups, permissions (RBAC) - **Packages**: surfaces, extensions, libraries, workflows - **Starlark sandbox**: capability-gated modules - **Storage**: object storage (PVC, S3), ext_data tables - **Realtime**: WebSocket hub, presence, multi-replica HA - **Ops**: audit log, notifications, maintenance goroutine ### Phase 0 (complete) | Step | Status | Description | |------|--------|-------------| | 1. Module rename | ✅ | `chat-switchboard` → `switchboard-core` | | 2. Delete packages | ✅ | 15 Go packages, 29 handler files removed | | 3. Gut stores/models | ✅ | 40 → 20 store interfaces, kernel-only models | | 4. Fresh migrations | ✅ | 9 files × 2 dialects, 27 tables | | 5. Fix compilation | ✅ | `go build ./...` clean, 300+ stale route lines cut | | 6. Fix tests | ✅ | 8 test packages pass, ~12K stale test lines pruned | | 7. Frontend gut | ✅ | Shell + SDK only, 50+ files of chat/notes/projects code removed | | 8. New ICD | ✅ | Full OpenAPI 3.0.3 spec — 160 operations across 22 tag groups | | 9. CI/CD + Dockerfile | ✅ | Single unified image, FE/BE split removed, DB names updated, k8s var alignment fixes (resource quantities, image name, rollout deployment name) | | 10. Smoke test | ✅ | K8s deploy live at switchboard.gobha.ai/test, nginx BASE_PATH fixed, login→admin flow verified, branding updated | ## v0.2.x — SDK & Triggers The contract that extensions build against. Three trigger primitives, SDK stabilization, and the first rebuilt extension (tasks). ### v0.2.0 — RBAC + Settings Cascade (complete) | Step | Status | Description | |------|--------|-------------| | Admin → RBAC group | ✅ | `surface.admin.access` permission + Admins system group replaces `role == "admin"` checks. Admin bypass removed from permission middleware. | | Settings cascade | ✅ | `user_overridable` flag, three-tier resolution (global → team → user), team settings API | | ~~Settings override model~~ | ✅ | Shipped with settings cascade above | ### v0.2.1 — Default Surface + ICD | Step | Status | Description | |------|--------|-------------| | Default surface routing | ✅ | `/` redirects to configurable default surface. No surfaces → admin. First install becomes default. Changeable in admin settings. | | ICD (API contract) | ✅ | Full OpenAPI 3.0.3 spec — 160 operations, 22 tag groups, reusable component schemas. Served at `/api/docs`. | ### v0.2.2 — Event Bus + Triggers | Step | Status | Description | |------|--------|-------------| | Event bus subscriptions | ✅ | Extensions register event patterns in manifest. Wired via `bus.Subscribe()` on startup. Async handler invocation. | | Webhook triggers | ✅ | Inbound HTTP at `/api/v1/hooks/:package_id/:slug`. HMAC-SHA256 verification. Synchronous Starlark handler response. | | Scheduled tasks | ✅ | User-created cron tasks with restricted sandbox (no raw HTTP, no DB table creation). Runs as creator identity. Templates from extensions. Dedicated schedules API. | | Trigger admin API | ✅ | CRUD for triggers + schedules. Enable/disable, execution logs, per-package listing. | ### v0.2.3 — SDK + Task Extension | Step | Status | Description | |------|--------|-------------| | SDK stabilization | ✅ | `sw.api.ext()`, `sw.storage`, `sw.theme.tokens`, `sw.ui`, `sw.slots`, `sw.actions` — six new SDK modules for extension development | | Task extension | ✅ | Full task surface rebuilt as Starlark extension: CRUD API, kanban/list views, event triggers, webhook integration, notifications on completion | ### v0.2.4 — Shell Navigation + Schedules | Step | Status | Description | |------|--------|-------------| | SDK Topbar | ✅ | `sw.shell.Topbar` — composable navigation bar (title + extension slot + bell + user menu). Surfaces get consistent nav for free. | | Schedules surface | ✅ | New `packages/schedules/` wrapping kernel cron API. Table view, cron preview, enable/disable, manual run, execution logs. | | Manifest icons | ✅ | `icon` field in manifest.json (emoji). Surfaces API returns icon. UserMenu renders per-surface icons. | | UserMenu cleanup | ✅ | Removed dead Chat/Notes/Projects links. Menu driven by surfaces API. Core surfaces filtered. | | isAdmin RBAC fix | ✅ | `can.js` isAdmin() now checks `surface.admin.access` grant instead of deprecated role column. | ### v0.2.5 — UI Polish + Dead Code Audit | Step | Status | Description | |------|--------|-------------| | UI bug pass | ✅ | Reviewed admin, settings, login, welcome surfaces in light/dark themes. Fixed settings crash (models API undefined). Removed dead chat settings from both user and admin settings. | | Dead code sweep | ✅ | Removed ~700 lines: orphaned CSS, dead Go types, stale event code, unused test helpers, dead settings UI (chat defaults, system prompt, default model, policies, web search, compaction, memory). | | Template cleanup | ✅ | Removed stale CSS link tags and orphaned chat-pane.html. Updated doc comments throughout. | | Package proof-of-concept status | ✅ | Created README.md for tasks + schedules with graduation criteria. Added missing manifest icons. | | Welcome surface | ✅ | New fallback surface when no extensions installed. Topbar + welcome card with admin link. Replaces `/admin` as final redirect target. | | Default surface routing | ✅ | Resolution chain: user preference → global config → first extension → `/welcome`. Users can set personal default in Settings > General. Admin sets global default in Admin > Settings. | | Admin navigation | ✅ | Replaced Back button with UserMenu in admin topbar. Eliminates back-button infinite loop. | ### v0.2.6 — Admin Settings Audit | Step | Status | Description | |------|--------|-------------| | Admin settings E2E | ✅ | All 7 admin settings sections verified (default surface, registration, banner, message bar, footer, vault, email). Dead code removed: `sectionCategory()` pruned of AI/routing/channel vestiges, `PublicSettings()` stripped of chat-era fields (system_prompt, retention_ttl, paste_to_file, allow_user_personas), dead `PolicyDefaults` removed (allow_raw_model_access, default_model), dead policy lookups removed (kb_direct_access), test seed data cleaned. | | Packages surface | ✅ | Package list loads (17 total/17 enabled), type filters work, enable/disable visible, settings/export buttons present, core package (admin) protected. Removed dead `chat` from CORE_IDS. | ### v0.2.7 — User Settings Audit | Step | Status | Description | |------|--------|-------------| | User settings E2E | ✅ | All 6 user settings sections verified (General, Appearance, Profile, Teams, Connections, Notifications). Dead code removed: BYOK nav section + state, personas gate filter, Message Font Size slider, `auth.permissions.changed` listener. localStorage key renamed `cs-appearance` → `sb-appearance` with one-time migration. | | Visibility gating | ✅ | Dead BYOK/personas policy lookups removed from bootstrap and permissions handlers. `allow_user_byok` removed from `PublicSettings`. `PolicyDefaults` cleaned of `allow_user_byok` and `allow_user_personas`. Dead `msgFont` early-apply removed from base template. Stale policy-gating test assertions replaced. No empty nav sections remain. | ### v0.2.8 — Team Admin Settings Audit (Pass 1) | Step | Status | Description | |------|--------|-------------| | Team admin E2E | ✅ | Audited team member management, settings cascade, role assignment. Removed dead code: `HasPrivateProviderRequirement` (BYOK vestige), `UserRole` on `TeamMember` (deprecated role column), `allow_team_providers` policy default, dead personas/providers/models ICD tests. | | Workflow stage UI cleanup | ✅ | Removed dead personas dropdown, `history_mode` selector, stale `chat_only` mode. Updated `STAGE_MODES` to match backend CHECK constraint (`form_only`, `form_chat`, `review`, `custom`). Removed stale comments referencing deleted files. | ### v0.2.9 — Builtin Extension Retirement | Step | Status | Description | |------|--------|-------------| | Retire builtin seeder | ✅ | Removed `SeedBuiltinPackages`, `seed_packages.go`, Dockerfile COPY, and `extensions/builtin/` directory. These extensions are dormant until a chat surface exists to consume them. | | Convert to regular packages | ✅ | Repackaged 6 extensions as standard directories in `packages/` with `js/` layout and `"requires": ["chat"]` manifest metadata. Built via `build.sh` like all other packages. No auto-install — explicit install only. | ## v0.3.x — Workflow Architecture Workflows are the core platform capability. This series implements the full multi-step automation system with team role integration and finalizes the extension lifecycle model. ### v0.3.0 — Schema Redesign + Stage CRUD Modernization (complete) | Step | Status | Description | |------|--------|-------------| | Workflow schema redesign | ✅ | Dropped `persona_id`, `history_mode` from `workflow_stages`. Renamed `transition_rules` → `stage_config`. Updated `stage_mode` CHECK to `(form, review, delegated, automated)`. Added `audience`, `stage_type`, `starlark_hook`, `branch_rules`. Both PG + SQLite. | | Model + store updates | ✅ | Go structs, constants, and PG/SQLite queries updated. New `ValidStageTypes`, `ValidAudiences` maps. Routing engine reads `branch_rules` directly. | | Handler + Starlark updates | ✅ | Stage CRUD validation for new fields. Package export/import updated. Hook handler reads `stage_config`. Starlark module exposes `audience`, `stage_type`. | | Frontend updates | ✅ | Team-admin and admin stage editors updated with new modes, audience selector, stage type selector, conditional Starlark hook input. Fixed admin `STAGE_MODES` bug. | ### v0.3.1 — Instance + Assignment Tables + Store (complete) | Step | Status | Description | |------|--------|-------------| | Instance schema | ✅ | `workflow_instances` table in 007_workflows.sql (PG + SQLite). Tracks execution state: workflow_version, current_stage, stage_data, status, entry_token. | | Assignment schema | ✅ | `workflow_assignments` table. Per-stage queue: instance_id, stage, team_id, assigned_to, status, review_data. Optimistic claim lock. | | Models + store interface | ✅ | `WorkflowInstance`, `WorkflowAssignment` structs. 15 store methods for instance lifecycle and assignments across PG + SQLite. | | Event types | ✅ | `workflow.started`, `workflow.cancelled`, `workflow.error` added to bus route table. | ### v0.3.2 — Workflow Engine + Handlers (complete) | Step | Status | Description | |------|--------|-------------| | Store tests | ✅ | Round-trip tests for all 15 v0.3.1 store methods (instance + assignment CRUD). TruncateAll updated for new tables. | | Stage execution engine | ✅ | `server/workflow/engine.go` — Start, Advance (with branch_rules), Cancel. Merges stage_data, creates assignments, emits events. | | Automated stages | ✅ | `server/workflow/automated.go` — fire Starlark hook, auto-advance, cycle guard (max 10 consecutive). | | Instance handlers | ✅ | HTTP API: Start, GetInstance, Advance, Cancel, ListInstances. Team-scoped mirrors. | | Assignment handlers | ✅ | HTTP API: Claim, Unclaim, Complete, Cancel, ListByTeam, ListMine. Claimer identity verification. | | Starlark module expansion | ✅ | `workflow.get_instance()`, `workflow.list_instances()` (read-only). Mutating builtins deferred pending interface extraction. | ### v0.3.3 — Public Entry + Background Jobs (complete) | Step | Status | Description | |------|--------|-------------| | Public entry | ✅ | `StartPublic`, `ResumePublic`, `AdvancePublic` — token-based anonymous workflow participation. Public routes at `/api/v1/public/workflows/`. Audience-gated: only `public` stages can be advanced anonymously. | | SLA scanner | ✅ | Background goroutine (5-min interval) checking active instances against per-stage `sla_seconds`. Fires `workflow.sla_breach` event, marks breach in instance metadata (idempotent). | | Staleness sweep | ✅ | Per-workflow `staleness_timeout_hours` column. Scanner marks idle instances as `stale`, cancels open assignments, fires `workflow.stale` event. | ### v0.3.4 — Team Roles + Multi-party Validation (complete) | Step | Status | Description | |------|--------|-------------| | Team roles | ✅ | Removed CHECK constraint on `team_members.role`. Custom roles stored in `teams.settings["roles"]`. Team roles API (`GET/PUT /teams/:teamId/roles`). Role-based stage assignment via `stage_config.required_role`. Frontend: dynamic role selects, role management panel. | | Multi-party sign-off | ✅ | `workflow_signoffs` table (both dialects). `StageConfig.validation` with `required_approvals`, `required_role`, `reject_action`. Engine validation gate in `advanceInternal`. `SubmitSignoff` engine method. Signoff HTTP API (`POST/GET /instances/:iid/signoffs`). Frontend signoff panel in monitor tab. | | Extension lifecycle | ✅ | Design doc: `docs/DESIGN-EXTENSION-LIFECYCLE.md`. Permanent vs PoC classification, graduation criteria, install model. | | Trigger composition | ✅ | Design doc: `docs/DESIGN-TRIGGER-COMPOSITION.md`. Triggers/schedules can start workflows, workflows emit events, no circular invocation. | ### v0.3.5 — Settings Audit + ICD + Tests | Step | Status | Description | |------|--------|-------------| | Clone endpoint | ✅ | `POST /api/v1/workflows/:id/clone` — deep copy workflow + stages. Handler-level composition of existing store methods. | | Integration tests | ✅ | 7 engine-level tests in `workflow_engine_test.go`: full lifecycle, branch routing, public entry, signoff gate, rejection, cancel-clears-assignments, error cases. 28 total tests. | | Settings audit pass 2 | ✅ | Added `staleness_timeout_hours` field to workflow editor. Added collapsible branch_rules JSON editor in stage form. | | ICD update | ✅ | Fixed stale Workflow/Stage schemas. Added WorkflowInstance, WorkflowAssignment, WorkflowSignoff schemas. Added ~20 new endpoints: instances, assignments, signoffs, public entry, clone, team roles. | ### v0.3.6 — Example Workflows + Interactive Demo Four installable `.pkg` workflow packages that prove the engine works end-to-end, plus a demo surface for guided exploration. See `docs/DEMO-WORKFLOWS.md` for full stage definitions and Starlark code. | Step | Status | Description | |------|--------|-------------| | Bug Report Triage | ✅ | Public entry, progressive fieldsets, severity-based branch routing, team assignment, SLA timer. Pure-manifest `.pkg`. | | Employee Onboarding | ✅ | Starlark automated stages (`db.insert`, `notifications.send`), signoff gate with `required_role`, rejection reroute. `.pkg` with `script.star`. | | Content Approval | ✅ | Multi-party signoff (quorum of 2), rejection reroute creating review cycle. `.pkg` demonstrating signoff + reroute loop. | | Webhook Notifier | ✅ | Starlark `http.post` + `connections.get` for outbound webhooks, delivery logging to ext_data. Proves HTTP + connections modules. | | Demo surface | ✅ | Browser-tier walkthrough: workflow cards, stage diagrams, Starlark viewer, "Try It" buttons, API curl examples. Auto-installed, removable. | | Engine context fix | ✅ | Add `started_by` to automated stage Starlark context dict (backward-compatible). | | SLA package installer | ✅ | Added `sla_seconds` support to `workflowPkgStage` struct and install/export paths. | | Snapshot format fix | ✅ | `parseSnapshotStages` helper handles both wrapped and legacy snapshot formats. | | Workflow adoption | ✅ | `POST /teams/:teamId/workflows/:id/adopt` + `GET .../available`. Team-admin "Adopt Global" button. `TeamID` in `WorkflowPatch`. | | Extension SDK boot | ✅ | `base.html` loads Preact globals + `boot()` for extension surfaces (was missing since Scorched Earth IV). | | Admin teams tab fix | ✅ | Extract `.data` from paginated response in admin teams list. | | Documentation | ✅ | `docs/DEMO-WORKFLOWS.md`: feature capability matrix, stage flows, API walkthrough, per-package READMEs. | | Review pass | | Docker E2E walkthrough: install all packages, adopt into team, activate, publish, run each workflow end-to-end. Fix remaining UI/UX issues. | ### v0.3.7 — Package Audit (complete) Verified all 16 packages install correctly. Packages with unmet `requires` auto-set to dormant. | Step | Status | Description | |------|--------|-------------| | Manifest fixes | ✅ | Fixed 6 chat-extension manifests (`"name"` → `"title"`, was blocking install). Added explicit `"type": "surface"` to hello-dashboard, icd-test-runner, sdk-test-runner. | | Dormant status | ✅ | Added `dormant` to `packages.status` CHECK constraint (both dialects). Installer auto-detects unmet `requires` and sets `status=dormant, enabled=false`. Enable endpoint returns 409 for dormant packages. | | Functional audit | ✅ | Navigated to every surface in browser. 7 working: schedules, tasks, team-activity-log, git-board, hello-dashboard, icd-test-runner, sdk-test-runner. 2 broken: dashboard + editor (depend on removed `sw.*` imperative SDK) — tagged `requires: ["legacy-sdk"]` → dormant. | | Chat-dependency tagging | ✅ | 6 chat-dependent extensions (csv-table, diff-viewer, js-sandbox, katex-renderer, mermaid-renderer, regex-tester) install as dormant. git-board and gitea-client are standalone. | | Dependency check fix | ✅ | Relaxed library dependency validation to allow `pending_review` libraries (gitea-client declares permissions). Only `suspended`/`dormant` libraries blocked. | | Admin UI | ✅ | Dormant badge, disabled Enable button with tooltip, Dormant stat card in admin packages view. | | Tests | ✅ | 4 handler tests (SetStatus dormant, enable blocked, surfaces exclude dormant, admin list includes dormant). All existing tests pass. | ### v0.3.8 — Distribution Builder image for faster builds, bundled packages for zero-config first run. | Step | Status | Description | |------|--------|-------------| | Builder image | ✅ | `Dockerfile.builder` with cached Go modules + Node vendor libs for faster custom builds. | | Bundled packages | ✅ | Dockerfile stage builds all 12 non-dormant packages into production image. `InstallBundledPackages` auto-installs on first run (skip-if-present). `SKIP_BUNDLED_PACKAGES=true` to disable. `BUNDLED_PACKAGES` allowlist for selective install (Helm/K8s). Migration 012 adds `bundled` source to CHECK constraint. | | Distribution docs | ✅ | `docs/DISTRIBUTION.md` — quick start, bundled packages, builder image, custom builds, production deployment. | | Tests | ✅ | 6 handler tests (fresh install, skip existing, missing dir, empty dir, dormant handling, allowlist filtering). All existing tests pass. | ## v0.4.x — Notes Surface Obsidian-style notes rebuilt as an installable surface package. Zero platform special-casing. Proves the full extension stack E2E. ### v0.4.0 — Core Notes CRUD + Markdown Editor | Step | Status | Description | |------|--------|-------------| | Package scaffold | ✅ | `packages/notes/` with manifest, script.star, JS, CSS, README. Type: full, tier: starlark. | | Notes CRUD backend | ✅ | Starlark `on_request()` — list, create, get, update, delete, search, stats. Lightweight list projection (no body). | | Notes table | ✅ | `ext_notes_notes` — title, body (TEXT), folder_id, pinned, archived, creator_id, updated_at. | | Markdown editor | ✅ | Preact+htm frontend: sidebar note list, title input, markdown textarea, auto-save (1s debounce). | | Live preview | ✅ | Inline markdown renderer (~100 lines): headings, bold, italic, code, links, lists, blockquotes, hr. | | Search | ✅ | Client-side LIKE search over title/body. Search bar in sidebar. | | Pin/archive | ✅ | Pin notes to top, soft-delete via archive, hard delete with `?hard=1`. | ### v0.4.1 — Folders + Navigation Tree (complete) | Step | Status | Description | |------|--------|-------------| | Folders table | ✅ | `ext_notes_folders` — name, parent_id, creator_id, sort_order. Indexed on parent_id and creator_id. | | Folder CRUD API | ✅ | 5 Starlark handlers: list, create, update, delete folders + `POST /notes/move`. Delete cascade orphans notes and reparents child folders. | | Folder tree UI | ✅ | `FolderTree` + `FolderNode` components. Flat-to-tree builder, expand/collapse, depth indentation, inline rename via context menu. | | Folder filtering | ✅ | Click folder → filter notes. "All Notes" / "Unfiled" virtual views. New notes inherit active folder. | | Editor folder select | ✅ | Dropdown with nested hierarchy (`└` prefix). Moves notes between folders via move-note API. | | Updated stats | ✅ | Stats include `unfiled` and `folders` counts. | ### v0.4.2 — Tags + Search (complete) | Step | Status | Description | |------|--------|-------------| | Tags table | ✅ | `ext_notes_tags` — note_id, tag. Indexed on both columns for bidirectional lookup. | | Tag CRUD API | ✅ | 3 Starlark handlers: list all unique tags, get tags for note, replace tags for note (delete+reinsert). Tags normalized: lowercase, trimmed, deduped. | | Tags in list/get/search | ✅ | `_list_notes` batch-fetches all tags in one query, attaches `tags` array to each item. `_get_note` includes tags. `_search_notes` matches against tags. | | Tag cascade delete | ✅ | Hard-deleting a note also deletes its tag rows. Stats include `tags` count. | | Tag input in editor | ✅ | `TagInput` component: removable pills + text field, comma/Enter to add, autocomplete dropdown from all tags. | | Tag pills on cards | ✅ | `NoteCard` renders up to 3 tag pills with "+N" overflow. | | Tag filter in sidebar | ✅ | `TagFilter` component: clickable pills, toggle active tag, client-side note filtering. | | Drag-and-drop | ✅ | `NoteCard` is draggable. `FolderNode`, "All Notes", and "Unfiled" are drop targets. Uses existing move-note API. | | Folder context menu | ✅ | Replaced `prompt()` hack with proper right-click popup menu: Add subfolder, Rename, Delete. Positioned at click coordinates, dismissed on outside click. | ### v0.4.3 — Backlinks + Wikilinks (complete) | Step | Status | Description | |------|--------|-------------| | Links table | ✅ | `ext_notes_links` — source_id, target_id, link_text. Indexed on both source_id and target_id for bidirectional lookup. | | Wikilink extraction | ✅ | `_extract_wikilinks()` parses `[[...]]` using `split("[[")` + `find("]]")` (no regex/while in Starlark). Deduplicates by lowercase. | | Link sync on save | ✅ | `_sync_links()` called from `_create_note` and `_update_note`. Delete-all + reinsert pattern (matches tags). Resolves titles to note IDs (case-insensitive). Unresolved links stored with `target_id=""`. | | Cascade delete | ✅ | Hard-deleting a note removes both outgoing links (source_id) and incoming backlinks (target_id). | | Link endpoints | ✅ | `GET /links/:note_id` (outgoing) and `GET /backlinks/:note_id` (incoming, enriched with source titles). | | Wikilink preview | ✅ | `[[Note Title]]` rendered as clickable accent-colored links in markdown preview. Unresolved links styled in danger/red. | | Wikilink navigation | ✅ | Clicking a resolved wikilink navigates to the target note. Clicking an unresolved (red) link creates the note, navigates to it, and re-saves the source so the link resolves. | | Backlinks panel | ✅ | Collapsible panel below editor showing all notes linking to current note. Click to navigate. Hidden when empty. | | Stats update | ✅ | `/stats` includes `links` count. Notes package version bumped to 0.4.0. | ### v0.4.4 — Rich Editor + Import/Export (complete) | Step | Status | Description | |------|--------|-------------| | CM6 integration | ✅ | Load vendored CodeMirror 6 bundle via dynamic `