All checks were successful
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
35 KiB
35 KiB
Changelog
All notable changes to Switchboard Core are documented here.
v0.4.0 — Notes Surface
Added
- Notes surface package (
packages/notes/): Obsidian-style markdown notes rebuilt as a standard installable.pkgarchive. Typefull, tierstarlark. Zero kernel changes — proves the extension stack end-to-end. - Starlark backend (
script.star): 7 API routes — CRUD, search, stats. Note bodies stored inext_notes_notesTEXT columns. List endpoint returns lightweight projections (no body); full content fetched on select. - Markdown editor: Preact+htm frontend with sidebar note list, monospace textarea, and toggle-able live preview. Inline markdown renderer (~100 lines) covers headings, bold, italic, code blocks, links, lists, blockquotes, and HR.
- Auto-save: Debounced save (1s) with dirty/saved status indicator.
Ctrl/Cmd+Sfor force save. Tab key inserts two spaces. - Pin & archive: Pin important notes to the top of the list. Archive
(soft-delete) via the delete button; hard delete with
?hard=1query param. - Search: Case-insensitive full-text search across title and body content. Search bar in sidebar filters the note list in real-time.
- Theme support: All styles use CSS variables — light and dark themes work out of the box. Responsive layout collapses to vertical on narrow viewports.
Data model
| Table | Columns |
|---|---|
ext_notes_notes |
title, body, folder_id, creator_id, updated_at, pinned, archived |
Indexes on folder_id, creator_id, pinned, updated_at.
Planned (v0.4.1–v0.4.4)
- Folders + navigation tree
- Tags + enhanced search
- Backlinks +
[[wikilinks]] - Rich editor (CodeMirror 6) + markdown import/export
v0.3.8 — Distribution
Added
- Bundled packages: Production Docker image now ships with 12 pre-built
.pkgarchives (4 workflows, 3 surfaces, 1 full, 1 library, 2 test runners, 1 extension). Auto-installed on first boot viaInstallBundledPackages(). Install-once, skip-if-present — admin uninstalls are respected on restart. - Package allowlist (
BUNDLED_PACKAGES): Comma-separated list of package IDs to install. Empty (default) installs all. Useful for Helm/K8s where different environments need different packages. - Skip bundled (
SKIP_BUNDLED_PACKAGES=true): Disables auto-install entirely. Intended for production until post-MVP packages are ready. - Builder image (
Dockerfile.builder): Pre-caches Go modules, Node dependencies, and vendor lib tarballs for faster custom builds. - Distribution docs (
docs/DISTRIBUTION.md): Quick start, bundled packages, builder image usage, custom build guide, production deployment reference. - Migration 012: Adds
bundledtopackages.sourceCHECK constraint (both Postgres and SQLite). - K8s manifest:
SKIP_BUNDLED_PACKAGESandBUNDLED_PACKAGESenv vars added tok8s/switchboard.yaml. - Tests: 6 handler tests (fresh install, skip existing, missing dir, empty dir, dormant handling, allowlist filtering).
Environment defaults
| Environment | SKIP_BUNDLED_PACKAGES |
BUNDLED_PACKAGES |
|---|---|---|
| Dev (compose) | false |
(empty = all) |
| Test (K8s) | false |
(empty = all) |
| Prod (K8s) | true |
— |
v0.3.7 — Package Audit
Added
- Dormant status: New
dormantvalue inpackages.statusCHECK constraint (both Postgres and SQLite). Installer auto-detects packages with unmetrequiresentries and setsstatus=dormant, enabled=false. Enable endpoint returns 409 for dormant packages. - Generalized requires check: Any unmet requirement triggers dormant status, not just specific values. Known capabilities checked against a whitelist; anything unknown is unmet.
- Admin UI indicators: Dormant badge, disabled Enable button with tooltip, Dormant stat card in packages admin view.
- Tests: 4 new handler tests covering dormant status, enable blocking, surface exclusion, and admin list inclusion.
Fixed
- Manifest fixes: Fixed 6 chat-extension manifests (
"name"→"title") that were blocking install. Added explicit"type": "surface"to hello-dashboard, icd-test-runner, sdk-test-runner. - Dashboard + Editor tagged dormant: Both depend on removed
sw.*imperative SDK (sw.tabs,sw.chat,sw.layout, etc.) — render blank. Tagged withrequires: ["legacy-sdk"]so installer auto-sets dormant. - Dependency check: Relaxed library dependency validation to allow
pending_reviewlibraries (gitea-client declares permissions). Onlysuspended/dormantlibraries blocked.
Package Audit Results
- 7 working surfaces: schedules, tasks, team-activity-log, git-board, hello-dashboard, icd-test-runner, sdk-test-runner
- 8 dormant: 6 chat-dependent (csv-table, diff-viewer, js-sandbox, katex-renderer, mermaid-renderer, regex-tester) + 2 legacy-sdk (dashboard, editor)
- 1 library: gitea-client (standalone, active)
v0.3.6 — Example Workflows + Interactive Demo
Added
- Bug Report Triage (
packages/bug-report-triage): Public entry, progressive fieldsets, severity-based branch routing, SLA timer (3600s on critical fix). - Employee Onboarding (
packages/employee-onboarding): Starlark automated stages (db.insert,notifications.send), manager signoff gate withrequired_role, rejection reroute.script.starwithon_provisionandon_welcomehooks. Createsprovisionsandonboarding_logext_data tables. - Content Approval (
packages/content-approval): Multi-party signoff (quorum of 2), rejection reroute creating a review cycle loop. - Webhook Notifier (
packages/webhook-notifier): Starlarkhttp.postwithconnections.getfallback, delivery logging towebhook_logext_data table. - Workflow Demo surface (
packages/workflow-demo): Interactive walkthrough with workflow cards, stage flow diagrams, Starlark viewer, API curl examples, and "Try It" buttons. Route:/s/workflow-demo. - Engine context fix:
started_byadded to automated stage Starlark context dict, enabling hooks to reference the workflow initiator. - SLA package installer:
sla_secondsfield added toworkflowPkgStagestruct and wired in both install and export paths. - Snapshot format fix:
parseSnapshotStageshelper handles both wrapped ({"stages":[...]}) and legacy flat array snapshot formats in the engine, fixingcorrupt version snapshoterrors when starting published workflows. - Workflow adoption:
POST /teams/:teamId/workflows/:id/adoptclaims a global (team_id=NULL) workflow for a team.GET /teams/:teamId/workflows/availablelists adoptable workflows.TeamIDadded toWorkflowPatchmodel. - Tests: 3 new engine tests (automated context, SLA install, manifest roundtrip). Total: 142 handler tests passing.
- Per-package
README.mdfiles for all 5 new packages.
Fixed
- Demo surface: Added
sw.userMenuto topbar. Fixed workflow install detection (was reading wrong response key). CSS uses theme variables for dark mode support. - Admin teams tab: Extracted
.datafrom paginated response — was stuck at loading becausesetTeamsreceived the envelope object, not the array. - Team-admin workflows: Added "Adopt Global" button to claim package-installed workflows into a team scope. Workflow list now unwraps paginated responses.
v0.3.5 — Settings Audit + ICD + Tests + Clone
Added
- Clone endpoint:
POST /api/v1/workflows/:id/clonedeep-copies a workflow and all its stages. Creates an inactive draft with "Copy of" prefix. Handles slug collisions with auto-suffix. Team-scoped mirror at/api/v1/teams/:teamId/workflows/:id/clone. - Integration tests: 7 new engine-level tests in
workflow_engine_test.gocovering full lifecycle, branch routing, public entry, signoff validation gate, signoff rejection, cancel-clears-assignments, and error cases. Total: 28 tests. - Staleness timeout UI:
staleness_timeout_hoursinput added to workflow editor in team-admin settings (was backend-only since v0.3.3). - Branch rules UI: Collapsible JSON textarea in stage form for configuring conditional routing rules (was backend-only since v0.3.2).
Changed
- ICD (OpenAPI spec): Fixed stale
Workflowschema (addeddescription,branding,is_active,on_complete,retention,staleness_timeout_hours). Fixed staleStageschema (removedhistory_mode/transition_rules, updatedstage_modeenum to[form, review, delegated, automated], addedaudience,stage_type,starlark_hook,branch_rules,stage_config,sla_seconds,auto_transition,assignment_team_id,surface_pkg_id). AddedWorkflowInstance,WorkflowAssignment,WorkflowSignoffschemas. Added ~20 new endpoint paths: instances, assignments, signoffs, public entry, clone, and team roles. Added tags: Workflow Instances, Workflow Assignments, Workflow Signoffs, Public Workflows.
v0.3.4 — Team Roles + Multi-party Validation
Added
- Custom team roles: Removed
CHECK (role IN ('admin','member'))constraint fromteam_members(both Postgres and SQLite). Custom roles are stored inteams.settings["roles"]as a JSON array. Builtinsadminandmemberare always present. - Team roles API:
GET /api/v1/teams/:teamId/rolesreturns configured roles.PUT /api/v1/teams/:teamId/rolesreplaces the roles array (builtins enforced). - Role-based stage assignment:
stage_config.required_rolerestricts which team members can claim an assignment.CheckClaimRoleverifies the user's team membership role before allowing claim; rolls back on mismatch (403). - Multi-party sign-off: New
workflow_signoffstable withUNIQUE(instance_id, stage, user_id)preventing double-signing.StageConfig.validationsupportsrequired_approvals,required_role, andreject_action(cancel or reroute to named stage). - Validation gate:
advanceInternalblocks stage advancement until the required number of approvals is met. Rejections trigger cancel or reroute based onreject_action. Engine.SubmitSignoff: Records approval/rejection, enforces signoff role if configured, emitsworkflow.signoffevent.- Signoff HTTP API:
POST /api/v1/instances/:iid/signoffs(submit),GET /api/v1/instances/:iid/signoffs(list current stage signoffs). Team-scoped mirrors at/api/v1/teams/:teamId/instances/:iid/signoffs. - New events:
workflow.signoff,workflow.rejected. - Frontend — Members page: Dynamic role selects populated from team roles API. "Manage Roles" panel for adding/removing custom roles inline.
- Frontend — Stage editor: "Required Role (claim)" dropdown and "Multi-party Validation" section (required approvals, signoff role, on reject action) appear when a team is selected for the stage.
- Frontend — Monitor tab: Signoff panel with approve/reject buttons, comment field, and approval progress display.
- 3 new store tests: CreateSignoff (with UNIQUE constraint check), ListSignoffs (ordering), CountSignoffs (decision filter). 20 total, all passing.
- Design doc:
docs/DESIGN-EXTENSION-LIFECYCLE.md— permanent vs PoC packages, graduation criteria, explicit install model. - Design doc:
docs/DESIGN-TRIGGER-COMPOSITION.md— triggers/schedules can start workflows, workflows emit events, no circular invocation.
Changed
addMemberRequestandupdateMemberRequestbinding relaxed fromoneof=admin membertorequired,min=1,max=50with application-level validation against the team's configured roles.TruncateAlltest helper updated to includeworkflow_signoffs.
v0.3.3 — Public Entry + Background Jobs
Added
- Public workflow entry: Unauthenticated routes for anonymous workflow
participation.
POST /api/v1/public/workflows/:id/startcreates an instance withstarted_by = "public:<uuid>"and returns an entry token.GET .../resume/:tokenandPOST .../advance/:tokenallow continuation. Only stages withaudience = "public"can be advanced anonymously. - SLA scanner: Background goroutine (5-minute interval) checks active
instances against per-stage
sla_seconds. Firesworkflow.sla_breachevent on first breach, markssla_breached: truein instance metadata (idempotent). - Staleness sweep: New
staleness_timeout_hourscolumn onworkflows. Scanner marks instances asstalewhenupdated_atexceeds the threshold, cancels open assignments, firesworkflow.staleevent. - New store methods:
ListActiveInstances(),MarkInstanceStale(). - New events:
workflow.sla_breach,workflow.stale. - 3 new store tests: MarkStale, ListActive, StalenessTimeoutHours round-trip.
v0.3.2 — Workflow Engine
Added
- Stage execution engine:
server/workflow/engine.go—Start,Advance(withbranch_rulesconditional routing), andCanceloperations. Mergesstage_dataacross stages, creates assignments, emits lifecycle events. - Automated stage handler:
server/workflow/automated.go— fires Starlark hook, auto-advances on success, cycle guard (max 10 consecutive automated stages). - Instance HTTP API: Start, GetInstance, Advance, Cancel, ListInstances.
Team-scoped mirrors under
/api/v1/teams/:teamId/workflows/. - Assignment HTTP API: Claim, Unclaim, Complete, Cancel, ListByTeam, ListMine. Claimer identity verification on unclaim/complete.
- Starlark module expansion:
workflow.get_instance(),workflow.list_instances()(read-only). - 14 store tests covering all 15 v0.3.1 methods (instance + assignment CRUD). All passing.
v0.3.1 — Instance Assignment
Added
workflow_instancestable: Tracks workflow execution state —workflow_version,current_stage,stage_data,status,entry_token.workflow_assignmentstable: Per-stage queue for instance assignments —instance_id,stage,team_id,assigned_to,status,review_data. Optimistic claim locking via status transition.- 15 new store methods: Full CRUD for instances (Create, Get, GetByToken, Update, List, AdvanceStage, Complete, Cancel) and assignments (Create, Claim, Unclaim, Complete, Cancel, ListByTeam, ListByInstance, ListByUser).
- New events:
workflow.started,workflow.cancelled,workflow.error.
v0.3.0 — Workflow Schema Redesign
Changed
workflow_stagesschema modernized: Dropped chat-era columns (persona_id,history_mode). Renamedtransition_rules→stage_config. Updatedstage_modeCHECK from(form_only, form_chat, review, custom)to(form, review, delegated, automated).- New stage fields: Added
audience(team | public | system),stage_type(simple | dynamic | automated),starlark_hook(package_id:entry_point), andbranch_rules(JSONB array of routing conditions). - Routing engine:
ResolveNextStagenow readsbranch_rules(flat array) instead oftransition_rules.conditions(nested object). Cleaner separation between routing rules and stage config. - Hook handler:
FireOnAdvanceHookreads fromstage_configinstead oftransition_rules. RenamedchannelIDparameter toinstanceID. - Stage CRUD validation: New fields validated on create/update.
delegatedmode requiressurface_pkg_id.dynamic/automatedstage_type requiresstarlark_hook. - Package export/import: Updated to use new field names. Workflow packages
now include
audience,stage_type,starlark_hook,branch_rules,stage_config. - Starlark workflow module: Stage dicts now include
audienceandstage_typekeys. Removedhistory_modeandpersona_id. - Frontend stage editor: Both admin and team-admin surfaces updated with
new mode values, audience selector, stage type selector, and conditional
Starlark hook input. Fixed pre-existing bug in admin workflows.js where
STAGE_MODESstill containedchat_only.
Removed
persona_idcolumn fromworkflow_stages(personas are extension concerns)history_modecolumn fromworkflow_stages(chat-era context management)StageModeCustom,StageModeFormOnly,StageModeFormChatGo constants
v0.2.9 — Builtin Extension Retirement
Changed
- 6 builtin extensions → standard packages: csv-table, diff-viewer,
js-sandbox, katex-renderer, mermaid-renderer, and regex-tester moved from
extensions/builtin/topackages/with standardjs/layout. Each manifest now declares"requires": ["chat"]and"type": "extension". Built viabuild.shlike all other packages — no auto-install.
Removed
SeedBuiltinPackagesseeder: Deletedseed_packages.go(function,builtinManifeststruct,buildFullManifesthelper) and the startup call inmain.go. Extensions are no longer auto-seeded into the DB.extensions/builtin/directory: Removed from repo and Dockerfile COPY.- Seed tests: Removed 8
TestSeed_*functions andmakeSeedDirhelper fromextension_test.go(~220 lines). - Stale comments: Removed
SeedBuiltinPackagesreferences frompackage_iface.goandtrigger_sync.go.
v0.2.8 — Team Admin Settings Audit (Pass 1)
Removed
- Dead
HasPrivateProviderRequirement: Store method checked team settings forrequire_private_providers(BYOK vestige). Removed from interface, PostgreSQL, and SQLite implementations. No callers existed. - Dead
UserRolefield onTeamMember: Joinedusers.rolecolumn (deprecated in v0.2.0 RBAC migration). Removed from model,ListMembersandGetMemberqueries in both stores. Frontend never consumed it. - Dead
allow_team_providerspolicy: Removed fromPolicyDefaults, both test seed data blocks, and ICD test assertions. No handler or UI read it. - Dead personas in workflow stage UI: Removed
sw.api.teams.personas()call (endpoint doesn't exist), personas state, persona dropdown in StageForm, and persona badge in stage list. - Dead
history_modein stage UI: Removed history mode selector and state from StageForm. Backend column retained for v0.3.x schema migration. - Dead ICD tests: Removed assertions for
/teams/:teamId/personas,/teams/:teamId/providers, and/teams/:teamId/models— endpoints were removed in Phase 0 fork. - Stale
chat_onlystage mode: FrontendSTAGE_MODESupdated from['chat_only', 'form_only', 'form_chat', 'review']to['form_only', 'form_chat', 'review', 'custom']matching the backend CHECK constraint. - Stale comments: Removed references to deleted
team_providers.go,personas.go, andapiconfigs.gofiles.
v0.2.7 — User Settings Audit
Changed
- localStorage namespace: Renamed
cs-appearancekey tosb-appearanceacross appearance settings, base template, and workflow template. One-time migration preserves existing user preferences. - Policy-gating tests: Replaced stale
allow_user_byok/allow_user_personasassertions withallow_registrationcheck (the only policy still in admin UI).
Removed
- Dead BYOK nav section in user settings: empty
BYOK_ITEMSarray,byokEnabledstate, "BYOK Enabled" footer badge, and the nav group that rendered an empty section. - Dead personas gate:
personasEnabledstate and.filter()on NAV_ITEMS for agateproperty no items have.auth.permissions.changedlistener removed (existed solely for BYOK + personas state). - Dead Message Font Size: Slider,
msgFontstate, and--msg-fontCSS variable application from appearance section and base template. - Dead policy defaults:
allow_user_byokandallow_user_personasremoved fromPolicyDefaults, profile bootstrap, permissions handler, andPublicSettings. Test seed data cleaned.
v0.2.6 — Admin Settings Audit
Changed
- Roadmap reorder: Extension Lifecycle moved from v0.2.6 to v0.3.x (Workflows series). Settings audit milestones renumbered: v0.2.7→v0.2.6, v0.2.8→v0.2.7, v0.2.9→v0.2.8. Added v0.2.9 for builtin extension retirement (chat-centric extensions dormant until chat surface ships).
Removed
- Dead admin section categories in
sectionCategory(): AI (providers, models, personas, roles, knowledgeBases, memory), routing (health, routing, capabilities), and channels. Default category changed fromaitosystem. - Dead PublicSettings fields:
system_prompt/has_admin_prompt,retention_ttl_days,paste_to_file_chars,allow_user_personaspolicy — all chat-era with no frontend consumers. - Dead PolicyDefaults:
allow_raw_model_access,default_model. - Dead policy lookups:
allow_raw_model_accessandkb_direct_accessfrom profile bootstrap and permissions handlers. - Dead test seed data:
model_rolesglobal setting,allow_raw_model_accesspolicy from test helper. - Dead CORE_IDS entry: Removed
chatfrom packages admin page.
[Unreleased] — v0.2.5
Added
- Welcome surface: New core surface shown as fallback. Detects whether extensions exist (shows "Set Default Surface") vs truly empty install (shows "Go to Packages"). Topbar + UserMenu included.
- User default surface: Users can set a personal landing page in Settings > General, overriding the admin-configured global default.
- UserMenu in admin topbar: Replaced Back button with UserMenu, providing consistent surface navigation and eliminating infinite loops.
- Package manifest icons: Added emoji icons to hello-dashboard, icd-test-runner, sdk-test-runner, and team-activity-log manifests.
- PoC documentation: README.md for tasks and schedules packages documenting Proof of Concept status and graduation criteria.
Changed
- Default surface resolution: Priority chain is now
user preference → global config → first extension →
/welcome. User preference read from JWT cookie on unauthenticated/route. Correctly resolvestype: "full"extension packages (not justtype: "surface"). - User settings General section: Replaced dead chat fields (Default Model, System Prompt, Max Tokens, Temperature, Show Thinking) with a Default Surface dropdown.
- Admin settings: Removed dead chat sections (System Prompt, Default Model, Policies, Web Search, Auto-Compaction, Memory Extraction).
- Roadmap restructured: Workflows → v0.3.x (includes team roles), Notes → v0.4.0, MVP → v0.5.0. Added settings audit milestones (v0.2.7 admin, v0.2.8 user, v0.2.9 team-admin pass 1).
- Updated bus doc examples and test labels from
chat.*toworkflow.*. - Renamed
channel-prefixed test paths totest-in storage tests. - Updated doc comments throughout to remove references to gutted surfaces.
Removed
- ~500 lines of dead CSS: Orphaned classes for gutted chat, channel,
project, notes, editor-chat, sidebar, and router-picker features from
layout.cssandsurfaces.css. - Dead Go types:
Grantstruct (persona-era),CompositeModelKeyfunc, comment-only stubs for NoteGraph, ProjectChannel, etc. - Dead event code:
chat.typing.*/channel.typing.*condition in WS subscriber, empty Chat/Channel event route table sections. - Dead test helpers:
seed_helpers.go(SeedTestMessage, SeedTestMessages, SeedTestCursor — all callerless). - Stale template refs: CSS link tags for non-existent
sw-chat-pane.css,sw-notes-pane.css,chat.css. Orphanedchat-pane.htmlcomponent. - Vestigial guards:
"chat"surface checks inIsSurfaceEnabled()andDisablePackage()(chat is no longer a surface). - Dead settings UI: Chat defaults from user settings, System Prompt / Default Model / Policies / Web Search / Compaction / Memory from admin.
- Unused
fmt.Sprintfreferences in team stores.
[Unreleased] — v0.2.4
Added
sw.shell.Topbar: Standard navigation bar component for surfaces. Composes title + extension slot + NotificationBell + UserMenu into a consistent 44px bar. Surfaces use<${sw.shell.Topbar} title="...">with children rendered in the extension slot. Graceful fallback if unavailable.- Schedules surface (
packages/schedules/): New package wrapping the kernel/api/v1/schedulesAPI. Table view with cron badge + human-readable preview, next fire time, enable/disable toggle, manual run, and execution logs panel. Create/edit dialog with live cron-to-english preview. - Manifest
iconfield: Packages can declare an emoji icon inmanifest.json("icon": "⏰"). Served via the surfaces APIiconfield. Rendered in the UserMenu flyout next to each surface name.
Changed
- UserMenu: Surface list now driven entirely by the
/api/v1/surfacesAPI. Removed hardcoded Chat, Notes, Projects links (gutted in Phase 0). Core surfaces (Admin, Settings, Team Admin, Workflow) filtered from the API list and handled as dedicated menu items with RBAC gating. - Tasks surface: Replaced custom
.tasks-headerwithsw.shell.Topbar. View tabs and create button rendered in the extension slot.
Fixed
sw.isAdminRBAC regression:isAdmin()incan.jswas checking the deprecateduser.role === 'admin'field instead of the v0.2.0 RBAC grantsurface.admin.access. Admin menu item and admin-gated features now appear correctly for users in the Admins group.
[Unreleased] — v0.2.2
Added
- Event bus subscriptions: Extensions declare event triggers in manifest
(
"triggers": [{"type": "event", "pattern": "workflow.completed", ...}]). Wired viabus.Subscribe()on startup. Handlers fire asynchronously. - Webhook triggers: Inbound HTTP at
/api/v1/hooks/:package_id/:slug. HMAC-SHA256 verification viaX-Switchboard-Signatureheader. Synchronous Starlark handler can return custom HTTP status and body. - Scheduled tasks: User-created cron-scheduled Starlark scripts with restricted sandbox (no raw HTTP, no DB table creation, connections-only outbound). Runs as creator identity with RBAC scoping. Admin-created tasks can opt into system context. Creator deactivation auto-pauses schedule.
- Schedule templates: Extensions ship pre-built schedule templates in
manifest (
schedule_templatesarray) with configurable params and default cron expressions. triggers.registerextension permission — required for event/webhook triggerstriggerstable — extension-declared event and webhook trigger definitionsscheduled_taskstable — user-created cron tasks with script, template, and identity fieldstrigger_logstable — unified execution audit log for both tiersTriggerStore+ScheduledTaskStoreinterfaces (postgres + sqlite)- Trigger engine (
server/triggers/) — orchestrates event subscriptions, webhook resolution, and cron scheduling viarobfig/cron/v3 SyncManifestTriggers()— declarative sync of event/webhook triggers from manifest. Hooked into seed, admin install, and package install flows.- Admin trigger API:
GET/PUT/DELETE /admin/triggers,/admin/triggers/:id/logs,/admin/packages/:id/triggers - Admin schedule API:
GET /admin/schedules, enable/disable/delete - User schedule API: full CRUD at
/api/v1/schedules, manual run, execution logs trigger.firedandtrigger.errorevent bus labels (DirLocal) for observability- OpenAPI spec: Trigger, ScheduledTask, TriggerLog schemas + all new endpoints
[v0.2.1] — 2026-03-26
Added
- Default surface routing:
/redirects to configurable default surface. Fallback chain: configured default → first enabled extension surface →/admin. First installed extension surface auto-becomes default. Admin can change via Settings > Default Surface dropdown. default_surfaceglobal config key (JSON{"id": "slug"})- Admin settings UI: Default Surface dropdown (extension surfaces only)
- ICD (API contract): Full OpenAPI 3.0.3 spec covering all 160 kernel
endpoints. 22 tag groups (System, Auth, Profile, Workflows, Packages,
Connections, Teams, Groups, Extensions, and Admin subsections). Reusable
component schemas for User, Team, Group, Workflow, Package, Extension, etc.
Served at
/api/docs(Swagger UI) and/api/docs/openapi.yaml.
Changed
disabledRedirect()now redirects to/admininstead of/to prevent redirect loops when the default surface is disabled- Disabled extension surfaces (
/s/:slug) redirect to/admininstead of/
Fixed
- Gin route param conflict causing backend startup hang: team-scoped
package settings routes used
:pkgIdwhile sibling routes used:id. Gin's radix tree entered an infinite loop on the conflicting param names. Unified to:idacross all/teams/:teamId/packages/routes. - Docker entrypoint: increased health check timeout (10s → 60s), added stale process cleanup and crash detection to prevent zombie backends on restart
[v0.2.0] — 2026-03-26
Added
- Full RBAC: all authorization flows through group membership and permission grants. No magic roles, no implicit group membership, no special-casing.
surface.admin.accesspermission — any group can grant admin panel access- Admins system group seeded with all platform permissions
- Everyone system group — all users explicitly added on creation
EnsureEveryoneGroup(),AddToAdminsGroup(),RemoveFromAdminsGroup()helpersSeedAdminsGroupMember(),SeedEveryoneGroupMember()test helpers- System groups re-seeded after
TruncateAllin test helper - OIDC
isIdPAdmin()— maps IdP role claims to Admins group membership - Settings cascade: three-tier resolution (global → team → user) with
user_overridableflag per manifest setting key. Admins can lock settings that team admins and users cannot override. package_team_settingstable for team-scoped package setting overrides- Team admin API:
GET/PUT/DELETE /api/v1/teams/:teamId/packages/:pkgId/settings RunContext.TeamIDfor team-aware Starlark settings resolutionstore.ResolveSettings()/store.FilterOverridableKeys()pure functionsstore.ParseSettingsSchema()extractsuser_overridablefrom manifests
Changed
RequireAdmin()/RequireAdminPage()checksurface.admin.accessgrantRequirePermission()no longer bypasses for admin roleResolvePermissions()unions explicit group memberships only (no implicit Everyone)- All user creation paths (builtin, OIDC, mTLS, admin, bootstrap, seed) add to Everyone group. Admin users added to Admins group.
- JWT claims no longer include
rolefield - Login response no longer includes
rolein user object - Profile endpoint no longer returns
role - Profile bootstrap resolves permissions from groups (no admin shortcut)
- Middleware auth cache tracks
isActiveonly (no role) - Admin create user accepts
is_adminbool (not role string) - Admin update role endpoint accepts
is_adminbool, manages Admins group directly - Demotion/deletion safeguards check Admins group member count
- Notifications
RoleFallbackHandlerqueries Admins group members - OIDC syncs Admins group on login (no role column writes)
- Kernel permissions: 6 → 7 (added
surface.admin.access) - Admin users UI: role dropdown removed, admin managed through groups
- Starlark
settings.get()uses cascade resolver instead of naive merge - User settings save (
POST /extensions/:id/settings) strips non-overridable keys
Removed
users.rolecolumn — dropped from schema, model, JWT, all handlersUserRoleAdmin,UserRoleUserconstantsCountByRole()store methodDefaultRoleconfig for OIDC and mTLS providersSyncAdminsGroupMembership()(replaced byAddToAdminsGroup/RemoveFromAdminsGroup)- OIDC
resolveRole()(replaced byisIdPAdmin()) - Token budgets from groups: columns,
ResolveTokenBudget(), all store/handler/UI - Allowed models from groups: column,
ResolveModelAllowlist(), UI - Admin groups UI: Token Budgets section, Allowed Models section
Migration notes
- 001_core.sql (both dialects): removed
rolecolumn from users table - 002_teams.sql (both dialects): added Admins group seed, removed
token_budget_daily,token_budget_monthly,allowed_modelscolumns - No new migration files — edited in place per pre-MVP policy
[v0.1.0] — 2026-03-26
Forked from chat-switchboard v0.38.5. Gutted to a pure extension platform.
Removed
- AI/Chat system: providers, model catalog, routing policies, personas, channels, messages, completion streaming, tool loop, compaction, memory, knowledge bases, notes, workspaces, projects, folders, files, export/import
- Task scheduler: entire scheduler package, task store, task handlers. Tasks will be rebuilt as a Starlark extension with three trigger primitives (time, webhook, event)
- Session system: channel-based anonymous sessions. Workflow instances will get new storage in v0.2.0
- Health accumulator: provider health windows, tool health tracking. Replaced with kernel-only Prune (ws_tickets, rate_limit_counters, presence)
- 15 Go packages: tools, compaction, extraction, roles, mentions, notelinks, export, memory, knowledge, providers, routing, capabilities, filters, retention, workspace
- 29 handler files, 6 test files, ~44K lines total
Fixed
- CI deploy: k8s resource quantity vars (
BE_MEMORY_REQUEST→MEMORY_REQUEST) aligned with CI workflow outputs —envsubstwas producing empty strings - CI deploy: image var (
BE_IMAGE→IMAGE) — causedInvalidImageNamein pods - CI rollout: deployment name (
switchboard→switchboard-be) — rollout verification was looking for wrong deployment name - Nginx BASE_PATH: regex cache-header locations intercepted static asset requests before alias could strip the sub-path prefix — moved inside alias block
- Post-login blank page: dead Go template references (
surface-chat,surface-notes,surface-projects) caused html/template to silently produce Content-Length: 0 responses - Login branding: "Chat Switchboard" → "Switchboard Core", updated tagline and feature pills to reflect platform pivot
Changed
- Module renamed:
chat-switchboard→switchboard-core - VERSION:
0.1.0 - Default DB name:
switchboard_core - Fresh migrations: 9 files × 2 dialects (postgres + sqlite), 27 tables
- Store interfaces: 40 → 20 (13 in interfaces.go + 7 in separate iface files)
- Stage modes:
chat_onlyremoved,customadded - Task output modes:
channel|note|webhook→notification|webhook|log - Kernel permissions: 16 → 6 (
extension.use,extension.install,workflow.create,workflow.submit,admin.view,token.unlimited) - Everyone group seed:
["extension.use","workflow.submit"] - Global settings seed: site name "Switchboard Core"
- Config: removed 7 dropped fields (SessionExpiryDays, WorkflowStaleHours, ProviderAutoDisableThreshold, ExtractionConcurrency, etc.)
- Health stores rewritten: kernel-only Prune for stale tickets, counters, presence
- Maintenance goroutine replaces scheduler for background cleanup
Retained
- Identity & auth (builtin, mTLS, OIDC)
- Teams, groups, permissions
- Package system (surfaces, extensions, libraries, workflows)
- Starlark sandbox with capability-gated modules
- Extension connections & dependencies
- Workflow definitions, stages, versions
- Notifications & preferences
- Audit log
- Object storage (PVC, S3)
- WebSocket hub & presence
- Multi-replica HA (ws_tickets, rate_limit_counters)
- Frontend shell (preact+htm, SDK, vendor libs)