debian-1, deployed as two swarm services that share a bind mount.
- Web: excalideck.augustin.ai
- Collab WS: excalideck-collab.augustin.ai (browser-only; the web app sends the URL to clients)
Architecture
excalideck-web— SvelteKit app, SQLite metadata,.excalidrawJSON + SVG thumbnails on diskexcalideck-collab— plain Node WebSocket server speaking the Yjs sync/awareness protocol, one room per diagram, flushes to disk every 10s and on shutdown- Shared state:
apps/excalideck/data/bind mount holdsexcalideck.db,diagrams/,thumbnails/ - Auth: single-user, session cookies, scrypt passwords, rate-limited
- Collab auth: web mints short-lived HMAC-signed tokens scoped to (userId, diagramId); collab verifies with the shared
COLLAB_SECRET— no DB access needed
Secrets
COLLAB_SECRET in apps/excalideck/.env. Rotating it invalidates in-flight collab sessions but does not log users out. Generate with openssl rand -base64 48; must be identical on both services (env_file: .env on both handles this).
Password reset
MCP server (AI diagram generation)
Excalideck hosts a token-authed MCP server athttps://excalideck.augustin.ai/mcp (Streamable HTTP, stateless). It’s the
replacement for the closed-source glyph MCP — diagrams are generated from a high-level
spec and saved straight into the gallery, with no client-side “visual mode” dependency.
Add it to any MCP client (Claude Code/Desktop/Cursor) with a personal access token:
create_diagram—{ name, spec, collectionId? }→ builds a laid-out Excalidraw diagram (longest-path layering, text-sized boxes, edge-bound arrows), validates it, saves it with an SVG thumbnail, and returns the URL.update_diagram—{ id, spec, name? }— replace an existing diagram’s contents.list_diagrams—{ limit? }— recent diagrams with URLs.
spec is structural: { layout: "TB"|"LR", nodes: [{ id, label, shape?, color? }], edges: [{ from, to, label? }] }. The server owns all geometry. Layout/validation/SVG
live in the @excalideck/diagram package; the route uses the official
@modelcontextprotocol/sdk web-standard transport behind a bearer check.
Tokens
Personal access tokens (exd_…) are stored as sha256 hashes in the api_tokens table.
Mint one with the create-token CLI (operator tool, like reset-password):
apps/excalideck/.env as EXCALIDECK_MCP_TOKEN.
REST ingest
The MCP server is built on a plain REST surface that’s also usable directly with session auth:POST /api/diagrams (create) + PUT /api/diagrams/:id ({ file, thumbnail? },
replace contents). Diagrams are per-account.
Upgrades
Images are built from amarcin/excalideck and pushed to the local registry. Seeapps/excalideck/AGENTS.md for the full build + redeploy recipe. Migrations run automatically on web boot.