pi-ask-user-questions
v0.1.1
Published
Let the agent ask you a question and type your answer. No multiple choice. Batch questions are answered consecutively.
Readme
pi-ask-user-questions
The agent asks a question. You type the answer. There is no list to pick from.
If you want the agent to offer you options — searchable lists, multi-select, split-pane
previews, overlay modes — use pi-ask-user
instead. It is further along and does more. This package is for the other case: you want
to be asked in words and answer in words, and you want to be asked less.
How it differs
| | pi-ask-user-questions (this) | pi-ask-user |
|---|---|---|
| Answer format | free-form text, always | option list, with freeform as an extra |
| Interaction | one question, one text field | menus, multi-select, split-pane preview, configurable overlay/inline |
| Effect on interruptions | guidelines push the agent to ask less | bundles a skill that mandates asking at decision gates |
| Maturity | new | 25 published versions, actively maintained |
That last row is the real trade. This package is deliberately narrower: fewer moving parts, and one abort-safe input path instead of a configurable TUI. If you want richer selection UI, the other package is the better tool and there is no reason to fight it.
The anti-pester stance
The usual failure mode is an agent that asks about everything. Three things push back,
all in the tool's promptGuidelines — which Pi appends to your system prompt while the
tool is active:
- Batch everything into one call. The agent collects all its questions up front, so you answer in a single pass instead of being interrupted repeatedly.
- Don't ask what you can work out. Reading the repo, inferring, or choosing a sensible default is preferred over asking. State the assumption and move on.
- Never invent an answer. Skipped questions come back marked as skips, with an explicit instruction not to fill in the blank. A skip means "no answer", not "assume something".
pi-ask-user takes the opposite position: it
ships a skill that requires the agent to stop and ask at high-stakes decision points. Both
are defensible. If being interrupted too much is your problem, this is the one you want.
The exact guidelines, verbatim:
- Batch every question you need into a single
ask_usercall; the user answers them in sequence.- Ask only when you truly cannot proceed. Never ask what you can read from the repo, infer, or decide yourself.
- State an assumption and continue instead of asking.
- Phrase each question to be answerable in one typed sentence — the user types text, they do not pick from options.
- A skipped question means the user declined to answer. Never fabricate an answer; re-ask or proceed without it.
Install
# from npm
pi install npm:pi-ask-user-questions
# from git
pi install git:github.com/qunm00/[email protected]
# try it for one run without saving
pi -e npm:pi-ask-user-questionsThen enable the tool in a session if it is not already active:
/toolsHow it behaves
- One dialog at a time, titled
Question 2 of 3: <the question>. Questions are asked and answered in the order given. - Enter submits. Escape skips that one question and moves to the next — you keep your momentum instead of restarting the batch.
- Submitting an empty answer re-prompts once, because a stray Enter is usually an accident. Press Escape at the re-prompt to skip.
- Skipped questions are reported to the model explicitly, with an instruction not to invent an answer.
- Batching holds even when the agent is careless: the tool is registered with
executionMode: "sequential", so three separateask_usercalls in one assistant message queue instead of stacking.
Limitations
These are deliberate, not oversights:
- Single-line answers.
ui.editor()accepts noAbortSignal, so aborting a turn while a multiline dialog is open would leave the dialog waiting and the turn unable to finish. Single-line input is abort-safe. Pasted multi-line text is preserved, but you cannot type a newline mid-answer. - No
placeholdersupport. In pi 0.87.1 theui.inputplaceholder argument is taken byExtensionInputComponentas_placeholderand never read. There is nowhere to put an example answer, so put any needed guidance in the question text. - No timeout. If the agent asks and you walk away, the dialog waits. Press Escape to skip.
- Needs an interactive session. In
print/jsonmode there is no UI; the tool returns a message telling the model to ask in plain text instead of failing the turn.
Development
npm install
npm run verify # lint + typecheck + all 27 tests
npm test # 27 tests, includes a real npm pack + install + load check
npm run test:unit # skips the slow sandbox install check
npm run lint # biome
npm run lint:fix # biome --write
npm run typecheck # tsc --noEmit
# load it into a live pi without installing
pi -e ./extensions/ask-user.ts
# then, in that session:
/ask-demo/ask-demo exercises the real dialog path without involving a model, so you can check
rendering and the skip/empty behaviour by hand.
Tests run on @marcfargas/pi-test-harness,
which keeps pi real — real extension loading, real hooks, real tool registry — and
substitutes only the model boundary (streamFn) and ctx.ui.*.
That harness targets pi 0.75.x. Three things moved by 0.87 and are bridged in
__tests__/support/pi-compat.ts and vitest.config.ts; the comments there explain each
one. Remove those shims once a harness release supports 0.87.
Because the harness substitutes ctx.ui.*, no automated test can check terminal
rendering. /ask-demo is the manual gate for that.
Linting is Biome for formatting and non-type-aware rules. It does
not replace tsc: Biome has no type information, so npm run typecheck is a separate and
non-redundant gate.
Requirements
Node >= 22.19.0, which is pi's own floor. Staged publishing additionally needs npm 12+ (the release workflow pins it).
Continuous integration
.github/workflows/ has two workflows:
ci.yml— lint, typecheck and test on Node 22.19 and 24, plus two package-specific jobs: one asserts the published tarball is exactlyLICENSE,README.md,extensions/ask-user.tsandpackage.json, the other asserts the pi package metadata (pi-packagekeyword, resolvablepi.extensionspaths, no runtime dependencies). A weekly job re-runs the suite againstpi@latestto catch the compat shims breaking before a user does.release.yml— on av*tag, verifies the tag matches thepackage.jsonversion, then stages the package withnpm stage publishrather than publishing it. Staging uploads the tarball to the registry in a non-public state and does not prompt for 2FA, which is what makes it usable from an automated workflow. Nothing becomes installable until a maintainer approves it with 2FA:npm stage list # see what is pending npm stage download <stage-id> # optional: inspect the tarball first npm stage approve <stage-id> # requires 2FA, makes it publicThis uses npm trusted publishing (OIDC), so there is no long-lived
NPM_TOKENin repository settings. Set up the trust relationship to grant stage publish:npm trust github \ --file release.yml \ --repo qunm00/pi-ask-user-questions \ --allow-stage-publishTwo constraints worth knowing: the dist-tag is fixed at stage time and is immutable, and short-lived tokens from a trust relationship can only run
npm stage publishandnpm publish— which is why approval has to be a human step. The workflow pins npm 12+, since staged publishing is not present in older npm.
Releasing:
npm version 0.1.0 # updates package.json
git tag -a v0.1.0 -m "Initial release"
git push origin main --follow-tags
# CI stages it; then approve:
npm stage list && npm stage approve <stage-id>The tag must match the manifest version; the release workflow fails if it does not.
License
MIT
