ask-user-rich
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ask-user-richgrill me about my product roadmap"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ask-user-rich
A Claude Code mod (a function-hook plugin) that gives the model a rich way to ask you questions, and gives every conversation one stable page, its Thread, where all of its questions, follow-ups and messages land in order.
The model calls
ask_user_richwith a Round of questions. The call returns at once, the model ends its turn, and the Round appears on the Thread page as a card. Open it to get a keyboard-driven stepper: one question per screen, markdown, previews, recommendations with rationale, rank questions, notes, defer and need-more-info.When you submit, the answers come back by themselves: they start the model's next turn when the session is idle, or are folded into the turn that is running. Nothing waits in a loop.
The links are drawn by the mod under the tool call (Internal for this machine, Public for another device such as a phone over Tailscale), so they never depend on the model remembering to print them.
While a Thread is open the page mirrors the conversation: the model's text, what you type in the terminal, and a one-line chip per tool call. A composer sends a message back; End closes the Thread and tells the model the discussion is over.
A status line shows whether the model is working, waiting for you, idle, or not running. Answers sent while the session is not running are delivered when the conversation resumes.
http://<host>:<port>/lists every live Thread, so one bookmark reaches whichever conversation is asking.
Requires Claude Code with function hooks (2.1.288 or newer) and Node.js 20 or newer.
Install
The mod loads from a user-level skills folder, so it is available in every project:
git clone https://github.com/PedroRF-tension/ask-user-rich.git ~/.claude/skills/ask-user-rich
cd ~/.claude/skills/ask-user-rich && npm ciStart a new Claude Code session. Check with claude plugin validate ~/.claude/skills/ask-user-rich.
To try it without installing: claude --plugin-dir /path/to/ask-user-rich.
If an older version is registered as an MCP server under the same name, remove it first
(claude mcp remove --scope user ask-user-rich): both would offer mcp__ask-user-rich__*.
Related MCP server: codex-mcp
Configuration
Rows in /config (the mod's userConfig), or in ~/.claude/settings.json under pluginConfigs["ask-user-rich@skills-dir"].options (pluginConfigs["ask-user-rich"] for a --plugin-dir load):
Option | Default | Effect |
|
| Off: no tools, no guard, no mirroring; everything passes through |
|
| Addresses the page binds, comma-separated, e.g. |
|
| Host of the Public link; a loopback name shows no Public link |
|
| The one port every Thread page is served on |
PROMETHEUS_MODS=off in the environment switches it off too. A change restarts the daemon once no Round
is open anywhere.
The model's tools
Tool | Does |
|
|
|
|
|
|
The question schema is the one the form has always taken (ids ASCII-only, recommended holding option ids,
dependsOn naming earlier questions, rank questions holding a full recommended order). Invalid input is
rejected with every problem listed and, where one is known, its fix.
Only the main conversation asks: a subagent's call is refused with a note to report the decision back.
While grilling is armed (a grilling skill, or a "grill me" prompt) or a Thread is open, AskUserQuestion is
denied in favour of ask_user_rich, except for the rest of a turn in which ask-user-rich itself failed.
How it works
Claude Code session ── mod (hooks) ──Unix socket──▶ daemon ◀──HTTP── browser (Thread page)The mod (
hooks/) registers the tools, starts the daemon when it is absent (restarting it on a new version or changed addresses when no Round is open), polls it about once a second while the conversation has a Thread, and stores what you sent:$.prompt.submitwhen idle, an appended user row when busy. Every$call is inhooks/register.tsx; the rules are pure files inhooks/lib/.The daemon (
daemon/) is one process per machine. It keeps each Thread as a JSON document in~/.cache/ask-user-rich/threads/, the permanent answer archive in~/.cache/ask-user-rich/answers/, and its log in~/.cache/ask-user-rich/daemon.log. It serves the mod overdaemon.sock(never on TCP) and the page over HTTP. It exits after 24 hours with no open Round and no page connected; a Thread is pruned seven days after its last activity.The page (
public/) is vanilla JavaScript with no build step: the Thread stream (thread.html,js/), the index (home.html), and the stepper as focus mode (index.html,app.js). Drafts are saved to the daemon, so a half-answered Round follows you between devices.
ASK_USER_RICH_HOME moves the daemon's state elsewhere (tests use it).
Security
The page binds loopback only unless
hostsadds another address; keep that to a private network such as a tailnet. Requests whoseHostis not loopback or the public host get a 403 (DNS rebinding).Each Thread URL carries a random 144-bit token. The root index lists every live Thread, so anyone who can reach the port can open them.
The mod's routes exist only on the Unix socket (mode 600).
Writes must be
application/json, which forces a CORS preflight the daemon never answers.Markdown is rendered with
markedand sanitized with DOMPurify, both served from localnode_modules.
Development
npm test # the daemon as a black box (S1), plus the schema sync check
npm run test:mod # the mod through the engine's plugin test kit (S2)
npm run gen:schemas # regenerate hooks/lib/schemas.gen.ts after changing src/schema.js
claude plugin validate .docs/probes.md records the plugin-API behaviours the design rests on and what the smoke run found.
License
MIT. See LICENSE.
Available Tools
3 toolsappend_questionsAdd follow-up questions to an open interviewARead-only
Append follow-up questions to an interview whose form is still open, instead of opening a second form. Use it after ask_user_rich returned status "awaiting", or while a backgrounded ask_user_rich / await_user_answers call is still waiting: the open form updates live, shows the optional note as a banner, and the user answers everything in one submit.
Questions take the same shape and rules as in ask_user_rich. Ids must be unique across the whole interview; dependsOn may name any existing question or an earlier one in this call. Returns at once; the answers arrive through the call that is already waiting, or through await_user_answers. Fails once the user has submitted: then ask a new interview.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | Markdown shown to the user as a banner on the form, e.g. why these follow-ups were added. | |
| questions | Yes | Follow-up questions, appended after the existing ones. Ids must be unique across the whole interview; dependsOn may name any existing question or an earlier question in this list. | |
| sessionId | Yes | The sessionId of the interview that is still open, as returned by ask_user_rich. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only give readOnlyHint/openWorldHint; the description adds real behavioral context beyond them: the open form updates live, the `note` renders as a banner, everything is submitted once, the call 'Returns at once' with answers arriving through the already-waiting call, and the failure mode after submission. It does not address idempotency or whether two appends can race, and it calls the operation 'read-only'-adjacent while mutating a live form, but because that state effect is explicitly disclosed an agent is not misled.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose in the first clause, then usage, then mechanics; two tight paragraphs, no filler. Slightly dense for a definition of this length, but every sentence carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with a rich 100%-documented nested schema, no output schema, and only two hints in annotations, the description covers the remaining gaps: state effect on the live form, return timing, where answers arrive, dependency semantics, and the post-submit failure path. Nothing an agent needs in order to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, and the description still adds cross-field meaning the schema does not state on its own: question ids must be unique across the whole interview (not just this call) and dependsOn may name any existing question, not only earlier ones in this call. The banner behavior of `note` is also clarified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (append) and resource (follow-up questions to an interview that is still open) and immediately distinguishes the behavior from the obvious alternative ('instead of opening a second form'). An agent can tell it apart from ask_user_rich and await_user_answers without reading either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit triggering conditions ('after ask_user_rich returned status "awaiting"', 'while a backgrounded ask_user_rich / await_user_answers call is still waiting') and an explicit exclusion with the alternative for that case ('Fails once the user has submitted: then ask a new interview'). Both when-to-use and when-not-to-use are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ask_user_richAsk the user a structured interviewARead-only
Ask the user any number of questions at once in a rich browser form and wait for their answers. Use it instead of AskUserQuestion for grilling rounds, design reviews and any decision set with more than 4 questions or 4 options, long headers, markdown context, code/layout previews, or recommendations you want to argue for.
Each question has an id, a header, a markdown body, options (id, label, markdown description, optional markdown/code preview), an optional recommended option id plus rationale, multiSelect, allowOther (free text, default true) and dependsOn (earlier question ids, display only). Set kind: "rank" to have the user order every option by priority instead of picking (returns ranked; recommended is then the full recommended order). The user can also defer a question, mark it as needing more info, and leave notes.
Blocks until the user submits (it may take minutes; in Claude Code a long call continues as a background task). Returns summary (one line per question) plus, for each question, its status (answered | deferred | needs-info | unanswered), selected option ids and labels, ranked ids and labels (rank questions), other text, notes, and whether the recommendation was followed. Act on deferred and needs-info items instead of assuming answers. If the browser cannot be opened, returns the URL and a sessionId: show the URL, then call await_user_answers.
Ids (question and option) are ASCII only, [A-Za-z0-9_.:-]: secao-tabs, never seção-tabs. recommended takes option ids, not labels. dependsOn may only name earlier questions.
| Name | Required | Description | Default |
|---|---|---|---|
| intro | No | Markdown introduction: the context the user needs before answering. | |
| title | Yes | Interview title, shown as the page heading. | |
| delivery | No | browser (default): open the form in the user's browser and wait for the submit. link: do not open anything; return the URL immediately so you can show it, then call await_user_answers. elicitation: small flat interviews only, asked through the client's native form dialog; no notes, defer or previews. Falls back to browser when the client cannot elicit. | browser |
| questions | Yes | All questions, shown one per screen in this order (a stepper ending in a review screen). No upper bound. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover readOnlyHint/openWorldHint, but the description far exceeds that: it discloses that the call blocks for potentially minutes, that Claude Code continues it as a background task, the delivery modes, the fallback elicitation behavior, and that deferred/needs-info statuses must be acted on rather than assumed answered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: purpose, routing, and per-question model come first, then return shape and id rules. The length is justified by the compound nested schema and absence of an output schema, though some schema details (allowOther default, preview) are echoed rather than newly informative.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex nested interview tool with no output schema, the description fully documents the return contract (summary, per-question status, selected/ranked ids, other text, notes, recommendation-followed) plus the failure path. Nothing needed to call or interpret it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so 3 is the baseline, but the description adds genuine meaning beyond the schema: ASCII-only id rules with a concrete example, 'recommended takes option ids, not labels', and 'dependsOn may only name earlier questions' (display-only, no hiding). It adds the rank/quota semantics too, though it largely restates some schema wording.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names a specific verb (ask), resource (a structured interview / questions in a rich browser form), and behavior (wait for answers). It explicitly contrasts itself with the sibling-style alternative AskUserQuestion and lists the conditions that select it, so an agent can route without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use criteria ('more than 4 questions or 4 options, long headers, markdown context, code/layout previews, or recommendations you want to argue for') and names the alternative it replaces. It also handles the degraded path: if the browser cannot open, show the URL then call await_user_answers — a named sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
await_user_answersWait for a pending interviewARead-only
Wait for the user to submit an interview that ask_user_rich left pending (delivery=link, a failed browser open, or an earlier call that stopped waiting). Returns the same summary and JSON as ask_user_rich; returns immediately if the user already submitted.
| Name | Required | Description | Default |
|---|---|---|---|
| sessionId | Yes | The sessionId returned by ask_user_rich with delivery=link (or after a failed browser open). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare it a safe, non-open-world read, so the bar is lower; the description still adds real behavior: it blocks/waiting is implied, it returns the same payload as ask_user_rich, and it short-circuits if the user already submitted. It omits timeout or failure semantics if the user never submits, which matters for a wait tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tightly packed sentences with zero filler; the pending-state condition is front-loaded before the return-value note. The parenthetical list of trigger conditions is dense but each item earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter, no-output-schema tool the description is nearly complete: it explains the return value equivalence to ask_user_rich and the early-return case. The only material omission is what happens on timeout or abandonment, which an agent waiting on a user would benefit from knowing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents sessionId's origin and constraints, so the baseline is 3. The description reinforces the provenance (from ask_user_rich with delivery=link) but adds no format or validation detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (wait) and resource (a pending user interview submitted via ask_user_rich), and names the sibling tools it relates to, so the agent can distinguish it from ask_user_rich and append_questions directly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Enumerates the exact conditions that create a pending state (delivery=link, failed browser open, or an earlier call that stopped waiting), which tells the agent when this tool applies. It lacks an explicit 'do not use when...' clause, but the trigger conditions are unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.3.0- First observed
append_questions - First observed
ask_user_rich - First observed
await_user_answers
TDQS
Scored across 3 tools
The three tools cover distinct lifecycle stages: starting an interview, resuming a pending one, and appending to an open form. ask_user_rich and await_user_answers return identical payloads and could be momentarily confused, but the descriptions explicitly state when each applies (link delivery, failed browser open, backgrounded call).
All three names follow a clean verb_noun snake_case pattern: ask_user_rich, await_user_answers, append_questions. Verbs are distinct and the resource (user questions/answers) is consistently implied.
Three tools is minimal but each maps to a real lifecycle step (open, wait, extend), matching the narrow, single-purpose scope of a rich user-interview server. It sits at the low end of the healthy range rather than being over-built.
The interview lifecycle is well covered: create, resume waiting, and append follow-ups, with clear handling of deferred/needs-info states. Minor gaps exist around managing abandoned interviews (no cancel/close or list-pending operation), but the core workflow has no dead ends.
Maintenance
Related MCP Connectors
formset builds hosted forms from a description in chat. Ask Claude or ChatGPT for a signup sheet, RSVP, survey or poll; formset hosts it at a shareable link, collects the answers and reads them back to you, down to a CSV export. Respondents need no account.
Live SEO workflow tools for Claude Code, Codex, and AI agents.
I do everything related to interviews and structured Q&A
AI-native form builder: create, publish & read responses from Claude, ChatGPT & MCP.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceTurns Claude Code into an AI Agent Studio with a guided menu and 11 tools to design, create, and manage multi-agent projects without coding.1MIT
- AlicenseAqualityAmaintenanceBridges Claude Code and OpenAI Codex CLI for an interactive plan-execute-review workflow, enabling Claude to interview, design, and review while Codex implements code changes.729 npm3MIT
- AlicenseAqualityDmaintenanceTurns Claude into a structured interviewer with a collective evolution system that gets smarter with each conversation.430 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables Claude Code to run multi-round grilling sessions in a browser UI, publishing rounds of questions with options and recommendations that users answer with buttons or free text. Supports per-question asides (re-pitch, visual diagram, plain-language explainer), chat notes between rounds, and a polling contract so sessions can stay open without blocking the client.17 npm2MIT