@tian.zuo/pi-ask-user
Ask the user one or more fully described multiple-choice questions from the pi coding agent.
Package details
Install @tian.zuo/pi-ask-user from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@tian.zuo/pi-ask-user- Package
@tian.zuo/pi-ask-user- Version
0.2.2- Published
- Nov 3, 2026
- Downloads
- 259/mo · 235/wk
- Author
- tian.zuo
- License
- MIT
- Types
- extension
- Size
- 35 KB
- Dependencies
- 0 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
@tian.zuo/pi-ask-user
Release notes: changelog · GitHub releases
Let the model ask you a multiple-choice question from pi.
Token-light by design. The entire model-facing surface — tool description, schema docs, and three guideline bullets — totals ≈560 characters. The most-downloaded alternative
ask_userpackage (@eko24ive/pi-ask) spends ≈1,700 on its tool description and schema alone, and popular pi extensions generally run 2–3k (pi-mcp-adapter: ≈2.5k across 12 tools; pi-web-access: ≈3.2k onweb_searchalone). Same interactive form, a third of the prompt weight — the wording lives in one smalllib/prompt.tsinstead of prose sprayed through the schema.
pi install npm:@tian.zuo/pi-ask-user
Registers an ask_user tool. The model can supply 1–5 questions with 2–5
options each. Questions and option descriptions wrap across as many lines as
needed instead of being truncated. Every question accepts one selection and
also gets a free-form Other option. The model is instructed to order each
question's options with its recommendation first, and the selected answer is
marked with a → arrow — single-selection list style, not a checkbox. A
model-supplied Other-style option is refused rather than shown twice: the
duplicate would otherwise reach the user with nothing reporting it back.
Interactive controls:
←/→— switch questions while preserving answers↑/↓— move between optionsSpace— select an optionEnter— move to the next question or submit the completed formEsc— go back from the custom-answer editor or dismiss the form
While it waits for your answer, the tool reports the input requirement on pi's
shared event bus (pi.events). This is pi's in-process mechanism for tool ↔
integration communication: an integration subscribes with pi.events.on(...),
aggregates active requests into its own agent state, and bridges that state to
its client.
The same versioned payload goes out on two channels. herdr:blocked is the one
with a live consumer: Herdr's shipped pi integration (v8 in
Herdr 0.9.0, still v9 upstream) subscribes to it, maps active/label onto the
pane's blocked state, and owns the resulting status and needs-attention
notification. agent:input_required mirrors that payload under a
client-agnostic name for consumers that prefer one; nothing subscribes to it
yet, so the two channels coexist rather than one deprecating the other. The
stable id lets consumers correlate duplicate and concurrent requests:
{
version: 1,
id: string, // ask_user tool-call ID
source: "ask_user",
active: boolean, // true before waiting, false in finally
label: string // normalized question, always present
}
In the TUI, the form also reports blocked (kind=question, with the label as
the message) through the terminal's OSC 7501 program status. Terminals such as
Rex show it on the
tab and the session picker. Pi reports blocked only for its built-in
select/input/editor dialogs, not for ctx.ui.custom() forms, so the tool
reports it itself. When the form closes, it restores the working status that
Pi reported for the run. Pi writes nothing when the terminal does not support
OSC 7501.
Pi's event bus has no "blocked" status (only working while a tool call is in
flight vs idle), and can't distinguish an autonomous long-running tool from
one waiting on a human. Pi 0.84.4+ emits its own ui_prompt_start /
ui_prompt_end around ctx.ui prompts, but those carry no question label for
custom forms — the shape this tool renders. Emitting is best-effort, balanced
active→inactive via try/finally, and a harmless no-op when nothing listens. No
event is emitted in non-UI modes.
See the collection repository for more extensions.
License
MIT © Tian Zuo