xml-pipeline/docs/nextra-architecture.md
dullfig f275382922 Add AI Flow Builder Assistant architecture
The assistant is itself a Nextra flow (dogfooding):
- Builder agent with catalog, validator, examples tools
- Queries real available nodes dynamically
- Self-validates generated YAML before returning
- Uses marketplace flows as few-shot examples
- Same billing model (LLM tokens)

Added Phase 4.5 to implementation roadmap.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 22:35:10 -08:00

989 lines
41 KiB
Markdown

# Nextra SaaS Platform — Architecture Design Document
**Version:** 1.0 (Draft)
**Date:** January 2026
**Status:** Planning
## Executive Summary
Nextra is a SaaS platform for building AI agent workflows using the xml-pipeline library. Users visually design message flows on a canvas, which generates the underlying YAML configuration. Flows run on isolated container instances with support for built-in tools, marketplace components, and custom WASM modules.
### Key Differentiators
- **Visual flow builder** with real-time YAML synchronization
- **Turing-complete** message routing (self-iteration, conditionals, parallel execution)
- **WASM sandboxing** for custom code (no Python upload = secure)
- **Marketplace** for sharing tools and complete flows
- **Anti-paperclipper** design with user-controlled memory
---
## System Overview
```
┌─────────────────────────────────────────────────────────────────────────┐
│ USERS │
│ (Browser / API Clients) │
└───────────────────────────────┬─────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ VERCEL (Frontend) │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Next.js Application │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Flow Canvas │ │ YAML Tab │ │ Monaco │ │ │
│ │ │ (React Flow)│ │ (Preview) │ │ (WASM) │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Dashboard │ │ Marketplace │ │ Settings │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └───────────────────────────────────────────────────────────────────┘ │
└───────────────────────────────┬─────────────────────────────────────────┘
│ REST / GraphQL
┌─────────────────────────────────────────────────────────────────────────┐
│ RENDER (Backend) │
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Control Plane (FastAPI) │ │
│ │ • User management (via Clerk webhooks) │ │
│ │ • Flow CRUD (organism.yaml storage) │ │
│ │ • Pump orchestration (start/stop/scale) │ │
│ │ • Trigger routing (webhooks → pump injection) │ │
│ │ • Marketplace catalog │ │
│ │ • WASM module registry │ │
│ │ • Billing integration (Stripe) │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │
│ │ Orchestrates │
│ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Pump │ │ Pump │ │ Pump │ │
│ │ Container │ │ Container │ │ Container │ │
│ │ (Flow A) │ │ (Flow B) │ │ (Flow C) │ │
│ │ │ │ │ │ │ │
│ │ StreamPump │ │ StreamPump │ │ StreamPump │ │
│ │ + WASM RT │ │ + WASM RT │ │ + WASM RT │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └─────────────────┼─────────────────┘ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Redis (Shared State) │ │
│ │ • Context buffers: tenant:{id}:flow:{id}:buffer:* │ │
│ │ • Thread registry: tenant:{id}:flow:{id}:registry:* │ │
│ │ • Project memory: tenant:{id}:flow:{id}:memory:* (opt-in) │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ PostgreSQL (Persistent) │ │
│ │ • Users, organizations │ │
│ │ • Flows (organism.yaml stored as text) │ │
│ │ • Marketplace listings │ │
│ │ • WASM modules (metadata, S3 refs) │ │
│ │ • Billing records │ │
│ └───────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ EXTERNAL SERVICES │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Clerk │ │ Stripe │ │ LLM APIs │ │ S3 │ │
│ │ (Auth) │ │ (Billing)│ │ (xAI,etc)│ │ (WASM) │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
```
---
## Tier Model
| Tier | Price | Flows | Tools | Custom Code | Features |
|------|-------|-------|-------|-------------|----------|
| **Free** | $0 | 1 | Built-in only | ❌ | Community support |
| **Paid** | $X/mo | Multiple | + Marketplace | ❌ | Email support |
| **Pro** | $XX/mo | Unlimited | + Marketplace | ✅ WASM/WIT | Priority support |
| **Enterprise** | Custom | Unlimited | + Private | ✅ WASM/WIT | SSO, roles, SLA |
### Limits (TBD)
| Resource | Free | Paid | Pro | Enterprise |
|----------|------|------|-----|------------|
| Flows | 1 | 10 | Unlimited | Unlimited |
| Executions/month | 1,000 | 10,000 | 100,000 | Custom |
| WASM modules | 0 | 0 | 10 | Unlimited |
| Project memory | ❌ | 10MB | 100MB | Custom |
| Team members | 1 | 1 | 1 | Unlimited |
---
## Component Architecture
### Frontend (Next.js on Vercel)
#### Tech Stack
- **Framework:** Next.js 14+ (App Router)
- **UI Generation:** Vercel v0
- **Components:** shadcn/ui + Tailwind CSS
- **Flow Canvas:** React Flow (Xyflow)
- **Code Editor:** Monaco Editor (TypeScript mode)
- **State:** Zustand or Jotai
- **API Client:** tRPC or React Query
#### Code Editor Architecture (Pro+ WASM)
AssemblyScript editing uses Monaco's built-in TypeScript language service — no separate
language server required. Since AssemblyScript is a strict TypeScript subset, this provides:
- Syntax highlighting
- Autocomplete / IntelliSense
- Type checking
- Error diagnostics
The AssemblyScript type definitions (`.d.ts`) are loaded into Monaco at startup.
```
User writes code in Monaco (TypeScript mode)
Real-time feedback from TS language service
(syntax, types, autocomplete)
User clicks "Build" / "Deploy"
Backend runs `asc` compiler
├── Success → .wasm file stored, module registered
└── Errors → Returned to UI with line numbers
(Monaco shows error markers)
```
**Why no AssemblyScript Language Server (asls)?**
- Monaco TypeScript covers 90%+ of editing needs
- The `asc` compiler catches AS-specific errors accurately at build time
- Eliminates $7+/month infrastructure cost
- Zero cold-start latency (runs in browser)
#### Key Pages
| Route | Purpose |
|-------|---------|
| `/` | Landing page |
| `/dashboard` | Flow list, usage stats |
| `/flow/[id]` | Flow canvas editor |
| `/flow/[id]/yaml` | YAML editor view |
| `/flow/[id]/runs` | Execution history |
| `/marketplace` | Browse tools/flows |
| `/settings` | Account, billing, API keys |
#### Flow Canvas Features
```
┌─────────────────────────────────────────────────────────────────┐
│ [Save] [Run] [Stop] [YAML] [Canvas] [Split] │
├─────────────────────────────────────────────────────────────────┤
│ ┌───────────┐ │
│ │ Palette │ ┌─────────┐ ┌─────────┐ │
│ │ │ │ Webhook │ ───▶ │ LLM │ ──┐ │
│ │ [Built-in]│ │ Trigger │ │ Call │ │ │
│ │ [Market] │ └─────────┘ └─────────┘ │ │
│ │ [Custom] │ │ │
│ │ │ ┌─────────┐ │ │
│ │ 📦 Trigger│ │ Code │ ◀─┘ │
│ │ 📦 LLM │ │ Block │ │
│ │ 📦 HTTP │ └────┬────┘ │
│ │ 📦 Code │ │ │
│ │ 📦 Branch │ ▼ │
│ │ ... │ ┌─────────┐ │
│ └───────────┘ │ Output │ │
│ └─────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Minimap │ Zoom: 100% │ Nodes: 4 │ Status: Saved │
└─────────────────────────────────────────────────────────────────┘
```
#### Node Types
| Node | Visual | Maps To |
|------|--------|---------|
| Trigger | 🎯 Circle | Injection endpoint |
| LLM Call | 🤖 Box | Agent listener |
| HTTP Request | 🌐 Box | HTTP tool |
| Code Block | 📝 Box | WASM handler |
| Conditional | ◇ Diamond | Branch logic |
| Output | 📤 Box | Terminal handler |
| Loop | ↻ Arrow back | Self-iteration |
#### Flow Lifecycle Controls
Simple two-state model: **Stopped****Running**
```
┌─────────────────────────────────────────────────────────────┐
│ Flow States │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ [▶ Run] ┌──────────┐ │
│ │ Stopped │ ─────────────▶ │ Running │ │
│ │ │ ◀───────────── │ │ │
│ └──────────┘ [■ Stop] └──────────┘ │
│ │ │ │
│ │ Edit allowed │ Edit blocked │
│ │ Triggers ignored │ Triggers processed │
│ │
└─────────────────────────────────────────────────────────────┘
```
**UI Controls:**
```
[▶ Run] [■ Stop] [Save] ← Action bar
```
**State Transitions:**
| Action | From | To | Behavior |
|--------|------|----|----------|
| Run | Stopped | Running | Start pump container, enable triggers |
| Stop | Running | Stopped | Kill container, lose in-flight threads |
| Save | Stopped | Stopped | Persist YAML to database |
| Save | Running | — | Blocked (must stop first) |
**Why no Pause?**
- Simpler state machine
- Matches user expectations (Zapier, n8n, Make all work this way)
- Flows should be stateless — restart is safe:
- Webhooks retry automatically (HTTP behavior)
- Schedules catch next tick
- Project memory (Pro) survives restart
**Why no Hot Edit?**
- Modifying a swarm mid-execution risks undefined behavior
- Agent could be mid-reasoning when peers list changes
- Stop → Edit → Start is safer and predictable
**Future consideration (Pro):** Graceful Stop
- Stop accepting new triggers
- Wait up to N seconds for in-flight threads to complete
- Force-stop after timeout
### Control Plane (FastAPI on Render)
#### Tech Stack
- **Framework:** FastAPI
- **ORM:** SQLAlchemy 2.0 + asyncpg
- **Validation:** Pydantic v2
- **Task Queue:** (Optional) Celery or arq
- **Container Orchestration:** Render Native (or Docker API)
#### API Endpoints
```
Authentication (via Clerk)
───────────────────────────
POST /webhooks/clerk # Clerk webhook for user sync
Flows
───────────────────────────
GET /api/flows # List user's flows
POST /api/flows # Create flow
GET /api/flows/{id} # Get flow details
PUT /api/flows/{id} # Update flow (canvas → YAML)
DELETE /api/flows/{id} # Delete flow
POST /api/flows/{id}/start # Start pump container
POST /api/flows/{id}/stop # Stop pump container
GET /api/flows/{id}/status # Pump status
GET /api/flows/{id}/logs # Stream logs
Triggers
───────────────────────────
POST /api/triggers/{flow_id}/webhook/{token} # Webhook ingress
POST /api/triggers/{flow_id}/inject # Manual injection
Marketplace
───────────────────────────
GET /api/marketplace/tools # Browse tools
GET /api/marketplace/flows # Browse flow templates
POST /api/marketplace/publish # Publish to marketplace
WASM Modules (Pro+)
───────────────────────────
GET /api/modules # List user's modules
POST /api/modules # Upload WASM module
DELETE /api/modules/{id} # Delete module
```
#### Database Schema (PostgreSQL)
```sql
-- Users (synced from Clerk)
CREATE TABLE users (
id UUID PRIMARY KEY,
clerk_id TEXT UNIQUE NOT NULL,
email TEXT NOT NULL,
tier TEXT DEFAULT 'free',
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Flows
CREATE TABLE flows (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
name TEXT NOT NULL,
description TEXT,
organism_yaml TEXT NOT NULL, -- The actual config
canvas_state JSONB, -- React Flow state
status TEXT DEFAULT 'stopped', -- stopped, starting, running, error
container_id TEXT, -- Render container ID
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- WASM Modules
CREATE TABLE wasm_modules (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
name TEXT NOT NULL,
description TEXT,
s3_key TEXT NOT NULL, -- S3 path to .wasm file
wit_interface TEXT, -- WIT definition
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Marketplace Listings
CREATE TABLE marketplace_listings (
id UUID PRIMARY KEY,
author_id UUID REFERENCES users(id),
type TEXT NOT NULL, -- 'tool' or 'flow'
name TEXT NOT NULL,
description TEXT,
content JSONB NOT NULL, -- Tool def or flow template
downloads INT DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Execution History
CREATE TABLE executions (
id UUID PRIMARY KEY,
flow_id UUID REFERENCES flows(id),
trigger_type TEXT, -- webhook, manual, schedule
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
status TEXT, -- success, error
error_message TEXT
);
```
### Pump Containers (Render)
Each flow gets its own container running:
- StreamPump (from xml-pipeline)
- WASM runtime (wasmtime)
- Redis connection (shared state)
#### Container Image
```dockerfile
FROM python:3.11-slim
# Install xml-pipeline
COPY requirements.txt .
RUN pip install -r requirements.txt
# Install wasmtime
RUN pip install wasmtime
# Copy entrypoint
COPY entrypoint.py .
# Environment variables provided by orchestrator:
# - FLOW_ID
# - ORGANISM_YAML (base64 encoded)
# - REDIS_URL
# - TENANT_PREFIX
CMD ["python", "entrypoint.py"]
```
#### Entrypoint
```python
# entrypoint.py
import os
import base64
import asyncio
from xml_pipeline.message_bus.stream_pump import StreamPump
from xml_pipeline.config.loader import load_config_from_string
from xml_pipeline.memory.shared_backend import get_shared_backend, BackendConfig
async def main():
# Load config from environment
yaml_content = base64.b64decode(os.environ["ORGANISM_YAML"]).decode()
config = load_config_from_string(yaml_content)
# Configure shared backend with tenant prefix
backend_config = BackendConfig(
backend_type="redis",
redis_url=os.environ["REDIS_URL"],
redis_prefix=os.environ["TENANT_PREFIX"],
)
backend = get_shared_backend(backend_config)
# Start pump
pump = StreamPump(config, backend=backend)
await pump.start()
# Keep running
try:
while True:
await asyncio.sleep(1)
except asyncio.CancelledError:
await pump.shutdown()
if __name__ == "__main__":
asyncio.run(main())
```
---
## Trigger System
Triggers inject messages into running pumps.
### Trigger Types
| Trigger | Implementation |
|---------|----------------|
| **Webhook** | Control plane receives POST, forwards to pump via Redis pub/sub |
| **Schedule** | Celery beat or Render Cron, injects at scheduled times |
| **Manual** | "Run" button in UI, calls control plane API |
| **Email** | (Future) IMAP polling service |
### Webhook Flow
```
External Service
│ POST /api/triggers/{flow_id}/webhook/{token}
┌─────────────────┐
│ Control Plane │
│ │
│ 1. Validate │
│ 2. Find pump │
│ 3. Publish │
└────────┬────────┘
│ Redis PUBLISH trigger:{flow_id}
┌─────────────────┐
│ Pump Container │
│ │
│ 1. Subscribe │
│ 2. Inject msg │
│ 3. Process │
└─────────────────┘
```
---
## Security Model
### Multi-Tenancy Isolation
```
┌─────────────────────────────────────────────────────────────┐
│ Tenant A │
│ ┌────────────┐ ┌────────────┐ │
│ │ Flow 1 │ │ Flow 2 │ │
│ │ │ │ │ │
│ │ Redis: │ │ Redis: │ │
│ │ tenantA: │ │ tenantA: │ │
│ │ flow1:* │ │ flow2:* │ │
│ └────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Tenant B │
│ ┌────────────┐ │
│ │ Flow 3 │ ← Cannot access tenantA:* keys │
│ │ │ │
│ │ Redis: │ │
│ │ tenantB: │ │
│ │ flow3:* │ │
│ └────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### WASM Sandboxing
Custom code runs in WASM, which provides:
- **Memory isolation** — Cannot access host memory
- **No filesystem** — Only WIT-defined host functions
- **No network** — Must use provided HTTP tool
- **CPU limits** — Fuel-based execution limits
- **Deterministic** — Same input → same output
### Memory Safety (Anti-Paperclipper)
```
┌─────────────────────────────────────────────────────────────┐
│ Memory Tiers │
├─────────────────────────────────────────────────────────────┤
│ Thread Memory (automatic) │
│ ├── Per-execution context buffer │
│ ├── Pruned when thread completes │
│ └── Swarm cannot prevent deletion │
├─────────────────────────────────────────────────────────────┤
│ Project Memory (opt-in, Pro+) │
│ ├── User explicitly enables per flow │
│ ├── Size limits enforced │
│ ├── User can view/delete anytime │
│ └── Cleared on flow deletion │
├─────────────────────────────────────────────────────────────┤
│ Cross-Flow Memory (FORBIDDEN) │
│ ├── Flow A cannot read Flow B's memory │
│ ├── Even same user, different flows = isolated │
│ └── Prevents swarm coordination across boundaries │
└─────────────────────────────────────────────────────────────┘
```
---
## Data Flow Examples
### User Creates Flow
```
1. User drags nodes on canvas
2. Frontend converts to organism.yaml
3. PUT /api/flows/{id} with YAML
4. Control plane validates YAML
5. Saves to PostgreSQL
6. Returns success
```
### User Starts Flow
```
1. User clicks "Start"
2. POST /api/flows/{id}/start
3. Control plane:
a. Fetches YAML from DB
b. Creates Render container
c. Passes YAML + Redis config as env vars
d. Updates flow.status = 'starting'
4. Container starts, pump initializes
5. Pump reports ready via Redis
6. Control plane updates flow.status = 'running'
7. Frontend shows green "Running" status
```
### Webhook Triggers Flow
```
1. External service POSTs to webhook URL
2. Control plane receives at /api/triggers/{flow_id}/webhook/{token}
3. Control plane validates token
4. Control plane publishes to Redis: PUBLISH trigger:{flow_id} {payload}
5. Pump container (subscribed) receives message
6. Pump injects message into StreamPump
7. Pipeline processes, handlers execute
8. Results logged to execution history
```
---
## Canvas ↔ YAML Synchronization
### Canvas → YAML
```javascript
// Frontend: Convert React Flow state to organism.yaml
function canvasToYaml(nodes, edges) {
const listeners = nodes
.filter(n => n.type !== 'trigger')
.map(node => ({
name: node.data.name,
handler: node.data.handler,
payload_class: node.data.payloadClass,
description: node.data.description,
agent: node.data.isAgent || false,
peers: edges
.filter(e => e.source === node.id)
.map(e => findNode(e.target).data.name),
}));
return yaml.dump({
organism: { name: flowName },
listeners,
});
}
```
### YAML → Canvas
```javascript
// Frontend: Convert organism.yaml to React Flow state
function yamlToCanvas(yamlContent) {
const config = yaml.load(yamlContent);
const nodes = config.listeners.map((listener, i) => ({
id: listener.name,
type: getNodeType(listener),
position: calculatePosition(i),
data: {
name: listener.name,
handler: listener.handler,
payloadClass: listener.payload_class,
description: listener.description,
isAgent: listener.agent,
},
}));
const edges = config.listeners.flatMap(listener =>
(listener.peers || []).map(peer => ({
id: `${listener.name}-${peer}`,
source: listener.name,
target: peer,
}))
);
return { nodes, edges };
}
```
---
## Marketplace
### Publishing a Tool
```
1. User creates WASM module (Pro+)
2. User clicks "Publish to Marketplace"
3. Frontend sends:
- Module metadata
- Description, icon, category
- Pricing (free or paid)
4. Control plane:
- Validates module
- Creates marketplace listing
- Makes module available to others
```
### Installing a Tool
```
1. User browses marketplace
2. User clicks "Install" on tool
3. Control plane:
- Adds tool to user's available tools
- Copies WASM module reference
4. Tool appears in user's palette under "Marketplace" tab
```
### Publishing a Flow Template
```
1. User creates working flow
2. User clicks "Publish as Template"
3. Frontend sends:
- Flow YAML (sanitized)
- Description, use case
4. Control plane creates listing
5. Other users can "Use Template" to clone flow
```
---
## Monitoring & Observability
### Metrics (Prometheus/Grafana)
| Metric | Description |
|--------|-------------|
| `nextra_flows_total` | Total flows by status |
| `nextra_executions_total` | Executions by flow, status |
| `nextra_pump_memory_bytes` | Memory per pump container |
| `nextra_pump_messages_total` | Messages processed |
| `nextra_api_requests_total` | API requests by endpoint |
### Logging
- **Control Plane:** Structured JSON logs → CloudWatch/Datadog
- **Pump Containers:** Stream to Redis → Viewable in UI
- **Execution History:** Stored in PostgreSQL
### Alerting
| Alert | Condition |
|-------|-----------|
| Pump crash | Container exits unexpectedly |
| High error rate | >5% executions failing |
| Memory pressure | Pump using >80% memory |
| Stuck flow | No messages processed in 5min |
---
## Scaling Considerations
### Render Service Types
| Component | Render Service | Scaling |
|-----------|----------------|---------|
| Control Plane | Web Service | Horizontal (multiple instances) |
| Pump Containers | Private Services | Per-flow, scale-to-zero |
| Redis | Managed Redis | Vertical |
| PostgreSQL | Managed Postgres | Vertical |
### Scale-to-Zero (Cost Optimization)
```
Free tier flows:
- Auto-stop after 15 min idle
- Webhook triggers wake container (~5s cold start)
- User sees "Starting..." briefly
Paid tier flows:
- Keep-alive option
- Faster cold starts (warm pool)
```
### Future: Multi-Region
```
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ US-East │ │ EU-West │ │ AP-Tokyo │
│ │ │ │ │ │
│ Control Plane│ ←───│ Control Plane│ ←───│ Control Plane│
│ Pump Pool │ │ Pump Pool │ │ Pump Pool │
│ Redis │ │ Redis │ │ Redis │
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
└───────────────────┼───────────────────┘
┌──────────────────┐
│ Global Postgres │
│ (CockroachDB?) │
└──────────────────┘
```
---
## AI Flow Builder Assistant
The platform includes an AI assistant that helps users create flows from natural language
descriptions. The key insight: **the assistant is itself a flow running on Nextra**.
### Architecture (Dogfooding)
```
User: "I want a flow that monitors my website and alerts me on Slack"
┌─────────────────────────────────────────────────────────────────┐
│ flow-builder (system flow, runs on Nextra) │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ builder │ ───▶ │ catalog │ │ examples │ │
│ │ (agent) │ ───▶ │ (tool) │ │ (tool) │ │
│ │ │ ───▶ │ │ │ │ │
│ │ │ └─────────────┘ └─────────────┘ │
│ │ │ │
│ │ │ ┌─────────────┐ ┌─────────────┐ │
│ │ │ ───▶ │ validator │ ───▶ │ responder │ │
│ │ │ │ (tool) │ │ (output) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Returns generated organism.yaml to UI
```
### Tools Available to Builder Agent
| Tool | Purpose |
|------|---------|
| `catalog` | List available nodes (built-in + user's marketplace + custom WASM) |
| `validator` | Check if generated YAML is valid against schema |
| `examples` | Search marketplace for similar flows as few-shot examples |
| `user-modules` | List user's custom WASM modules (Pro) |
### Flow Definition
```yaml
# The AI assistant is itself a flow!
organism:
name: flow-builder-assistant
listeners:
- name: builder
agent: true
prompt: |
You help users create Nextra flows from natural language.
Process:
1. Call catalog to see available nodes
2. Call examples to find similar flows
3. Generate organism.yaml
4. Call validator to check your work
5. Fix any errors and re-validate
6. Return final YAML via responder
Rules:
- Every flow needs at least one trigger
- Agents can only call declared peers
- WASM code blocks require Pro tier
peers:
- catalog
- validator
- examples
- user-modules
- responder
- name: catalog
handler: nextra.builtin.catalog.list_nodes
description: "Returns available node types with schemas"
- name: validator
handler: nextra.builtin.validator.check_yaml
description: "Validates organism.yaml, returns errors if invalid"
- name: examples
handler: nextra.builtin.examples.search
description: "Search marketplace for example flows"
- name: user-modules
handler: nextra.builtin.modules.list_user
description: "List user's custom WASM modules"
- name: responder
handler: nextra.builtin.respond.to_ui
description: "Return result to the UI"
```
### Benefits of This Approach
| Benefit | Why It Matters |
|---------|----------------|
| **No special infrastructure** | Same StreamPump, same handlers, same security |
| **Always accurate catalog** | Queries real available nodes, not static list |
| **Self-validating** | Checks its own work before returning |
| **Learns from marketplace** | Uses community flows as few-shot examples |
| **Same billing** | Just LLM tokens like any agent flow |
| **Customizable (Pro)** | Users could fork and customize the builder |
### Implementation Phases
**Phase 1:** System prompt + validator tool
- Bake common nodes into prompt
- Validate before returning
- 10-20 curated example flows
**Phase 2:** Dynamic catalog
- `catalog` tool queries user's actual available nodes
- Marketplace examples as RAG source
**Phase 3:** Learning loop
- Track AI-generated → user-edited corrections
- Use as fine-tuning signal or RAG pairs
### Content Strategy
Documentation becomes training data:
- Every doc page = context the AI can reference
- Every marketplace flow = few-shot example
- JSON Schema = ground truth for validation
Good docs help humans AND train the AI — double value.
---
## Implementation Phases
### Phase 1: MVP (4-6 weeks)
- [ ] Control Plane basic CRUD
- [ ] Single pump container (manual start/stop)
- [ ] Canvas with basic nodes (LLM, HTTP, Output)
- [ ] YAML preview (read-only)
- [ ] Clerk authentication
- [ ] Free tier only
### Phase 2: Core Features (4-6 weeks)
- [ ] Automatic pump orchestration
- [ ] Webhook triggers
- [ ] Execution history
- [ ] Canvas ↔ YAML sync
- [ ] Paid tier + Stripe billing
### Phase 3: Pro Features (4-6 weeks)
- [ ] WASM module upload
- [ ] Monaco editor integration
- [ ] Project memory (opt-in)
- [ ] Pro tier
### Phase 4: Marketplace (4-6 weeks)
- [ ] Tool publishing
- [ ] Flow templates
- [ ] Browse/search/install
- [ ] Ratings/reviews
### Phase 4.5: AI Flow Builder (2-4 weeks)
- [ ] Builder agent flow (system prompt + tools)
- [ ] Catalog tool (list available nodes)
- [ ] Validator tool (check YAML)
- [ ] Examples tool (search marketplace)
- [ ] UI integration ("Help me build" button)
### Phase 5: Enterprise (TBD)
- [ ] Team/org management
- [ ] Role-based access
- [ ] SSO (SAML)
- [ ] SLA dashboard
- [ ] Private marketplace
---
## Open Questions
1. **Pricing specifics** — What are the actual price points?
2. **Execution metering** — How to count/limit executions fairly?
3. **WASM module review** — Manual review before marketplace publish?
4. **Cold start optimization** — Warm container pool for paid users?
5. **Mobile support** — Canvas on mobile, or just monitoring?
---
## Appendix: Technology Decisions
| Decision | Choice | Rationale |
|----------|--------|-----------|
| Frontend Framework | Next.js | v0 generates it, Vercel hosts it |
| Canvas Library | React Flow | Most popular, good docs, n8n uses it |
| Code Editor | Monaco (TS mode) | No LSP server needed; asc compiler catches AS errors |
| Flow Controls | Run/Stop only | No pause, no hot-edit; stateless flows, safe restarts |
| AI Assistant | Self-hosted flow | Dogfooding: builder is a flow with catalog/validator tools |
| Control Plane | FastAPI | Matches xml-pipeline, async-native |
| Database | PostgreSQL | Render managed, reliable |
| Cache/Pubsub | Redis | Already needed for xml-pipeline shared backend |
| Auth | Clerk | Free to 10K, great DX, handles OAuth |
| Billing | Stripe | Standard, good APIs |
| Frontend Hosting | Vercel | Built for Next.js |
| Backend Hosting | Render | Simple, good DX, containers |
| WASM Runtime | wasmtime | Best WIT support |
---
*Document generated: January 2026*
*Next review: After Phase 1 completion*