@ftrdotdev/pi-inquiry
Interactive questions for the pi coding agent: a single `question` tool renders option lists, tabbed forms, and free-text answers
Package details
Install @ftrdotdev/pi-inquiry from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@ftrdotdev/pi-inquiry- Package
@ftrdotdev/pi-inquiry- Version
0.5.1- Published
- Sep 19, 2026
- Downloads
- 469/mo · 17/wk
- Author
- felixnorden
- License
- MIT
- Types
- extension
- Size
- 199.9 KB
- Dependencies
- 2 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-inquiry
Interactive questions for the pi coding agent. Registers a
single question tool that asks the user one or more multiple-choice
questions: a selectable option list for a single question, a tabbed form with
a submit tab for several. Every question keeps an open "Type something." path,
so the user can type a custom answer when the listed options do not fit.
Package: @ftrdotdev/pi-inquiry · MIT
What it is
inquiry is a pi extension. It is a package named @ftrdotdev/pi-inquiry and
registers exactly one tool: question.
The question tool asks the user to decide: pick between options, or confirm
a decision. It renders as a selectable list (single question) or a tabbed form
(multiple questions). Use it instead of ending a reply with a question in
plain text — the model guidance is contributed through promptSnippet and
promptGuidelines at tool registration, so the agent knows when to call it
and how to present questions.
The tool renders in pi's TUI. Outside TUI mode it returns an error instead of showing a question.
Installation
Install from npm:
pi install npm:@ftrdotdev/pi-inquiry
From git or a local checkout:
pi install git:github.com/felixnorden/pi-mono
pi install ./path/to/pi-mono/packages/inquiry
To try the package without installing it, use -e (temporary, current run
only):
pi -e npm:@ftrdotdev/pi-inquiry
Registration lives in package.json under the pi field:
"pi": {
"extensions": ["./src/tool/question.ts"]
}
The extension entry is src/tool/question.ts. It wires the tool definition
(name, JSON Schema parameters, prompt contributions, renderers) to pi's
ExtensionAPI. The core logic lives in pure Effect modules under src/core/,
with pi-specific adapters under src/sdk/.
Using the question tool
The model calls question whenever it needs the user to decide something,
pick between options, or confirm a decision. Ask all open questions in one
question call. Put one question per entry in questions[].
Parameters
{
"questions": [
{
"prompt": "The full question text to display",
"options": [{ "label": "Short label", "description": "Optional one-line description" }],
"id": "optional-unique-id", // defaults to q1, q2, ...
"label": "Scope", // short tab-bar label, defaults to Q1, Q2
"allowOther": true, // defaults to true; false forces the listed options
"multiple": false // defaults to false; true asks for one or more answers
}
]
}
questions— one or more questions. A single question shows a simple option list; multiple questions show a tabbed interface with a submit tab.options— 2–5 short options per question, each alabelplus an optional one-linedescription.allowOther— whentrue(default), the user can also type a free-text answer ("Type something."). Set it tofalseonly when one of the listed options is required.multiple— whentrue, the question is multi-select: the options render as checkboxes and the user picks one or more of them, then presses Enter to confirm the selection instead of choosing a single one. Space toggles a checkbox on or off; Enter confirms. This is the natural way to ask "which of these apply?" without turning each option into its own binary question.
Multi-select answers
A multi-select question keeps an "Add your own answer" entry (when
allowOther is true) so the user can type additional alternatives; each typed
answer becomes one more chosen value. Space toggles each option and removes a
typed chip; Enter confirms and records the whole selection. As with a
single-select question, pressing Enter on the "Add your own answer" row opens
the type mode (Space does too). In the result, a multi-select question
contributes one Answer per chosen option or typed alternative, all sharing
the question's id.
Result
The tool returns its answers both as human-readable content and in
details:
{
questions: [...], // the normalized questions asked
answers: [
{
id: "q1",
label: "the chosen option or typed answer",
wasCustom: false, // true when the user typed a free-text answer
index: 2 // option index, absent for custom answers
}
// A multi-select question contributes one entry per chosen value.
],
cancelled: false // true when the user dismissed the form
}
The tool groups a question's answers together in its output, so a
multi-select question reads as e.g. Q1: user selected: 1. A, 2. B, user wrote: X rather than several detached rows.
Treat a cancelled result as a declined answer. Do not re-ask unless the answer is needed for the next step. When you re-ask, change the form.
Pairing with the tracker
question is a decision tool, not a tracker. Pair it with pi's tracker
tool when a session spans several pieces of work. Keep one tracker list per
piece of work, and use question when you need the user to steer the session:
- which task list to work on next, when several pieces of work are open
- which option or approach to take for the current item
- whether to change scope, reprioritize, or drop an item
- confirm a decision instead of guessing
Group related decisions into one question call with multiple entries in
questions[]. They render as a single tabbed form with a submit tab, so the
user resolves several open points in one pass.
Architecture
The core is a pure Effect toolkit with zero pi imports; all pi interaction lives on the fringe.
src/core/— pure Effect, no pi importsdomain.ts— Effect Schema wire contract. The single source of truth: the tool'sparametersJSON Schema is generated from it, anddecodeParamsvalidates every call.machine.ts— pure reducerstep(state, key). Exhaustive tests pin the legacy UX contract (tab navigation, editor mode, cancel semantics).flow.ts— the interaction program: keyboard events in, machine steps, result out, via theKeyboardandRendererservices.keyboard.ts,editor.ts,scene.ts,text.ts— key event model, code-point editor, style-token scene model, width-aware wrapping.
src/sdk/— the pi fringe (all pi imports live here)pi-ui.ts—ctx.ui.custombridge: key events via a queue, scene painting at the current width, result completion.keys.ts— raw pi key data to coreKeyEvents.painter.ts— scene style tokens to pi theme ANSI.schema.test.ts— pins pi's runtime validation against the generated schema.
src/tool/question.ts— tool registration: discovery content (promptSnippet/promptGuidelines), the legacyprepareArgumentsshim, renderers.
Development
bun install
bun run test # vitest (pure tests + @effect/vitest flow tests)
bun run lint # oxlint
bunx tsc --noEmit # typecheck