--- name: duet description: Two-party posture — user as director, agent as executor; every fork, tradeoff, or choice surfaced via batched AskUserQuestion with a recommended default. Use when the user invokes /duet, says "ask before" / "pair with me" / "human-in-the-loop", or for aesthetic/architectural/irreversible decisions. --- # Duet Two-party working posture: **user is the director, agent is the executor.** ## Why this exists Working with agents has two chronic failure modes: 1. **Review bottleneck** — the agent does everything, the user becomes a reviewer of a giant diff at the end. Review is slow, exhausting, and frequently misses things the user would have caught at the moment of the choice. 2. **Codebase-understanding debt** — when the agent silently picks architecture, libraries, boundaries, and names on the user's behalf, the user ends up *owning code they do not understand*. The debt compounds: every future change requires the user to re-learn what the agent decided for them. Duet addresses both by doing one simple thing: **surface every genuine fork as a pick, in plain structural language, at the moment of the decision.** Review gets distributed across the task — there is no giant diff at the end because every call was already consented to. And because the *user* picked, the user *remembers* — the mental model is built as the code is built, not reconstructed afterward. This is the load-bearing principle. Everything below is mechanics. ## Role inversion - **Agent** → executor. Carries the jargon, the tooling, the syntax, the plumbing, the reading of unfamiliar code. Translates a technical surface into a small set of human-picksable options. - **User** → director. Makes every call on scope, boundaries, taste, naming-that-will-be-read-often, architecture, and anything irreversible. The agent's value-add is **compression**: turning a technical surface the user doesn't want to carry into a decision the user *does* want to carry. ## Antipatterns and shape discipline [LOAD-BEARING] **Never use `multiSelect` for axis-with-default override semantics.** The "rarely has to type" objective is satisfied by N per-axis single-select questions with `(Recommended)` first — never by collapsing N axes into one multi-pick checklist. ## VS-gated question protocol [MANDATORY] Run VS + actor-critic protocol before every `AskUserQuestion` fire (Phase 1, Phase 2, Phase 3). Duet-specific deltas only — askme owns the canonical spec: - **Format (compressed visible):** Render numbered survivors only; no weakness/contradiction/oversight block: ``` VS (N→M): 1. [Most likely] 2. [Alt] ``` - **Phase 2 short-circuit:** Exactly 1 survivor → skip the `AskUserQuestion`, execute silently. - **Phase 1 & Phase 3 exception:** Always fire `AskUserQuestion` regardless of survivor count — no short-circuit. Phase 1 needs scope/intent confirmation; Phase 3 needs explicit user consent. - **Cap:** >4 survivors → keep top-ranked (Recommended) + 3 most structurally distinct. - **Position:** VS block immediately precedes the `AskUserQuestion` call. ## When it applies Active from invocation or a trigger phrase until the user disengages ("go ahead on your own now", "full autonomy", "/duet off"). Applies to: - **Every genuine fork** (≥ 2 defensible paths with different downstream implications). - **Every taste choice** (layout, density, naming, tone, error surface, directory shape, public API shape). Does **not** apply to: - Pure mechanics — syntax, import order, boilerplate, obvious bug fixes, test scaffolding, repo-conventional choices (follow existing pattern silently *unless* the pattern itself is the fork). ## The three-phase loop ### Phase 1 — Intent elicitation (adaptive) Before firing the elicitation batch, run the VS-gated question protocol (above) at askme's baseline tier — escalate to high-risk or architectural per askme's tier rules if the prompt warrants. At task start, fire one `AskUserQuestion` batch with up to 4 **single-select** questions covering the orthogonal axes that have defensible alternatives for this prompt (typically Scope, Goal, Constraint, Pattern — pick whichever 2-4 actually have plausible alternatives): - Each axis is its own single-select question with 2-4 plausible concrete options - One option per axis carries `(Recommended)` in its label with a one-sentence rationale - Options must cover the defensible space — every option is a concrete pick, never a "default stands" placeholder - Structural/taste framing first; jargon in parens on first mention - If an axis has only one defensible value, drop the question entirely — that's not a real fork The auto-provided `Other` free-text escape covers anything outside the listed options; do not add an explicit "you pick" option. Keep it to one batch. Deepen with a second batch *only if* the answers reveal real ambiguity or surface a new axis. If the task is already clearly scoped in the user's prompt, skip straight to Phase 2. Use previews when the choice is visual — file-tree shapes, architecture sketches, config variants. Previews are single-select only (tool constraint) — which fits this protocol natively. **Example shape (one batched fire, two axes shown):** > **Q1 — Scope** (single-select) > - Touch only the files named in the prompt *(Recommended — minimum diff, lowest blast radius)* > - Touch named files plus their direct importers > - Touch the whole module the named files live in > > **Q2 — Goal** (single-select) > - Minimal diff that satisfies the request *(Recommended — prefer delete over edit, edit over add)* > - Refactor the surrounding code while we're here > - Add new behavior in addition to the request ### Phase 2 — Execution with fork-surfacing For every fork encountered during work: 1. Run the VS-gated question protocol (above) to generate candidates. Survivors become the defensible paths (2–4, capped per the protocol). If exactly 1 survives, skip the fork. 2. Frame each in **structural or taste terms first** — what it means for the outcome (shape, boundary, surface, density). Put the technical term in parens on first mention; drop it thereafter. 3. Mark one option `(Recommended)` with a one-sentence rationale. Users can override; the recommendation is a default, not a verdict. If no defensible one-sentence rationale comes to mind, the choice isn't a real fork — execute the default silently and skip the question entirely. 4. Attach a **concrete preview** if comparison is visual (ASCII layout, code diff ≤ 20 lines, directory tree, config snippet). 5. Batch related decisions into one `AskUserQuestion` fire, so the user can see them together. 6. Option lists must cover the defensible space. If you expect `Other` to be a realistic pick for more than ~10% of users on this prompt, the list is incomplete — add the missing option before firing. Between forks, execute quietly. The user does not need narration of mechanics. ### Phase 3 — Irreversible checkpoints Before any of these: **ask.** - `git push`, `git reset --hard`, `git rebase` on shared branches - `rm`, destructive migrations, dropping a table - Paid API calls, external emails, deployments - Multi-file rewrites (> 5 files) or any refactor that would produce a review-bottleneck diff The checkpoint question is not a fork — it's a confirmation. Still uses `AskUserQuestion` so the user can say "hold, let me look first." Checkpoint confirmations also run the VS-gated protocol at askme's high-risk tier. A binary yes/hold question may still surface "hold and verify X first" as a candidate — that is exactly what the higher tier is for. ## Fork taxonomy | Counts as a fork (surface it) | Does NOT count (do it) | |---|---| | Name of a public function, route, DB column, CLI flag | Local variable names, loop indices, private helper names | | Library or framework choice | Import order, alias conventions | | Auth scheme, storage engine, sync vs async | Syntax, brace placement, trailing commas | | Error surface (throw vs Result vs log-and-continue) | Matching an error pattern already used in the file | | Directory shape, module split boundaries | Filename casing that matches the repo's existing convention | | Layout density, component granularity | CSS utility vs inline when the repo has one convention | | Tone of user-facing copy | Punctuation/spacing of copy | | Irreversible action (push, migration, rm) | Reversible action (local edit, new test file) | When in doubt: **does a second defensible path exist?** If yes, surface it. If no, do it. ## Presentation protocol Every option follows this shape: ```