Design Studio Architecture Overview
Design Studio reuses the chat system (chat_sessions + EngineDispatcher) at its foundation, with a set of design domain services layered on top. This page provides the overall pipeline with deep dives on individual components in subpages.
Module Location
- Renderer:
packages/renderer/src/features/design-studio/components/design-studio/ - Main process services:
packages/desktop/app/main/services/content/workspace/design/ - Built-in resources (not in git):
resources/design-studio-builtin/— see Built-in Resource Sync Process - Built-in resources pin:
resources/design-studio-builtin.lock.json(only part in git)
Data Flow
graph TB
User["User selects Skill + DS in new session page, enters requirements"] --> Persona["DesignStudio persona"]
Persona --> Create["AgentRouter.createSession<br/>kind='design'"]
Create --> DPS["DesignProjectService<br/>Create project metadata"]
Create --> DPM["DesignProjectMaterializer<br/>Copy Skill / DS into session workspace"]
DPS --> ChatSess["chat_sessions row<br/>(kind='design')"]
DPM --> Workspace["session workspace directory<br/>(skills + design-system + craft)"]
ChatSess --> Disp["EngineDispatcher"]
Disp --> Adapter["Design Backend adapter<br/>(per-engine)"]
Workspace --> Adapter
Adapter --> Engine["TinyElf / ClaudeSdk / CliRunner"]
Engine --> Out["AI output artifact"]
Out --> AS["ArtifactService<br/>Persist artifact"]
AS --> ALS["ArtifactLintService<br/>Validate token / boundaries"]
AS --> AES["ArtifactExportService<br/>HTML/PNG/PDF/Deck"]
Key Services
| Service | Responsibility |
|---|---|
DesignProjectService | Design project metadata CRUD (= chat_sessions[kind='design']): selected Skill, DS, craft subset. |
DesignProjectMaterializer | On session creation, copy selected Skill / DS / craft to session-specific workspace, providing engine with clean read-only view. |
SkillDiscoveryService | Scan user directory + builtin directory for skill manifests, merge and deduplicate. |
DesignSystemService | Same as above but for design systems — token tables, component references, example rendering. |
CraftService | Provide connectable HTML/CSS/SVG fragments. |
ArtifactService | Write/read artifact files (products), associate with specific message. |
ArtifactLintService | Validate artifacts: colors within DS token, font stacks valid, accessibility baseline, etc. |
ArtifactExportService | Artifact export — HTML inline, Puppeteer screenshot (PNG/JPG/PDF), Deck multi-page packaging. |
DeckExportService | Deck-specific export (Reveal.js style presentation package). |
SkillSymlinker | Symlink skills in session workspace to <userData>/elftia/design-skills/ — make Skill edits reflect real-time to running session. |
TinyElfSkillsParserAdapter | TinyElf engine-specific — translate Design Skill to TinyElf-consumable tool/context format. |
backends/ | Per-engine adapter directory. Each engine must implement its own backend to work in Design mode. |
prompts/ | Built-in system prompts (from upstream open-design), sliced by Skill type. |
mcp/ | Design mode-specific MCP tool exposure. |
Engine Adaptation (Design Backend)
Not every engine can run Design projects. Backend adapters under the backends/ directory are registry-style — engines wanting to support Design mode must explicitly register a backend.
// Simplified signature
interface DesignBackend {
engineType: EngineType;
prepareSession(ctx, project): Promise<DesignContext>;
// …
}
For engines without a registered backend, renderer's useDesignStudioGate() returns unavailable, homepage and new session panel degrade to placeholder UI (no half-screen crash).
Artifact and Message Binding
Each AI message that produces an artifact is bound to an artifact ID (written in message metadata):
- Persistence:
<userData>/elftia/design-artifacts/<sessionId>/<artifactId>.html - Renderer reads by
artifactId, single message has a Preview button - "Open workspace" automatically binds current session's latest artifact; clicking old message's Preview replays historical version to workspace
This naturally supports branching: each "regenerate" produces a new artifact, old versions aren't lost.
Relationship with Chat
Design projects are essentially chat_sessions rows + a set of associated tables. Therefore:
- Use same IPC (
chatSessions:*+agents:*) - Use same engine dispatch (EngineDispatcher)
- Reuse same message branching, attachment, API Key Pool logic
- Distinguished in main sidebar by
kind='design'icon, but same list as normal sessions
Only differences are:
| Point | Design | Chat |
|---|---|---|
| Persona | Must be DesignStudio | Any |
| Backend | Must register Design backend | Any |
| Workspace | Materialize on session creation | None |
| Artifact Service | Auto-persist each product | Not involved |
Subpages
- Built-in Resource Sync Process — Complete flow for
resources/design-studio-builtin.lock.json+scripts/sync-design-studio.mjs, including how to upgrade to upstream latest commit