Built a self-hosted form builder where you can chat to create forms (open source)
Posted by Careful_Patience_815@reddit | LocalLLaMA | View on Reddit | 2 comments
I built a self-hosted form builder where you can chat to develop forms and it goes live instantly for submissions.
The app generates the UI spec, renders it instantly and stores submissions in MongoDB. Each form gets its own shareable URL and submission dashboard.
Tech stack:
- Next.js App router
- Thesys C1 API + GenUI SDK (LLM → UI schema)
- MongoDB + Mongoose
- Claude Sonnet 4 (model)
Flow (LLM → UI spec → Live preview)
1) User types a prompt in the chat widget (C1Chat).
2) The frontend sends the user message(s) (fetch('/api/chat')) to the chat API.
3) /api/chat constructs an LLM request:
- Prepends a system prompt that tells the model to emit JSON UI specs inside
<content>…</content>. - Streams responses back to the client.
4) As chunks arrive, \@crayonai/stream`` pipes them into the live chat component and accumulates the output.
5) On the stream end, the API:
- Extracts the
<content>…</content>payload. - Parses it as JSON.
- Caches the latest schema (in a global var) for potential “save” actions.
- If the user issues a save intent, it POSTs the cached schema plus title/description to
/api/forms/create.
System Prompt
It took multiple iterations to get a stable system prompt that:
- always outputs valid UI JSON
- wraps output inside
<content>for the renderer - knows when to stop generating new UI
- handles a multi-step “save flow” (title + description) without drifting
- responds normally to non-form queries
const systemPrompt = `
You are a form-builder assistant.
Rules:
- If the user asks to create a form, respond with a UI JSON spec wrapped in <content>...</content>.
- Use components like "Form", "Field", "Input", "Select" etc.
- If the user says "save this form" or equivalent:
- DO NOT generate any new form or UI elements.
- Instead, acknowledge the save implicitly.
- When asking the user for form title and description, generate a form with name="save-form" and two fields:
- Input with name="formTitle"
- TextArea with name="formDescription"
- Do not change these property names.
- Wait until the user provides both title and description.
- Only after receiving title and description, confirm saving and drive the saving logic on the backend.
- Avoid plain text outside <content> for form outputs.
- For non-form queries reply normally.
<ui_rules>
- Wrap UI JSON in <content> tags so GenUI can render it.
</ui_rules>
`
You can check complete codebase here: https://github.com/Anmol-Baranwal/form-builder
(blog link about architecture, data flow and prompt design is in the README)
If you are experimenting with structured UI generation or chat-driven system prompts, this might be useful.
j17c2@reddit
I know sometimes people speak about cloud models even though they're on r/locallama, that's up for debate, but this... i mean... why is this even here?
Mediocre-Waltz6792@reddit
Looks interesting