Repository navigation
Support structured agent questions via ACP form elicitation #114
Description
Before filing
- I searched open and closed issues for duplicates.
- I am using the latest release (v0.6.2) and this does not already exist.
- This is one request, not several bundled together.
Closest existing issue
None found. I searched open and closed issues for elicitation, ask user, request user input, AskUserQuestion, and interactive.
Is this new, or an improvement?
New capability — Berd cannot do this end to end today.
The problem, in your terms
I use skills such as a 20-question interview that depend on the agent pausing for structured human input. In Berd, those turns cannot reliably reach the app as an interactive question. Depending on the harness, the agent either cannot see an ask-user tool, waits without presenting anything actionable, or has to improvise a plain-text menu.
That breaks the agent loop at exactly the point where human judgment is required. It also makes the same skill behave differently in Berd than it does in a first-party coding-agent client.
The transport has a nested-client wrinkle: Berd talks ACP to goose serve, while managed Claude/Codex bridges talk ACP to Goose. A provider-originated session/elicitation/create therefore has to cross Goose and become a request on Berd's outer ACP connection; it is not enough to add a React form alone.
What you do today
I tell the agent to ask the same question in prose, answer with a number or free text, and hope the prompt survives provider differences. For workflows that require a structured ask-user call, I leave Berd and run the provider's own client instead.
What you'd like to see
Support ACP form elicitation end to end for agent harnesses that expose it:
- Berd advertises form-elicitation support and renders the requested schema in the existing chat composer area.
- The form covers single-select, multi-select, free text/number/boolean input, and a typed custom
Otheranswer when the bridge declares one. - Multi-question requests support direct navigation, keyboard submission, validation, explicit decline/cancel actions, and accessible focus behavior.
- A backgrounded session uses the existing sidebar hierarchy to show that it needs input; no new Home surface is required.
- Draft answers and the current question survive navigation and an app restart. If the original provider responder no longer exists after a full backend restart, Berd clearly labels the recovery and continues through one normal follow-up prompt rather than pretending it resumed the dead request.
- Harnesses without structured elicitation degrade to one concise prose question instead of reporting a missing client tool.
Because Berd pins and launches Goose, this likely needs a dependency-ordered implementation: Goose first forwards live nested ACP form requests/responses. Berd owns the client state, UI, and honest recovery; replaying a dead live responder is a separate contract.
Why this belongs in Berd itself
A skill can decide what to ask, but it cannot add an ACP client capability, forward a nested provider request through goose serve, persist the pending responder lifecycle, or render trusted native controls in the desktop client. Those responsibilities belong to the agent transport and Berd's session UI.
Non-goals
- No Interviews widget, Home node, canvas object, inbox, or archive.
- No arbitrary model-authored HTML, React, Mermaid, or executable rich UI in the form payload.
- No URL-mode elicitation in this first slice.
- No redesign of permissions or tool approvals.
- No claim that every harness has identical capabilities. Unsupported harnesses should degrade honestly.
- No provider-specific clone of Claude Code's presentation; this should use Berd's existing chat, sidebar, component, and copy conventions.
Alternatives you considered
- Prompt-only fallback: useful as a last resort, but loses structured choices, validation, accessibility, durable draft state, and reliable tool semantics.
- A skill or extension-owned widget: cannot implement the ACP client/server lifecycle and would fragment a core interaction across skills.
- Direct integrations for every provider: duplicates transport and UI logic and still leaves restart behavior inconsistent.
- A generic rich-content protocol now: could eventually support a validated diagram, existing artifact, image, or diff beside a question, but arbitrary rich payloads add security, layout, and accessibility concerns. That should be a later allowlisted capability, not a prerequisite for form elicitation.
Mockups, prior art, or other context
Local prototype validation against current managed harnesses found a meaningful capability matrix:
claude-agent-acp: structured single-select, multi-select arrays, custom answers, and same-turn continuation work.codex-acp@1.2.0: structured questions and custom answers work, but its current request adapter serializes every question as a string, so multi-select intent is lost before Berd receives the schema.cursor-agent: Berd currently reaches Cursor through Goose's directcursor-agent --print --output-format jsonprovider, not a managed ACP bridge. It can only use the prose fallback on that transport.
The prototype also verified navigation persistence, full app/backend restart recovery, background attention state, and continuation after answering a recovered question on macOS 26.0.1 (Apple Silicon).
I also checked the current work in flight. No open issue, pull request, or contributor branch implements ACP form elicitation. The nearest active changes are #19 (provider/model lifecycle), #28 (composer quoting), and #67 (ChatView memory UI), so an implementation should coordinate or rebase around those files rather than expand this request into their scopes.
Cursor's official ACP server now exposes a separate cursor/ask_question extension with multi-select support. Translating that extension at a general ACP adapter boundary could make Cursor participate later, but it is deliberately not part of this first Berd issue.

Activity
lnittman commentedon Aug 19, 2026
A draft reference implementation is available in my fork: https://github.com/lnittman/berd/pull/1
This is intentionally not an upstream pull request. It exists so maintainers can inspect the concrete UI, ACP boundary, persistence/recovery behavior, accessibility coverage, and full verification evidence while the issue is evaluated. End-to-end nested delivery still depends on aaif-goose/goose#11346.
lnittman commentedon Aug 19, 2026
Reference implementation update: the final diff is scoped to ACP capability/transport wiring, elicitation state/UI, ChatView placement, and the existing sidebar attention slot.
Verification is 202/202 across elicitation, chat integration, runtime registration, and sidebar attention, 71/71 in the elicitation feature suite, with
just check, Tauri checks, and warnings-denied Clippy green.Since the last update, mostly hardening at the boundaries where an agent's request meets the client:
cancel, so an agent can tell a client limitation from a considered decline.Known limitations
Worth stating plainly rather than leaving to be discovered:
patterns go through a matcher that refuses over-long patterns and the common catastrophic-backtracking shapes, caps field and option counts, and retires any pattern that exceeds its time budget. JavaScript cannot interrupt a running regex, so an ambiguous-alternation pattern that slips past the shape check can still cost one evaluation. A real bound needs a non-backtracking engine or a terminable worker.Provider limits remain explicit: Claude has full structured parity; Codex is structured but its current adapter loses true multi-select intent; Cursor remains prose-only on Berd's current direct Goose route. Clean end-to-end managed-provider proof still depends on aaif-goose/goose#11346.