The Question Types Reference¶
The type key for each question in your config.yml tells VIBE what kind of input to show the user. Here is a reference for all available types.
Common Attributes¶
Most question types share a set of common configuration keys.
| Key | Type | Required? | Description |
|---|---|---|---|
label |
string | Yes | The user-facing text for the question. |
type |
string | Yes | The type of question widget to display (e.g., text, number). |
required |
boolean | No | Controls required validation, completion gating, and required UI markers. Defaults to true (fields with a default still count as optional for completion). |
default |
any | No | A default value to pre-fill the answer with. |
help |
string | No | Longer, more detailed helper text that appears with the question. Can contain Markdown. |
hint |
string | No | A short hint that often appears as placeholder text inside the input field. |
# Example showing all common attributes
questions:
project_code:
label: Project Code
type: text
required: false
default: PROJ-2024
help: The internal code for tracking this project, like `PROJ-2024-FIN`. Can be found in the project charter.
hint: e.g., PROJ-2024-FIN
Note: Required validation only kicks in after a field is submitted/answered (to avoid blocking every auto-submit), and newly relevant fields are only auto-validated when required: true.
options Format¶
The options key is used by radio, select, and multichoice to define the available choices. It accepts two formats that can be freely mixed within the same list.
Simple string format — the string is used as both the stored value and the display label:
options:
- Standard
- Premium
- Enterprise
Object format — for separate values and labels, help text, or followups:
options:
- value: standard
label: Standard Plan
- value: premium
label: Premium Plan
help: Includes priority support and SLA guarantees.
followups:
- premium_contact
| Key | Type | Required? | Description |
|---|---|---|---|
value |
string | Yes | The stored value (what your template sees). Required when using object format. |
label |
string | No | The display text shown to the user. Defaults to value if omitted. |
help |
string | No | Explanatory text shown with the option. Supported by radio and multichoice only — causes a validation error on select. |
followups |
list | No | List of question IDs to show nested under this option when selected. See Follow-up Questions below. |
You can mix both formats in one list:
options:
- Simple Option # string → value and label are both "Simple Option"
- value: detailed
label: Detailed Option
help: This one has extra metadata.
Follow-up Questions¶
Follow-up questions let you nest related questions inside a parent widget, so they appear indented directly under the option that triggers them. This is a UI placement hint — it controls where the question renders, not when it's relevant (that's still determined by your template's {% if %} logic via the probing mechanism).
Supported types: multichoice, radio/select, and bool.
Per-option followups (multichoice, radio, select)¶
Add a followups list to any option object. When the user selects that option, the listed questions appear nested underneath it.
questions:
delivery_method:
type: radio
label: Preferred delivery method
options:
- value: courier
label: Courier delivery
followups:
- courier_company
- value: pickup
label: Self pickup
- value: digital
label: Digital delivery
followups:
- download_format
courier_company:
type: text
label: Preferred courier company
download_format:
type: select
label: Download format
options:
- PDF
- DOCX
Question-level followups (bool)¶
For bool, followups are a mapping on the question itself, keyed by yes and no:
questions:
needs_insurance:
type: bool
label: Does the shipment require insurance?
followups:
yes:
- insurance_amount
no:
- waiver_reason
insurance_amount:
type: amount
label: Insurance coverage amount
currencies:
- USD
waiver_reason:
type: text
label: Reason for declining insurance
Note: Followup questions must be defined as regular questions in the same questions block. They are rendered inside the parent widget instead of as standalone top-level questions. Followups can be nested — a followup question can itself have followups.
text / textarea¶
For freeform text input. Use textarea for longer, multi-line text.
questions:
project_name:
type: text
label: Project Name
project_description:
type: textarea
label: Project Description
help: Provide a brief summary of the project goals.
required: false
assisted¶
An enhanced textarea that includes an AI-powered assist button to help the user draft text. It is ideal for fields requiring creative or descriptive content.
Extension note: assisted is part of the Assistant extension and requires LLM endpoints to be configured.
| Key | Type | Required? | Description |
|---|---|---|---|
type |
string | Yes | Must be set to assisted. |
label |
string | Yes | The user-facing text for the question. |
prompt |
string | Yes | A Jinja2 template string that will be rendered and sent to the LLM as its instruction. |
model |
string | No | The ID of the LLM endpoint to use, as defined by the administrator in the system config.yml. If omitted, the system default is used. |
Example:
questions:
procurement_object:
type: text
label: What do you want to buy?
procurement_description:
type: assisted
label: Describe the thing you want to buy
model: claude-opus
prompt: Create a one-paragraph description of {{ procurement_object }} suitable for a procurement process.
User Interaction:
- The user can type in the text area manually.
- Clicking the assist button sends the rendered
promptto the specified LLM. - The AI's response is streamed directly into the text area.
- If the button is clicked again, the user is prompted for refinement instructions, and the AI generates a new version based on the original prompt, the current text, and the new instructions.
Template Access:
In your .md or .docx template, an assisted variable behaves exactly like a standard text variable. You access its final content with {{ procurement_description }}.
number¶
For numeric input. You can specify min and max values for validation.
questions:
contract_duration:
type: number
label: Contract Duration (months)
min: 1
max: 60
help: Enter the length of the contract in full months.
amount¶
For monetary values, combining a numeric input with a currency.
Fixed Currency Example: If you provide only one currency, it will be displayed as a static symbol or code next to the number input.
questions:
project_budget:
type: amount
label: Project Budget
min: 0
currencies:
- USD
currency_position: left
Selectable Currency Example: If you provide multiple currencies, a dropdown menu will appear for the user to select from.
questions:
transaction_fee:
type: amount
label: Transaction Fee
required: false
currencies:
- USD
- EUR
- GBP
amount Specific Options:
| Key | Type | Description |
|---|---|---|
currencies |
list | A list of allowed currency codes (e.g., ["USD", "EUR"]). If only one is provided, the currency is fixed. |
min |
number | The minimum allowed numeric value. |
max |
number | The maximum allowed numeric value. |
currency_position |
string | left (default) or right. Where to display a fixed currency symbol. |
currency_symbol |
string | Manually override the currency symbol (e.g., "$"). By default, it's looked up from a standard map. |
Template Access:
An amount variable is automatically formatted for printing. You can also access its parts.
The total budget is {{ project_budget }}.
Value: {{ project_budget.value }}
Currency: {{ project_budget.currency }}
bool¶
For a simple "Yes" or "No" choice, rendered as radio buttons. Supports question-level followups keyed by yes and no.
questions:
include_nda:
type: bool
label: Does this project require an NDA?
default: true
required: false
tristate¶
For a three-way choice: "Yes", "No", or "Don't know", rendered as radio buttons. Use this when you need to distinguish between "No" and "uncertain/not applicable/don't know".
questions:
is_international:
type: tristate
label: Is this an international transaction?
help: Select "Don't know" if you're unsure or if this doesn't apply.
Customizing the third option label:
questions:
requires_legal_review:
type: tristate
label: Does this require legal review?
none_label: Not applicable
has_data_privacy_concerns:
type: tristate
label: Are there data privacy concerns?
none_label: Maybe
required: true
tristate Specific Options:
| Key | Type | Description |
|---|---|---|
none_label |
string | Label for the third option (default: "Don't know"). Use values like "Not applicable", "Maybe", "Uncertain", etc. |
default |
boolean or null | Default selection: true for Yes, false for No, null for the third option, or omit to leave unselected. |
Template Access:
A tristate variable has three possible values: true, false, or none (Python None). All three are valid answers that satisfy required: true.
{% if is_international is true %}
This is an international transaction.
{% elif is_international is false %}
This is a domestic transaction.
{% elif is_international is none %}
The international status is unknown.
{% endif %}
Important: Always use the is operator with true, false, or none when checking tristate values. Other comparison operators are not supported and will cause validation errors.
When to use tristate vs bool:
- Use
boolwhen you need a definitive yes/no answer and uncertainty should block progress - Use
tristatewhen "don't know" or "not applicable" is a valid, meaningful answer that allows the document to proceed
date¶
For collecting a date from a calendar picker. Dates are in YYYY-MM-DD format.
effective_date:
type: date
label: Agreement Effective Date
min_date: 2020-01-01
radio / select¶
For a list of choices where the user can only choose one option. Supports per-option followups.
contract_type:
type: radio
label: Contract Type
options:
- value: premium
label: Premium Support
help: Includes 24/7 phone support.
- value: standard
label: Standard Support
help: Email support with a 48-hour response time.
Use radio for a set of radio buttons (all options always visible). Use select for a dropdown menu (the help attribute cannot be used with select).
multichoice¶
For a list of checkboxes where the user can select multiple options. Supports per-option followups.
service_scope:
type: multichoice
label: Services Included
required: false
options:
- Discovery & Strategy
- UI/UX Design
- Backend Development
- Ongoing Support
structured¶
For collecting complex, nested data structures based on definitions. Structured questions create grouped fields with dot notation form names.
Basic structured question using a definition:
questions:
primary_contact:
label: Primary Contact Person
type: structured
definition: person_definition
help: Main person responsible for this project
definitions:
person_definition:
first_name:
label: First name
type: text
help: Enter the person's first (or given) name
last_name:
label: Last name
type: text
help: Enter the person's last name (surname)
email:
label: Email Address
type: email
required: false
Template access with dot notation:
**Contact:** {{ primary_contact.last_name }}, {{ primary_contact.first_name }}
**Email:** {{ primary_contact.email }}
Form field naming: Structured fields use dot notation (primary_contact.full_name, billing_address.street) to avoid namespace collisions.
period¶
For collecting time periods in four modes: duration (quantity + unit), until (end date), indefinite (no end), or event (event-based). Period questions create sophisticated time-based inputs with validation, date arithmetic, and template access patterns.
All Modes Available (Default Behavior):
By default, all four modes are available to users unless restricted via the modes property.
questions:
contract_duration:
label: Contract Duration
type: period
default_mode: duration
default_unit: months
min_quantity: 1
max_quantity: 60
help: How long should this contract last?
Restricting Available Modes:
Use the modes property to limit which modes users can choose from.
questions:
project_deadline:
label: Project Deadline
type: period
modes:
- until
min_date: 2024-01-01
max_date: 2030-12-31
help: When must the project be completed by?
Multiple Modes with Constraints: Allow specific modes and configure each one appropriately.
questions:
service_term:
label: Service Term
type: period
modes:
- duration
- indefinite
duration_units:
- weeks
- months
- years
default_mode: duration
default_unit: months
min_quantity: 1
max_quantity: 36
required: false
help: Choose a fixed duration or indefinite service term
Event Mode Configuration: For periods that end when a specific event occurs.
questions:
project_phase:
label: Project Phase Duration
type: period
modes:
- duration
- event
default_mode: event
duration_units:
- days
- weeks
allowed_events:
- milestone completion
- budget approval
- client signoff
required: false
help: When does this phase end?
Period Configuration Options:
| Key | Type | Description |
|---|---|---|
modes |
array | List of allowed modes: ["duration", "until", "indefinite", "event"]. Defaults to all four modes. |
default_mode |
string | Which mode to pre-select. Must be one of the allowed modes. Defaults to "duration" if available. |
duration_units |
array | List of allowed units for duration mode: ["days", "weeks", "months", "years"]. Defaults to all units. |
default_unit |
string | Which unit to pre-select for duration mode. Must be one of the allowed duration_units. Defaults to "months". |
min_quantity |
number | Minimum allowed quantity for duration mode (default: 1). |
max_quantity |
number | Maximum allowed quantity for duration mode (optional). |
min_date |
string | Earliest allowed date for until mode in YYYY-MM-DD format (optional). |
max_date |
string | Latest allowed date for until mode in YYYY-MM-DD format (optional). |
allowed_events |
array | List of allowed event names for event mode (optional). |
Template Usage: Periods are accessed as structured objects with mode-specific properties and convenience methods.
{% if contract_duration %}
**Contract Duration:** {{ contract_duration.display }}
{% if contract_duration.is_duration %}
Duration: {{ contract_duration.quantity }} {{ contract_duration.unit }}
{% elif contract_duration.is_until %}
End Date: {{ contract_duration.date }}
{% elif contract_duration.is_indefinite %}
No fixed end date
{% elif contract_duration.is_event %}
Ends when: {{ contract_duration.event }}
{% endif %}
{% endif %}
Date Arithmetic: Duration periods can be added to dates for calculations.
{% if start_date and duration_period and duration_period.is_duration %}
**Start Date:** {{ start_date }}
**Duration:** {{ duration_period }}
**End Date:** {{ start_date + duration_period }}
{% endif %}
Available Properties:
period.mode- One of "duration", "until", "indefinite", or "event"period.display- Enhanced formatted string (e.g., "6 months", "until August 15, 2025", "indefinitely")
Convenience Properties:
period.is_duration- Boolean: true if mode is "duration"period.is_until- Boolean: true if mode is "until"period.is_indefinite- Boolean: true if mode is "indefinite"period.is_event- Boolean: true if mode is "event"
Mode-Specific Properties:
- For duration mode:
period.quantity- The numeric duration (e.g., 12)period.unit- The time unit (e.g., "months")- For until mode:
period.date- The end date in YYYY-MM-DD format (e.g., "2025-12-31")- For event mode:
period.event- The event name (e.g., "project completion")
Built-in String Formatting: Periods automatically format to readable text when used directly in templates:
- Duration mode: "12 months", "1 year", "3 weeks"
- Until mode: "until 2025-12-31" or "until August 15, 2025"
- Indefinite mode: "indefinitely"
- Event mode: "until project completion"
Validation Rules:
- Duration mode: Quantity must be a positive number within specified min/max bounds
- Until mode: Date must be valid YYYY-MM-DD format within specified date range
- Event mode: Event name must be provided; if
allowed_eventsis specified, must be from that list - Indefinite mode: No additional validation required
- Required validation: If required=true, user must provide a complete period value
Common Patterns:
# Flexible period with all modes available (default behavior)
project_timeline:
label: Project Timeline
type: period
default_mode: duration
default_unit: weeks
min_quantity: 1
max_quantity: 104
help: Choose duration, end date, indefinite, or event-based
# Date-only period for deadlines
submission_deadline:
label: Submission Deadline
type: period
modes:
- until
min_date: 2024-06-01
max_date: 2024-12-31
help: Final date for submission
# Duration-only period for contracts
service_period:
label: Service Period
type: period
modes:
- duration
duration_units:
- months
- years
default_unit: months
min_quantity: 3
max_quantity: 36
help: Length of service commitment
# Event-based period with constrained options
warranty_period:
label: Warranty Period
type: period
modes:
- event
allowed_events:
- first failure
- one year elapsed
- contract termination
help: When does the warranty coverage end?
# Duration or indefinite for ongoing arrangements
maintenance_agreement:
label: Maintenance Agreement Duration
type: period
modes:
- duration
- indefinite
duration_units:
- months
- years
default_mode: indefinite
help: Duration of ongoing maintenance coverage
list¶
For collecting multiple items of the same structure. Lists can use either inline field definitions or definition references.
List using a definition:
questions:
team_members:
label: Team Members
type: list
item_label: Team Member
uses: person_definition
min_items: 1
max_items: 10
project_tasks:
label: Project Tasks
type: list
item_label: Task
uses: task_definition
required: false
definitions:
# person_definition as above
task_definition:
name:
label: Task Name
type: text
due_date:
label: Due Date
type: date
required: false
priority:
label: Priority
type: select
options:
- Low
- Medium
- High
Template access:
# Team Members
{% for member in team_members %}
- **{{ member.last_name}}**, {{ member.first_name }} ({{ member.email }})
{% endfor %}
# Project Tasks
{% for task in project_tasks %}
- **{{ task.name }}** - Due: {{ task.due_date }} (Priority: {{ task.priority }})
{% endfor %}
List options:
min_items: Minimum number of items requiredmax_items: Maximum number of items alloweditem_label: Singular label for each item (e.g., "Team Member")uses: Reference to definition name for item structure
For more details on structured questions and lists, see the "Reusable Data with definitions" guide.