@mrclrchtr/supi-ask-user
SuPi ask-user extension — rich questionnaire UI for structured agent-user decisions
Package details
Install @mrclrchtr/supi-ask-user from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@mrclrchtr/supi-ask-user- Package
@mrclrchtr/supi-ask-user- Version
1.14.0- Published
- Jun 18, 2026
- Downloads
- 2,589/mo · 421/wk
- Author
- mrclrchtr
- License
- MIT
- Types
- extension
- Size
- 175.9 KB
- Dependencies
- 1 dependency · 3 peers
Pi manifest JSON
{
"extensions": [
"./src/extension.ts"
],
"image": "https://raw.githubusercontent.com/mrclrchtr/supi/main/packages/supi-ask-user/assets/logo.png"
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@mrclrchtr/supi-ask-user
Adds a redesigned ask_user tool to the pi coding agent. It lets the model pause and request a small decision form when explicit human input is required.
Install
pi install npm:@mrclrchtr/supi-ask-user
For local development:
pi install ./packages/supi-ask-user
Preview
What you get
After install, pi gets one new tool:
ask_user— open a blocking decision form during a run
The tool presents a structured questionnaire in the TUI form and blocks the agent turn until the user responds. It is designed for focused decisions, not long surveys or open-ended discovery.
Typical use cases:
- Clarify a narrow implementation choice
- Confirm a risky or destructive action
- Ask for a preference the repo cannot answer
- Gather one short cluster of related decisions before proceeding
Package surfaces
@mrclrchtr/supi-ask-user/extension— pi extension entrypoint, registers theask_usertool@mrclrchtr/supi-ask-user/api— reusable types and utilities
Example:
import { normalizeQuestionnaire, AskUserController } from "@mrclrchtr/supi-ask-user/api";
const questionnaire = normalizeQuestionnaire(params);
const controller = new AskUserController(questionnaire);
Request shape
ask_user accepts a small form with optional framing text:
| Field | Type | Description |
|---|---|---|
title |
string (optional) | Short overall title for the form |
intro |
string (optional) | Why the agent is asking |
questions |
array (1–10) | Choice or text questions |
All questions are always required for a full submission. Unanswered questions produce a needs_discussion outcome instead of a silent partial submit. The deprecated fields allowPartialSubmit, required, initial, and allowOther are rejected with a validation error.
Questions
Each question has a type, id, header, and prompt. Two question types are supported:
choice — fixed options
| Field | Type | Description |
|---|---|---|
options |
array (2–12) | Allowed answers; each option has the fields below |
multi |
boolean (default: false) |
Allow selecting multiple options |
recommendation |
string | string[] | Recommended option value(s). Single-select: a string (default: first option). Multi-select: an array (default: none). |
Each options entry:
| Field | Type | Description |
|---|---|---|
value |
string | Returned identifier for the response |
label |
string | Displayed option label |
description |
string (optional) | Short sub-label shown under the option |
preview |
string (optional) | Longer explanatory text rendered in the side preview panel |
Model yes/no questions as a choice with { value: "yes", label: "Yes" } and { value: "no", label: "No" }.
text — freeform input
| Field | Type | Description |
|---|---|---|
recommendation |
string (optional) | Suggested text prefilled in the editor |
placeholder |
string (optional) | Placeholder shown before the user types |
Result
A completed form returns a result with details.outcome set to one of:
| Outcome | Meaning |
|---|---|
submitted |
Full submit, every question was answered |
needs_discussion |
One or more questions were left unanswered |
details.responses is an ordered array matching the original question order. Each response has:
questionId— matching the original question IDquestionComment(optional) — user comment on this specific questionanswer— structured response withkind,answered, and type-specific data
Choice responses include only touched options (selected options and/or options with comments):
{
answer: {
kind: "choice",
answered: boolean,
options: Array<{
value: string;
label: string;
selected: boolean;
comment?: string;
}>;
}
}
Text responses:
{
answer: {
kind: "text",
answered: boolean,
value?: string;
}
}
details.comment is the form-level user comment when one was entered.
The tool result details also includes title, intro, and the normalized questions array (same order as the original request, with internal fields such as multi and recommendedIndexes). Consumers should rely on responses for the user's answers; questions is kept for rendering and is not part of the model-facing answer contract.
Internal cancel and abort results are not persisted as user responses — they cause the agent turn to be aborted and return an error-style result to the model.
Behavior
- Requires pi in interactive (TUI) mode with custom form support — no degraded fallback
- Only one
ask_userform may be active at a time; callingask_userwhile another form is in flight returns an error - Cancellation or abort stops the current agent turn
- Completed forms are summarized in the session tree
- In pi's normal chat history, completed
ask_userresults can be expanded into a read-only review withCtrl+O; this does not reopen the live form and is separate from/tree - Do not use
ask_userfor open-ended interviews or repo facts the agent can discover on its own
Tool guidance
The tool registers the following prompt guidance that the model sees:
- Use ask_user only for blocking user input, not open-ended interviews or repo facts.
- Use ask_user with 1-10 related questions; prefer one when possible.
- Use ask_user
choicefor fixed options and ask_usertextfor freeform input; yes/no should be achoice. - Keep one ask_user form active at a time.
- Use
recommendationto suggest default choices or prefilled text. - Comments are user UI affordances — do not reference removed fields like
required,initial,allowOther, orallowPartialSubmit.
UI controls
Choice questions
↑↓— move between optionsSpace— select the focused option (single-select) or toggle (multi-select)Enter— on single-select, selects the focused option and advances; on multi-select, accepts current selections and advances (no toggling)Tab/→— go to the next question; from the last question, go to reviewShift+Tab/←— go to the previous questionn— edit a comment for the focused choice option (whether selected or not)c— edit a comment for the current questionu— mark the current question unanswered and show an unanswered status line (preserves comments)Esc— cancel the whole form
The recommended/preselected option is labeled [recommended].
On wide terminals, option previews render side-by-side with the option list. On narrow terminals, previews stack below.
Text questions
- The editor is visible immediately with any recommendation prefilled
Enter— submit the current text and advanceTab— go to the next questionAlt+C— edit a comment for the current questionAlt+U— mark the current question unanswered- Plain printable characters, including
candu, are inserted into the editor Esc— cancel the whole form
Review screen
↑↓— move between questions and the Submit rowEnter— on a question, open that question for editing; on the Submit row, submit the form←/Shift+Tab— return to the last questionc— edit the form-level commentEsc— cancel the whole form
The review screen shows every question with an answered/unanswered marker and any option comments before submission. The final question always moves to review rather than submitting immediately, and the Submit row is focused by default so the form can be submitted with a single Enter. When a question is opened from review, saving/advancing that question returns to review instead of walking through later questions.
Comment editors
Question, option, and form-level comment editors are opened with c, n, or Alt+C depending on the current screen.
Enter— save the comment and return to the form or review screenEsc— discard unsaved comment edits and return to the form or review screen without cancelling the whole interaction
Example
{
"title": "Formatter decision",
"intro": "I need a couple of explicit choices before I update the repo config.",
"questions": [
{
"type": "choice",
"id": "formatter",
"header": "Formatter",
"prompt": "Which formatter should I configure?",
"options": [
{
"value": "biome",
"label": "Biome",
"description": "Lint + format in one tool",
"preview": "Rust-based linter/formatter. Replaces ESLint + Prettier. Only JS/TS/JSON/CSS. Fastest option."
},
{
"value": "prettier",
"label": "Prettier",
"description": "Standalone formatter",
"preview": "Mature formatter with a large ecosystem of plugins and configuration presets."
}
],
"recommendation": "biome"
},
{
"type": "choice",
"id": "features",
"header": "Features",
"prompt": "Which extra tooling should I set up?",
"options": [
{ "value": "vitest", "label": "Vitest" },
{ "value": "knip", "label": "Knip" },
{ "value": "lefthook", "label": "Lefthook" }
],
"multi": true,
"recommendation": ["vitest"]
},
{
"type": "text",
"id": "reason",
"header": "Reason",
"prompt": "Anything I should optimize for?",
"placeholder": "optional"
}
]
}
Source layout
src/extension.ts— pi extension entrypointsrc/api.ts— reusable public surfacesrc/index.ts— package barrelsrc/ask-user.ts— tool registration and execution boundarysrc/schema.ts— tool-call parameter schema (TypeBox)src/types.ts— internal normalized types and response shapessrc/normalize.ts— validation and lowering into internal typessrc/tool/guidance.ts— prompt guidance and tool descriptionsrc/session/controller.ts— headless decision-form state machine with comment/responsessrc/session/lock.ts— session-scoped concurrency locksrc/ui/choose-renderer.ts— custom-form capability gatesrc/ui/form.ts— form runner that creates the custom interaction sessionsrc/ui/form-component.ts— keyboard orchestration for question screens, comment editors, and reviewsrc/ui/form-view.ts— choice row helperssrc/ui/form-render.ts— main form rendering for choices, text, comments, and layout framesrc/ui/form-review-render.ts— review-screen summary cardssrc/ui/form-render-primitives.ts— shared rendering primitives for boxes, wrapping, prompts, and paddingsrc/ui/types.ts— shared UI runner typessrc/render/result.ts— tool result shapingsrc/render/transcript.ts— transcript renderingsrc/render/tree-summary.ts— session-tree summary labels
