

From prompt to production: building intake forms with Healthie's Dev Assist

The time between "we need a custom intake form" and "the form is live in production" is one of the more reliable ways to measure how well a healthcare platform is actually built for developers.
Most of that time is not spent on the form. It's spent on the API β reading schema documentation, identifying the right mutations, figuring out required fields, testing each call in isolation before writing a single line of product code. A form that takes 20 minutes to describe takes two days to build.
Dev Assist eliminates the schema lookup and execution overhead. You describe what you want. Dev Assist handles the schema exploration, writes the mutations, and executes them against your sandbox. The engineering decisions β what the form does, how it connects to your clinical workflow, what happens downstream β are still yours. Dev Assist removes the part that doesn't require your judgment.
This guide walks through that workflow: building a new form, modifying it as requirements change, and moving it to production.
What Dev Assist is
Dev Assist is Healthie's open-source MCP server. It connects AI coding agents β Claude Code, Cursor, Claude Desktop β directly to Healthie's live GraphQL API.
When you connect Dev Assist to your coding agent, the agent gains four capabilities against Healthie's schema:
healthie.search(query, options?) // Search the schema by keyword
healthie.introspect(typeName) // Get full details on any type or mutation
healthie.query(graphql, variables?) // Execute a GraphQL query
healthie.mutate(graphql, variables?) // Execute a GraphQL mutation
healthie.mutate() executes mutations against your sandbox directly β it doesn't scaffold code for you to run later. When you ask Dev Assist to build a form, the form is created. When you ask it to add a question, the question is added. The API is the output, not a code file.
Dev Assist 2.0 runs on a code execution model β the agent writes a small TypeScript program that handles schema search, introspection, and mutation in a single turn. Schema exploration that previously required 5β10 round-trips resolves in 1β2. The schema is cached locally, so lookups are instant.
Dev Assist is open source and MIT licensed: github.com/healthie/healthie-dev-assist
Setup
git clone https://github.com/healthie/healthie-dev-assist.git
cd healthie-dev-assist
npm install
Add your sandbox API key to .env:
HEALTHIE_API_KEY=your-sandbox-api-key-here
Download and cache the schema locally:
npm run regenerate-schema
Connect to Claude Code:
claude mcp add healthie -- npx tsx /path/to/healthie-dev-assist/src/server.ts
Or run npm run setup to auto-configure Claude Desktop. Full setup for Cursor and other agents: github.com/healthie/healthie-dev-assist#quick-start
Use sandbox only. Dev Assist ships configured for staging by default. Most AI platforms don't have a BAA in place, and production data contains PHI. Healthie strongly advises against repointing Dev Assist at a production environment.
Building a form
Open a session with Dev Assist connected. Then describe what you want.
Prompt 1 β Create the form
Build me a behavioral health intake form with three questions:
presenting concern (free text), insurance type (radio: Insurance
or Self-pay), and a sliding scale fee question that only appears
when the patient selects Self-pay.
Dev Assist searches the schema for the right mutations, introspects the required fields for createCustomModuleForm, createCustomModule, and updateCustomModule, and executes the full sequence in a single turn.
What gets created:
- A
CustomModuleFormscoped to intake (use_for_charting: false,use_for_program: false) - Three
CustomModulequestions with the correctmod_type, labels, and index values - A
custom_module_conditionon the sliding scale question, configured to display only when insurance type equals "Self-pay"
The form exists in your sandbox immediately. Query it, test it, and iterate before moving on.
⚠ FILL IN before publishing. Replace the block below with the actual Dev Assist session output from running this prompt in sandbox. Run the prompt, capture what Dev Assist returns (the created object IDs, confirmation messages, or the TypeScript output), and paste it here verbatim. This is the moment that makes the post credible β the reader sees Dev Assist actually working, not just a description of it.
Example of what to capture and paste:
✓ Created CustomModuleForm: id [form-id]
✓ Created question "What brings you in today?" (textarea): id [q1-id]
✓ Created question "How will you be paying?" (radio): id [q2-id]
✓ Created question "Sliding scale preference" (radio): id [q3-id]
✓ Set condition: question [q3-id] displays when question [q2-id] = "Self-pay"
Prompt 2 β Add a question
The practice needs to add a preferred appointment time question:
Add a question to this form asking for the patient's preferred
appointment time. Dropdown with three options: Morning, Afternoon,
Evening. Not required.
The coding agent (Claude Code, Claude Desktop, or Cursor) carries the form ID forward from the previous prompt. Dev Assist adds the question to the existing form, correctly indexed after the three questions already created.
The same pattern applies to any modification: adding questions, updating labels, changing mod_type, adjusting conditional logic. Describe the change. Dev Assist finds the right mutation and executes it.
⚠ FILL IN before publishing. Replace the block below with the actual Dev Assist output from running this prompt in the same sandbox session. Capture the confirmation that the new question was added and its assigned ID.
Example: ✓ Added question "Preferred appointment time" (dropdown): id [q4-id], index 3
Prompt 3 β Register the webhook
When a patient submits, your system needs to act on it:
Register a webhook for this form that fires when a patient submits.
Point it at https://your-system.com/webhooks/healthie.
Dev Assist creates the webhook for form_answer_group.created. When a patient submits, your endpoint receives:
{
"resource_id": "98765",
"resource_id_type": "FormAnswerGroup",
"event_type": "form_answer_group.created"
}
Use resource_id to query the FormAnswerGroup and read the answers. From there, drive whatever downstream logic your care model requires β create a task, assign a care plan, trigger a scheduling workflow, feed answers into a chart note. The form submission is the event. What happens next is yours to define.
See the full automation example for a complete createTask walkthrough, and the webhook event reference for the full payload spec.
Modifying a form in production
Care models change. The intake form that works today needs an additional question next quarter. Updating a production form is the same workflow as building one β describe the change, Dev Assist handles the schema, but you execute against production directly.
Adding a question to an existing form
Show me the mutation to add a question to form ID [your-form-id]
asking for the patient's emergency contact name. Free text, not
required. Don't run it β show me the mutation to review first.
Dev Assist returns the createCustomModule mutation with the correct fields pre-filled. Review it, then run it against your production endpoint:
# Run against production β swap in your production API key
curl -X POST https://api.gethealthie.com/graphql \
-H "Authorization: Basic YOUR_PRODUCTION_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "query": "mutation { createCustomModule(input: { ... }) { customModule { id } messages { field message } } }" }'
The same pattern applies to any production change: prompt Dev Assist to generate the mutation without running it, review it, execute it against production yourself. Dev Assist handles the schema work. You handle the production execution.
Updating conditional logic
Show me the mutation to update the condition on question ID
[your-question-id] so it appears when the patient selects
"Medicaid" instead of "Self-pay". Don't run it.
Dev Assist returns the updateCustomModule mutation with the updated custom_module_condition. Same review-and-execute pattern.
Debugging
When something goes wrong, Healthie surfaces errors in the messages field of the mutation response β not as top-level GraphQL errors. Always include messages { field message } in your mutation selection set:
mutation {
createCustomModule(input: { ... }) {
customModule { id label }
messages {
field # the field that caused the error
message # what went wrong
}
}
}
A successful mutation returns a non-null object and an empty messages array. If messages is non-empty, the mutation did not execute β read the field and message values to understand why.
Common failure patterns
Mutation returns null with no messages. The input is likely missing a required field. Ask Dev Assist to introspect the input type: "What are the required fields for createCustomModuleInput?" β it will show which fields are non-null.
Webhook isn't firing. Check four things in sequence:
- The webhook was registered with
is_enabled: trueβ query it back to confirm - Your endpoint is publicly reachable from the sandbox environment β use ngrok or similar for local development
- The event type string matches exactly:
form_answer_group.created - The form submission has
finished: trueβ partial submissions create aFormAnswerGroupbut may not fire the webhook until the patient completes and submits
Form ID not found. If a subsequent prompt fails because Dev Assist can't locate the form, query it directly to confirm it exists in sandbox: "Query the form with ID [your-form-id] and show me its questions."
See error handling for the full response structure.
Moving to production
Dev Assist runs against sandbox by default. Moving to production is a manual step β intentionally. Production data contains PHI, and most AI platforms don't have a BAA in place.
Step 1 β Get the mutations from Dev Assist
Show me all the mutations to recreate this form in production.
Don't run them β I need to execute them against the production
endpoint myself.
Dev Assist returns the complete mutation sequence: createCustomModuleForm, each createCustomModule, any updateCustomModule calls for conditional logic, and createWebhook. Review each one before running.
Step 2 β Execute against production
| Sandbox | Production | |
|---|---|---|
| API endpoint | staging-api.gethealthie.com/graphql | api.gethealthie.com/graphql |
| API key | Sandbox key from Organization settings | Production key from Organization settings |
| Data | Synthetic test data β no PHI | Real patient data β PHI applies |
| Forms | Sandbox only β do not transfer | Re-create using mutations from Step 1 |
| Webhooks | Sandbox only β do not transfer | Re-register against production endpoint |
Run the mutations in sequence against api.gethealthie.com/graphql with your production API key. Each mutation returns an ID β you'll need it for the next call in the sequence, exactly as in sandbox.
Step 3 β Verify
After running the production mutations, query the form back to confirm it was created correctly before sending it to patients:
Query form ID [your-production-form-id] and show me all its
questions and their conditional logic.
Review authentication requirements before going live.
What you end up with
A fully custom intake form in production β specialty-specific questions, conditional routing, and automated downstream logic β built and maintained through conversation rather than documentation.
The same workflow that built the form handles every subsequent change: new questions, updated conditions, additional downstream actions. The form layer stays current with your care model because changing it requires a prompt, not a sprint.
The intake form is often the first thing a patient touches before care begins. The time your engineering team spends rebuilding and maintaining that layer is time not spent on the clinical model, the patient experience, or the outcomes logic that differentiates your product.
Dev Assist on GitHub: github.com/healthie/healthie-dev-assist
Forms API reference: docs.gethealthie.com/guides/forms/
Dev Assist 2.0 release notes: gethealthie.com/blog/dev-assist-2-0
Webhook event reference: docs.gethealthie.com/guides/webhooks/event-reference/
Automation example β intake form: docs.gethealthie.com/guides/automation-examples


