Technical Overview

Architecture

Formspec is a JSON-native form specification where structure, behavior, and presentation are independent, composable documents. A single definition drives validation, computed fields, conditional logic, and repeatable sections across five runtimes — web, React, iOS, Android, and server.

Document Model

Document layers

Every Formspec project is a set of composable document layers. Each layer adds a concern without modifying the layers below. Presentation layers (Theme, Components) never affect data collection, validation, or behavioral semantics — they are swappable overlays on an unchanging behavioral core.

Dependency Model

The specification as abstraction boundary

Formspec inverts the usual dependency between frontend and backend. The specification — JSON Schemas, normative prose, and the FEL grammar — is the stable center that all implementations conform to. A Rust shared kernel provides one implementation of all pure logic — FEL evaluation, assembly, linting, mapping, and more — exposed via WASM to TypeScript (browser and React) and PyO3 to Python. Native mobile renderers (iOS and Android) bridge to the same WASM kernel through a hidden WebView. The TypeScript engine keeps Preact Signals for reactive UI state; the React package bridges those signals to React via useSyncExternalStore. Submit a form on Android; re-validate it on the server with full confidence in semantic equivalence — backed by a single Rust implementation across all five runtimes.

Dependency graph: Specification at top, Rust shared kernel in the middle exposing WASM to TypeScript/React and PyO3 to Python, Layout Planner and Studio Core below, with five renderers (web component, React, iOS, Android, server) and authoring tools at the bottom

Rendering is two layers, not one

The layout planner sits between the engine and any renderer. It resolves the theme cascade, expands custom components, merges responsive breakpoints, and produces a plain LayoutNode tree — a JSON-serializable blueprint that says "put a TextInput here with these styles" without knowing anything about the DOM, React, SwiftUI, or Jetpack Compose.

Three renderers consume that blueprint today. The <formspec-render> web component walks the LayoutNode tree, creates DOM elements, and wires Preact Signals for live reactivity. The formspec-react React package does the same via hooks and useSyncExternalStore, with an overridable component map for plugging in Shadcn, Material UI, or any React component library. Native mobile renderers (formspec-swift and formspec-kotlin) bridge to the engine through a hidden WebView and expose platform-native state (SwiftUI @Published, Compose State<T>) — same engine, native components.

The engine owns data and logic. The planner owns presentation decisions. Renderers own pixels.

Headless adapter architecture

The web component uses a headless behavior/adapter split. Behavior hooks extract reactive state from the engine and return a typed contract — ARIA attributes, keyboard navigation, focus management, and validation announcements are all handled here. Render adapters build the DOM structure and CSS classes for a specific design system, then call bind() to wire everything up. This separation means every adapter inherits WCAG 2.1 AA and Section 508 compliance automatically — accessibility lives in the behavior layer, not the DOM layer.

A USWDS adapter ships out of the box for federal agency branding. The same architecture supports Bootstrap, Tailwind, Material, or any custom design system — write a render adapter, and the behavior hooks handle the rest. Missing component entries fall back to the default adapter, so you can adopt incrementally. The React package uses a different approach — an overridable component map where you replace individual field renderers (e.g., components={{ fields: { TextInput: MyShadcnInput } }}) while keeping all behavior and accessibility logic intact.

Studio Core is an authoring adapter — every edit is a serializable command with undo/redo, replay, and cross-artifact diagnostics. CLI tools, LLM agents, and visual editors all drive Studio Core through the same command API.

Expression Engine

FEL (Formspec Expression Language)

A small, deterministic expression language embedded in bind and shape declarations. FEL handles calculated fields, conditional visibility, cross-field constraints, and aggregation — no custom code required. Defined once as a formal grammar with 61 stdlib functions, implemented identically in both runtimes.

FEL examples
// Conditional visibility — show EIN field only for nonprofits
"relevant": "$org_type = 'nonprofit'"

// Calculated field — monthly budget from total and duration
"calculate": "$amount / $duration"

// Cross-field validation — budget must balance
"constraint": "sum($line_items) <= $award_amount"

// Aggregation with filtering
"calculate": "countWhere($items, $status = 'approved')"

FEL was designed from the start to be JSON-native, deterministic, and side-effect-free. Field references use $field_id syntax. Variables use @name. The language is small enough to fit in a single grammar file, yet expressive enough to handle multi-level budget calculations, conditional visibility chains, and cross-field constraint composition. The Rust shared kernel provides a single FEL implementation with base-10 decimal arithmetic (28-digit precision), compiled to WASM for the browser and PyO3 for the server.

Specifications

Specifications & schemas

Structural truth lives in JSON Schemas. Behavioral semantics that schemas cannot encode live in the normative spec prose. Clean separation: schemas handle structure, specs handle behavior.

Tier Spec Schema
Core Core Spec, FEL Grammar definition, response, validationReport, validationResult
Theme Theme Spec theme
Components Component Spec component
Mapping Mapping DSL mapping
Extensions Extension Registry, Changelog registry, changelog
Companions References, Ontology, Locale, Assist references, ontology, locale, assist
Catalogs fel-functions, core-commands, conformance-suite
TypeScript & React

TypeScript packages

Package Role Description
formspec-types Core Types auto-generated from JSON Schemas — zero-runtime, shared across all packages
formspec-engine Core FormEngine, FEL pipeline, assembler, reactive signals
formspec-layout Rendering Layout planner — renderer-agnostic blueprint from definition + theme + components. Consumed by formspec-webcomponent; available to any renderer (React, native, PDF).
formspec-webcomponent Rendering <formspec-render> — built-in browser renderer, component registry, 34 built-in components
formspec-react Rendering React hooks + auto-renderer. <FormspecForm> walks the LayoutNode tree; overridable component map for Shadcn, Material UI, or any React library. Exports formspec-react (full) and formspec-react/hooks (hooks only).
formspec-adapters Rendering Design-system render adapters — USWDS ships built-in; adapter contract supports Bootstrap, Tailwind, Material, or custom systems
formspec-core Authoring Project core — 17 handlers, normalization, page resolution, theme cascade
formspec-studio-core Authoring Authoring core — command model, undo/redo, queries, diagnostics
formspec-studio Authoring Visual form editor (React 19) — desktop-first authoring, inspector, logic builders
formspec-mcp Integration MCP server — 28 consolidated tools for LLM-driven form authoring (stdio transport)
formspec-assist Integration Form-filling agent protocol — context resolution, profile matching, WebMCP transport + shim. No LLM, no renderer.
formspec-chat Integration Chat core — conversational form builder logic, AI adapter interface, issue queue
formspec-assist-chat Integration Conversational form-filling — LLM-powered Q&A, guided walkthrough, proactive suggestions, document extraction. Consumes formspec-assist tools.
Rust In Progress

Rust shared kernel

A set of Rust crates replacing duplicated logic across the TypeScript and Python implementations. One codebase, compiled to WASM (browser/Node) and PyO3 (Python). Read the full story.

Crate Description
fel-core FEL lexer, parser, evaluator (base-10 decimal), environment, extensions, dependency extraction, AST printer
formspec-core FEL analysis, path utils, schema validator, extension analysis, runtime mapping, assembler, registry client, changelog
formspec-eval Definition Evaluator — 4-phase batch processor with topo sort, inheritance, NRB, wildcards
formspec-lint 7-pass static linter — 35 diagnostic codes, pass gating, authoring/runtime modes
formspec-wasm WASM bindings (wasm-bindgen) — exposes all capabilities to TypeScript
formspec-py PyO3 bindings — exposes all capabilities to Python
Python

Python modules

The Python package is a plain library — import it into any backend framework. Most pure logic is migrating to the Rust kernel (via PyO3). What stays: format adapters (JSON, XML, CSV serialization) and the artifact orchestrator CLI.

Module Description
fel/ FEL parser, AST, evaluator, dependency extractor
validator/ Multi-pass static linter (~40 diagnostic codes across 9 validation passes)
mapping/ Bidirectional rule engine
adapters/ JSON, XML, CSV serializers
evaluator.py 4-phase form processor (rebuild → recalculate → revalidate → apply NRB)
validate.py Directory-level artifact validator (10-pass, auto-discovery)
Native Mobile

Native iOS and Android renderers

Native mobile packages render Formspec definitions using platform-native UI frameworks — SwiftUI on iOS/macOS and Jetpack Compose on Android. Both use the same architecture: a hidden WebView bridges to the Formspec engine (identical WASM kernel), while a thin platform layer (~500 lines) converts engine signals into native state types (@Published on iOS, State<T> / StateFlow<T> on Android).

This design keeps Rust as the shared logic layer while giving native developers the experience they expect: Swift packages for iOS, Gradle/Maven for Android. Both packages support "bring your own components" — override any field renderer with a custom @Composable or SwiftUI View. No INTERNET permission is required for basic form operation on Android; forms work fully offline on both platforms.

Platform Package UI Framework Engine Bridge Status
Web (any) formspec-webcomponent Custom Elements Direct (WASM in-process) Shipping
Web (React) formspec-react React 18+ Direct (WASM in-process) Shipping
iOS / macOS formspec-swift SwiftUI Hidden WKWebView Shipping
Android formspec-kotlin Jetpack Compose 1.5+ Hidden Android WebView ADR accepted
Server formspec (Python) N/A PyO3 native binding Shipping

Why separate native packages instead of Kotlin Multiplatform or Compose Multiplatform? Because the Rust crates already provide the shared logic layer. Platform binding code is thin. iOS developers expect Swift packages; Android developers expect Gradle/Maven. And Compose Multiplatform would kill the "bring your own components" story — the whole point is that a team using Material Design 3 on Android and a custom design system on iOS can override individual components without forking the package.

Examples

Worked examples

The examples directory includes complete worked examples that exercise different tiers and capabilities of the spec.

Example Description
invoice Line-item invoice with repeat groups and calculated totals
clinical-intake Healthcare intake form with screener routing and nested repeats
grant-application 6-page federal grant form — all tiers exercised
grant-report Grant reporting variants (tribal-long, tribal-short)
refrences Cross-reference dashboard — fields, binds, FEL, shapes
Status

Project status

Version 1.0.0-draft.1 — Draft specification under active development. Design rationale lives in Architecture Decision Records. See the project build story for how the specification, schemas, and both implementations were built in three weeks.

Stop building forms by hand.

Describe what you need. AI builds it. Automatic validation makes sure it's right. One definition deploys to web, React, iOS, and Android. Open source, no vendor lock-in. Your team ships in days, not months.

Formspec Studio Visual editor for building, editing, and managing complex forms. Full control over every field, rule, and workflow.
MCP Server 28 typed tools that let AI agents build forms through structured tool calls. Add it to Claude Desktop or your IDE in 30 seconds.
Chat AI-powered kickstart. Describe what you need, get a working form in minutes. No install, no IDE.