Studio CLI — Raise Blocking Questions Through the Harness's Native Question Dialog
Context
Studio asks the user through PDSL's EMIT_MENU / EMIT primitives, which render as text inside the assistant's message. Nothing in the prompt corpus reaches for a harness question affordance: there are zero references to AskUserQuestion or any equivalent across skills, modules and workflows.
The consequence is that a blocking question is indistinguishable from a finished turn. Both end the same way — a message, then silence. To find out which happened, the user has to read the message body, locate the question inside it (it is not reliably the last thing in the turn), and work out what answer is expected. Nothing in the interface says "you are being waited on".
Modern harnesses expose a question or menu affordance that makes waiting unambiguous: a distinct interactive element with selectable options. Studio does not use it, so it forfeits the one signal the user does not have to read prose to receive.
Naming a single tool is not a sufficient fix. Harnesses name the affordance differently, and a hardcoded tool name only works where that exact name is defined. The naming is similar enough across major harnesses that a per-target binding plus an intent description covers most of the field, and Studio already generates per-harness integration files for claude, codex, cursor and copilot via cfs generate-agents — so a place to carry per-target conventions already exists.
This is a distinct problem from question volume. #128 reduces how often Studio asks. This issue is about the asks that remain being impossible to miss. Neither substitutes for the other: reducing the count of invisible questions still leaves invisible questions.
Functional Requirements
- Native dialog for blocking questions: When Studio blocks on a user answer, it requests the harness's own question or menu affordance rather than emitting the question as prose.
- Per-harness binding: The tool name and invocation convention is resolved per generation target (
claude, codex, cursor, copilot, and others we support), not hardcoded to one harness's name.
- Description-based fallback: Where the tool name differs or is unknown, the instruction describes the intent so a harness exposing an equivalent affordance can still match it.
- Graceful degradation: On a harness with no question affordance, Studio falls back to text rendering, and the question remains clearly marked as blocking and appears in a predictable position — at the end of the turn.
- Waiting state is unambiguous: A turn that ends on a blocking question is visibly distinct from a turn that ends on completed work, on every harness.
- Applies to existing gates: Menus currently rendered through
EMIT_MENU route through the same mechanism, so the change is not limited to newly written prompts.
- Presentation only: This changes how a question is surfaced, not whether it is asked, and not the workflow's control flow.
Non-Functional Requirements
| Quality Attribute |
Requirement |
| Portability |
Behaviour is defined for every generation target Studio supports, with a documented fallback for the rest. |
| Compatibility |
Harnesses without a question affordance keep working, with no lost questions. |
| Maintainability |
Harness-specific naming lives in one place, alongside the existing per-target generation matrix — not scattered across prompt modules. |
| Token cost |
The mechanism must not add a per-turn prompt overhead proportional to the number of workflows. |
Acceptance Criteria
- In Claude Code, a Studio workflow that blocks on a choice presents it through the harness's question dialog, not as prose in the message body.
- The same workflow, run under Codex and under Cursor, presents the question through each harness's own affordance.
- On a harness with no such affordance, the question still appears, is marked as blocking, and is the last thing in the turn.
- A user can tell, without reading the message body, whether the turn ended because Studio is waiting or because work finished.
- Existing
EMIT_MENU sites are covered by the mechanism without each one being rewritten by hand.
- Adding support for a new harness requires changing the per-target binding only.
Additional Context
Studio CLI — Raise Blocking Questions Through the Harness's Native Question Dialog
Context
Studio asks the user through PDSL's
EMIT_MENU/EMITprimitives, which render as text inside the assistant's message. Nothing in the prompt corpus reaches for a harness question affordance: there are zero references toAskUserQuestionor any equivalent across skills, modules and workflows.The consequence is that a blocking question is indistinguishable from a finished turn. Both end the same way — a message, then silence. To find out which happened, the user has to read the message body, locate the question inside it (it is not reliably the last thing in the turn), and work out what answer is expected. Nothing in the interface says "you are being waited on".
Modern harnesses expose a question or menu affordance that makes waiting unambiguous: a distinct interactive element with selectable options. Studio does not use it, so it forfeits the one signal the user does not have to read prose to receive.
Naming a single tool is not a sufficient fix. Harnesses name the affordance differently, and a hardcoded tool name only works where that exact name is defined. The naming is similar enough across major harnesses that a per-target binding plus an intent description covers most of the field, and Studio already generates per-harness integration files for
claude,codex,cursorandcopilotviacfs generate-agents— so a place to carry per-target conventions already exists.This is a distinct problem from question volume. #128 reduces how often Studio asks. This issue is about the asks that remain being impossible to miss. Neither substitutes for the other: reducing the count of invisible questions still leaves invisible questions.
Functional Requirements
claude,codex,cursor,copilot, and others we support), not hardcoded to one harness's name.EMIT_MENUroute through the same mechanism, so the change is not limited to newly written prompts.Non-Functional Requirements
Acceptance Criteria
EMIT_MENUsites are covered by the mechanism without each one being rewritten by hand.Additional Context