How do I generate and check forms with AI agents?
A Formhaus form is a JSON definition, so an agent writes data instead of component code. The JSON Schema at https://formhaus.dev/schema/form-definition.json tells the agent and the editor which keys are valid, the Formhaus Claude Code plugin adds the /formhaus:formhaus-create-form skill that drafts definitions from a description, CSV or screenshot, and the @formhaus/mcp server that checks the result against the real FormEngine with validate_definition and simulate_path.
Definition
A support form an agent might produce. The $schema line enables completion and validation in VS Code, Cursor and JetBrains editors.
{
"$schema": "https://formhaus.dev/schema/form-definition.json",
"id": "support-request",
"title": "Contact support",
"submit": { "label": "Send request" },
"steps": [
{
"id": "topic",
"title": "What is it about?",
"fields": [
{
"key": "topic",
"type": "select",
"label": "Topic",
"validation": { "required": true },
"options": [
{ "value": "billing", "label": "Billing" },
{ "value": "bug", "label": "Something is broken" },
{ "value": "other", "label": "Other" }
]
},
{
"key": "orderId",
"type": "text",
"label": "Order number",
"show": [{ "field": "topic", "eq": "billing" }],
"validation": { "required": true, "pattern": "^[0-9]{6}$", "patternMessage": "Six digits" }
}
]
},
{
"id": "details",
"title": "Details",
"fields": [
{ "key": "message", "type": "textarea", "label": "Describe the problem", "rows": 5, "validation": { "required": true, "minLength": 20 } }
]
},
{
"id": "screenshot",
"title": "Screenshot",
"show": [{ "field": "topic", "eq": "bug" }],
"skip": { "label": "No screenshot" },
"fields": [
{ "key": "screenshot", "type": "file", "label": "Screenshot", "accept": "image/*", "validation": { "required": true } }
]
},
{
"id": "contact",
"title": "How do we reach you?",
"fields": [
{ "key": "email", "type": "email", "label": "Email", "validation": { "required": true } }
]
}
]
}1. Install the Claude Code plugin
claude plugin marketplace add ignsm/formhaus && claude plugin install formhaus@formhausInside a Claude Code session, /plugin marketplace add ignsm/formhaus and /plugin install formhaus@formhaus do the same. The plugin bundles the /formhaus:formhaus-create-form skill and the @formhaus/mcp server, which exposes validate_definition, simulate_path, capabilities and example_definitions.
To add only the server, run claude mcp add formhaus -- npx -y @formhaus/mcp. For Claude Desktop and Cursor, see MCP Server setup.
2. Generate a definition
/formhaus:formhaus-create-formThen describe the form: "Support form: topic select, order number for billing, message, screenshot for bugs, email". The skill infers field types and validation, asks about steps and conditions when the input does not say, and checks the result with the MCP server.
3. Validate it
validate_definition with { "definition": <the JSON above> } returns:
{ "valid": true, "errors": [], "warnings": [] }Errors come from the JSON Schema and from checks the engine enforces. A route from details back to topic returns:
{
"valid": false,
"errors": ["Invalid route from \"details\" to \"topic\": targets must be later steps or null."],
"warnings": []
}4. Simulate a path
simulate_path with these answers and actions walks the bug branch and skips the screenshot:
{
"answers": { "topic": "bug", "message": "The export button does nothing.", "email": "ann@example.com" },
"actions": ["next", "next", "skip"]
}Output, without the validation report and with path entries shown without title:
{
"ok": true,
"multiStep": true,
"path": [
{ "id": "topic", "visited": true, "skipped": false, "visibleFields": ["topic"] },
{ "id": "details", "visited": true, "skipped": false, "visibleFields": ["message"] },
{ "id": "screenshot", "visited": true, "skipped": true, "visibleFields": ["screenshot"] },
{ "id": "contact", "visited": true, "skipped": false, "visibleFields": ["email"] }
],
"currentStep": { "id": "contact", "title": "How do we reach you?", "index": 3 },
"isLastStep": true,
"trace": [
{ "action": "next", "from": "topic", "to": "details", "moved": true },
{ "action": "next", "from": "details", "to": "screenshot", "moved": true },
{ "action": "skip", "from": "screenshot", "to": "contact", "moved": true }
],
"errors": {},
"wouldSubmit": true,
"submitValues": { "topic": "bug", "message": "The export button does nothing.", "email": "ann@example.com" }
}With "topic": "billing" the screenshot step leaves the path and orderId appears on the first step.
5. Add instructions to your repository
Paste this into AGENTS.md or CLAUDE.md so every agent session follows the same rules. Cursor users can copy .cursor/rules/formhaus.mdc into their project's .cursor/rules/ instead, as described in Cursor rule.
## Forms
Forms are Formhaus JSON definitions rendered with `FormRenderer` from `@formhaus/react` or `@formhaus/vue`.
- Start every definition with `"$schema": "https://formhaus.dev/schema/form-definition.json"`.
- Use `fields` for a single page or `steps` for a multi-step form, never both.
- Put conditional fields and steps in `show` / `showAny`, and branching in `routes`. Route targets must be later steps or `null`.
- Keep visibility, validation and step logic in the definition, not in components.
- After every change, call the `formhaus` MCP tool `validate_definition` and fix all errors and warnings.
- For multi-step forms, call `simulate_path` once per branch and check `path` and `submitValues`.
- Call `capabilities` for the supported field types, validation rules and condition operators.How it works
- The schema is generated from the TypeScript
FormDefinitiontype and ships in@formhaus/coreas@formhaus/core/schema.json. validate_definitionruns the schema andvalidateDefinition()from@formhaus/core. It reports unknown route targets, backward routes, duplicate step ids and branches that fall through into a sibling.simulate_pathappliesanswersas initial values and pressesnext,backandskipin order. Withoutactionsit presses Next until the last step or the first blocking error.simulate_pathdoes not run custom validators,onStepValidateor lifecycle hooks. Test those in the app.capabilitieslists field types, field props, validation rules, condition operators and route semantics, so the agent does not invent keys.
Related
- MCP Server: setup and tool reference
- /formhaus:formhaus-create-form: input formats and output
- Definition Reference: the JSON Schema
- Figma to React: draw the generated definition in Figma