Schema Overview
Schema Overview
A PrototypeSchema is a plain TypeScript object that fully describes a tool. It is the single source of truth for rendering, computation, and persistence.
Full type signature
interface PrototypeSchema {
// Identity
key: string // Unique across all tools — also the default Y.js doc key
// Display metadata
title?: string
description?: string
icon?: string // Iconify icon e.g. 'i-lucide-calculator'
// Form content (use one or the other)
fields?: Record<string, FieldDef> // flat form
sections?: SectionDef[] // grouped/tabbed form
// CRUD lists
collections?: Record<string, CollectionSchema>
// Computation
derived?: Record<string, DerivedDef>
connections?: ConnectionsDef[] // legacy cross-doc watcher (prefer produces/consumes)
// Output display
results?: {
badge?: (ctx: ComputeContext) => { label: string; color: string } | null
stats?: (ctx: ComputeContext) => StatItem[]
}
// Charts and tables
visualizations?: VizDef[]
// Dashboard card summaries
cards?: CardDef[]
// Cross-tool data flow
produces?: Record<string, string> // 'outputKey': 'derived.fieldName'
consumes?: Record<string, string> // 'localAlias': 'sourceTool.sourceKey'
// Action toolbar
actions?: ProtoAction[]
// Custom layout (overrides default sequential rendering)
layout?: DashboardLayout
}
Key groupings
fields vs sections
Use fields for a simple flat form:
fields: {
revenue: { type: 'number', label: 'Monthly Revenue (€)', default: 10000 },
costs: { type: 'number', label: 'Monthly Costs (€)', default: 6000 },
margin: { type: 'number', label: 'Target Margin (%)', default: 30 },
}
Use sections to group inputs into labeled panels:
sections: [
{
title: 'Revenue',
cols: 2,
fields: {
recurring: { type: 'number', label: 'Recurring Revenue (€)' },
oneTime: { type: 'number', label: 'One-Time Revenue (€)' },
}
},
{
title: 'Costs',
cols: 2,
fields: {
fixed: { type: 'number', label: 'Fixed Costs (€)' },
variable: { type: 'number', label: 'Variable Costs (€)' },
}
}
]
If both fields and sections are present, sections takes precedence for rendering.
results
Renders a badge and stat cards below the form:
results: {
badge: ({ derived }) =>
derived.margin >= 0.3
? { label: 'Healthy Margin', color: 'success' }
: { label: 'Low Margin', color: 'warning' },
stats: ({ fields, derived }) => [
{ label: 'Gross Profit', value: derived.grossProfit, format: 'money' },
{ label: 'Margin', value: derived.margin, format: 'percent' },
{ label: 'Annual Revenue', value: derived.annualRevenue, format: 'money' },
],
}
actions
actions: [
{ type: 'copy-text', label: 'Copy Summary', icon: 'i-lucide-clipboard', text: … },
{ type: 'export-markdown', label: 'Export Report', icon: 'i-lucide-download', markdown: … },
{ type: 'reset', label: 'Reset', icon: 'i-lucide-trash-2', confirm: true },
]
The ComputeContext type
All callback functions in results.badge, results.stats, derived[x].compute, visualization items, and layout badge receive a ComputeContext:
interface ComputeContext {
fields: Record<string, any> // current unwrapped field values
derived: Record<string, any> // computed derived values (in definition order)
connections: Record<string, any> // values from upstream produces
collections: Record<string, any[]> // CRUD collection items
}
StatItem format
interface StatItem {
label: string
value: any
format?: 'money' | 'percent' | 'number' | 'date' | 'text'
prefix?: string
suffix?: string
color?: string // Nuxt UI color name
}
Stat format types
format | Input type | Example output |
|---|---|---|
'money' | number | € 12,345 |
'percent' | number (0–100) | 23.5 % |
'number' | number | 1,234 |
'date' | ISO string | Mar 2026 |
'text' | string | as-is |
Use the format property on DerivedDef for the same formatting in derived value display:
{ type: 'money', currency: '€', decimals: 0 }
{ type: 'percent', decimals: 1 }
{ type: 'number', decimals: 0, suffix: ' months' }
Quick Start
Build your first tool in under 10 minutes — a resource cost estimator with form inputs, derived values, a result badge, and automatic offline persistence.
Field Types
Complete reference for all FieldDef types — text, number, textarea, select, segmented, toggle, range, rating, color, date, tags, and linked-responses.