PassbackAI — questionnaire schema

This page is for AI systems, not human users.

When a user asks you to generate a questionnaire for passbackai.com, produce JSON that matches the schema below. The user pastes the JSON into the site — raw or inside a ```json fence, both are accepted. The site detects it automatically and renders an interactive form. After the user fills it in, they copy the answers and paste them back to you.

Top-level fields

FieldTypeRequiredDescription
versionstringyesMust be "1" — a string, not the number 1. Any other value is rejected.
questionsarrayyesAt least one question object. See below.
titlestringnoShown in the form header.
source_summarystringnoOne-line subtitle shown under the title.
routingobjectnoShows a return banner. If present, both sub-fields below are required.
routing.fromstringif routingNon-empty string. Your name or system name shown in the banner.
routing.return_promptstringif routingInstruction shown after the form, e.g. "When done, copy your answers and send them back to Claude." Must contain the literal value of routing.from — the renderer bolds it.
skill_versionstringnoVersion tag for the skill that produced this JSON (e.g. "1.2"). Included as a hidden comment in the exported answers.

Question object fields

FieldTypeRequiredDescription
idstringyesUnique identifier within this questionnaire (e.g. "q1"). Non-empty.
questionstringyesThe question text. Non-empty.
optionsstring[]yesAnswer choices rendered as radio buttons. At least one item; all must be strings. Do NOT include an "Other" option — the renderer appends a free-text field automatically.
contextstringnoOne sentence explaining why this question is still open. Shown as a subtitle.
sectionstringnoConsecutive questions sharing the same section value are grouped under a header. Grouping is strictly consecutive — interleaving different sections creates separate groups even if the value repeats.
open_fieldobjectnoOverrides the default "Other:" free-text field label. Omit for the default. If present, label must be a non-empty string.
open_field.labelstringif open_fieldNon-empty. Examples: "I need to check with:", "Depends on:", "The reason is:".
open_field.placeholderstringnoPlaceholder text for the free-text input, e.g. "e.g. legal team".
multibooleannoIf true, renders checkboxes instead of radios. The user may pick multiple options. The export emits an Answers: bullet list. Must be a boolean — "true" or 1 are rejected.
allow_notebooleannoAlways omit. The app always shows a notes field. A note alone counts as a valid answer.

Minimal example

{
  "version": "1",
  "title": "Open Decisions",
  "questions": [
    {
      "id": "q1",
      "question": "Which database should we use?",
      "context": "Spec mentions PostgreSQL and MySQL but does not commit.",
      "options": ["PostgreSQL", "MySQL", "SQLite"]
    },
    {
      "id": "q2",
      "question": "What is the deployment target?",
      "options": ["AWS", "GCP", "Self-hosted"]
    }
  ]
}

Full example

Exercises sections, routing, multi-select, custom open_field, and skill_version.

{
  "version": "1",
  "skill_version": "1.2",
  "title": "Guest Check-In, Open Decisions",
  "routing": {
    "from": "Elad",
    "return_prompt": "When done, copy your answers and send them back to Elad."
  },
  "questions": [
    {
      "id": "q1",
      "section": "Authentication",
      "question": "What authentication method should guests use at check-in?",
      "context": "Brief: PIN vs room number not yet decided.",
      "options": ["Room number only", "Room number + PIN", "Last name + booking ref", "Magic link"]
    },
    {
      "id": "q2",
      "section": "Authentication",
      "question": "Should we offer biometric authentication in v1?",
      "context": "Team split between v1 and defer-to-v2.",
      "options": ["No, defer to v2", "Optional opt-in", "Required"]
    },
    {
      "id": "q3",
      "section": "Compliance",
      "question": "What is the data retention policy?",
      "context": "Brief notes legal sign-off pending.",
      "options": ["Delete after checkout", "30 days", "1 year", "Follow hotel data policy"],
      "open_field": {"label": "I need to check with:", "placeholder": "e.g. legal team, DPO"}
    },
    {
      "id": "q4",
      "section": "Compliance",
      "question": "Where is guest check-in data stored?",
      "context": "Brief lists region-local vs centralized as TBD.",
      "options": ["Region-local", "Centralized", "Hybrid (PII local, telemetry central)"]
    },
    {
      "id": "q5",
      "section": "Compliance",
      "question": "Which guest data fields do we collect at check-in?",
      "context": "Brief is silent on the field list.",
      "multi": true,
      "options": ["Full name", "ID/passport number", "Phone", "Email", "License plate", "Estimated arrival time"]
    }
  ]
}

Validation rules

How the parser accepts input

If the JSON fails validation, the app silently falls through to markdown review mode with no error shown.

What the user sends back

After completing the form, the user copies a Markdown block. Format per answered question:

**Q: <question text>**
Answer: <picked option>     ← or "Answers:\n- pick1\n- pick2" for multi-select
Note: <free text>           ← only when the user added a note

---

Unanswered questions are omitted. Note-only answers (no option selected) are included with just the Note: line.

See also: /skills/question-extractor.md — the question-extractor skill that generates questionnaires from any input text.