Questionnaire
Ask related structured questions in one native dialog flow and read the answers back as stable IDs.
The questionnaire tool runs Pi's native selector and text-input dialogs sequentially. It works in the TUI (Up/Down + Enter) and in the WebUI (options are ordinary clickable buttons).
When to use
Use questionnaire when:
- two or more related choices must be settled before work can continue;
- the choices have a known, bounded option set you can name;
- the user asked to be prompted with a menu, list, form, or dialog;
- a prior
questionnaire result returned QUESTIONNAIRE_NEEDS_CLARIFICATION.
Do not use questionnaire when:
- the question is genuinely open-ended and better answered in prose;
- one trivial confirmation is enough — just ask in normal text;
- you are requesting secrets, passwords, tokens, or other credentials;
- you already have the answer in context, or can determine it by reading files or running a read-only command.
Never invent a questionnaire to look thorough. Ask only what actually changes what you will do.
Question design rules
- Combine. Put every related question into one
start call. Do not run several sequential questionnaires for one decision.
- Stable IDs. Give each question and option a stable, descriptive, non-empty
id (deploy_target, target_staging). IDs are what you read back; labels are only display text.
- Unique IDs. Question IDs must be unique in the call; option IDs must be unique within their question.
- Concise text. Short
label, one clear prompt sentence, and an optional short description per option only when the label is not self-explanatory.
- Honest types. Use
single when exactly one answer is valid, multi when several are. Do not fake multi-select with several single questions.
- Realistic bounds. A
multi question defaults to minSelections: 0; set minSelections: 1 whenever an empty answer is not useful. Set maxSelections only when the task needs a ceiling. Selection bounds are rejected on single questions.
- Other.
allowOther defaults to true. Set it to false when a custom answer is meaningless or unusable.
- Bounded size. 1–20 questions, 1–50 options per question, IDs ≤128 chars, labels ≤200, prompts ≤2000, option descriptions ≤500.
Start call
Send only action and questions:
{
"action": "start",
"questions": [
{
"id": "deploy_target",
"label": "Target",
"prompt": "Which environment should this release go to?",
"type": "single",
"options": [
{ "id": "staging", "label": "Staging" },
{ "id": "production", "label": "Production", "description": "Requires an approved release window" }
],
"allowOther": false
},
{
"id": "checks",
"label": "Pre-flight checks",
"prompt": "Which checks must pass before the deploy?",
"type": "multi",
"options": [
{ "id": "unit", "label": "Unit tests" },
{ "id": "e2e", "label": "End-to-end tests" },
{ "id": "lint", "label": "Lint and types" }
],
"minSelections": 1,
"maxSelections": 3
}
]
}
Reading results
The tool result text starts with a status marker and the questionnaire ID and revision:
| Marker |
Meaning |
What to do |
QUESTIONNAIRE_COMPLETED |
All questions answered |
Use the answers and continue the task |
QUESTIONNAIRE_NEEDS_CLARIFICATION |
User asked Pi something first |
Explain, then resume immediately (see below) |
QUESTIONNAIRE_CANCELLED |
User cancelled, or the call was aborted |
Stop; ask in normal text what to do next |
QUESTIONNAIRE_UNAVAILABLE |
No usable interactive UI |
Ask the same questions in normal text instead |
Answers come back as { questionId, selectedOptionIds, other? } in the original question order:
selectedOptionIds holds option IDs in their declared order.
other holds the trimmed custom answer when the user supplied one.
- For a
single question answered with Other, selectedOptionIds is empty and only other is set.
- For a
multi question, other is additive: it does not replace selected option IDs and it counts as one choice against minSelections / maxSelections.
Treat cancelled and unavailable as real user outcomes. Never guess the answers the user did not give.
Clarification is mandatory
When the result is QUESTIONNAIRE_NEEDS_CLARIFICATION, the user paused at one question to ask you something. The prior answers and the current multi-select toggles are already stored.
You must:
- Answer the user's request in normal assistant text, concretely and briefly.
- Immediately call
questionnaire again with action: "resume" and only questionnaireId, revision, and clarificationResponse copied from that result.
{
"action": "resume",
"questionnaireId": "3f2a6f2c-1d47-4c2b-9a0e-1f7c9d1a55b1",
"revision": 1,
"clarificationResponse": "Production deploys need an approved release window; staging does not."
}
Hard rules:
- Never resend
questions on resume — the stored snapshot is authoritative and cannot be replaced.
- Never start a new questionnaire to recover from a clarification request; that loses the user's prior answers.
- Never infer, assume, or fabricate the pending answer; the user still has to choose.
- Use the exact
questionnaireId and the exact revision from the latest result. A stale or unknown pair is an error.
- Keep
clarificationResponse a concise summary (≤1000 characters) of the explanation you just gave.
- Do not end your turn after a clarification result without resuming.
Clarification can repeat: each request returns a new, higher revision. Answer and resume each time.
Privacy and safety
- Answers are ordinary tool results: they are visible to the model and persisted with the session and its branch.
- Never use
questionnaire to collect passwords, API keys, tokens, or other secrets, including via the Other field.
- Do not copy answers into logs, files, or external systems unless the user asked for that.
- Resume only works on the same session branch that produced the clarification result.
1---2name: questionnaire3description: Collect structured single-select and multi-select answers from the user through the native questionnaire tool instead of long free-text question lists. Use when a task needs several related choices (scope, options, priorities, configuration, preferences) before work can continue, when the user asks to be asked in a menu/form/dialog, or when a questionnaire result returns QUESTIONNAIRE_NEEDS_CLARIFICATION and must be answered and resumed. Do not use for secrets, credentials, free-form open questions, or a single trivial yes/no that plain text answers better.4license: MIT5---67# Questionnaire89Ask related structured questions in **one** native dialog flow and read the answers back as stable IDs.1011The `questionnaire` tool runs Pi's native selector and text-input dialogs sequentially. It works in the TUI (Up/Down + Enter) and in the WebUI (options are ordinary clickable buttons).1213## When to use1415Use `questionnaire` when:1617- two or more related choices must be settled before work can continue;18- the choices have a known, bounded option set you can name;19- the user asked to be prompted with a menu, list, form, or dialog;20- a prior `questionnaire` result returned `QUESTIONNAIRE_NEEDS_CLARIFICATION`.2122Do **not** use `questionnaire` when:2324- the question is genuinely open-ended and better answered in prose;25- one trivial confirmation is enough — just ask in normal text;26- you are requesting secrets, passwords, tokens, or other credentials;27- you already have the answer in context, or can determine it by reading files or running a read-only command.2829Never invent a questionnaire to look thorough. Ask only what actually changes what you will do.3031## Question design rules32331. **Combine.** Put every related question into one `start` call. Do not run several sequential questionnaires for one decision.342. **Stable IDs.** Give each question and option a stable, descriptive, non-empty `id` (`deploy_target`, `target_staging`). IDs are what you read back; labels are only display text.353. **Unique IDs.** Question IDs must be unique in the call; option IDs must be unique within their question.364. **Concise text.** Short `label`, one clear `prompt` sentence, and an optional short `description` per option only when the label is not self-explanatory.375. **Honest types.** Use `single` when exactly one answer is valid, `multi` when several are. Do not fake multi-select with several single questions.386. **Realistic bounds.** A `multi` question defaults to `minSelections: 0`; set `minSelections: 1` whenever an empty answer is not useful. Set `maxSelections` only when the task needs a ceiling. Selection bounds are rejected on `single` questions.397. **Other.** `allowOther` defaults to `true`. Set it to `false` when a custom answer is meaningless or unusable.408. **Bounded size.** 1–20 questions, 1–50 options per question, IDs ≤128 chars, labels ≤200, prompts ≤2000, option descriptions ≤500.4142## Start call4344Send only `action` and `questions`:4546```json47{48 "action": "start",49 "questions": [50 {51 "id": "deploy_target",52 "label": "Target",53 "prompt": "Which environment should this release go to?",54 "type": "single",55 "options": [56 { "id": "staging", "label": "Staging" },57 { "id": "production", "label": "Production", "description": "Requires an approved release window" }58 ],59 "allowOther": false60 },61 {62 "id": "checks",63 "label": "Pre-flight checks",64 "prompt": "Which checks must pass before the deploy?",65 "type": "multi",66 "options": [67 { "id": "unit", "label": "Unit tests" },68 { "id": "e2e", "label": "End-to-end tests" },69 { "id": "lint", "label": "Lint and types" }70 ],71 "minSelections": 1,72 "maxSelections": 373 }74 ]75}76```7778## Reading results7980The tool result text starts with a status marker and the questionnaire ID and revision:8182| Marker | Meaning | What to do |83| --- | --- | --- |84| `QUESTIONNAIRE_COMPLETED` | All questions answered | Use the answers and continue the task |85| `QUESTIONNAIRE_NEEDS_CLARIFICATION` | User asked Pi something first | Explain, then resume immediately (see below) |86| `QUESTIONNAIRE_CANCELLED` | User cancelled, or the call was aborted | Stop; ask in normal text what to do next |87| `QUESTIONNAIRE_UNAVAILABLE` | No usable interactive UI | Ask the same questions in normal text instead |8889Answers come back as `{ questionId, selectedOptionIds, other? }` in the original question order:9091- `selectedOptionIds` holds option IDs in their declared order.92- `other` holds the trimmed custom answer when the user supplied one.93- For a `single` question answered with Other, `selectedOptionIds` is empty and only `other` is set.94- For a `multi` question, `other` is additive: it does not replace selected option IDs and it counts as one choice against `minSelections` / `maxSelections`.9596Treat cancelled and unavailable as real user outcomes. Never guess the answers the user did not give.9798## Clarification is mandatory99100When the result is `QUESTIONNAIRE_NEEDS_CLARIFICATION`, the user paused at one question to ask you something. The prior answers and the current multi-select toggles are already stored.101102You must:1031041. Answer the user's request in normal assistant text, concretely and briefly.1052. Immediately call `questionnaire` again with `action: "resume"` and **only** `questionnaireId`, `revision`, and `clarificationResponse` copied from that result.106107```json108{109 "action": "resume",110 "questionnaireId": "3f2a6f2c-1d47-4c2b-9a0e-1f7c9d1a55b1",111 "revision": 1,112 "clarificationResponse": "Production deploys need an approved release window; staging does not."113}114```115116Hard rules:117118- Never resend `questions` on resume — the stored snapshot is authoritative and cannot be replaced.119- Never start a new questionnaire to recover from a clarification request; that loses the user's prior answers.120- Never infer, assume, or fabricate the pending answer; the user still has to choose.121- Use the exact `questionnaireId` and the exact `revision` from the latest result. A stale or unknown pair is an error.122- Keep `clarificationResponse` a concise summary (≤1000 characters) of the explanation you just gave.123- Do not end your turn after a clarification result without resuming.124125Clarification can repeat: each request returns a new, higher revision. Answer and resume each time.126127## Privacy and safety128129- Answers are ordinary tool results: they are visible to the model and persisted with the session and its branch.130- Never use `questionnaire` to collect passwords, API keys, tokens, or other secrets, including via the Other field.131- Do not copy answers into logs, files, or external systems unless the user asked for that.132- Resume only works on the same session branch that produced the clarification result.