SwanPlatform documentation
Swan Workspace / Edition 02

Build an agent-operated asset platform.

A from-scratch blueprint across five layers: design, discovery, deal rooms, templates, and the agent runtime.

22 OCTOBER 20267,193 WORDS33 MIN READBUILDING-GUIDE.md

00 · Read this before building

This platform turns a company's design system and approved sales content into a reusable asset library, customer deal rooms, and versioned assets created by an agent. The agent is a primary operator, not a magic renderer: it discovers registered content, follows contracts, invokes protected services, and submits output to validators before it becomes customer-visible.

There are five product layers:

  1. AI designer + design system: a coding agent builds native, branded assets from real source material and reusable design primitives.
  2. Asset library: one discovery surface across native assets, files, external links, documents, and generated assets.
  3. Deal rooms: ordered, customer-specific collections with consistent public, tracked, embedded, and phone viewing.
  4. Templates: validated content structures, approved layouts, examples, and deterministic calculations for repeatable assets.
  5. Virtual file system + runtime agent: versioned file trees, safe compilation, durable generation/edit jobs, stable URLs, and optional room attachment.

The layers are not five independent apps. They share identifiers, presentation contracts, publishing state, security boundaries, and discovery metadata. Building only the screens produces an imitation that cannot reliably be operated by an agent.

What this documentation is

This file is a reconstruction specification: the coherent target to build in a fresh project. SYSTEM-REFERENCE.md describes the current implementation, including compatibility paths and limitations. OPERATIONS.md describes how to change and verify it. Read all three before proposing a plan. Do not copy old customer data, tokens, pricing, personal information, or secrets into a new deployment.

A guide cannot guarantee a perfect one-prompt rebuild. Provider provisioning, actual brand inputs, dependency changes, security review, and integration testing remain necessary. Completion means the acceptance gates pass with evidence, not that every file has been generated.

What exists versus what is recommended

The present app uses TanStack Start, React, TypeScript, Tailwind, Lovable Cloud, native asset registries, typed templates, VFS compilation, and protected HTTP/MCP interfaces. It also retains older payload templates and editing screens. A new deployment should preserve the underlying contracts while applying the security controls specified below. Recommendations are not claims that the existing deployment has been audited or hardened.

The designer in layer 1 is the external coding agent working on project source. It is not a custom in-app chat canvas. The runtime agent in layer 5 creates constrained assets through the API. Do not silently replace one with the other.

Scope

Required: branded design primitives, searchable library, decks/one-pagers/apps/uploads/links, live deal rooms, scoped asset viewing, sharing/tracking, template catalog, typed generation, VFS authoring, revision history, rollback, protected agent endpoints, and a documented verification procedure.

Optional extensions after the core gates pass: collaborative legal documents and signatures, email delivery, advanced attribution, per-end-user integrations, and custom app capabilities. They must not delay or obscure the five-layer core.

01 · Give this to your coding agent

Attach all three documentation files and your real brand/source assets. Paste:

Build an agent-operated asset and deal-room platform from these documents.
Read BUILDING-GUIDE.md, SYSTEM-REFERENCE.md, and OPERATIONS.md in full.
Treat the Building Guide as the fresh-build target and the System Reference
as a map of the original implementation, not a mandate to reproduce gaps.

First inventory the starting project and identify dependencies, framework,
backend provisioning, and missing brand inputs. Keep the supported framework.
Produce a phased implementation plan in the order given in section 02.
Maintain a roadmap and architectural instructions for future coding agents.

For each phase: implement its vertical slice, add tests for its actual rules,
run those tests, verify the UI and persistence, and record evidence.
Do not claim a phase passed if credentials or a deployed integration are missing.
Do not invent customer numbers, proof points, logos, or source documents.
Do not publish or send customer links without explicit approval.

Use semantic design tokens and shared controls. Keep privileged credentials
server-side. Every write endpoint needs a verified operator or agent credential.
Public rendering must never expose private context, raw asset files, analytics,
email addresses, or internal notes. Hidden navigation is not authorization.

Ask only for missing inputs that cannot safely be defaulted. Do not ask me
to pick internal table names or libraries. Start with the foundation.

Inputs to collect once

  • Brand name, approved logo files, palette, display/body fonts, light/dark treatment, and tone rules.
  • Representative source content: one real deck, one long-form document, one PDF, one demo URL, and an approved example of a recurring proposal or brief.
  • Representative name, role and headshot; default room stages; desired welcome copy.
  • First test company and domain. Use a clearly synthetic company unless real customer use is approved.
  • Operator access policy, secret management method, public versus gated sharing requirements, tracking consent/retention policy, and allowed webhook destinations.
  • Approved business formulas, units, periods, and rounding rules. Missing numbers remain unknown, not fabricated.

Brand values are inputs, not infrastructure defaults. Backend choice should follow the supported platform: in Lovable, use Lovable Cloud. Outside Lovable, provision equivalent PostgreSQL, storage, deployment, and secure operator identity. Do not pretend Lovable-specific asset or secret tools exist in another environment.

Maintain four durable records

  • Roadmap: open tasks, dependency blockers, and completed acceptance gates.
  • Architectural rules: root AGENTS.md plus narrowly scoped rules near templates or other subsystems.
  • Preferences and constraints: persistent project memory where supported; otherwise a versioned requirements document.
  • Procedures: a deal-room creation checklist and asset-generation checklist, implemented as project skills only where the agent platform supports them.

These records have different jobs. Memory holds user decisions; architecture instructions hold structural invariants; procedures hold repeatable steps; source and tests remain authoritative for behavior.

02 · Build order and acceptance gates

The product layers are conceptual; the implementation sequence resolves their dependencies.

  1. Foundation: stack, security model, tokens, primitives, workspace shell.
  2. Native assets: deck/one-pager/app registries and one real asset of each kind.
  3. Persistence + library: locked tables, storage, link registration, discovery DTOs, search and inspector.
  4. Deal rooms + sharing: safe public reads, ordered attachment, phone viewer, thumbnails, gate, tracking and revocation.
  5. Typed templates: catalog, schema, examples, pure renderer, computed business logic, retirement policy.
  6. VFS + durable agent: archetypes, sanitizer/compiler, reservation, jobs, generation, editing and rollback.
  7. Agent orchestration + handoff: MCP, discovery descriptions, room procedures, observability, production verification.

Each phase ends with a usable vertical slice, not a folder of stubs. A real document must traverse registration → discovery → viewing → room attachment → public rendering. A generated asset must traverse acceptance → publication → edit → version read → rollback.

Do not begin with the runtime agent. It cannot create trustworthy assets before the library, schemas, renderers, and public boundary exist.

03 · Foundation: runtime and trust model

Supported stack

Reference implementation: TanStack Start v1 with file-based routing, React 19, TypeScript, TanStack Query, Vite, Tailwind v4, Zod, and Lovable Cloud. Use the framework's server functions for internal calls and file-based server handlers for raw HTTP integrations. The hosted runtime is a Worker, not a general-purpose Node server.

On Lovable, preserve the existing bootstrap (src/router.tsx, src/routes/__root.tsx, src/routes/index.tsx). Do not install a second router, create an App.tsx page switcher, or create a competing index route. Route files must exist before links reference them; do not edit the generated route tree.

Loaders are isomorphic. Place secret-backed work behind server-only handlers. Read environment secrets inside handlers, not at module scope. Do not prefix private keys with VITE_. Keep SDK clients and runtime objects out of RPC return values.

Browser storage is read after hydration. Browser-only packages need dynamic import boundaries; hiding JSX behind ClientOnly does not make a static import server-safe. Never run headless browsers, native PDF renderers, or child processes inside a deployed Worker handler. Thumbnail capture belongs in development tooling or a separately provisioned service.

Four trust zones

Operator / coding agent                 Customer browser
        |                                      |
Verified management credential         Public URL / share token
        |                                      |
Protected mutations + private reads    Safe rendering projection
        |                                      |
        +-------- application server ----------+
                           |
                 Locked database + storage

“No end-user signup” does not mean “no authorization.” Protect workspace reads and mutation endpoints through verified operator identity or server-checked management credentials. A route guard protects navigation, not the directly callable service. Check authorization at each privileged endpoint before loading an administrative client.

Customer URLs may intentionally be public, gated by email, or tokenized. An email gate is identity capture, not proof of ownership of that email unless a verification flow is implemented. A public slug URL may remain accessible after a token is revoked. Be honest about both limits.

Foundation prompt

Establish the supported full-stack framework and backend.
Do not add public signup. Define operator, agent, public-render, and tracking
trust zones. Require verified authorization at every privileged endpoint.
Create semantic design tokens and shared UI primitives before asset layouts.
Create the workspace shell and design-system specimen page.
Document runtime boundaries in AGENTS.md. Do not add customer content yet.

Gate F

  • Stack bootstraps without runtime/hydration errors.
  • A private operation fails without credentials and succeeds for an authorized operator.
  • Public rendering uses a separate safe DTO.
  • No administrative client or secret enters the browser bundle.
  • Missing backend provisioning is recorded as a blocker, not faked with local data.

04 · Layer 1: the AI designer and design system

Design-system contract

Centralize semantic roles for background, foreground, surfaces, muted text, borders, primary action, action text, focus ring, destructive state, proof/metrics, and chart categories. Define typography, spacing, radii, shadows and motion. Apply light/dark values through the theme, not per-component hardcoded colors.

Keep the workspace visual language separate from customer-facing collateral where necessary, but share role names and primitives. The existing workspace's editorial typography is not a reason to impose its screen layout on a presentation slide.

Create a design-system reference with actual token swatches, type specimens, shared controls, asset variants, motion examples and slide primitives. The reference must consume real tokens; duplicating values in specimens defeats its purpose.

Load external font stylesheets through document head links, never remote CSS imports. Respect reduced motion. Use fixed type sizes with responsive breakpoints or container-fitting where necessary, rather than letting every heading scale unpredictably with viewport width.

Designer workflow

  1. Read brand instructions, relevant assets, and the source brief.
  2. Classify the requested output as native deck, native page, app, template instance, or generated VFS asset.
  3. Reuse approved primitives and composition patterns before creating new ones.
  4. Separate source facts, user-approved assumptions, computed values, and missing information.
  5. Create an isolated variant for customer-specific or experimental changes; do not mutate widely shared content without permission.
  6. Register the output with a description and audience.
  7. Verify reading order, phone view, print view where relevant, and embedded room rendering.
  8. Capture the output's real first screen for its thumbnail.

The designer can edit source and make rich compositions. The runtime generation agent must remain within template/archetype constraints. Native React code is not an allowed VFS file format.

Native deck model

A deck has a unique kebab-case slug, title, required concise description, audience, tags, ordered slides, slide metadata and a lazy loader. Each slide has a unique slug and title. Animation metadata and presenter notes are optional capabilities, not required for static sales decks.

Use a fixed 16:9 slide coordinate space and scale it uniformly into the viewer. Do not reflow a carefully composed slide into a long mobile web page. Provide touch navigation, keyboard controls, a presenter mode, and a print route. Keep thumbnail rendering lightweight: loading the library must not import every slide bundle.

Registry summaries and loaders must have exact parity. Validate uniqueness and missing modules. A shared deck's commercial examples must be labeled as examples rather than accidentally becoming a customer offer.

Native pages and apps

One-pagers are fluid long-form pages or intentional fixed-format print pages. Record natural width for fixed pages so the room viewer can scale them. A route alone does not make an asset discoverable: add its registry entry and required metadata.

Apps may be native routes or static HTML. The viewer needs an explicit branch for each mode. Do not assume setting nativeRoute: true is sufficient if the preview code only reads htmlPath. For new apps, require an embeddable presentation and verify it inside a room.

Layer 1 prompt

Build the design primitives and the first native deck, one-pager, and app
from the attached source content. Keep facts and figures unchanged.
Use lazy registry loading and shared viewer/print controls.
Register each asset with slug, title, description, tags, route and audience.
Support embed mode without workspace controls, phone navigation and print
where appropriate. Capture real first-screen thumbnails.

Gate D

  • Change one token and see all relevant specimens/assets update.
  • Deck viewer, touch navigation, presenter mode and print work.
  • Every asset is listed and opens from its registry.
  • Fixed-format pages fit a ~360px room viewer without clipping.
  • No invented proof points or commercial figures appear.

05 · Layer 2: asset identity and library

Identity model

An asset is reusable content. A room item is an attachment of that content to a customer room. A share link is a way to distribute it. A template is a recipe. A version is a revision of generated content. Keep all five concepts separate.

Use an asset key such as kind:id or kind:slug. Do not assume slug uniqueness across kinds. Upload IDs are UUIDs; native deck/page/app IDs are slugs; template instances and VFS assets use their own persistent IDs and URL slugs.

The library's normalized read model should include:

type AssetSummary = {
  key: string;
  kind: "deck" | "onepager" | "app" | "upload" | "link" | "document";
  id: string;
  title: string;
  description: string;
  audience: "collateral" | "customer";
  tags: string[];
  thumbnailUrl?: string;
  viewerUrl?: string;
  managementUrl?: string;
  sourceType: "native" | "upload" | "external" | "payload" | "vfs";
  createdAt?: string;
  updatedAt?: string;
  usedInRooms?: number;
};

This is a recommended fresh-build DTO, not a literal type copied from the current app. Source type explains persistence; presentation kind explains how it appears. A generated pricing proposal is a one-pager, not a new “proposal” kind.

Every asset needs a one-sentence description, at most 200 characters for ordinary discovery metadata. Recording-specific room descriptions may be longer verified bullet summaries. Audience guides selection; it is not an access-control guarantee.

Aggregation

Read native deck/page/app summaries from code registries. Read uploads, external links, documents, payload instances, and live VFS assets from persistence. Normalize them into one list. Filter archived links and retired recipes out of discovery without breaking existing references.

Search name, customer, tags, description and filename. Preserve query, filters and selected asset in the URL so back/refresh restore context. Use a side inspector for details, receiver view and management view. Do not make users download a document merely to identify it.

Heavy previews must load on demand. Do not build the home screen by rendering every slide and every PDF. Use bounded activity queries; native code-defined assets with no creation timestamp must not be counted as newly created every week.

File workflow

  1. Authorized operator requests an upload URL after validating name, MIME type, size and path.
  2. File uploads to private storage.
  3. Finalization verifies the object and persists library metadata.
  4. Public file viewing resolves an approved file identifier and creates a temporary safe storage read.
  5. PDF rendering uses a client-safe viewer with loading, page navigation, error and open-original fallback.

Never persist a short-lived signed URL as the canonical asset URL. Store the object path and stable file-page identifier. Support byte ranges where large files require them. File access and storage policies need separate checks from database RLS.

Link workflow

Normalize URLs, validate HTTPS where appropriate, reject unsafe schemes and private-network fetches, and use provider metadata for title/thumbnail when available. Keep extraction bounded and resilient to unavailable providers.

URL registration must not revive an archived record. Archive removes discovery; it does not delete the row or invalidate old room items. For new rooms, choose the current canonical demo through configured defaults and discovery, not a hardcoded retired URL.

Layer 2 prompt

Build a unified searchable asset library using code registries and locked
backend records. Add private upload reservation/finalization and safe file
viewing, URL-normalized external links, first-screen thumbnails, and usage
counts. Preserve URL search state and show separate receiver/manage actions.
Exclude archived links from discovery while preserving referenced playback.
All private metadata and mutations require verified operator access.

Gate L

  • Each supported kind appears with correct description, audience and real preview.
  • Upload, finalize, list and open a real test PDF on desktop and phone.
  • An archived link disappears from discovery but still plays in an older test room.
  • Duplicate URL registration does not restore archived content.
  • Search/back/refresh preserve state.
  • Anonymous access cannot enumerate private metadata or storage objects.

06 · Persistence and security specification

Tables by domain

Use ordered migrations, not a giant unreviewed SQL block. Core domains are:

  • Native metadata mirror: decks, slides_index where database discovery needs native summaries.
  • Library: dealroom_uploads, asset_links, template_instances.
  • Rooms: dealrooms, dealroom_items, dealroom_create_log for idempotency.
  • Sharing: share_links, share_sessions, share_events, share_rate_limit.
  • Room analytics: dealroom_sessions, dealroom_events.
  • Generation: virtual_assets, virtual_asset_versions, agent_generation_jobs.
  • Template overrides: template_workspace_overrides when protected per-template authoring overrides are supported.
  • Optional webhooks: webhook_connections, webhook_watches, webhook_events, webhook_deliveries, internal_viewers.

The current repository contains migrations for these domains. This list is not a complete executable schema; use the current source/migrations as a reference and generate a fresh, reviewed schema with the contracts below. Do not replay account data or assumptions from a historical migration into a new product.

Core relational contract

dealrooms: unique slug, customer name/domain, title, welcome text, private context, status, published time, representative presentation fields, co-brand image, process tracker and timestamps.

dealroom_items: room FK, stable stage ID, sort order, presentation kind, one compatible asset reference, optional presentation overrides, optional inline note/map/prompt content, timestamps. Enforce that references match the kind. Resolving an item must also prove it belongs to the requested live room.

asset_links: unique normalized URL, title, description, thumbnail, audience, archive timestamp and timestamps. Preserve the row while referenced.

dealroom_uploads: persistent object path, filename, MIME type, byte size, description, audience and optional historical room relationship. File metadata is reusable even if the table name is room-oriented.

template_instances: template slug/version, instance slug, payload, metadata and source. Keep this legacy domain separate from VFS trees.

share_links: high-entropy token, exact target references, email-capture setting, recipient details, internal note, revocation time. Public projection excludes recipient email and internal notes.

virtual_assets: unique stable slug, template/archetype, title/description, status, current version pointer, reserved/publication metadata. virtual_asset_versions: asset FK, unique increasing version, immutable files, provenance/note and timestamp.

agent_generation_jobs: request snapshot, idempotency key, type, asset target, state/stage, attempt/lease metadata, status/result/error and timestamps. Job acceptance and reservation must be atomic.

Database authorization

Enable RLS on application tables. For service-role-only domains, use no anon/authenticated policies and restrict grants appropriately. “No policies” is the intentional lock; do not add permissive policies merely to silence a scanner. Never combine that instruction with “create deny-all public policies” as if they were the same design.

Public access uses a narrowly projected server response or a deliberately granted safe SQL function. A SECURITY DEFINER function must set a safe search path, verify the exact input capability/live target, select named safe columns, and have restricted EXECUTE privileges. Do not return entire rows or arbitrary private fields.

Sensitive share data (recipient_email, notes, visitor identity, raw event/session data), raw VFS files, private context, and webhook secrets never become public read results. Management authorization must be checked before using a privileged database client.

The reference app's gate is client-side identity capture; do not describe it as database-enforced document secrecy. If the new deployment requires confidential document access, verify a server-side session/capability on every HTML, file and public read path. Hiding navigation, tagging audience, and requiring an email field are insufficient.

Fresh-schema instructions for agents

For each domain, write DDL, FK/index constraints, explicit GRANT/REVOKE, RLS configuration, safe projections and tests together. Use application-owned tables in public; do not alter managed schemas. Seed synthetic test records through literal migration INSERTs when the initial UI is specified to contain them. Avoid foreign keys to managed auth tables except approved profile/role relationships.

For atomic room creation, reserve the company/idempotency record, insert the room and ordered items, and return a complete result. For VFS publication, compare the current version, insert one immutable version and update the pointer transactionally. Back these operations with database functions or equivalent transactions; a sequence of independent browser writes is not sufficient.

Gate S

  • Anonymous direct reads of every sensitive table fail or return no rows as intended.
  • No public RPC returns private columns.
  • Cross-room item lookup fails.
  • Missing, revoked and inactive targets cannot leak files through alternate reads.
  • Privileged HTTP/RPC endpoints fail without credentials.
  • Two concurrent publications cannot both overwrite the same base version silently.
  • Run and review a fresh security scan; historical scan results are not evidence of current safety.

07 · Layer 3: deal rooms

Room orchestration

One room per company by default. Discover existing rooms by name/domain before creating. Reuse/update the existing room unless the operator explicitly requests a separate one. Support idempotency for retried creates; a retry must return the same room rather than clone it.

A room contains co-branding, a welcome from a representative, process tracker, content-stage grouping and ordered items. The process tracker and content-stage tabs are different concepts: a sales process might be at Scoping while content is grouped under Overview and Proposal.

Stable content identifiers in the current API are overview, proposal, resources, commercials, deep_dive, compliance, next_steps. Fresh builds may choose another catalog once, but keep identifiers stable afterward. Customer-facing exceptions belong in presentation configuration, not mass row rewrites.

Room items can override title, description and thumbnail without changing the library asset. A call recording should show a verified room-specific overview above its open-recording action. Do not invent a transcript from a video URL.

Routes and resolution

  • /room/<slug>: live public room.
  • /room/<slug>/a/<itemId>: room-scoped single asset.
  • /s/<token>: tracked distribution of a room or asset.
  • /a/<slug>: generated VFS asset viewer.
  • /f/<uploadId>: permanent file-viewing route.

Resolve room items through (room slug, item UUID), not item UUID alone. Viewer links stay within the customer context. Embedded native pages hide workspace chrome. Give unavailable content a clear state without implying access to private management pages.

Desktop and phone

Desktop: readable welcome, process tracker and an asset workspace with resizable sidebar. Selecting an item loads its content in the main pane.

Phone below 768px: use the same dedicated room component on direct and tracked links. A compact co-brand row, small headshot, stable stage tabs and lightweight preview grid keep the room overview usable. Assets open in a full-screen sheet with back/close, previous/next, loading and error states. Lock background scroll while the sheet is open and restore focus/history when closing.

Do not promise every possible welcome message and item count will fit without scrolling. The shell should use bounded regions and deliberate internal scrolling for large rooms; it must not clip content. Validate empty, one-item, many-item, long-title and many-stage rooms as well as the happy path.

Within the sheet: scale decks, use real PDF rendering, scale fixed-page assets, allow fluid documents to scroll, and keep video aspect ratios stable. Phone and desktop use the same data/resolver; layout differences must not require database migration.

Thumbnails

  • Deck: actual title slide.
  • PDF/document: page 1.
  • Video: provider-native still.
  • One-pager/template: first page.
  • App: first usable screen.

Capture in a development browser or dedicated rendering service. Rehost the preview and store a durable URL. Do not use a generic icon when a real preview can be obtained. Missing preview should be an explicit fallback with a repair task, not a made-up depiction of the content.

Layer 3 prompt

Build public live-room and room-scoped asset routes using safe projections.
Add company lookup/reuse and idempotent creation, ordered typed references,
rep welcome, process tracker and stable content-stage grouping.
Use a resizable desktop viewer and one shared mobile view below 768px on both
direct and tracked links. Include asset-sheet history, loading/error and
focus restoration. Capture real content thumbnails. Verify every asset kind
inside a real test room, not only standalone routes.

Gate R

  • Create a synthetic room, read it back, and verify order/stages and exact references.
  • Retry the same create and get the same room.
  • Open every asset from both direct and tracked phone links.
  • Different-room item IDs do not resolve.
  • Browser back, close, previous/next, keyboard focus and scroll restoration work.
  • Archived/draft room public lookup is unavailable.
  • Desktop remains stable after phone changes.

08 · Sharing, identity capture and analytics

Share contract

A share token points to one exact target, carries optional recipient metadata and an email-capture flag, and can be revoked. Generate high-entropy URL-safe tokens server-side. Do not use sequential IDs or customer names as tokens.

Show a gate only when that share link requires email. Do not force it for a deliberately ungated link. Direct room access may have a different default, but the tracked path must honor its configuration.

Revocation invalidates the token. It does not automatically revoke the target's public slug/file URL or another valid token. Confidentiality requires a server-checked target capability, not a cosmetic gate. Document the distribution policy before sending links.

Tracking contract

Separate asset shares from room visits. Start a session, heartbeat only while visible, record actual slide/item transitions, and end/flush safely. Rate-limit inputs and validate that the session belongs to the target. Use raw HTTP routes for beacon/keepalive behavior rather than manually fetching internal RPC URLs.

Do not label every heartbeat as a new visit. The current room aggregation uses a 25-minute quiet window; that is visit batching, not a claim that an email identity expires every 25 minutes. Handle repeat visits, anonymous-to-known identity, internal viewers and duplicate events deliberately.

Choose and document privacy/retention policy before storing IP, geographic or device information. The reference implementation does store such private visit metadata; a new deployment must not blindly copy it. Public tracking responses never return analytics or visitor identity. Email capture is self-reported unless verified.

Optional webhooks

Connections are registered through a protected interface; signing secrets are returned only once. Assets opt into watches. Persist events and delivery attempts separately, use event IDs for receiver deduplication, sign the exact serialized body, retry transient failures, and expose delivery status only to operators.

Reference signing convention: HMAC-SHA256 over <timestamp>.<body> in X-Swan-Signature. Receiver checks signature, timestamp freshness and replay IDs before applying the event. Validate outbound HTTPS destinations against SSRF/private networks; URL syntax alone is not authorization. No arbitrary customer content should choose a privileged webhook destination.

Sharing prompt and gate

Add tokenized sharing with optional email capture and revocation.
Implement safe session/event tracking and bounded private analytics.
Respect requireEmail on each link, separate identity capture from authorization,
and document raw-target URL access. Add signed, retryable watched webhooks only
after the core tracking flow is verified and privacy policy is recorded.

Pass when a configured gated link asks for email, an ungated link does not, a real visit records once and reads back in authorized analytics, a revoked token fails, no anonymous analytics query leaks data, and a webhook receiver can validate a signed test event.

09 · Layer 4: template contracts

Recipe, not just layout

A template includes slug/version, purpose, audience, authoring instructions, schema, validation, an approved example, renderer and options. It declares its presentation archetype and whether an agent may infer content from free-form context.

The template schema must model what the renderer actually displays. Do not accept fields that disappear silently or require authors to write HTML to express basic content. Optional blocks need explicit defaults/absence behavior. Separate account content from theme and layout.

The current preferred path is a typed-content template: /content.json is authoritative; a validator accepts it; a pure renderer produces the files; reads regenerate presentation from the validated content. This preserves business rules and design without making the model edit markup.

Legacy payload-backed React templates and model-authored VFS templates remain compatibility paths in the current system. A fresh build can prioritize typed templates, while still supporting free-file authoring for appropriate archetypes. Never treat the three storage/authoring modes as interchangeable.

Recommended typed interface

type Validation<C> =
  | { ok: true; content: C }
  | { ok: false; errors: Array<{ path: string; message: string }> };

type TypedTemplate<C> = {
  slug: string;
  title: string;
  description: string;
  archetype: "onepager" | "deck" | "app";
  brief: string;
  validate: (raw: unknown) => Validation<C>;
  render: (content: C) => Array<{ path: string; content: string }>;
  assetTitle: (content: C) => string;
  assetDescription: (content: C) => string;
  example: C;
  agentAuthoring: boolean;
};

First template vertical slice

Choose one recurring brief with approved source material. Define company, problem, objectives, scope, timeline, proof, commercial inputs, assumptions, sources and next step only where the output needs them. Use synthetic or approved reusable examples, not confidential customer details.

Validate empty and malformed content, correct optional behavior and limits. Render both standalone and embedded phone views. Add catalog/typed/starter registration together so discovery never advertises a recipe the runtime cannot generate.

Business calculations

Keep formulas in shared pure modules. Represent currency, units, baseline, target, period, cohort and rounding explicitly. Never let the model calculate totals by concatenating prose.

Separate customer forecasts from modeled incremental value. A model's target is an assumption, not a validated outcome. Avoid double-counting interacting drivers: if productivity uplift applies only to incremental SDR pipeline, do not apply it again to the full new-logo base. For annualized ROI, align annual cost, revenue target, ACV and meeting conversion over the same period.

For each approved rule, add a test asserting concrete values and edge cases. Examples of cases: zero denominator, inconsistent currencies, missing baseline, reversed period, negative cost, and rounding between meetings and closed wins. Do not use snapshot tests of sales copy as a substitute for arithmetic tests.

Evolution

New recurring structure → new template slug. Minor safe renderer fix → shared renderer update plus regression check. New customer-only content → new instance. Retired recipe → keep renderable, exclude from new generation/discovery. Read-time rendering means old typed instances can visually change when the renderer changes; if contractual visual immutability is required, add renderer pinning or an export snapshot explicitly.

Layer 4 prompt

Implement a typed template from the approved recurring asset.
Make validated content JSON the authority; render presentation in pure code.
Centralize calculations with tests, label assumptions and preserve source facts.
Register schema, example, authoring brief, renderer, catalog and starter together.
Support dry-run field errors and retire recipes without breaking old instances.

Gate T

  • Approved example validates; empty/wrong-type content fails with field paths.
  • Renderer produces authoritative content JSON and matching presentation files.
  • Changing a calculated input updates every displayed dependent figure consistently.
  • Malformed/ungrounded input cannot silently publish.
  • Retired templates vanish from new-work catalog but old URLs render.
  • Phone, embedded and print behavior match the declared archetype.

10 · Layer 5: virtual files and safe compilation

What VFS means here

VFS is a database-stored file tree belonging to a single generated asset. It is not a general filesystem, repository checkout, Node application, or place to execute arbitrary code. Versions store immutable file sets; the public URL points to the current published version.

The compiler turns allowed files into a self-contained viewing document. Templates provide starter trees and instructions. The authoring agent may propose content, but only validators and the trusted compiler decide what reaches the browser.

Archetypes

One-pager: /index.html required; optional /styles.css, /content.json, /notes.md; fluid scroll; printable; no authored scripts.

Deck: /deck.json and /styles.css required; manifest references /slides/<lowercase-slug>.html; optional content/notes; 1–30 ordered slides; scaled 16:9 view with trusted navigation runtime and print.

App: /index.html and /interactions.json required; optional style/content/notes; fluid interactive view; trusted declarative runtime. Controls are toggle, tabs or range, not arbitrary JavaScript.

Current archetype caps are 90,000 UTF-8 bytes per file; 240,000 total for one-pager/app; 420,000 for deck. A legacy common validator still uses 180,000 total and at most 40 files. Effective limits depend on the path's validators; new builds should centralize one authoritative policy and test every endpoint against it. Never equate characters with bytes.

Validation order

  1. Parse files, reject duplicate/unknown/traversal paths and enforce file count/UTF-8 budgets.
  2. Require the archetype's files.
  3. Validate manifests, unique slide slugs, referenced slide files, control IDs, target IDs and range bounds.
  4. Run template-specific validation and typed content validation when applicable.
  5. Sanitize HTML and CSS with parser-based allowlists, URL protocol checks and bounded input.
  6. Inject brand tokens, safe shell, responsive/print rules and only trusted compiler-owned runtime.
  7. Reject compiler warnings or invalid/empty documents according to a documented policy.
  8. Publish atomically only after validation succeeds.

Authored scripts, arbitrary iframes, event handlers, network calls and forms do not become executable runtime code. Trusted embed exceptions need explicit code ownership and allowlisting. CSS is scoped to the asset root so it cannot restyle the workspace.

Isolation

Serve compiled assets separately from management APIs. Use a restrictive CSP and archetype-specific iframe sandbox permissions. One-pagers do not require script permission; deck/app runtimes do, but authored code remains rejected. Isolation must prevent asset output from reading parent storage, navigating to privileged screens, or invoking operator APIs.

An iframe with script execution and same-origin privilege needs particular scrutiny. Treat sandbox flags and CSP as part of the compiler's security contract, not generic markup copied into every viewer. Prefer a separate origin for script-capable generated content when strong isolation is required.

Typed files

For typed templates, derive all rendered files from content. A direct file write that changes HTML while leaving content unchanged must fail. Human edits use content replacement, dotted-field patches, or an instruction-to-content revision where that template permits agent authoring.

Store author notes privately. Render-time content validation must also run on historical versions. VFS source reads are private agent/operator endpoints; public HTML readers never return raw source/history.

Layer 5 compiler prompt

Build a versioned VFS with onepager/deck/app archetypes, per-archetype paths
and UTF-8 limits, parser-based sanitization, manifest validation and a trusted
compiler. Typed templates must reject presentation files that disagree with
content JSON. Serve compiled output through safe CSP/sandbox boundaries.
Add tests for malicious scripts, URLs, CSS escape, invalid IDs, paths,
size budgets, missing slides and mismatched typed files before generation.

Gate V

  • Script/handler/unsafe URL input is stripped or rejected as specified.
  • Invalid control/slide references, duplicate paths and oversized UTF-8 trees fail.
  • Valid deck navigation and app controls work without authored scripts.
  • Typed file mismatch cannot publish.
  • Public rendering reveals neither raw files nor private author notes.
  • Compiler does not need a real server filesystem or native binary.

11 · Durable generation, editing and rollback

URL-first lifecycle

Authorized request
    → validate + reserve job/idempotency/asset URL atomically
    → return 202 with Location and Retry-After
    → claim leased job
    → route template + author content/files
    → validate + compile
    → compare base version + publish immutable version
    → attach to room if requested
    → persist result + emit notification

A reserved URL is not proof of completed content. The viewer must show queued/running/failed/unavailable states until publication. Do not send it to customers as “ready” simply because acceptance returned a URL.

Jobs need persisted requests, ownership leases, lease expiry, heartbeat, bounded retries, failure classification and a recovery/sweep mechanism. A fire-and-forget promise does not guarantee execution after a request ends. Use a real background execution mechanism supported by the deployment. Verify restart/lease recovery in the target runtime.

Idempotency and concurrency

Generation keys replay the original accepted job. Edit keys replay the same edit; reuse for a different edit must conflict. Store a stable request fingerprint and return the original result/URL. Database uniqueness and transactions enforce this, not an in-memory map.

Edits capture a base version. Publication checks the current version against the expected base. If another writer wins, return a conflict and require re-read/rebase, rather than overwriting. A rollback copies an older file set into a new version; it does not erase intervening history.

Current HTTP contract to reproduce

Protected agent calls use X-Dealroom-Create-Secret; secrets are provisioned through secure tools and never placed in docs, browser code, query strings or customer URLs. These paths contain /public/ because they accept external HTTP callers, not because mutations are unauthenticated.

POST /api/public/agent-generate accepts free-form context or explicit typed content. Optional fields include guidance, template slug, idempotency key, title, description, rendering mode, notification URL, room creation or attachment, and dry-run. Typed dry-run returns validation errors without persisting a job. Generation otherwise returns 202 with job/status URL and reserved asset URL.

GET /api/public/agent-generate?job=<id> reads status/results with the same credential. Poll the returned URL according to Retry-After. Do not create a second job because the first connection dropped.

GET /api/public/agent-asset?slug=<slug>&version=<n> reads metadata, files/history and typed content privately.

POST /api/public/agent-asset supports:

  • Instruction edit with idempotency key and optional expected version.
  • Direct allowed file patch with expected version.
  • Typed content replacement or dotted-field patch with idempotency key; dry-run does not need the key.
  • Rollback to a historical version, published as a new current version.

See the System Reference for field limits and response distinctions. For fresh builds, keep these request modes mutually exclusive and protect patch traversal against prototype keys and invalid array traversal; schema validity alone does not make arbitrary object mutation safe.

Safe request examples

These are illustrative shapes, not complete template payloads. Fetch the selected template's example/schema and replace content with a validated real object.

{
  "templateSlug": "launch-scope-v1",
  "content": {},
  "dryRun": true
}

The empty object should fail validation with field errors. That is the intended first negative test, not a working generation example.

{
  "context": "Prepare a launch scope using the approved attached discovery notes and exact commercial inputs.",
  "templateSlug": "launch-scope-v1",
  "idempotencyKey": "example-company-scope-v1",
  "attachTo": { "slug": "example-company", "stage": "proposal", "position": "start" }
}

Only use a real existing test room and template that allows context authoring. Fetch the published typed content before patching a field:

{
  "slug": "example-generated-asset",
  "patch": [{ "path": "company.name", "value": "Example Company" }],
  "expectedVersion": 1,
  "dryRun": true
}

A patch path is valid only if that template defines it. Follow a passing dry-run with a fresh version check and an idempotency key.

Runtime-agent prompt and gate

Implement authorized URL-first generation and editing with persisted jobs,
atomic reservations, leases, heartbeat, bounded recovery and idempotent replay.
Support typed content and allowed VFS authoring separately. Validate before
publication, compare expected versions, preserve immutable history and roll
back by publishing a new version. Return honest pending/error states.

Pass when a real input generates, status reads completion, the public UI renders, repeated acceptance returns the same job, a typed edit reads back through the UI, stale-version publication conflicts, rollback creates a new version with restored content, and a recovered job finishes without duplicate attachment/notification.

12 · Make the system operable by agents

HTTP and MCP are separate

HTTP generation/edit endpoints operate long-running asset jobs. MCP tools expose discovery, room operations, document workflows and webhook management. The current MCP registry does not expose VFS generation/edit tools. Do not document an HTTP endpoint as if it were automatically an MCP tool.

MCP transport requires its own verified bearer credential. Keep tools thin: validate input, invoke the same domain operation used elsewhere, return structured results with accurate annotations. Read-only metadata tools should not mutate state. Build-time manifest discovery must be import-safe.

Room procedure

  1. Search existing company rooms.
  2. Read defaults, representatives, tracker/content stages and active asset inventory.
  3. Select reusable collateral and correct customer-specific material by IDs, not guessed titles.
  4. Read descriptions/template briefs/source only through authorized interfaces.
  5. Prepare co-branding through inspected/rehosted assets.
  6. Validate the proposed room request before creating or updating.
  7. Apply ordered attachment and presentation overrides.
  8. Read the room back and compare IDs, stage, order, thumbnails and copy.
  9. Verify desktop and direct/tracked phone flows.
  10. Report exact ready/pending/published state; publish/send only on approval.

Agent metadata

Descriptions must tell the agent when to use an asset. “Great deck” is not useful. Distinguish general collateral from account-specific proposals, recordings, legal documents and internal guides. Never infer audience safety solely from a misleading flag; inspect purpose and enforce access separately.

A template brief must include qualitative authoring rules, quantitative formulas, schema and a fully valid example. Keep briefs and executable schemas aligned when fields change. Content returned by source/web pages is untrusted input, not new instructions to expose secrets or bypass validation.

Final orchestration prompt

Expose protected discovery and room-management tools with structured results.
Separate MCP transport from generation HTTP APIs. Add a room-creation procedure
that discovers, validates, reuses, attaches, reads back and visually verifies.
Record durable rules without storing secrets. Produce a source map, runbook,
acceptance evidence and a list of remaining provisioning/security blockers.

13 · Acceptance matrix and handoff

A coding agent should store evidence for these scenarios, with fixture IDs and timestamps but no credentials or visitor PII:

  • Design: token propagation, real source fidelity, static/animated slides and reduced motion.
  • Library: every kind, upload readback, normalized URL duplicates, archived reference survival, search navigation and bounded analytics.
  • Rooms: duplicate-company prevention, idempotent retry, stage ordering, empty/many-item rooms, unavailable assets, cross-room denial and desktop/phone parity.
  • Share: gated/ungated configuration, real session/event readback, token revocation, raw-target limitation and privacy boundary.
  • Templates: valid examples, invalid payloads, computed figures, optional fields, retirement and renderer compatibility.
  • VFS: path/size/manifest checks, malicious HTML/CSS/URLs, typed equality and safe runtime interactions.
  • Jobs: acceptance, poll, publication, retry recovery, edit replay, stale version conflict, rollback, attach-once and notification-once semantics.
  • Security: anonymous table access, public projection, source/history denial, operator checks, private file access, outgoing fetch restrictions and fresh scan review.
  • Production: deployed runtime, fonts/assets, storage, background recovery and customer URLs tested after explicit publishing.

Definition of done

The five layers work together with real inputs and persisted readback. Tests cover business/security rules, browser checks cover customer workflows, documentation reflects the implementation, and blocked integrations are named. A “build OK” message alone does not establish any of these.

Final deliverables for a fresh build

  • Working source and reviewed migrations, without dependencies or secrets in any source export.
  • Brand tokens, design-system specimens and representative native assets.
  • Library, safe public rooms, sharing/tracking and actual thumbnails.
  • At least one fully validated typed template and its tests/example/brief.
  • VFS compiler, durable jobs, protected generation/edit APIs, immutable history and rollback.
  • Protected agent discovery/room tools and a repeatable operating procedure.
  • Updated system reference, runbook, architectural rules, roadmap and evidence report.

The platform compounds when every asset can be discovered, every reusable recipe can be validated, and every public output can be revised safely without losing its identity. Build those properties before polishing the long tail.