feat(chat): shared Plan → questions → review → implement flow for Codex and ACP harnesses

Author: illegalcallCreated Sep 8, 2026Updated Sep 19, 2026
Labelsenhancementcomp/daemoncomp/desktop

Problem

AO should offer a consistent Plan → questions → review → implement flow across Codex and ACP-based harnesses. Today, question handling, planning controls, remembered permissions, and continuation are split across provider adapters, live configuration endpoints, and renderer heuristics.

A user can select Plan without that choice being durable, have it overwritten by a remembered permission setting, or encounter a native question that AO cannot present and answer correctly. Adding a Codex toggle alone would leave those lifecycle problems in place.

Goal: one daemon-owned workflow and shared interface, with each adapter translating its provider's native capabilities. Preserve the existing Go service/ports/storage boundaries and keep desktop, mobile, and CLI as clients.

Source: user-provided screenshot from anaya, dated 31 August 2026, asking why the question tool is not available for all agents; subsequent investigation requested a generic approach inspired by T3 Code. No source-chat URL was provided.

Investigation status and existing groundwork

  • Rechecked relevant code against main at 0e8038d7b before filing.
  • Earlier investigation on 7–8 September reproduced two ACP wire-level defects with a scripted provider. These are protocol-boundary reproductions, not a claim that every packaged harness was tested live.
  • Main already provides ChatInputRequest, structured-input activities, ResolveInput, shared ElicitationCard, Claude ACP forms, and Cursor's native question extension. PR #4398 added sequential Claude questions.
  • A local prototype exists on codex/shared-agent-questions, commit ba33bb5e5132cfd75438f4b5c8274699f0087825. It adds Codex native question normalization, shared validation, and ordered question groups. It is not on main and has no published PR. Review/reuse that work where appropriate; do not count it as shipped.
  • The prototype's live round trip passed with Codex CLI 0.153.4, explicitly starting native Plan mode, answering a structured question, and observing the resumed response. It bypassed the ordinary public turn-settings path, so it does not prove the complete product flow.
  • Confidence: high in the traced settings/dispatch defects. Cross-harness mode availability and the proposed complete workflow still require live validation. The original screenshot does not establish an exact packaged AO version.

Concrete gaps

1. Working mode is missing from durable settings

ConversationSettings remembers model, reasoning effort, and approval mode. Planning intent is absent.

SetConfigOption changes the live ACP provider first; settingsFromConfigOptions only copies recognized model/effort/permission values into durable state. Restart, queue drain, and non-renderer callers cannot reliably preserve the selected working mode.

2. Permission settings can overwrite Plan before the prompt

ACP applyTurnSettings translates remembered approval settings into session/set_mode before a turn. For Claude, a nondefault preference such as acceptEdits, auto, or bypass can replace the previously selected Plan mode. Default currently maps to no mode setter, so the overwrite is specifically tied to a nondefault preference.

Scripted reproduction:

  1. Advertise native acceptEdits and plan modes, plus the modern mode config option.
  2. Select plan through AO's config-option interface.
  3. Send a message with the remembered acceptEdits permission preference.
  4. Inspect the native mode setter emitted before dispatch.

Observed: native mode after selecting plan and dispatching = "acceptEdits"; want plan.

3. Modern ACP options lose to legacy routing

Session setup enables legacy routing whenever legacy modes/models are present. SetConfigOption then chooses the legacy setter even when a modern catalog was supplied.

Scripted reproduction: advertise both APIs, select plan, and inspect calls.

Observed: modern setters = 0; legacy mode = "plan"; want modern setter exclusively.

ACP recommends that clients supporting config options use that mechanism exclusively when both are offered. ACP config-options specification

4. Presentation currently decides provider semantics

TurnSettingsBar identifies Plan/Agent using label/value regexes, synthesizes Agent from Manual, and leaves Plan by choosing another provider value rather than restoring the user's prior execution preference.

Claude-specific permission annotations also live in the service. Move those semantics into harness bindings; the renderer should consume a shared contract.

5. Settings changes and turn dispatch have separate ordering

Configuration uses configMu while dispatch uses sendMu. A live setting can change independently of active work. Dispatch also overwrites message settings from current conversation preferences, so queued messages use settings at dispatch rather than submission.

6. Question transport and resolution need a complete contract

Main still classifies Codex requestUserInput as an approval. The local prototype fixes the native callback bridge, but asynchronous questions require a different continuation route.

There is also a resolution-history race: ResolveInput records action/content after delivery, while input.resolved can first resolve the same activity with only a provider-closure marker. The SQL update accepts pending rows only, preventing the later receipt from enriching the result. Define the accepted disposition and redact secret-marked answers before storing historical details.

Proposed direction

Domain concepts

Keep these concepts separate:

Concept Meaning
Working mode How the provider approaches the task, such as planning or execution; separate from Chat/TUI interface mode
Permission preference The user's permission policy for execution; some providers couple active permissions to working mode
Next-turn settings Remembered choices used when accepting subsequent work
Question A request for information; answering it does not itself authorize tool execution or leaving Plan
Proposed plan A provider's description of work offered for review
Progress plan A changing checklist of execution steps and status

Ownership and public interface

Deepen the existing chat controller. It owns durable intent, submissions, interaction identity, resolution, and continuation. Adapters own wire formats, native mode/permission composition, and capability interpretation. SQLite remains the durable source; the renderer presents the result.

Illustrative operations, extending the existing service rather than adding another manager:

go
Controls(ctx, conversationID) (Controls, error)
ConfigureNextTurn(ctx, conversationID, expectedRevision, patch) (Controls, error)
Send(ctx, conversationID, message) (Turn, error)
ResolveInput(ctx, conversationID, inputID, response) (Resolution, error)
ContinuePlan(ctx, conversationID, proposalRef, clientMessageID) (Continuation, error)

Controls should expose remembered choices, the adapter-described catalog, observed provider values, and actionable configuration problems. Patch semantics distinguish omitted fields from an explicit reset. A revision prevents two clients from overwriting newer choices.

Keep native mode IDs opaque and scoped to the harness. An adapter can annotate a confirmed planning/execution meaning; unknown modes remain usable without forcing them into a binary Agent/Plan model. Preserve generic select/boolean extension controls and make their live/persistent behavior explicit.

Configuration invariants

  • Saving composer settings affects subsequent submissions; it does not mutate the running turn or its questions.
  • Resolve the entire working-mode/permission/model/effort tuple once inside the adapter. Avoid independent setters that overwrite one another.
  • Apply configuration and prompt dispatch through one ordering boundary.
  • If ACP setters partially fail, do not prompt under the accidental mixture. Refresh observed state, retain desired intent, and surface the error.
  • Re-read provider catalogs on recovery and revalidate saved choices. Do not persist catalog availability or derived display status.
  • On a different-harness handoff, translate only confirmed semantic intent; never blindly copy opaque provider IDs.
  • Provider notifications update observed state. An acknowledged user action to leave Plan can update remembered mode with revision checking; arbitrary notifications must not overwrite a newer composer choice.
  • Permission changes requiring a restart must be reported honestly.

Deliberate queue behavior change: freeze settings when a message is accepted and persist them with its turn. A request submitted in Plan mode must remain Plan even if the composer later switches to Agent. Show the queued mode. Preserve legacy behavior for old rows without snapshots; new rows use snapshots. A deliberate retry can use current composer choices, frozen into the new attempt.

Provider bindings

Provider Required behavior
Codex Expose supported collaboration modes; build the complete collaborationMode with effective model/effort; keep approval/sandbox settings independent; explicitly send Default when leaving Plan
Claude ACP Treat native planning and permission modes as one composed configuration; keep execution permission dormant during Plan and restore it when leaving
Cursor ACP Reuse native question IDs/options and plan/approval extensions; discover mode choices; preserve restart constraints
Kimchi ACP Resolve its combined permissions-mode values together so auto/yolo-style preferences do not erase Plan
OpenCode, Kimi, Droid, OMP, Pi, future ACP bindings Respect offered controls and existing launch/admission constraints; annotate planning only where verified; retain generic forms and native option catalogs

For ACP, use modern config options when supplied, and legacy mode routing for legacy-only sessions. Replace catalogs from authoritative responses/notifications and revalidate dependent choices. Categories support presentation, not correctness. ACP configuration contract

The installed Codex 0.153.4 experimental schema inspected during the earlier investigation includes collaborationMode, asynchronous agent-message questions, requestUserInput.isBlocking, and proposed plan items. AO's generator omits --experimental.

Correct generation with recorded provider/schema provenance and focused generator fixtures. Avoid accumulating handwritten experimental payload types. Populate collaboration-mode model/effort from the effective selection because that object takes precedence over separate overrides. Prefer native built-in instructions unless AO needs a specific documented override. Schema presence alone does not establish live availability for every model/build.

Shared questions, two continuation routes

Reuse ChatInputRequest, ElicitationCard, and the existing activity lifecycle. Bring forward the prototype's shared validation and ordered field groups after review.

Preserve question order, original IDs, option values/descriptions, multiple selection, custom answers, and secret hints. Make choice versus Other explicit so stale custom text cannot silently override a later option selection. Keep arbitrary ACP forms and URL consent intact; do not guess that every schema is a questionnaire. Preserve decoding of historical activities.

The shared card supports two answer routes:

  1. Native reply: answer a pending provider request. Whether it blocks the turn is a separate fact; respect actual blocking/expiry semantics.
  2. Follow-up message: record an idempotent answer submission through the existing durable send/queue path. The adapter formats the native input; it must not start an unrecorded turn inside ResolveInput. Use explicit steering only through AO's existing steer action.

Scope AO interaction identity to the owning conversation/branch/provider instance using existing generation fencing. Reject stale cards and duplicate delivery. Reconnecting to a still-live Codex host differs from restarting a dead ACP process; restore callbacks only when they remain live.

Persist one consistent disposition and allow an authoritative receipt to enrich an earlier closure event. Distinguish answered, skipped, cancelled, expired, and uncertain delivery. Redact secret-marked values in AO's historical details. Never automatically replay an uncertain delivery after a crash without evidence it is safe.

Proposed plans and implementation

Model proposed plans separately from the current progress checklist, reusing existing turn/activity lineage and revisions.

  • Render a completed native proposal with Implement plan and Request changes.
  • Request changes submits feedback in Plan mode with the proposal reference.
  • ContinuePlan validates branch/revision and creates one idempotent execution submission, restoring the remembered permission preference. Update remembered working mode in the same transaction.
  • If an ACP provider is already waiting on a native mode-switch approval, answer its offered decision through the pending request rather than creating a competing turn. Test that execution auto/bypass preferences cannot accidentally skip a review AO presents as explicit. ACP mode-switch flow
  • Where no structured proposal is available, offer Continue in Agent mode after a completed planning turn. Do not interpret arbitrary prose as a structured approval.

T3 Code inspiration

T3 demonstrates the useful boundaries:

Borrow those behaviors into AO's existing controller, queue, and adapters. Copying T3's orchestration framework or instruction text is unnecessary.

Alternatives considered and scope

  • Only add a Plan toggle: leaves persistence, permission coupling, queues, and continuation unresolved.
  • Universal generic configuration engine: handles arbitrary settings but creates more machinery than this workflow needs. Use typed remembered settings plus the existing provider catalog.
  • Separate workflow manager: duplicates the current controller's lifecycle and ownership.
  • AO-owned MCP question tool: possible future fallback where a harness can register external tools but cannot emit native questions; still requires per-harness registration. It is not required for the shared native workflow.
  • Prompt-only Plan or parsing questions from prose: does not establish native capability or dependable semantics.

“All harnesses” means shared contracts and faithful capability handling across all adapters. It does not mean AO can make an unavailable native Plan mode or question tool exist. Planning mode must not be described as an OS-enforced no-write sandbox.

Implementation sequence

Phase 1 — Durable mode and correct dispatch

  • Review/reuse local shared-question groundwork; establish the native Codex callback path on main.
  • Correct Codex experimental schema generation and provenance.
  • Add durable working mode and submitted settings snapshots with a backwards-compatible migration.
  • Consolidate mode/permission/model/effort resolution in bindings and serialize apply/dispatch.
  • Fix modern ACP precedence and combined Claude/Kimchi mode mappings.
  • Replace renderer mode regexes with adapter metadata and expose current versus next-submission settings.

Phase 2 — Complete question lifecycle

  • Shared validation and ordered grouping for native questions, with existing generic form/URL compatibility.
  • Codex asynchronous questions through durable message delivery; blocking status independent from reply transport.
  • Consistent resolution receipts, cancellation/expiry behavior, stale-generation handling, and secret-history redaction.
  • Explicit option-versus-custom-answer interaction.

Phase 3 — Review and continuation

  • Proposed-plan projection separate from progress plans.
  • One idempotent continuation command with branch/revision checks.
  • Implement plan / Request changes, plus capability-appropriate native continuation.
  • Native ACP mode-switch approvals integrated without a second turn or duplicate approval.

Keep implementation PRs focused. Regenerate sqlc from new queries/migrations; regenerate OpenAPI and frontend types together when changing the API. Preserve daemon ownership and existing CDC rules.

Acceptance criteria and validation

Primary scenario: Plan → question → answer → review → implement → execution, exercised through the ordinary product/service path for Codex, modern ACP, and legacy ACP.

  • Selecting Claude Plan after accept-edits/auto/bypass stays in Plan on send; leaving restores the execution preference.
  • Codex Plan/Default dispatch preserves selected model and effort.
  • Modern ACP routing wins when both APIs are advertised; legacy-only providers remain function

Source: Untrivial-ai/agent-orchestrator