Robin Khanduri
PAR --:--
Contact
Case 01 · Build · 2025 → now

Dafolle OS

The operating system that runs a design studio, from the brief to the invoice.

Role
AI engineer → CTO
Company
Dafolle (Verity Studio SAS), Paris
Timeline
Nov 2025 → now
Stack
React, Supabase, Deno, Claude, Stripe

Dafolle sells design by subscription. When I arrived, production lived in one SaaS, data in Airtable, a sync tool mirrored it into Postgres, and the business rules ran as numbered Airtable automations. Dafolle OS replaced that with one system: the client portal, the production floor, the billing, and DaLab, an AI studio where 14 agents and a node-graph engine do real design work.

One app, three roles
Team
Admins and designers run production, review and staffing.
Client
Clients brief, review, pay and manage credits in the portal.
Lab
Self-serve accounts use the AI studio directly.
(01) At a glance

A studio’s worth of tools.

  • 14AI agents45 tools, one orchestrator
  • 33Pipeline node types9 categories, 17 typed sockets
  • 8Retrieval corporaCalls, tasks, contracts, briefs and more
  • 13MCP toolsRead-only, run as the designer
(02) What it replaced

From a stack of tools to one system.

The old setup did its job across several tools. The rewrite moved the rules into code and the truth into Postgres, and kept the legacy tools in sync while they retire.

Before
  • Production in Orchestra, a design-subscription SaaS
  • Data in Airtable, mirrored into Postgres by Whalesync
  • Business rules as numbered Airtable automations
  • Rules scattered across tools, no single source of truth
After
  • Postgres 17 as the source of truth, RLS on every table
  • Airtable automations ported to edge functions
  • Two-way Orchestra sync while the legacy mirror retires
  • Money rules enforced by triggers, not by people
(03) Architecture

Trace a request through the system.

Five layers, twenty-two moving parts. Pick a flow, or hover any node. Every box here maps to real code: edge functions, a Deno worker, a remote MCP server and one Postgres doing a lot of the thinking.

Auto-tracing · pick one
ClientsEdge / APIAIDataExternalSSEvector searchWeb appTeam · client · labFigma pluginPush to StudioClaude CoworkRemote MCP clientSupabase AuthJWT · rolesPostgRESTRLS everywherePlugin functionsDevice flow · uploadsMCP connectorOAuth 2.1 · 13 toolsBilling functionsStripe · creditsSync functionsOrchestra · daily · insightsOrchestratorChat · tool loopGeneratorSites · decks · editsPipeline queueRuns as rowsRender workerDeno · SKIP LOCKEDBatch AIIndexing · health · sizingPostgres 17Source of truth · pgvectorpg_cron · pg_netVault · schedulesStorage · RealtimeAssets · live progressOpenRouterClaude · Gemini · falStripe14 event typesOrchestra ↔Airtable → WhalesyncClaapCalls · AI fieldsResend · SlackMail · alerts
(04) The AI layer

Agents are rows, not code.

Every agent is a record: prompt, model, allowed tools, context sources, output kind. Versions are pinned to each conversation, and clients can get locked forks. Shipping a better agent is a migration, not a deploy.

Models
  • Design generationClaude OpusGenerator
  • ChatClaude SonnetOrchestrator
  • Memory, cheap editsClaude Haikuextraction, micro-edits
  • Images, visionGeminiFlash Image, Pro vision

Routed through OpenRouter and streamed over SSE, with prompt caching on long system prompts. Every call logs its token and cache usage.

14 agents
Design 9

Specialists for sites, decks, mockups, social and images.

Assistants 4

For the team, for clients and for operations.

Copilot 1

Drafts pipeline graphs from a sentence.

  1. 01ContextAgent row, pinned version, tenant scope
  2. 02RetrieveEmbeddings in pgvector, scoped per client
  3. 03GateConfident → answer; otherwise tools
  4. 04Tool loopBounded rounds, set per agent type
  5. 05GenerateSites, decks, PPTX, micro-edits
  6. 06LintAnti-generic rules, same turn

Retrieval with a confidence gate.

Chunks are entities, not token windows: one document per client per source, across eight corpora. There is no reranker. Instead, if the three best hits agree strongly enough, the agent answers straight away. If not, it gets its tools, including read-only SQL.

ClientsClaap recapsTasksTeamContractsCommentsDeliverablesOnboarding briefs
Top 3 hits · cosine similarity
0.45

mean 0.523

ConfidentAnswer from retrieved context
(05) Pipelines

A node graph that does real work.

DaLab has a ComfyUI-style editor for design automations. The node catalogue has zero imports, so the same file runs in the browser, on the edge and on the worker. Graphs are stored as immutable versions with a lockfile.

DaLab · pipeline editor · demoDrag nodes · run · edit the brief · run again
Concurrency
0
Ran
0
Cache hits
0
Time
0.0 s
InputBriefidle
text
“Launch post for a coffee roaster, three variants (rev 1)”
ContextBrand packidle
brand
brand.md · tokens.json · rules.json
TextLLM · Copyidle
textbrand
copy
Claude Sonnet3 headlines, 3 captions, alt text
AgentDesign agentidle
copybrand
html
Claude Opus3 layouts at 1080 × 1350
ImageImageidle
copy
image
Gemini Flash Image3 hero images, on-brand grade
GateHuman reviewidle
htmlimage
ok
Waiting for a designer
OutputDeliverableidle
ok
Task version, PNG + HTML
  1. Ready. Press run.
Catalogue
33 node types, 9 categories, 17 typed sockets
Scheduler
Topological wavefront, bounded concurrency
Reruns
Per node, descendants follow, dead branches pruned
Cache
SHA-256 content-addressed, scoped per client
Humans
Runs pause for questionnaires and review
Apps
Graphs deploy as public apps

Postgres is the job queue.

Edge functions stop at about 400 seconds, and design pipelines do not. Runs are rows; a Deno worker claims them with FOR UPDATE SKIP LOCKED, sends heartbeats, and runs the exact executor the edge runs. A pg_cron reaper fails anything whose heartbeat goes quiet.

A copilot drafts graphs from a sentence. It proposes a compact graph, a validator expands it and checks it against the schema and the database, and the errors go back to the model as diagnostics until it compiles.

Graph shape
{
  version,
  nodes: [{ id, type, data, position }],
  edges: [{ source, sourceHandle,
            target, targetHandle }],
  inputs: []
}
(06) Studio tools

Three tools inside the studio.

DaLab

DaLab, the studio inside the studio.

Designers brief agents the way they brief each other. Each project is a thread; up to six stay open as live tabs.

  • Attachments: images, PDFs (text plus first pages rendered), Markdown, CSV, JSON
  • Image generation and editing, 25 styles with real renders
  • Design systems specified in conversation, checked against a token contract
  • Decks with presenter mode and speaker notes
  • Inspect-to-edit, undo and redo, an append-only revision log
  • Export to HTML, a handoff zip with manifest, PDF and PPTX

The DaLab interface is modelled on the Apache-2.0 Open Design project, credited in the repository.

Brand OS · Shipping now

Brand OS compiles a brand.

A brand goes in as a seven-section document, a token import (DTCG and three other formats) or a single image. Publishing validates it, compiles the rules and freezes an immutable version with a pack of files. Every generation afterwards reads brand.md as the authority.

brand.mdbrand.jsontokens.jsonrules.jsonmanifest.jsonREADME
  • Brand book in the client portal
  • A public, shareable brand page
  • Deterministic brand checks, optional narrative
Claap insights

Every client call becomes context.

A scheduled job pulls AI fields from Claap in batches, with retries, and survives the API changing shape. Sections are upserted per recording, template, section and language, then embedded for retrieval and turned into health scores and risk flags.

SentimentPain pointsAction itemsBudgetBANT
(07) Billing & credits

Money rules live in the database.

Dafolle moved from cycle subscriptions to a credit model. The ledger was validated with a first client, and existing agreements were untouched: a trigger sets each agreement’s pricing model from its plan.

Credit ledgerappend-only · illustrative data
operationlotdeltabalance
·
·
·
·
·
·

One row per lot touched. A trigger stamps the running balance.

Price books
Versioned: draft, active, archived. Immutable once active and pinned per agreement.
Credit lots
Every grant is its own lot with a unique source, so a grant can never land twice.
Movements
Append-only. One row per lot touched, a unique operation key, and the running balance stamped by a trigger.
Stripe
  • Checkout, billing portal, setup intents, payment links with promo codes
  • Proration previews and scheduled plan changes; pause, extend, cancel
  • 14 webhook event types, disputes, credit notes, manual invoices
  • Nightly reconciliation and a dry-run-by-default invoice replay
(08) Figma plugin

Signing into Figma without a password field.

Figma plugins cannot host a normal login, so the plugin uses a device flow in the spirit of RFC 8628. The designer sees a short code, confirms it in the app, and the plugin receives a token it can never be given twice.

Figma pluginEdge functionsWeb appPostgresrequest a device code01device code, short user code, poll interval, expiry02designer confirms the code, signed in03store only a hash of the new token, narrowly scoped04poll until confirmed05consume the authorisation under a row lock06plaintext token, exactly once, then nulled07create version → signed upload → commit08
(09) MCP connector

Claude can read the studio. Safely.

A remote MCP server lets designers ask Claude about clients, tasks and calls. It is its own OAuth 2.1 authorisation server, supports dynamic client registration and PKCE, and hands sign-in to Supabase. It never holds a service key: every query runs as the designer, so row-level security is the boundary, and every tool call is logged.

13 read-only toolsRFC 8414 · 9728 · 7591PKCETeam members onlyAudited per call
(10) Discipline

How the codebase stays honest.

RLS rewrite
Wrapping auth calls so Postgres evaluates them once per query (an InitPlan) took a client’s board from 1,375 ms to 59 ms.
Migrations
Dry-run inside transactions that roll back, with simulated JWT claims. Schema snapshots before any money change.
CI
Build, image-size budget and npm audit are hard gates.
Tests
Node specs for the app, Deno tests for the functions.
One rewrite, measured
Before1,375 ms
After59 ms

A client’s board query, same data, same policy intent.

(11) Timeline

From a list view to a studio.

  1. Nov 2025Work begins on the new system
  2. Dec 2025List view, Supabase auth
  3. Jan 2026First Stripe integration, comments
  4. Feb 2026Kanban overhaul, Figma import, first edge functions
  5. Mar 2026Query layer, AI chat with pgvector RAG and memory, RLS on every table
  6. Apr 2026S3 and CloudFront, health monitoring, Figma plugin, first design agent
  7. May 2026Deck system, DaLab, six specialist agents, pipelines with the off-edge worker
  8. Jun 2026Cowork MCP connector, off-edge site builds, portal rebuild, parallel execution
  9. Jul 2026Designer pay, deploy-as-app, pipeline copilot
  10. Aug 2026Image-to-brand-system, streamed tool loop, client-facing assistant, Lab OS
  11. Sep 2026Studio remake, engine registry, the credit model, Brand OS
(12) What the database taught me.

Postgres ended up being more than storage. It is the job queue, the rules engine and the audit log. Every time a piece of truth moved into the database, a class of bugs disappeared, because there was one less place for the story to disagree with itself.

Next Case 02 · Recognition→
Replantify