OD '26
All Chapters

PART I: FOUNDATIONS · SECTION 02

Install and Architecture

Desktop app, daemon, SQLite, Electron, and Docker

Reading time

20 min

Chapter

02

Install and Architecture

Desktop app, daemon, SQLite, Electron, and Docker

Installing Open Design is choosing one of three paths, and understanding the daemon-plus-iframe architecture is what makes everything later make sense.

2.1 Three Ways to Install

Desktop app, from source, or Docker Compose — pick based on what you intend to do

Open Design ships three installation paths. The one you choose sets the ceiling on what you can do: the desktop app hands you a running system in minutes; the from-source path lets you modify skills and plugins; Docker Compose gets you a server deployment. Knowing the tradeoff upfront prevents the most common first-run frustration.

As of June 2026, Open Design is at v0.9.0 (released June 2, 2026). All three paths install the same version of the daemon and frontend; they differ only in packaging and environment control.

Choose Your Install Path (Open Design v0.9.0, June 2026)
Path Best for Trade-off
Prebuilt desktop app Product designers, first-time users, anyone who wants a running Open Design in under five minutes without touching Node You cannot modify skills or plugins; updates come as app releases
From source (pnpm) Design engineers who intend to author custom skills, fork plugins, or contribute to the repo Requires Node ~24 and pnpm 10.33.x; native module builds fail silently on version mismatch
Docker Compose Teams deploying Open Design to a shared server, CI pipelines, or headless environments without Electron No Electron shell; the UI is served in the browser only; requires Docker and the deploy/ directory
My Take

Start with the prebuilt desktop app even if you are a design engineer who eventually wants to modify skills. The most common first-run failure is a native module build error caused by a Node or pnpm version mismatch, and the desktop app skips that entirely. Get comfortable with the tool first. Switch to from-source when you have a concrete reason to modify something. The exception is if you are onboarding a whole team onto a shared instance --- Docker Compose is worth the setup cost there.

Desktop App

Download the prebuilt installer from open-design.ai. Run it like any desktop application. The daemon starts automatically on first launch; the Electron shell wraps the frontend and communicates with the daemon via sidecar IPC. No terminal required.

From Source with pnpm

The from-source path requires exactly Node ~24 and pnpm 10.33.x. corepack enable ensures pnpm is at the right version before you install.

Command
$ git clone https://github.com/nexu-io/open-design.git
$ cd open-design
$ corepack enable
$ pnpm install
$ pnpm tools-dev run web

Native build failures on version mismatch. Open Design pins Node ~24 and pnpm 10.33.x (as of June 2026). The better-sqlite3 package compiles a native binary at install time. If your Node version doesn't match the pin, the build fails --- sometimes silently --- and the daemon crashes at startup with a module-not-found or ABI-mismatch error. Check your Node version with node --version before running pnpm install. Use nvm or fnm to switch if needed.

Docker Compose

If you're deploying Open Design to a server or shared machine, Docker Compose handles the daemon, frontend, and SQLite volume in one command. The deploy/ directory at the repo root contains the Compose configuration.

Command
$ cd deploy
$ docker compose up -d

Docker Compose brings up the daemon and serves the frontend at http://localhost:7456 by default. There is no Electron shell in this mode; you access Open Design through any browser. The SQLite database persists in a named volume so your projects survive container restarts.

2.2 First Run

Launch, verify, and confirm the daemon is healthy before generating anything

The daemon owns the truth. Before you can generate an artifact, the daemon must be running and healthy. These steps apply to the from-source path; desktop app users can skip to step 4 --- the app handles steps 1 through 3 automatically.

1

Start the dev daemon. Run pnpm tools-dev run web from the repo root. You should see the daemon and the Next.js dev server both starting in the same terminal output. The daemon serves the API and the frontend on port 7456 by default.

Command
$ pnpm tools-dev run web
# Expected: daemon and frontend serving on :7456
2

Verify the daemon health endpoint. Open a second terminal and hit the daemon's health route. A 200 response with a JSON status confirms the daemon is up and the SQLite database has been initialized.

Command
$ curl -s http://localhost:7456/health
# Expected output:
{"status":"ok","version":"0.9.0"}
3

Open the frontend. Navigate to http://localhost:7456 in your browser. You should see the Open Design dashboard with no projects yet. If the preview area stays blank or the dashboard shows a connection error, the daemon isn't reachable --- check the terminal output for startup errors.

Open Design v0.15.1 home surface with hero prompt composer, template strip, and recent projects
Figure 2.1 — The Open Design home surface (v0.15.1). One composer with template, mode, agent, design-system, and working-directory levers; a template strip; recent projects; and a community rail. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026). For the older v0.9.0 artifact-tile layout, see archival figures in Appendix D.

Once you have more than a handful of runs in flight, the Projects sidebar becomes the supervision surface. As of v0.15.1 it is a kanban board with a dedicated Needs input column --- paused agent turns that explicitly wait for a human reply rather than failing silently in the background. The full board layout is shown in Figure D.7.

4

Create your first project. Click "New Project" in the dashboard. Open Design creates a project directory under ~/.od/projects/<uuid>/ and writes a new row to ~/.od/app.sqlite. The daemon owns both; the frontend is showing you what the daemon holds.

5

Connect a coding-agent CLI. Chapter 03 covers this in full. For now, confirm the MCP (Model Context Protocol) settings panel is reachable from the project sidebar --- that's where you'll register your agent in the next chapter.

Open Design settings dialog open on Execution mode with Local CLI and BYOK tabs and a list of detected coding-agent CLIs
Figure 2.2 — Settings → Execution mode (v0.15.1). Local CLI versus BYOK, Rescan for newly installed agents, and per-CLI model plus reasoning controls. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026).
Open Design Settings dialog open on General with navigation rail for Execution mode, Instructions, Memory, and Design Jury
Figure 2.2a — The Settings shell (v0.15.1). Execution mode, Instructions, Memory, and Design Jury share one dialog reachable from the gear menu. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026).

Instructions, Memory, and Design Jury

Settings also separate three knowledge layers that older releases buried or omitted. Treat them as different contracts with the agent:

  • Instructions / Rules — fixed global rules injected into every chat. Stable policy, not facts.
  • Memory — saved facts categorised as User, Project, Reference, or Rule, with a master toggle and per-item edit/delete. Extracted from chats and injected when relevant.
  • Design Jury — optional five-panel scored review that streams alongside generation so you can interrupt before shipping. Covered in depth in Chapter 08.
Open Design Settings showing Instructions / Rules panel for global rules followed in every chat
Figure 2.2b — Instructions / Rules. Fixed instructions for every chat; distinct from Memory. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026).
Open Design Settings Memory panel with saved memories and User, Project, Reference, and Rule category filters
Figure 2.2c — Memory. Categorised saved facts with a master toggle. Use Memory for preferences and project context; use Instructions for immutable rules. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026).

The rest of Settings

As of v0.15.1 the Settings dialog carries a left navigation rail with every configuration surface in one place. The knowledge layers above are the ones you touch most often during generation; the table below is a complete map of the rail so you know where to look when the environment changes.

Settings navigation rail (Open Design v0.15.1, July 2026)
Category Job
Execution mode Choose Local CLI vs BYOK, rescan for newly installed agents, and set per-CLI model tiers
Instructions / Rules Fixed global rules injected into every chat
Memory Saved facts by category (User, Project, Reference, Rule) with a master toggle
Design Jury Optional five-panel scored review streamed beside generation (Chapter 08)
Media providers Configure image and video generation providers and their API keys
External MCP Register third-party MCP servers the agent may call during a run
Connectors Composio-backed external data sources for Live artifacts (Chapter 10)
MCP server Copy-paste config that exposes Open Design tools to agent CLIs (Chapter 10)
Appearance Theme, density, and UI chrome preferences
Notifications Desktop and in-app alert preferences
Pets Optional companion settings (delight layer, not load-bearing)
Design systems Gallery of installed brand systems and quick attach controls (Chapter 05)
Project locations Default folders and paths for new projects and exports
Language Application locale
Privacy Telemetry, sharing, and data-handling toggles
About Version, updates, and license information
Open Design Settings Media providers panel listing image and video generation providers with API key fields
Figure 2.2d — Media providers. Wire image and video backends before you ask the agent for rich media in a Heavy Design run. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026).
Open Design Settings External MCP panel for registering third-party MCP servers
Figure 2.2e — External MCP. Register servers beyond Open Design's own MCP surface; see Chapter 10 for the full integration model. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026).
Open Design Settings Connectors panel with Composio API key entry and connector activation controls
Figure 2.2f — Connectors in Settings. Same Composio-backed wiring as the Integrations sidebar, reachable without leaving configuration. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026).
Open Design Settings MCP server panel showing copy-paste mcpServers configuration for agent CLIs
Figure 2.2g — MCP server. Copy the mcpServers block into Claude Code, Cursor, or any supported CLI; one daemon, many brains. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026).
Open Design Settings Design systems panel showing a gallery of installed brand systems
Figure 2.2h — Design systems in Settings. Quick view of installed brand contracts; authoring and presets live in the sidebar surface covered in Chapter 05. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026).
Open Design Settings Project locations panel for default project and export paths
Figure 2.2i — Project locations. Set default folders before your first client engagement so artifacts land where your backup scripts expect them. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026).
Open Design Settings Appearance panel with theme and density controls Open Design Settings Language panel with application locale selector
Figure 2.2j — Appearance and Language. Chrome preferences and locale; both also reachable from the gear menu shortcut. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026).
Open Design Settings Notifications panel with desktop and in-app alert toggles Open Design Settings Pets panel with optional companion controls
Figure 2.2k — Notifications and Pets. Alert routing plus an optional delight layer that does not affect generation. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026).
Open Design Settings Privacy panel with telemetry and data-handling toggles Open Design Settings About panel showing version and update information
Figure 2.2l — Privacy and About. Data-handling toggles and version metadata for support tickets. Mock-safe screenshot from Open Design desktop v0.15.1 (July 2026).

The full visual tour of every Settings panel --- including Execution mode and Design Jury --- is in Appendix D.7.

When the First Run Breaks

Native build errors and version mismatches account for most first-run failures. Here are the patterns I encounter most often.

First-Run Troubleshooting (Open Design v0.9.0, June 2026)
Symptom Cause Fix
Error: Cannot find module 'better-sqlite3' or ABI mismatch at startup Node version doesn't match the pin (~24); native module compiled against the wrong ABI Run node --version; switch to Node 24 with nvm use 24; delete node_modules and run pnpm install again
pnpm install hangs or fails with unsupported engine error pnpm version isn't 10.33.x; corepack enable not run first Run corepack enable, then pnpm --version to confirm 10.33.x, then retry install
Dashboard shows "daemon unreachable" or blank preview area Daemon process failed to start, or is not serving on the expected port Check terminal for startup errors; confirm daemon is running on port 7456; restart with pnpm tools-dev run web
Docker Compose: frontend loads but projects don't persist after restart SQLite volume not mounted; container using an ephemeral filesystem Check deploy/docker-compose.yml for a named volume attached to the SQLite path; verify with docker volume ls
Desktop app: "update required" banner on first launch App installer is older than the current release; auto-updater requires internet access Allow the auto-update to complete, or download the latest installer from open-design.ai

2.3 The Daemon

The Express process that owns orchestration, storage, and streaming

The daemon owns the truth. It is a long-lived Node 24 Express process that owns three things: the SQLite database, the project files on disk, and the agent orchestration loop. The frontend and the preview iframe are both just windows onto what the daemon holds. Understanding this split resolves most confusion about where state lives and why a browser refresh doesn't lose your work.

The daemon exposes an HTTP API consumed by the Next.js frontend. For artifact generation, it uses Server-Sent Events (SSE) to stream tokens from the agent back to the browser in real time. SSE is unidirectional --- the daemon pushes; the frontend listens --- which keeps the streaming path simple and resilient to browser tab-switching.

Agent CLI

Claude Code, Cursor, or any of the 21 supported CLIs. Sends prompts and receives completions via MCP.

Daemon (Express)

Node 24. Owns orchestration, the SQLite database, and project files. Streams artifact tokens over SSE.

Frontend (Next.js 16)

React 18 + TypeScript. Reads daemon state via HTTP. Receives artifact stream over SSE and passes it to the preview.

Preview (srcdoc iframe)

Sandboxed. The streaming artifact parser writes tokens into the iframe as they arrive. Safe from the host page.

Figure 2.3 — Request flow: agent prompt through daemon SSE to the sandboxed preview iframe. The daemon holds all persistent state; the frontend and iframe are display layers only.

SSE and the Streaming Artifact Parser

When the daemon receives an artifact generation request, it opens an SSE stream to the client. Tokens arrive as data: events. The frontend's streaming artifact parser assembles them progressively --- which is why you see the artifact appear word by word in the preview before generation is complete.

This matters for troubleshooting: if the preview stops mid-generation, the SSE connection dropped. This is almost always a network proxy or a browser extension killing long-lived connections. Disable proxy-caching extensions or set a generous SSE timeout if you're behind a corporate proxy.

better-sqlite3 and Synchronous Storage

The daemon uses better-sqlite3 for all persistent state. Unlike the async SQLite drivers, better-sqlite3 runs synchronously --- writes block until committed, reads return immediately. This keeps the daemon's internal state machine simple: no callback hell, no partial-write races, no connection pool. For a single-user local daemon, synchronous SQLite is exactly the right call.

The tradeoff is that every write to ~/.od/app.sqlite is a blocking operation on the daemon's event loop. In practice this is not a problem for interactive use, but if you write a plugin that writes frequently to the database in a tight loop, you'll feel it. Batch writes where you can.

2.4 Where Your Work Lives

The .od directory layout and what to back up

Open Design stores everything under ~/.od/. Two things matter here: the project directories under ~/.od/projects/ hold your artifact files; ~/.od/app.sqlite is the index that makes sense of them. Back up both or you lose either the files or the ability to navigate them.

~/.od/
├── projects/
│   ├── <project-uuid-1>/
│   │   ├── artifacts/      # Generated HTML, PDF, PPTX, MP4, ZIP, MD files
│   │   ├── previews/       # Cached preview snapshots
│   │   └── exports/        # Final exported files
│   └── <project-uuid-2>/
│       └── ...
├── app.sqlite              # All project metadata: names, histories, settings
├── config.json             # Daemon configuration: ports, model provider keys
└── logs/                   # Daemon logs, one file per day

What to Back Up

The daemon owns the truth, and the truth lives in two places. Backing up one without the other leaves you in an inconsistent state.

Backup Priority for .od Contents
Path Contains Backup priority
~/.od/app.sqlite All project metadata, artifact history, settings, and the index linking UUIDs to project names Critical. Losing this makes the project directories orphaned and unnavigable through the UI
~/.od/projects/ All generated artifact files, previews, and exports Critical. Losing this means no exportable files even if the database is intact
~/.od/config.json Daemon port, model provider API keys (if stored here), and runtime settings Important. Losing it requires reconfiguring your agent connections and provider keys
~/.od/logs/ Daemon logs for debugging Low. Useful for debugging but not needed for recovery

Portability Between Machines

To move an Open Design installation to a new machine, copy the entire ~/.od/ directory. Because the daemon indexes projects by UUID, not by absolute path, the projects should be navigable on the new machine once you start the daemon. If you're using Docker Compose, the named volume is the equivalent of ~/.od/; export it with docker volume export.

2.5 The Frontend and the Sandboxed Preview

Next.js 16, React 18, and the srcdoc iframe that keeps generated code isolated

The frontend is a Next.js 16 application built on React 18 and TypeScript. It talks to the daemon over HTTP and receives the artifact stream over SSE. The most important design decision in the entire preview system is the choice to render generated artifacts inside a sandboxed srcdoc iframe --- not in the React component tree directly. That choice is what Open Design documents as isolating agent-generated HTML, JavaScript, and CSS from the host page's browser session, cookies, and DOM. (This describes documented design intent for v0.9.0; it is not a security guarantee — see the not-security-advice note in front matter.)

Why srcdoc, Not innerHTML

A naive implementation would parse the generated HTML and inject it into a DOM node with innerHTML. The problem: any JavaScript in the generated artifact would execute in the same origin as the Open Design frontend. A generated artifact with a document.cookie access or a localStorage.clear() call would run against your real session.

The srcdoc iframe solves this by giving the artifact its own isolated document. Open Design's sandbox configuration omits allow-same-origin while including allow-scripts; in this configuration, the browser prevents scripts inside the iframe from accessing the parent frame's DOM or storage. The streaming artifact parser writes tokens into the iframe's document as they arrive from the daemon, so you see the artifact build in real time. (This describes the sandbox configuration as documented for v0.9.0; sandbox attributes may be adjusted in future versions — verify current behavior against the repo.)

Official Open Design entry view showing the project dashboard and frontend interface at v0.9.0, with the project sidebar on the left and the main canvas area on the right
Figure 2.4 — The Open Design frontend (entry view). Official Open Design screenshot reproduced under Apache-2.0; source: docs/screenshots/01-entry-view.png in the Open Design repository. Original copyright: Open Design authors.

The sandbox is not a restriction on what the artifact can do --- it's a restriction on what the artifact is configured to do to the host page. Generated CSS animations, interactive JavaScript, and complex layouts all work inside the iframe. What the v0.9.0 sandbox configuration prevents is cross-frame access to the host page's DOM and storage. Keep the sandbox on, and verify the sandbox attributes haven't been relaxed if you're building on a fork.

The Next.js 16 Frontend

As of June 2026, the frontend runs on Next.js 16 with React 18. The App Router is used throughout. The frontend is a display layer --- it does not hold authoritative state. If you close the browser tab and reopen it, the project list and artifact history are still there because the daemon and its SQLite database didn't change. The daemon owns the truth; the frontend renders it.

This separation has a practical consequence: you can restart the frontend server without losing work. The daemon continues running and holds all state. When the frontend reconnects, it reads the current state from the daemon. This also means you can have multiple browser tabs showing different projects simultaneously, each connected to the same daemon --- they stay in sync because they're all reading from the same source.

2.6 The Electron Shell and Docker Option

Desktop packaging with sandboxed renderer, and server deployment with Compose

The prebuilt desktop app wraps the frontend and daemon in an Electron shell. Electron handles process management, auto-update, native OS integration, and the sandboxed renderer that adds a second layer of isolation on top of the srcdoc iframe. If Electron is the wrong fit for your deployment --- shared servers, headless CI, Docker-native infrastructure --- the Docker Compose path gives you the same daemon and frontend without it.

The Electron Shell

Electron hosts the Next.js frontend in a sandboxed renderer process. The renderer communicates with the daemon via sidecar IPC --- a lightweight inter-process channel that the Electron main process manages. This means the daemon is a separate Node process from the Electron main process, not a thread inside it. If the daemon crashes, the Electron shell can report it and offer a restart without the whole app exiting.

The Electron sandboxed renderer disables Node.js integration in the browser context, so the frontend JavaScript cannot make arbitrary filesystem calls even though it's running inside a desktop app. Open Design's desktop packaging is designed with two sandbox boundaries between agent-generated code and your filesystem: the srcdoc iframe boundary, and the Electron renderer boundary. (This describes documented design intent for v0.9.0; it is not a security warranty — see the not-security-advice note in front matter.)

Electron Shell

Optional desktop wrapper. Sandboxed renderer process + sidecar IPC. Handles auto-update and native OS integration.

Absent in Docker Compose and from-source browser paths.

↓ hosts
Next.js 16 Frontend

React 18 + TypeScript. Display layer only — holds no authoritative state. Served at localhost:7456.

↓ HTTP + SSE · localhost:7456
Node 24 Daemon (Express)

The single source of truth. Owns the better-sqlite3 database, project files on disk, and agent orchestration. Streams artifact tokens to the frontend over SSE.

↓ writes
SQLite (~/.od/app.sqlite)

All project metadata, artifact history, and settings. Synchronous writes via better-sqlite3. Persistent volume in Docker Compose.

Figure 2.5 — Open Design architecture: the Next.js web frontend is hosted inside the optional Electron shell and communicates with the local Node daemon (Express + SQLite) over localhost:7456. The Electron shell is absent in Docker Compose and browser-only deployments. Schematic illustration (not a screenshot).

When to Use Docker Compose

Docker Compose is the right choice when you need Open Design accessible to multiple people without installing Electron on each machine, or when you're deploying to a Linux server. The Compose file in deploy/ runs the daemon and frontend as separate services with a shared SQLite volume.

Electron Shell vs Docker Compose: When to Use Each
Constraint Use Electron shell Use Docker Compose
Single developer, local machine Yes — zero overhead, native OS integration Unnecessary; adds Docker maintenance cost
Shared team deployment on a server No — Electron requires a display server Yes — headless, browser-accessible
CI/CD pipeline with artifact generation No Yes — composable with existing Docker tooling
Need auto-update from open-design.ai Yes — built into the desktop app No — requires manual image pulls
Air-gapped or proxy-heavy corporate network Possible, with download caching Yes — once image is pulled, fully offline

Architecture in One View

At this point you have a mental model of the full system. The daemon owns the truth: it owns the SQLite database, the files, and the agent orchestration. The frontend and the preview iframe are windows. The Electron shell is optional packaging. Docker Compose is an alternative runtime environment. All of these serve the same daemon core.

Electron Shell

Optional. Sandboxed renderer + sidecar IPC. Native OS integration and auto-update.

Next.js 16 Frontend

React 18, TypeScript. Display layer only. Reads state from daemon via HTTP; receives artifact stream via SSE.

Express Daemon (Node 24)

Owns orchestration, better-sqlite3 database, and project files. Streams artifacts over SSE.

srcdoc iframe

Sandboxed preview. Streaming artifact parser writes tokens in real time. Isolated from host page.

Figure 2.6 — Full Open Design architecture from Electron shell to sandboxed preview. The daemon is the single source of truth; everything else is a layer over it.
My Take

The daemon-as-truth-owner design is the part of Open Design's architecture that most people underestimate on first use. I've seen teams try to back up just the project files and wonder why the UI can't find them after a machine migration. The daemon owns the truth means the SQLite database is the first thing you back up, not the last. The files are useless without the index, and the index is useless without the files. Treat them as a single unit.

Next Chapter

Your First Artifact

The complete generate-preview-iterate-export loop

Continue Reading

©2026 Mehran Mozaffari. Free for personal/noncommercial use (CC BY-NC-ND 4.0); commercial license required for business use.