Interactive Questions Pattern
Planu tools are designed to act autonomously by default. When a tool cannot proceed without user input — because an action is irreversible, ambiguous, or policy-blocked — it returns an InteractiveQuestion[] instead of blocking the call or making a silent assumption.
Why Tools Return Questions
The autopilot-first design means tools choose the safest default and proceed whenever possible. But some decisions must be explicit:
- Destructive actions. Deploying to production, deleting a spec, overwriting locked content.
- Ambiguous inputs. Multiple specs match a search term; the tool cannot pick for you.
- Policy gates. Approving a spec with 0 passing criteria requires explicit confirmation.
Rather than throwing an error or hanging, the tool returns an array of structured questions. The LLM receives this array in the tool response, relays each question to the user via AskUserQuestion, collects the answers, and re-invokes the tool with the answers supplied as arguments.
No blocking I/O
Tools never block on user input. The call always returns immediately — either with a result or with InteractiveQuestion[]. This makes tools safe to use in async pipelines and agent loops.
The InteractiveQuestion Type
json
{
"id": "confirm-target-env",
"question": "Which environment should this deploy to?",
"type": "choice",
"options": ["staging", "production"],
"default": "staging"
}| Field | Type | Description |
|---|---|---|
id | string | Unique identifier — used to match answers to questions on re-invocation |
question | string | Human-readable question text |
type | enum | choice / multiChoice / text / confirm |
options | string[] | Valid options for choice and multiChoice types |
default | any | Pre-selected value — used in autonomous mode |
required | boolean | If false, the tool can proceed with the default if the user skips |
Question Types
| Type | Behavior |
|---|---|
choice | Single selection from a fixed options list |
multiChoice | Multiple selections from a fixed options list |
text | Free-text input — validated against pattern if provided |
confirm | Boolean yes/no — maps to true / false |
How the LLM Relays Questions
1. LLM invokes tool (e.g. update_status("SPEC-NNN", "approved"))
2. Tool detects gate condition (0 passing criteria)
3. Tool returns { interactiveQuestions: [ { id: "confirm-low-criteria", ... } ] }
4. LLM reads the array
5. LLM calls AskUserQuestion with the question text
6. User answers "yes"
7. LLM re-invokes: update_status("SPEC-NNN", "approved", { answers: { "confirm-low-criteria": true } })
8. Tool proceeds past the gateIn Claude Code, the relay mechanism is the built-in AskUserQuestion tool. In other hosts, the pattern is the same but the relay mechanism differs (e.g. an HTTP endpoint or a chat UI input field).
When to Expect Questions
| Tool | When it returns questions |
|---|---|
create_spec | When the spec title matches an existing spec (duplicate check) |
update_status(approved) | When check_readiness returns 0 passing criteria |
update_status(done) | When validate finds unmet acceptance criteria |
deploy_spec | When the target environment is production |
delete_spec | Always — deletion is irreversible |
lock_spec | When the spec is in draft status (unusual to lock early) |
Autonomous Mode and Questions
In Autonomous Mode, Planu uses the default field of each question instead of relaying it to the user. This allows fully unattended pipeline runs. If a question has no default and required is true, autonomous mode will block the transition and surface the question to the operator.
Cross-links
- Auto-Status Transitions — transitions that trigger questions
- Autonomous Mode — how autonomous mode handles questions using defaults