Add per-agent whiteboard with Excalidraw thin relay architecture#752
Open
selfcontained wants to merge 9 commits into
Open
Add per-agent whiteboard with Excalidraw thin relay architecture#752selfcontained wants to merge 9 commits into
selfcontained wants to merge 9 commits into
Conversation
Agents construct raw Excalidraw element JSON directly via MCP tools (whiteboard_update, whiteboard_get, whiteboard_clear). The server is a thin relay — it merges elements by id, persists to Postgres with optimistic locking, and pushes updates via SSE. The frontend renders an interactive Excalidraw canvas with live sync in both directions. Key pieces: - Migration 0030: whiteboards table (agent_id PK, JSONB scene, version) - MCP tools with embedded Excalidraw element format cheat sheet (~200 lines) - REST endpoints for user-side scene save with optimistic locking - Whiteboard tab in center pane with lazy-loaded Excalidraw component - Self-hosted Excalidraw fonts via Vite plugin (excluding CJK for 12MB savings) - SSE-driven React Query invalidation with "agent drew" dot indicator - 31 unit tests + 4 E2E tests covering REST API, MCP tools, and UI Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the whiteboard tab is hidden (display:none) and an agent updates the scene via MCP, Excalidraw's updateScene() updates internal state but the canvas can't repaint at zero dimensions. Call refresh() when the tab becomes visible so the canvas repaints with the latest content. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…dration Raw server elements lack Excalidraw internal properties (seed, version, roughness, opacity, strokeWidth, etc.) needed for rendering. Use restoreElements() to hydrate sparse server elements before updateScene() so the canvas renders correctly without requiring a page reload. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…cture, wireframe, UI inputs)
…t access to shape libraries
Add a useEffect in WhiteboardCanvas that fetches all four .excalidrawlib files in parallel and loads them into Excalidraw via updateLibrary(). Includes proper cleanup via cancelled flag to prevent state updates after unmount. Library loading is best-effort and fails silently. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… whiteboard library - Key the library catalog Map by category:name instead of name alone so duplicate item names across different .excalidrawlib files (e.g. "Button" in both html-input-elements and universal-ui-kit) no longer silently collide. get()/stamp() accept a bare name (first match) or category:name for an exact lookup. - Remap groupIds through a dedicated groupIdMap in stamp() instead of reusing the element idMap, so stamping the same item twice no longer shares groupIds between the two copies. - Wrap the LibraryCatalog.fromDirectory() startup call in try/catch so a missing/malformed library directory logs a warning and disables library support instead of crashing the server; all downstream consumers already treat libraryCatalog as optional.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
whiteboard_update(with embedded ~200-line Excalidraw element format cheat sheet),whiteboard_get, andwhiteboard_clear. REST endpoints for user-side scene saves with optimistic locking (version check + 409 on conflict).New files
apps/server/src/db/migrations/0030_whiteboards.sql— whiteboards tableapps/server/src/shared/whiteboard.ts— shared types +simplifyElements()apps/server/src/shared/whiteboard-store.ts— persistence layerapps/server/src/shared/mcp/whiteboard-tools.ts— MCP tool definitionsapps/server/src/server/mcp-whiteboard-handlers.ts— thin relay handlersapps/server/src/routes/whiteboard.ts— REST endpointsapps/web/src/hooks/use-whiteboard.ts— React Query hookapps/web/src/components/app/whiteboard-tab.tsx— Excalidraw canvasapps/web/src/components/app/whiteboard-pane.tsx— lazy mount wrapperTest plan
simplifyElements,isValidScene, handler merge/upsert/delete/retry/overflow logicpnpm run check— type checking passespnpm run finalize:web— production build succeedspnpm run test— all 2295 unit tests passpnpm run test:e2e— all 182 E2E tests pass (12 pre-existing skips)🤖 Generated with Claude Code