Skip to main content

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

ServiceResponsibility
DesignProjectServiceDesign project metadata CRUD (= chat_sessions[kind='design']): selected Skill, DS, craft subset.
DesignProjectMaterializerOn session creation, copy selected Skill / DS / craft to session-specific workspace, providing engine with clean read-only view.
SkillDiscoveryServiceScan user directory + builtin directory for skill manifests, merge and deduplicate.
DesignSystemServiceSame as above but for design systems — token tables, component references, example rendering.
CraftServiceProvide connectable HTML/CSS/SVG fragments.
ArtifactServiceWrite/read artifact files (products), associate with specific message.
ArtifactLintServiceValidate artifacts: colors within DS token, font stacks valid, accessibility baseline, etc.
ArtifactExportServiceArtifact export — HTML inline, Puppeteer screenshot (PNG/JPG/PDF), Deck multi-page packaging.
DeckExportServiceDeck-specific export (Reveal.js style presentation package).
SkillSymlinkerSymlink skills in session workspace to <userData>/elftia/design-skills/ — make Skill edits reflect real-time to running session.
TinyElfSkillsParserAdapterTinyElf 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:

PointDesignChat
PersonaMust be DesignStudioAny
BackendMust register Design backendAny
WorkspaceMaterialize on session creationNone
Artifact ServiceAuto-persist each productNot 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