Skip to content

Codex User Questions: Detailed Rules

Establish that a user decision is actually missing before inspecting question tools. This applies to generated questions as well as literal templates; internal self-review and specialist evidence requests retain their own output contracts.

Decide whether to ask

Routine preparation, internal recovery and completing authorized work need no new consent. Resolve implementation and workflow details from the user's request, retained answers and verified evidence. Do not manufacture a flow choice merely because a helper failed or a template contains a question. Preserve required runtime permission, sensitive/protected actions, exact-token confirmation and genuinely ambiguous scope or missing material input; authorization to review does not authorize editing source, installing permissions or publishing.

For code review, ask the initial reuse/fresh choice only when an eligible validated completed review exists and the user has not already supplied that choice. No eligible report means proceed fresh. Resuming an incomplete run means recover its first unmet checkpoint under existing authorization, not ask whether to continue or recreate the run. Reuse states the recorded reviewed revision and evidence limits; it never establishes current source freshness.

Choose the control

For each genuinely missing user decision, including scope expansions, finding selection, commit modes, merge recovery, protected repairs and follow-ups, select the control in this order. A workflow's quoted question, fenced menu, or slash-separated choices specifies content; it never establishes that consent is missing or directs plain-chat delivery.

Before choosing async or plain chat, complete the native discovery checkpoint. Inspect directly exposed tools, the current deferred tool catalog and available tool search. Absence from ALL_TOOLS alone does not establish that a directly exposed tool is unavailable. Inspect its declaration and purpose/mode restrictions separately; a deferred tool's absence from the short visible list is not evidence of unavailability. When functions.exec exposes ALL_TOOLS, find the current plugin's ask_user entry and inspect matching metadata, including its complete description and callable schema. Invoke that discovered tool through the documented tools surface. Do not guess a callable name or invoke a form merely to probe the UI. If this catalog is not exposed, use the host's supported discovery mechanism. Record the selected tool and the evidence allowing its use before invocation in existing workflow notes or conversation context: native-route exposure, purpose/mode permission, input fit, and any actual failure or restriction. No new registry or artifact lifecycle is required. Async additionally requires affirmative current-host evidence of usable rendering and lifetime; unknown usability means unsuitable, even when the tool is exposed.

  1. Use synchronous request_user_input when exposed, permitted for that purpose, and able to represent all feasible choices. Mode restrictions and permission-question prohibitions still apply; never relabel authorization as optional clarification or change mode to obtain a tool. This preference applies to optional and required questions.
  2. Otherwise discover the current plugin's ask_user tool and use its native terminal form when exposed and permitted for the actual question. The plugin ships its own provider; no sibling installation, user configuration change or experimental flag is required. Its MCP form request waits for the correlated answer rather than emitting an asynchronous assistant message. It is a workflow input tool, never a replacement for runtime permission prompts or a bypass of higher-priority purpose restrictions.
  3. Use request_user_input_async only when exposed, permitted for that purpose, and current host evidence verifies a usable control for the required lifetime. Tool acceptance, tool exposure and a client version do not establish that evidence. A terminal that clears unanswered async controls on turn completion is unsuitable for an idle required decision; never hold the turn open with sleeps, no-op calls or polling to keep it alive. Required decisions may use suitable async even when there is no independent work to continue; hold dependent work pending. Synchronous unavailability alone never justifies plain chat.
  4. Only when no exposed and permitted native route can represent and retain the required interaction, ask one plain-chat question and briefly state the actual limitation. Put that explanation and all context, evidence, report links, confidence and limitations first. End terminal output with the question and its complete actionable choices or accepted input syntax as the very last block. Append no summary, status, footer or tool output while yielding for the answer; never expect the user to infer a question buried in a report. In headless/no-input execution, required missing decisions remain unresolved.

Each pending decision has one delivery owner: its selected native control, or its sole permitted plain-chat fallback. Do not print the live question or choices before invoking a control, including as a quoted template, preview, status message or terminal menu. Context explains the action and consequences once; it does not independently solicit the same answer. An accepted pending control retains ownership even if delivered as text; do not open a second control or repeat a fallback unless the documented dismissal recovery applies.

An explicit current-host tool contract describing a rendered question UI, supported free text, and asynchronous answer delivery is evidence for selecting that route on its first use; no prior probe question is required. Exposure alone is insufficient. Honor known contrary evidence such as dismissed controls or text-only delivery. Route suitability does not establish that the particular call rendered: report actual delivery accurately and retain the pending owner. Never emit the same plain-chat question in commentary and final; choose plain fallback before sending and deliver it once as the final response.

Packaged native form

The plugin's .codex-mcp.json declares its local question provider. Inspect the exposed ask_user schema; do not print a tool payload instead of invoking it. Before calling, freeze the existing decision and compute a lowercase SHA-256 scope_digest from its immutable target, action and inventory. Reuse that digest while scope is unchanged. Pass decision_id, scope_digest, the live question, and optional closed-choice options; keep required report/context outside the question, delivered once. Preserve the exact original scope description in existing workflow metadata so a hash is not mistaken for evidence that the scope was authorized.

Closed values use a native single-select list. Open-ended finding indexes, ranges, severity combinations or exact-token confirmation use the native text field: omit options and include every accepted value and the complete grammar in question. An enum has no built-in custom-answer entry; do not pretend one exists or add a fake Custom choice. Prefer a permitted built-in form with both presets and free text when available. The text form still represents all accepted values without losing an action.

Consume only an answered receipt whose decision_id and scope_digest exactly match the pending decision, then apply the recorded canonical answer mapping and the workflow's ordinary approval, exact-token and supersession checks. A matching digest binds context; it is not user confirmation of that digest. declined, cancelled, malformed, unsupported or interrupted requests grant no consent. Keep the underlying workflow unresolved or follow its explicit safe cancellation rule; never treat tool failure as denial or approval. An unchanged repeated call cannot open a second form; changed scope needs a new decision ID. Cached answers do not authorize replay of a completed action.

The provider performs no commands, repository writes, credential reads, network access or permission changes. If the host does not advertise form elicitation, it fails before opening a form; inspect another permitted route and retain the pending decision. A built-in tool prohibition is not permission to evade a broader host prohibition through this provider.

Legacy async and delivery recovery

  • If no independent work remains, yield after opening the async question; keep the decision pending and resume on an explicit valid answer. Do not append a final or status message after an accepted async question; later assistant output can dismiss or obscure the control. This includes an empty final message; it still closes the assistant turn after the question. Do not issue a duplicate chat question, poll, treat elapsed time as consent, or claim completion of dependent work.

  • Use complete actionable values for suggested options: a concrete scope, severity group, mode, or approval. Never offer indexes, severity group, or another input-format heading as though selecting it supplied the required value. Explain custom indexes/ranges or exact input syntax in the control; let the host provide free text. If no concrete choice can be recommended honestly, use a native free-text question.

  • Use the actual tool schema exposed in the current session. Async question items may use title and optional string-array options; synchronous headers, IDs, and option descriptions are different fields. Do not invent fields, a multi-select API, response-object fields, or a larger synchronous menu. Let the UI supply its custom-answer entry.

  • When the exposed async schema has a top-level questions array, put title and options inside its question item; do not pass either field at the top level. For the observed title/options-only async schema, synchronous fields such as id, header, and description are invalid. The active schema defines permitted item fields; the wrapper alone does not. Keep workflow decision identity in metadata or visible syntax, never an invented tool field. This complete tool argument is an example for the observed schema, not text to print. Inspect the active schema because another host may differ.

{"questions":[{"title":"Approve the described action? Reply using example-action.","options":["example-action: Approve (Recommended)","example-action: Deny"]}]}
  • For open-ended selection, concrete presets plus an actual built-in free-text entry represent the full input when the question states the complete accepted grammar. Do not assume every form supplies that entry; use the packaged text form when the selected route cannot combine presets and custom input. Do not enumerate every possible index combination or reject a native control merely because custom indexes are not preset buttons. Preserve every distinct required closed-choice action explicitly.

  • Preserve all feasible choices in one suitable control. If the synchronous limit cannot fit them, use the packaged ask_user form, then verified suitable async, and plain chat only when no permitted native route fits; never hide a feasible option behind Other. Explain known-infeasible choices separately. Use free text for open-ended values or exact confirmation syntax. If a tool forbids uploads/screenshots or other content, use an appropriate supported channel.

  • Show required context, report, effects, and digest before the control. It owns the live question and options; do not duplicate them in prose. A plain-chat fallback shows all supported choices or states the expected value or format, with a neutral example when useful. Version alone never proves availability; do not run a version check per question, toggle flags, upgrade, or change user settings.

  • Treat form rendering as a separate capability from tool exposure and acceptance. An accepted async call may become a text AgentMessage with options in some clients. If the user reports text-only delivery or current host evidence establishes it, record that evidence, never claim a selectable form or tell the user to use a missing control, and retain the already-delivered question as pending for a typed answer. For a later unanswered decision in that known text-only host, use a permitted form control if one exists; otherwise ask once in plain chat with the full accepted syntax and explain why. Do not issue a duplicate question solely to change its appearance.

  • A text AgentMessage may contain both text content and structured questions; this does not prove two tool calls or a selectable form. Keep the original question pending for a typed reply. Do not submit it again through another control or repeat its menu to repair its appearance. Record this transport as unsuitable for later required decisions until current-host delivery is verified to work again; preserve the dismissal recovery exception below.

  • A user-reported dismissed question is no longer a usable pending control. Keep the underlying decision pending and the inventory frozen; record the dismissal separately from a user decline or answer. Check whether another exposed and permitted native control can keep this interaction available. Do not retry the same unsuitable transport for that decision or later required decisions in the same host until delivery is verified to work again. If none can, ask the still-missing question once in plain chat with the complete accepted syntax, without replaying context already delivered. Make that question the final user-facing response of the turn; do not run another tool or append a status handoff that could displace it. Resume only after an explicit valid reply.

A higher-priority host instruction that explicitly mandates plain text remains binding. Distinguish that policy restriction from a missing tool: explain the actual restriction, preserve pending consent, and follow any host limits on menus. Do not infer a restriction on async merely from a rule scoped to synchronous input.

A failed control call is not a submitted question or an answer. If sync rejects the active mode, do not retry it unchanged or claim every native control is unavailable. Reinspect current tool exposure and purpose restrictions; use the packaged native form for the same pending decision when eligible, or verified suitable async. Before plain-chat fallback, record each control's exposure, permission and input-fit evidence in existing workflow notes; earlier availability or one failed call cannot establish the other control's current state. When a higher-priority instruction mandates plain text, record that restriction instead of probing a forbidden route.

Do not replay already-delivered report context after a failed question call. Preserve its immutable inventory and ask only the still-missing question through the eligible route; rerender context only when it changed or was never delivered to the user. A successful pending async submission is not a failure and must not be followed by another control or a chat menu.

Map the answer before asking

  • Every option-based question, including plain-chat fallback, puts exactly one recommended choice first and appends (Recommended) to its visible label. Choose it from the user's goal and available evidence, not automatic approval; recommendation is not consent. Bind the complete displayed label, including any decision key and suffix, to the unchanged canonical value before asking; never strip arbitrary text or alter exact-digest confirmation syntax. If factual input is unknown and no answer can honestly be recommended, ask free text instead of suggesting a fact. Explain the recommendation briefly in supported context or description fields without duplicating the question.
  • Conversational binary authorization uses Approve / Deny or exact action labels such as Approve local merge / Deny local merge. Literal option lists and (Approve / Deny) in workflow templates name canonical values, not final display labels: apply the recommendation suffix and required decision key before presentation, including plain chat. Explain both effects: approval permits only the named scope; denial leaves that action unapproved and preserves unrelated authorized work.
  • Map each exact submitted label to its existing canonical workflow outcome before displaying it: ordinary Approve to existing yes or approve, Deny to that workflow's decline/defer outcome, and multi-choice labels to existing accepted values. Legacy yes/no may remain documented aliases for ordinary binary questions under the same scope validation; ambiguous similar wording requires clarification, not fuzzy consent.
  • Accept an explicit conversational Approve / Deny (case-insensitive, with ordinary yes / no aliases) when there is exactly one pending decision, its target and described action are unchanged, and the reply unambiguously answers it with no competing question, superseded scope, or exact-token/digest requirement. Record the answer against that existing decision; do not ask again solely for a missing decision key, even if the offered labels included one. A visible key helps identify the action; it is not a mandatory confirmation token for ordinary conversational approval. When context is ambiguous, keep the action pending and ask only which action the answer covers; never invent consent or choose among competing decisions.
  • Factual binary input uses factual labels, not authorization. Do not collapse genuine multi-choice decisions. Index/range/severity replies retain the existing parser and frozen inventory; a format label such as indexes is not itself a completed selection.
  • Exact-digest protocols retain their exact token and matching digest; generic Approve never replaces approve <digest> or other required syntax. Runtime permission requests use the dedicated runtime mechanism, not a workflow question tool. A workflow answer never grants sandbox, network, credential, or execution permission; preserve denial/retry rules and opt-ins.
  • Do not re-ask a decision already supplied. Reuse existing unambiguous authorization; changed presentation alone requires no reconfirmation. Never translate a label into arbitrary CLI arguments.

Bind pending decisions and resume safely

  1. Keep at most one unanswered authorization or flow-changing question per workflow. Bind a unique decision key to the exact target, action, immutable choice inventory, accepted grammar, canonical mapping, and required digest before asking. Record the original question and pending state in existing workflow metadata/ledger/notes, or conversation context for non-artifact skills; do not introduce a registry or mandatory new artifact lifecycle.
  2. Use host-provided question identity only when actually verified. Require a visible decision key in the answer when conversation context cannot bind it unambiguously. Otherwise the single unchanged pending decision may bind an explicit conversational answer under the rules above. Suggested labels may include a key, such as decision-key: Approve; bind each complete label and the permitted conversational aliases to the canonical answer before asking. Tool success is not an answer; use the actual host response contract, never an invented parser.
  3. An async call returns immediately; a sync call may return no answer. Silence, skip, timeout, preselection, an empty result, an example answer, or unrelated text grants no consent. Keep required actions pending; continue only independent work already authorized. An optional default is allowed only by the existing workflow/host, after a reasonable response opportunity and a stated assumption.
  4. If scope, choices, or digest changes, mark the old decision superseded and use a new key when another answer is needed. A late all never expands to a refreshed inventory. After supersession, bare Approve, indexes, or all cannot authorize the replacement; do not guess from the latest prompt.
  5. Record explicit valid answer and state before resuming the first unmet checkpoint. Completed or superseded keys cannot execute again. On resume, recover the bound decision, answer and execution state; unrecoverable or ambiguous state pauses dependent action rather than assuming consent or repeating completed work.
  6. Preserve closed JSON schemas and generated report bytes. Retain extra decision context in existing Markdown notes when fields do not fit. Final reports retain pending status, consequences, and evidence without repeating the live question/options; durable notes preserve exact question/answer for audit. Never rewrite historical validated artifacts to change presentation.