22 KiB
Originmain — Implementation Handoff
Living document. Updated after each layer is completed or substantially advanced. Reference:
Originmain-Implementation-Guide-v1_0.md(v1.0, April 2026)
Layer Status Summary
| Layer | Name | Status | Notes |
|---|---|---|---|
| 0 | Infrastructure & DevOps | ⏳ Deferred | Skipped for now per plan |
| 1 | Canvas UI Shell | ✅ Complete | ArtboardTree, CodebaseFileTree, CodeDiffPanel |
| 2 | Live Rendering Engine | ✅ Complete | postMessage protocol, fiber hook, MF config, LiveArtboard iframe |
| 3 | Visual Editing & Diff Engine | ✅ Complete | Diff engine (49 tests), SelectionOverlay, history store |
| 4 | Origin Graph & Data Store | ✅ Complete | 3 migrations, RLS, Zod types, query helpers |
| 5 | Design Language Runtime | ✅ Complete | New package, JSON Schema, Zod validator, token pipeline |
| 6 | AI Completion Layer | ✅ Complete | Gateway, 5 features, prompt caching, Claude Opus 4.7 |
| 7 | Agent Bridge (MCP) | ✅ Complete | 5 tools, HMAC auth, rate limiter, Cursor + Claude Code adapters |
| 8 | Multi-Origin Ingestion | ✅ Complete | OriginIngester interface + 4 connectors |
| 9 | Multiplayer & Presence | ✅ Foundation | Room schema, adapter interface, cursor palette — no app integration yet |
| 10 | Platform & Extensions | ✅ Foundation | Plugin API, enterprise types (SSO/SCIM/audit), white-label theming |
Layer 1 — Canvas UI Shell ✅
Completed: 2026-04-25
What was built
Diff Engine integration (pre-Layer 1)
packages/diff-engine/src/schemas.ts— Zod schemas forComponentSnapshotandComponentDiffpackages/diff-engine/src/engine.ts— Core diff computation, Myers LCS, recursive child diffingpackages/diff-engine/src/myers.ts— Myers longest-common-subsequence algorithmpackages/diff-engine/src/patch.ts— Unified patch generationpackages/diff-engine/src/serialize.ts— Snapshot serialization to text- 49 tests, ~88% coverage, all passing
Canvas UI Shell components (NEW — additive only)
packages/app/src/components/navigator/ArtboardTree.tsx— Fluent 2Tree/TreeItem/TreeItemLayoutfor workspace artboard hierarchypackages/app/src/components/codebase/CodebaseFileTree.tsx—@pierre/treesstandalone codebase file browser (separate from ArtboardNavigator.tsx)packages/app/src/components/diff/CodeDiffPanel.tsx—@pierre/diffsPatchDiffrenderer with unified diff patch string input
Critical invariants
ArtboardNavigator.tsxmust never be reversed or have its@pierre/treesFileTree removedArtboardTree.tsxandCodebaseFileTree.tsxare separate components- All new components are additive
Layer 2 — Live Rendering Engine ✅
Completed: 2026-04-25
Files created
packages/renderer/src/protocol.ts—HostMessage/RendererMessageunions,isHostEnvelope(),isRendererEnvelope(),createHostEnvelope(),createRendererEnvelope(); source discriminants'originmain-host'/'originmain-renderer'packages/renderer/src/fiber-hook.ts—buildFiberHookScript(artboardId)generates injectable script that patches__REACT_DEVTOOLS_GLOBAL_HOOK__.onCommitFiberRoot, walks Fiber tree, postsFIBER_TREE_UPDATEenvelopes towindow.parentpackages/renderer/src/module-federation.ts—createRendererHostConfig()andcreateRemoteConfig()MF host config helpers with shared React singletonpackages/renderer/src/index.ts— exports all of the abovepackages/app/src/components/canvas/LiveArtboard.tsx— React iframe component;sandbox="allow-scripts allow-same-origin allow-forms"; injects fiber hook onREADY; sendsSET_DESIGN_TOKENSon token change
Layer 3 — Visual Editing & Diff Engine ✅
Completed: 2026-04-25
Files created
packages/app/src/store/history.ts— Zustand store:stacks: Record<string, {past, future}>,pushEdit(),undo(),redo(),canUndo(),canRedo(),clearHistory(). Max 100 entries per artboard.packages/app/src/components/canvas/SelectionOverlay.tsx— Transparentcursor: crosshairlayer;hitTestFiber()depth-first Fiber tree search by mouse position +domRect;SelectionHandlescorner drag-to-resize; commitsPropChange[]viapushEdit()
Layer 4 — Origin Graph & Data Store ✅
Completed: 2026-04-25
Files created
packages/origin-graph/migrations/001_initial_schema.sql— 5 enum types, 7 tables (workspaces, artboards, origins, intent_diffs, agent_sessions, design_language_files, team_members), FK indexes,set_updated_at()triggerpackages/origin-graph/migrations/002_artboard_ancestry.sql— Recursive CTE materialized viewartboard_ancestry(artboard_id, ancestor_id, depth), unique index forCONCURRENTLYrefresh, trigger on artboard insert/updatepackages/origin-graph/migrations/003_rls_policies.sql—is_workspace_member(ws_id UUID)SECURITY DEFINER function, SELECT/INSERT/UPDATE/DELETE policies on all 7 tablespackages/origin-graph/src/types.ts— Zod schemas for all 7 tables + insert typespackages/origin-graph/src/queries.ts—DbClientgeneric interface + 13 query helpers (no hard Supabase dependency)
Layer 5 — Design Language Runtime ✅
Completed: 2026-04-25
New package: packages/design-language
src/schema.ts—DesignLanguageFileBodySchemawithtokens,components,screens,voice,accessibilitysubsectionssrc/validator.ts—validateDesignLanguageFile()returnsValidationSuccess | ValidationFailure;checkComponentConstraints()for real-time per-edit validationsrc/tokens.ts—extractColorTokens(),tokensToCssVars(),dlfToCssVars(),dlfSummary()tsconfig.base.json— path alias added:"@originmain/design-language": ["./packages/design-language/src/index.ts"]
Layer 6 — AI Completion Layer ✅
Completed: 2026-04-25
New package: packages/ai-layer
src/client.ts—getClient(): Anthropic,MODEL = 'claude-opus-4-7'src/gateway.ts—AIGatewayclass: 60 RPM rate limiter, 3 retries on 429/529/5xx, cost tracking (computeCost()). Note:thinking: {type: 'adaptive'}pending SDK ≥0.58 upgradesrc/prompts/system.ts—buildSystemPrompt({role, dlfJson?})returnsTextBlockParam[]; DLF block hascache_control: {type: 'ephemeral'}as stable system prompt prefixsrc/completion-zone.ts—fillCompletionZone(): 3-retry JSON validation loop, temp 0.3src/diff-summary.ts—generateDiffSummary(): temp 0.3, 128 tokens maxsrc/artboard-query.ts—queryCrossArtboard(): temp 0.3src/drift-report.ts—generateDriftReport(): base64 image, temp 0.3src/agent-qa.ts—answerAgentQuestion(): temp 0.7
SDK note
@anthropic-ai/sdk v0.56.0 is installed. Adaptive thinking (thinking: {type: 'adaptive'}) requires ≥0.58 — a TODO comment marks all 5 feature files for upgrade. All features remain fully functional at temperature level.
Layer 7 — Agent Bridge (MCP) ✅
Completed: 2026-04-26
New package: packages/agent-bridge
src/protocol.ts— JSON-RPC 2.0 types:JsonRpcRequest,JsonRpcSuccess<T>,JsonRpcError,MCP_ERRORconstants (UNAUTHORIZED: -32001,RATE_LIMITED: -32002),AuthRequest/AuthAckhandshake,textResult()/jsonResult<T>()helperssrc/auth.ts—issueWorkspaceToken(workspaceId, agentType)HMAC-SHA256 base64url token;verifyWorkspaceToken(token)with timing-safe comparison, 30-day TTL; uses Nodecryptobuilt-insrc/rate-limiter.ts— Sliding window: 100 requests/60-min/workspace; in-process Map of timestamp arrays (replace with Redis for multi-instance)src/tools.ts—ToolContextinterface (db + ai adapters),McpToolinterface, 5 tools:get_pending_diffs(rate-guarded),get_artboard_context,ask_design_agent,update_diff_status,get_design_language;TOOLSarray,TOOL_MAP,getToolList()src/adapters/cursor.ts—generateCursorConfig(): generates.cursorrulesmarkdown +cursor_settings.jsonMCP server entry with Bearer authsrc/adapters/claude-code.ts—generateClaudeCodeConfig(): generatesCLAUDE.mdsection +.claude/settings.jsonMCP server declaration with SSE transport
Notes
- Added
@types/nodedevDep +"types": ["node"]in tsconfig forcrypto/Buffer/process AgentType:'CURSOR' | 'CLAUDE_CODE' | 'GENERIC'
Layer 8 — Multi-Origin Ingestion ✅
Completed: 2026-04-26
Package: packages/integrations
src/types.ts—OriginIngester<TPayload>interface:parsePayload(raw): TPayload+ingest(payload): IngestionResult;IngestionResultcarriesorigin: InsertOrigin,artboardTitle, optionalrenderUrlsrc/connectors/linear.ts—linearIngester: Zod-validates Linear Issue webhook payload; maps toLINEAR_ISSUEorigin; prefers attachment URL forrenderUrlsrc/connectors/slack.ts—slackIngester: Zod-validates Slackmessage_postedevent; extracts first image attachment; maps toSLACK_MESSAGEoriginsrc/connectors/github.ts—githubIngester: Zod-validates GitHubpull_requestwebhook (opened/synchronize/reopened/closed); maps toGIT_COMMITorigin with PR metadatasrc/connectors/intercom.ts—intercomIngester: Zod-validates Intercomconversation.user.createdwebhook; extracts annotated screenshot attachment; maps toURLorigin with user context
Design note
Each connector validates untrusted webhook JSON at the boundary with Zod (parsePayload throws ZodError on invalid input). The origin output maps directly to InsertOrigin from @originmain/origin-graph — no workspace_id on origins (that scoping lives on the artboards table via origin_id).
Package Inventory
| Package | Status | Notes |
|---|---|---|
packages/app |
Active | Next.js 15 app; Layers 1–3 complete |
packages/diff-engine |
Complete | 49 tests, ~88% coverage |
packages/ui |
Active | Theme + FluentProvider |
packages/renderer |
Complete | Layer 2: postMessage protocol, fiber hook, MF config |
packages/origin-graph |
Complete | Layer 4: migrations, RLS, Zod types, query helpers |
packages/design-language |
Complete | Layer 5: DLF schema, validator, token pipeline |
packages/ai-layer |
Complete | Layer 6: gateway, 5 features, prompt library |
packages/agent-bridge |
Complete | Layer 7: MCP tools, auth, rate limiter, adapters |
packages/integrations |
Complete | Layer 8: OriginIngester + 4 connectors |
packages/multiplayer |
Foundation | Layer 9: room schema, MultiplayerAdapter, cursor palette |
packages/platform |
Foundation | Layer 10: Plugin API, SSO/SCIM/audit types, theming |
packages/e2e |
Not started | Playwright E2E; Phase 1 completion target |
Key Technical Decisions
| Decision | Choice | Rationale |
|---|---|---|
| Artboard tree | Fluent 2 Tree/TreeItem |
ARIA, Fluent token integration, <100s of nodes |
| Codebase file tree | @pierre/trees |
Virtualization for 5k+ files, git status, search |
| Diff renderer | @pierre/diffs PatchDiff |
Shiki syntax highlight, split/unified modes |
| Canvas state | Zustand | Lightweight, supports undo/redo middleware |
| TS imports in Next.js | extensionAlias .js → .ts |
ESM-compatible workspace packages |
| AI model | Claude Opus 4.7 | Max intelligence for design engineering tasks |
| Prompt caching | DLF as stable system prompt prefix | ~60% input token cost saving per session |
| MCP auth | HMAC-SHA256 workspace token | Stateless, 30-day TTL, timing-safe verify |
| Rate limit | In-process sliding window | Simple; swap for Redis in multi-instance deploy |
| Webhook validation | Zod at connector boundary | ZodError → HTTP 400 before any DB write |
exactOptionalPropertyTypes |
Conditional spread ...(v !== undefined ? {k: v} : {}) |
Required by strict TS config throughout monorepo |
Layer 9 — Multiplayer & Presence (Foundation) ✅
Completed: 2026-04-26 (Phase 3 foundation only — no Liveblocks app integration per guide)
New package: packages/multiplayer
src/room-schema.ts— Liveblocks room schema types:UserPresence— cursor{x,y},activeArtboardId,selectedComponentIds,cursorColor; updated ≤50ms throttleArtboardStorageObject— CRDT-backed artboard state (viewport, locked, lastModifiedAt)WorkspaceStorage—artboards: Record<id, ArtboardStorageObject>+artboardOrderLiveblocksRoomTypes— generic type params forcreateRoomContext<Presence, Storage, UserMeta, RoomEvent>RoomEvent— broadcast events:ARTBOARD_LOCKED,DIFF_EXPORTED,COMPLETION_ZONE_ACCEPTEDworkspaceRoomId(workspaceId)— room ID convention:"workspace:<uuid>"
src/adapter.ts—MultiplayerAdapterinterface matching Zustand store API surface (presence reads/writes, artboard storage, subscribe);createLocalAdapter()stub for Phase 1/2src/cursor-colors.ts—cursorColorForUser(userId)deterministic 12-colour palette assignment
Phase 3 integration note
Actual createClient / createRoomContext calls go in packages/app/src/lib/liveblocks.ts (Phase 3). @liveblocks/client and @liveblocks/react are declared as optional peer deps — not installed yet.
Layer 10 — Platform & Extensions (Foundation) ✅
Completed: 2026-04-26 (Phase 4 foundation — types and contracts only)
New package: packages/platform
src/plugin-api.ts— Plugin API:PluginManifest— reverse-DNSid,version,entryUrl,bundleHash,permissions[]PluginPermission— 7 scopes:artboards:read,artboards:write,diffs:read,diffs:export,completion-zones:register,ingesters:register,design-language:readPluginReadAPI/PluginWriteAPI— async APIs exposed to sandboxed plugin via postMessagePluginContext—read,write(null unlessartboards:writegranted),notify()CustomCompletionZoneDefinition— custom zone type withsystemPromptAddendum+outputSchemaCustomIngesterDefinition— custom connectorhandleWebhook()interfacePluginRegistry—list / install / uninstall / setEnabledper workspace
src/enterprise.ts— Enterprise features:SsoConfig— SAML 2.0:idpEntityId,idpSsoUrl,idpCertificate,enforced,emailDomains; providers: okta/azure/google-workspace/onelogin/customScimUser/ScimGroup— SCIM 2.0 normalized objects withrolemapped toTeamRoleAuditLogEntry— 30 audit actions across auth/workspace/artboard/diff/AI/plugin/DLF/agent-bridgebuildAuditEntry()— convenience constructor with auto-timestamp
src/theming.ts— White-label theming:BrandTokens—primaryColor,secondaryColor,logoUrl,productName,faviconUrlbrandVariantsFromHex(hex)— derives 16-shade Fluent 2BrandVariantsfrom single hex colour via HSL interpolation (shade10=lightest → shade160=darkest)
Known Pending Items
@anthropic-ai/sdkupgrade to ≥0.58 — unlocksthinking: {type: 'adaptive'}in all 5 AI feature files (marked with TODO comments)- Redis-backed rate limiter —
packages/agent-bridge/src/rate-limiter.tsis in-process only; needs Redis for multi-instance MCP server deployment - Layer 0 — Infrastructure (Vercel, Supabase, Render, GitHub Actions) deferred per plan
- Layer 9 Phase 3 — Wire
MultiplayerAdapterinto app components; addcreateClient/createRoomContextinpackages/app/src/lib/liveblocks.ts; install@liveblocks/client+@liveblocks/react - Layer 10 Phase 4 — Plugin sandbox runtime (iframe + postMessage bridge); SCIM webhook endpoint; SSO provider registration UI; audit log Supabase table + extension
packages/e2e— Playwright E2E tests not yet created
Product Bug Audit (2026-04-26) — Work In Progress
The following is a second-pass audit of all real product gaps, independent of layer status. These are being worked on in the current session.
✅ Completed — Session 1
.env.examplefixed:CLERK_PUBLISHABLE_KEY→NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, addedAGENT_BRIDGE_SECRET,GITHUB_WEBHOOK_SECRET,INTERCOM_WEBHOOK_SECRETproject_idadded toArtboardSchemaintypes.tsandgetArtboardsquerycreateArtboardMutationexported fromuseArtboards.ts, used inCanvas.tsxartboard tooluseArtboardsreturnsrawArtboards: Artboard[](full DB rows) alongside canvas-mapped shapes- Inspector props tab now shows real
metadata_jsonbfields from selected artboard - ArtboardNavigator shows real artboard names (not hardcoded FILE_PATHS)
- Canvas keyboard shortcuts: V/H/A/Z for tools, Escape to cancel
- All 4 error boundary files created (global, workspaces, workspace, canvas)
- Design Language upload UI in workspace page
- Webhook
project_id: nullplaceholder added (awaiting full project param support) PATCH /api/artboards/[id]+DELETE /api/artboards/[id]+ origin-graph helpersPOST /api/workspace/[id]/tokens— workspace token issuance for IDE integrationWorkspaceCard.tsx+ProjectCard.tsxextracted as'use client'components → fixed server-side exception on breadcrumb click
✅ Completed — Session 2 (2026-04-26)
- Server-side crash fixed:
workspaces/page.tsxandworkspace/[wid]/page.tsxconfirmed usingWorkspaceCard/ProjectCardclient components (noonMouseEnterin server components) - Inspector fully rewired: removed
useDiff/ARTBOARD_SNAPSHOTShardcoded data; now usesuseDiffs(real DB diffs) +useHistory(pending local changes) - Export Diff button: Inspector Diff tab shows pending
PropChange[]from history store with "Export diff →" button that callsPOST /api/diffs renderUrlinline editor: Inspector Props tab has inline input forrenderUrl; saves viaPATCH /api/artboards/[id];patchArtboard()added touseArtboards.ts- Inspector status bar: now reads
liveArtboardIdsfrom canvas store — shows pulsing green dot when live render connected, grey + hint when not - Empty canvas state: removed
DEMO_ARTBOARDSfallback fromuseArtboards.ts; Canvas shows dashed hint "Press A to create an artboard" when empty - Zone tool drag preview: Canvas draws live dashed rectangle + dimension label during zone drag; cleans up on mouse-up
- Workspace settings page:
GET+PATCH /api/workspace/[id],/workspace/[wid]/settingspage +WorkspaceSettingsFormclient component (rename, IDE token issuance with full config snippets, danger zone) - Settings link in workspace page: gear icon button added next to "New project"
🔧 Remaining — In Order of Priority
CRITICAL — all done ✅
HIGH
- Replace
useDiff.tswith realuseDiffs.ts✅ renderUrledit UI ✅- Export Diff button ✅
- Zone tool canvas drag preview ✅
- Empty canvas state ✅
- Workspace settings page ✅
- Artboard content fallback — Artboard.tsx still shows UUID as a placeholder title when no fiber tree is connected
MEDIUM
handleComponentSelected→ canvasselectComponent()→ Inspector shows selected component's fiber props- Graph tab wired to real fiber tree (currently shows hardcoded DashboardCard tree)
- Navigator files tree selectable + artboard delete/rename actions
- Artboard drag-to-move (label drag →
PATCH /api/artboards/[id]with new x/y in metadata_jsonb) - Artboard delete (trash icon → confirm →
DELETE /api/artboards/[id]) - Artboard rename (double-click label → inline edit → PATCH name)
- Viewport persistence to localStorage
- Webhook
project_idfrom?project=query param @anthropic-ai/sdkupgrade to ≥0.58 forthinking: {type: 'adaptive'}
LOW
- Project settings page
- Team invitation UI (in workspace settings —
POST /api/workspace/[id]/inviteexists) - Drift Report UI (in Inspector AI section)
- Cross-Artboard Query UI (in navigator)
- Vitest test files (diff-engine + origin-graph)
- Multiplayer basic Liveblocks wiring
- Plugin system stub page
- Zone tool: after drag, show prompt input →
POST /api/ai/completion-zonewith bounds
Key Technical Notes for Next Agent
Artboard.tsx and component selection:
The handleComponentSelected callback inside Artboard.tsx receives the clicked FiberNode (from LiveArtboard). It needs to call useCanvas.getState().selectComponent(node.id, node). The Inspector's PropsTab should check selectedComponentId/selectedComponentData and show the fiber node's props when a component is selected (vs. showing artboard metadata when nothing is selected).
Artboard drag-to-move:
The Artboard component label area needs onMouseDown → tracks mouse delta → PATCH /api/artboards/[id] with { metadata_jsonb: { ...meta, x: newX, y: newY } }. Use patchArtboard(id, { metadata_jsonb: ... }) from useArtboards.ts then queryClient.invalidateQueries.
Zone tool completion:
After the zone drag ends (mouse-up), show a floating prompt input at the zone position. On submit → POST /api/ai/completion-zone with { artboard_id, bounds: {x,y,w,h}, prompt }. Show result inline in the canvas.
@anthropic-ai/sdk upgrade path:
All 5 AI feature files in packages/ai-layer/src/ have // TODO: upgrade to adaptive thinking when SDK ≥0.58 comments. After pnpm add @anthropic-ai/sdk@latest in packages/ai-layer, replace the temperature-based calls with thinking: {type: 'adaptive'} on the gateway.complete() calls.
Last updated: 2026-04-26 — Session 2 complete