# Pear โ€” Roadmap > This document tracks what's shipped, what's actively being built, and what comes next. > For architecture decisions and data model details, see `[PEAR_MVP.md](./PEAR_MVP.md)`. --- ## Legend - โœ… Shipped - ๐Ÿ”จ In progress / partially done - ๐Ÿ“‹ Planned - ๐Ÿ’ก Exploratory / future --- ## Phase 0 โ€” Foundation (MVP) *Goal: A self-hostable Notion alternative with the core page + database loop working.* ### Core data layer - โœ… SpacetimeDB module โ€” all tables, types, reducers in Rust - โœ… `Page` + `PageContent` tables โ€” create page creates both atomically - โœ… Soft deletes โ€” `deleted_at` field, trash view, restore - โœ… Page history โ€” `PageSnapshot` table, history panel, one-click restore - โœ… `PagePropertyValueHistory` โ€” append-only audit trail for property changes - โœ… Auth โ€” SpacetimeAuth as default (email/password, zero config) ### Editor - โœ… BlockNote integration โ€” rich text editor with slash commands *(legacy โ€” superseded by the component-tree editor; see [Rendering substrate](#rendering-substrate--componentnode-tree) below)* - โœ… Local-first storage โ€” IndexedDB primary, SpacetimeDB periodic backup (30s debounce) *(BlockNote pages only; component-tree pages sync block-level through SpacetimeDB directly)* - โœ… PageLink block โ€” inline page reference with live title sync - โœ… Page history panel โ€” timeline of snapshots, preview, restore ### Database / Grid - โœ… Database page type with `DatabaseSchema` - โœ… Property types โ€” Text, Number, Date, Select, MultiSelect, Checkbox, URL, Relation - โœ… Grid view โ€” rows and columns, inline cell editing - โœ… Conditional select options โ€” formula syntax `this[Field]="Value"?"Label"` - โœ… Select option colors โ€” per-option color picker in options editor - โœ… Filter bar โ€” filter rows by any property - โœ… Sort bar โ€” sort rows by any property, multi-sort - โœ… Fill handle โ€” drag corner of selected cell to populate cells below - โœ… Relation property โ€” link rows across two databases - โœ… Row detail modal โ€” open any row as a full page with editor + properties - โœ… Full-page view โ€” navigate directly to any row's page (URL-routable) - โœ… Properties panel in full-page view โ€” edit database properties when viewing a page - โœ… Column header menu โ€” rename, change type, edit options, delete ### Self-hosting - โœ… Docker + Docker Compose for SpacetimeDB + Next.js - โœ… Deploy script โ€” builds WASM module + web image, pushes to registry, SCPs to remote --- ## Phase 1 โ€” Polish & Core Completeness *Goal: Make what's built feel solid and fill obvious gaps before adding major new features.* ### Storage & attachments *Foundation for image block, audio block, page covers, and future file-backed features.* - โœ… Blob storage backend โ€” MinIO in Docker Compose (S3-compatible); env defaults so web uses it; override `S3_`* for external (R2, S3) - MinIO service + `minio-init` creates `pear-attachments` bucket - Web service env: `S3_ENDPOINT`, `S3_BUCKET`, `S3_ACCESS_KEY`, `S3_SECRET_KEY` default to MinIO - Attachment metadata in SpacetimeDB โ€” `Attachment` table + `create_attachment` / `delete_attachment` reducers - โœ… Upload API โ€” `POST /api/upload/request` (presigned PUT URL), `GET /api/upload/url?key=...` (presigned GET); hooks `usePageAttachments`, `useCreateAttachment`, `useDeleteAttachment` ### Database / Grid - โœ… List view โ€” simplified single-column view of database rows - โœ… Column widths โ€” drag to resize, persisted in `DatabaseView.config` - ๐Ÿ“‹ Row reordering โ€” drag rows to manually sort (when no active sort rule) - โœ… Multi-select rows โ€” bulk delete, shift-click range, Ctrl+A; bulk delete action bar - โœ… Keyboard navigation โ€” arrow keys between cells, Tab to move right, Enter to edit - โœ… Frozen first column โ€” Name column stays visible when scrolling right ### Editor - โœ… Audio recording block โ€” record or upload audio (S3/MinIO), inline player, live transcript via Web Speech API where available *(Chrome / Safari)* - Floating **meeting** banner when microphone permission is granted and an audio input device label looks like a conferencing app (Zoom, Meet, Teams, etc.) โ€” best-effort; optional **Allow microphone** prompt first to unlock device labels - `/audio` slash command; paste/drop audio files - ๐Ÿ“‹ Whisper / OpenAI cloud transcription โ€” not wired yet (`PEAR_TRANSCRIPTION_BACKEND` roadmap) - โœ… Image block โ€” paste, drop, or /Image to upload; stored in S3, block uses proxy URL; caption supported - โœ… Table block โ€” included in BlockNote default schema (distinct from database grid) - โœ… Code block improvements โ€” language picker (createCodeBlockSpec with supported languages), copy via โŒ˜โ‡งC / Ctrl+Shift+C when cursor in code block ### Navigation & UX - โœ… Sidebar improvements โ€” drag to reorder pages, collapse/expand subtrees - โœ… Quick switcher โ€” `โŒ˜K` fuzzy-search across all pages by title - โœ… Breadcrumb navigation โ€” show page hierarchy in the header (Workspace / Parent / Current) - โœ… Page emoji โ€” per-page icon (emoji picker) in sidebar, Doc page header, and Database page header; `Page.icon` + `update_page_icon` reducer - ๐Ÿ“‹ Cover image โ€” per-page cover photo *(uses blob storage)* - ๐Ÿ“‹ Trash improvements โ€” 30-day countdown, purge all, bulk restore ### Settings - โœ… Settings page โ€” `/workspace/settings` with theme toggle, clear cached data, about; link in sidebar and "Open settings" in gear popover - โœ… Clear local cache โ€” "Clear cache for this page" and "Clear cache for workspace" in page โ‹ฎ menu; "Clear cached data" in sidebar settings - ๐Ÿ“‹ Custom OIDC โ€” UI for entering `PEAR_OIDC_ISSUER` without editing env file manually --- ## Phase 2 โ€” AI Integration *Goal: Make Pear's relational data model useful to AI agents. AI as infrastructure, not a sidebar.* ### Semantic search - โœ… Embedding pipeline โ€” `POST /api/embed` runs `Xenova/all-MiniLM-L6-v2` (384-dim, quantized) in the Next.js server; `PearEditor` indexes the open page every 45s (or on first tick) and stores vectors in `Page.embedding` via `set_page_embedding` - *(Tier 2 Ollama / Tier 3 OpenAI not wired yet โ€” same reducer expects 384-dim MiniLM only.)* - *(Ship notes: root `pnpm.overrides` pins `sharp` so the transformers stack resolves native binaries on darwin-arm64; embedding work is scheduled with `setTimeout` so markdown export does not run during React commit and avoids `flushSync` warnings.)* - โœ… Semantic search UI โ€” Quick Switcher (โŒ˜K) merges title fuzzy-match with cosine similarity over `Page.embedding`; semantic hits show a small โ€œsemanticโ€ badge when the query is 2+ chars; stable embedding index + query-scoped selection so hybrid ranking does not loop - โœ… Audio transcript search โ€” audio block transcripts are merged into semantic indexing (`collectAudioTranscripts` + markdown) and included in AI page context extraction ### Orcha integration - โœ… Embed Orcha coordination layer in Pear's SpacetimeDB module โ€” `OrchaJob`, `OrchaTask`, `OrchaAgent`, `OrchaSharedContext` tables + `create_job`, `claim_task`, `submit_result`, `fail_task`, `register_agent`, `set_shared_context` reducers. Jobs linked to Pear pages via `page_id`. External instance supported via `ORCHA_SPACETIMEDB_URI` / `ORCHA_SPACETIMEDB_DB_NAME` env vars. - โœ… TypeScript module bindings regenerated โ€” `orcha_job`, `orcha_task`, `orcha_agent`, `orcha_shared_context` tables + all 6 reducers available client-side - โœ… `hooks/useOrcha.ts` โ€” `useOrchaJobsForPage`, `useOrchaTasksForJob`, `useOrchaAgents`, `useCreateJob`, and all reducer hooks - โœ… `AiPanel` component โ€” star button in page header opens a right-side panel; shows all jobs for the page with task-level status; prompt textarea creates new jobs (โŒ˜โ†ต to submit) - โœ… `PreAgentEdit` / `PostAgentEdit` snapshots โ€” the worker brackets every mutating tool call with before/after snapshots - โœ… Pending-changes review โ€” per-page panel lists agent edit brackets with accept / reject (rollback to pre-snapshot) - ๐Ÿ“‹ Schema generation agent โ€” describe what you want to track, agent generates `DatabaseSchema` + `PropertyDefinitions` - ๐Ÿ“‹ Natural language filter โ€” "show me all tasks due this week assigned to me" โ†’ filter config - ๐Ÿ“‹ Workspace summarization โ€” "summarize my open tasks" pulls from `PropertyValues`, not raw text - ๐Ÿ“‹ Relation suggestions โ€” agent notices structural patterns across databases, suggests relation columns - ๐Ÿ“‹ Audio meeting summaries โ€” after transcription, agent generates structured summary + action items as database rows ### AI conversation engine - โœ… Token usage tracking โ€” `input_tokens`, `output_tokens`, `cache_creation_input_tokens`, `cache_read_input_tokens` columns on `ConversationMessage`; cost attribution per assistant turn persisted in SpacetimeDB - โœ… `MessageSender::System` variant โ€” synthetic system-role messages (e.g. compaction events) stored alongside human/AI messages - โœ… `record_compaction` reducer โ€” persists agent compaction summaries as floor-marker messages; session resume discards pre-floor messages and injects the summary into the system prompt - โœ… `SystemPromptBuilder` โ€” dynamic system prompt assembly: workspace context, instruction pages, compaction summary injection, mandatory prompt-injection defense block always appended last - โœ… `WorkspaceContext` + `discover_instruction_pages` โ€” walks page tree to find pages flagged with the `agent_instruction` checkbox property; `summarize_page_history` surfaces recent edits - โœ… `reconstructSessionTail` โ€” compaction floor detection; reconstructs `Session.messages` from the tail only, skips pre-compaction history - โœ… `seed_agent_instruction_property` reducer โ€” idempotent; seeds the `agent_instruction` checkbox `PropertyDefinition` for a given schema so instruction page discovery works out of the box ### Sentinel and untrusted content - ๐Ÿ”จ [Sentinel foundation](./docs/SENTINEL.md) โ€” fixed mail operation/grant/exposure contracts, strict offline eligibility checks, canonical operation fingerprints, frozen byte-bound requests, synthetic containment tests, an entry-point inventory, and covered worker diagnostic privacy regressions. The package is not connected to a runtime and grants no execution authority. - ๐Ÿ”จ [Private mail storage (S1a)](./docs/PROTECTED_MAIL_STORAGE.md) โ€” private collection/source/record/receipt tables, explicit human owner views, atomic deduplication, legacy sync and ordinary-restore fences, and cache/export exclusions. No owner UI, runner or protected activation yet. - ๐Ÿ”จ Private policy and provenance (S1b) โ€” source ceilings and current generations, narrowing/revocation, cumulative registered exposure snapshots and immutable derived ancestry. No model/prompt integration or approval authority. - ๐Ÿ”จ [Reviewed instructions (S1c)](./docs/PROTECTED_MAIL_INSTRUCTIONS.md) โ€” immutable exact revisions, scoped owner decisions, edit-to-draft and retained ancestry. No trusted review UI or runtime use yet. - ๐Ÿ”จ [Authority state (S2a)](./docs/PROTECTED_MAIL_AUTHORITY.md) โ€” retained epochs/tombstones, frozen processor revisions and controlled restart coverage. Configuration alone grants no execution authority. - ๐Ÿ”จ [Governed instruction inputs (S2b1)](./docs/PROTECTED_MAIL_INSTRUCTIONS.md) โ€” exact source references, current-only first enrollment and retained ceilings across edits. Source policy remains separate from current instruction approval. - ๐Ÿ”จ [Local summary admission (S2b2a)](./docs/PROTECTED_MAIL_ADMISSION.md) โ€” exact owner-issued artifact grants, service-bound runs, shared budgets and atomic private promotion receipts. No mailbox, model, network, cursor or runtime activation. - ๐Ÿ“‹ [Owner read surface design](./docs/PROTECTED_MAIL_READ_SURFACE.md) โ€” owner-only, body-free windowed summaries and a one-body read for Trellis components, bound through code-rendered chrome. Design only; the gate before any mailbox becomes a component source. - ๐Ÿ“‹ Protected mail runtime โ€” trusted UI/recipe authorization, admitted connector/inference effects, isolated brokers and host egress tests, then restricted workflow UI and a private canary. Ordinary assistant mail access waits for outgoing-path enforcement. - ๐Ÿ“‹ Governed assistants โ€” extend enforcement to native/API/MCP paths, inference/output, memory/delegation/schedules, then separately constrained browser/remote execution. Prompt warnings and classifiers alone do not establish containment. ### Extensions & MCP tools *Pear's plugin system โ€” lets users and third-party developers extend the AI agent with custom tools via the Model Context Protocol.* - โœ… Schema โ€” `ExtensionManifest`, `InstalledExtension`, `ExtensionMcpServer`, `ExtensionPermission`, `ToolCallAuditLog` tables; `ExtensionType` (`ConfigBundle`, `McpServer`, `Hybrid`, `Builtin`), `AuthScheme`, `InstallStatus`, `PermissionScope`, `PermissionAction` enums - โœ… Reducers โ€” `publish_extension`, `install_extension`, `confirm_extension_install`, `cancel_extension_install`, `uninstall_extension`, `set_extension_enabled`, `grant_extension_permission`, `revoke_extension_permission`, `set_mcp_server_api_key`, `update_extension` - โœ… Sensitive capability gate โ€” extensions requesting `tool-bash`, `tool-http`, workspace-write permissions, etc. land in `PendingConfirmation` and require explicit human confirmation before sub-resources are created - โœ… MCP client (`mcp-client.ts`) โ€” SSE transport, connects to one `ExtensionMcpServer` endpoint, lists tools, executes tool calls, wraps results in trust-boundary marker - โœ… `McpToolExecutor` โ€” loads all enabled MCP servers on startup, routes tool calls by name, handles first-registered-wins collision - โœ… `StaticToolExecutor` โ€” wraps all 14 built-in native tools (`create_page`, `search_pages`, `web_search`, etc.) in the unified executor interface - โœ… `CompositeToolExecutor` โ€” unified tool dispatch: static wins over MCP on name collision, `PermissionChecker` enforces scope/action rules for MCP tools, `AuditLogger` records every call - โœ… `PermissionChecker` โ€” scope hierarchy (`Page โŠ‚ Subtree โŠ‚ Workspace`), domain allowlist for `HttpOutbound`, unconditional block of RFC 1918 + loopback hosts - โœ… `AuditLogger` โ€” SHA-256 hashes input/output, writes `ToolCallAuditLog` rows, never throws on failure - โœ… Extensions UI โ€” installed extensions list with enable/disable toggle, uninstall, upgrade badge; available manifests browser; install form (API key + endpoint override); sensitive-capability confirmation modal; "Publish manifest" form; "Install from URL" (fetches manifest JSON from any URL) - โœ… Built-in extension โ€” `ExtensionType::Builtin`; `extensions/pear-workspace-tools.json` in the repo is both the canonical manifest and the copyable template for users; auto-seeded in `init`; `seed_builtin_extensions` reducer for existing deployments; collapsible "Built-in" section in settings UI with indigo badge and no uninstall controls --- ## Phase 3 โ€” Collaboration & Workspaces *Goal: Make Pear useful for teams, not just individuals.* ### Real-time multi-user editing - ๐Ÿ”จ Live block-level sync โ€” component-tree pages sync per-block through SpacetimeDB subscriptions; per-block Yjs state merges server-side. Streaming awareness (presence, cursors) still open. - ๐Ÿ“‹ Presence indicators โ€” avatars on page title bar showing active collaborators - ๐Ÿ“‹ Named cursors โ€” per-user cursor positions in the editor (`y-protocols/awareness`) - ๐Ÿ“‹ "Last edited by X" metadata on pages and properties ### Multi-workspace client - โœ… Local workspace connection storage โ€” workspace connections panel in settings; connection list stays local - โœ… Workspace snapshot export / import โ€” download a full-workspace JSON snapshot, import into an empty workspace - ๐Ÿ“‹ Invite link generation and join flow โ€” `pear://host:port?invite=token` - ๐Ÿ“‹ One-time invite tokens with expiry ### Permissions - โœ… Page & block access rules โ€” `set_page_access_rule` / `set_block_access_rule` reducers with server-side enforcement - โœ… Access requests โ€” `request_page_access` / `resolve_page_access_request` flow - ๐Ÿ“‹ Workspace roles โ€” Owner, Admin, Member, Guest (today: admin flag + per-page rules) - ๐Ÿ“‹ Personal views โ€” `DatabaseView.owner_identity` already in schema, needs UI --- ## Phase 4 โ€” Automations *Goal: Let users connect Pear's data model to the outside world and to AI without writing code.* - ๐Ÿ”จ [IMAP mail monitor](./docs/MAIL_MONITOR.md) โ€” implemented connection settings per workspace, Inbox/Sent ingestion, encrypted app passwords, durable checkpoints, and optional per-message AI suggestions. Deployment and real-mailbox verification pending. Thread-level follow-ups, digests, and mail-triggered actions remain planned. - โœ… Automation substrate (v0) โ€” typed trigger/action graphs in the module (`PageCreated`, `PageUpdated`, `PropertyChanged`, `Scheduled`, โ€ฆ), event queue, scheduled routines (interval / one-shot / cron), and **dry-run execution** so rules can be drafted, validated, and simulated safely - ๐Ÿ”จ Live action execution โ€” side effects stay behind the queue boundary in v0; live mode exists as a flag but actions are not yet executed for real - ๐Ÿ“‹ Action types (live): - `HttpRequest` โ€” webhooks, Zapier, n8n, Make - `SendEmail` โ€” SMTP notification - `CreatePage` โ€” auto-create rows in response to events - `UpdateProperty` โ€” auto-set values - `OrchaJob` โ€” delegate work to AI agent pool - ๐Ÿ“‹ Automation worker โ€” Orcha-based worker that subscribes to the event queue, executes action chains - ๐Ÿ“‹ Automation run log โ€” UI showing what ran, when, result per action - ๐Ÿ“‹ Automation builder UI โ€” create/edit rules and action chains --- ## Phase 5 โ€” Views & Advanced Data *Goal: More ways to look at the same data.* - โœ… Kanban / board view โ€” group rows by a Select property (`ViewType::Kanban` + `BoardView`) - ๐Ÿ“‹ Calendar view โ€” group rows by a Date property, month/week display *(`ViewType::Calendar` exists in schema; no renderer yet)* - ๐Ÿ“‹ Gallery view โ€” card grid, show a cover image property *(`ViewType::Gallery` exists in schema; no renderer yet)* - โœ… Formula columns โ€” client-evaluated expressions over sibling properties (`PropertyType::Formula`) - โœ… Rollup columns โ€” aggregate values from a related database (`PropertyType::Rollup`, client-evaluated) - โœ… AI columns โ€” model-computed values over row data (`PropertyType::Ai`, evaluated by the worker with cached evaluations) - ๐Ÿ“‹ Timeline view โ€” Gantt-style, requires date range properties - ๐Ÿ“‹ Board status transitions โ€” enforce allowed `Status` changes (state machine for Select) - ๐Ÿ”จ Database schema inheritance โ€” a database inherits its parent's columns OOP-style (`DatabaseSchema.parent_schema_id`, module 0.14.1: `set_schema_parent` reducer, effective-schema resolver, no-shadowing guards; UI lands with the substrate `Table` component โ€” see `docs/FEATURE_schema_inheritance.md`) --- ## Phase 6 โ€” Ecosystem *Goal: Pear as a platform, not just a product.* - โœ… Import from Notion โ€” `import_notion` reducer rebuilds page tree, databases, properties, and content into an empty workspace; settings panel drives it via an external OAuth + transform service - โœ… Pear snapshot export / import โ€” full-workspace JSON snapshot for backup or migration between instances - ๐Ÿ’ก Import from Markdown โ€” flat file import with front-matter as properties - ๐Ÿ’ก Export to Markdown โ€” full workspace export - ๐Ÿ’ก Native desktop app โ€” Tauri v2 (an earlier prototype lived in this repo; not currently maintained here) - ๐Ÿ’ก Mobile app โ€” iOS/Android via Tauri v2 (read-first, then edit) - ๐Ÿ’ก Public Pear Cloud โ€” managed hosting for users who don't want to self-host - โœ… Plugin system โ€” Extensions + MCP tools (see Phase 2 above) - ๐Ÿ’ก Canvas / Whiteboard โ€” freeform visual workspace (deliberately out of scope until core is solid) - ๐Ÿ’ก `pear upgrade` CLI โ€” automated schema migration + version upgrade tool --- ## Rendering substrate โ€” `ComponentNode` tree *Cross-cutting infrastructure replacement. Replaces BlockNote as Pear's document model with a typed component tree owned by SpacetimeDB.* ### Substrate layer (shipped) - โœ… `ComponentNode`, `ComponentYjsState`, `ComponentTypeDefinition` tables - โœ… Component-tree reducer surface โ€” `create_component_tree_page`, `insert_component`, `update_component_props`, `move_component`, `delete_component`, `restore_component`, `save_component_yjs_state`, `register_component_type`, `update_component_type`, plus migration reducers - โœ… Built-in registry โ€” 18 idempotently-seeded types: `Container`, `RichText`, `Heading`, `Image`, `ImageBlock`, `Audio`, `Form`, `Input`, `Button`, `Table`, `Card`, `List`, `CodeRef`, `PageLink`, `Conversation`, `BulletListItem`, `NumberedListItem`, `ChecklistItem` - โœ… Per-block Y.Doc storage via `ComponentYjsState` (legacy `PageYjsState` retained for unmigrated BlockNote pages) - โœ… `PageSnapshot` payload extension โ€” `component_tree_v1` JSON shape carries node tree + base64-encoded Yjs blobs; restore reassigns IDs and remaps parent refs - โœ… Purge cascade โ€” page purge cascades into `component_node` + `component_yjs_state` - โœ… Integrity model โ€” server-side reducers enforce tree-shape invariants (parent existence, no cycles, registered types, `accepts_children`, `has_yjs_state` consistency, leaf-only soft-delete, restore requires live ancestor chain, access control) - โœ… Client-side prop-schema validator โ€” dependency-free JSON Schema subset covering every built-in - โœ… End-to-end smoke harness โ€” `pnpm --filter web smoke` against a local stack - โœ… [`@eclosion-tech/react-native-yjs-text` v0.1](https://www.npmjs.com/package/@eclosion-tech/react-native-yjs-text) โ€” native RN rich-text editor primitive, MIT ### Editor & renderers - โœ… **Web editor (`packages/pulp`)** โ€” storage-agnostic component-tree editor: rendering against the registry, per-block ProseMirror rich text over Yjs, slash menu, drag handles, multi-block selection, turn-into, undo/redo. Wired to SpacetimeDB by the web app's component renderers. - โœ… **BlockNote โ†’ `ComponentNode` migration** โ€” new Doc pages default to the component tree; existing BlockNote pages migrate in place - โœ… **AI authoring** โ€” the worker authors component-tree content directly (markdown โ†’ component block specs โ†’ component reducers, with per-insert verification) - ๐Ÿ“‹ **React Native renderer** โ€” RN renderer over the `ComponentNode` tree; `react-native-yjs-text` provides the rich-text primitive - ๐Ÿ“‹ **Custom-view runtime** โ€” data-bound components (cursors, bindings, write-back) for building app-like views from the same primitives - ๐Ÿ“‹ **Server-side prop-schema enforcement** โ€” client-side validation is the authority today; promote to a reducer-side gate once `prop_schema` evolution patterns settle - ๐Ÿ“‹ **Templates** โ€” shareable custom views, type-based binding remap on install --- ## Deferred / Won't Do (v1) These are explicitly not being built until the core is solid: - Real-time multiplayer cursors / presence โ† post-Phase 3 - Workspace roles (Owner/Admin/Member/Guest) โ† post-Phase 3 *(per-page/block access rules already shipped)* - Calendar / Gallery / Timeline views โ† post-Phase 5 *(Kanban board shipped)* - Mobile โ† post-Phase 6 - Whiteboard / Canvas โ† post-Phase 6 --- *Last updated: June 10, 2026 โ€” component-tree editor (`packages/pulp`) is now the default document surface; BlockNote retained as legacy path with in-place migration. Also landed since May: page/block access rules + access requests, automations v0 substrate (dry-run), board view, formula/rollup/AI columns, Notion import, workspace snapshot export/import, custom REST API endpoints (`docs/API_ENDPOINTS.md`). Earlier โ€” May 2026: rendering substrate layer (tables, reducers, registry, smoke harness). April 2026: Phase 2 semantic search; agent runtime + Extensions/MCP; Phase 6 plugin system โœ…*