Skip to content

Support structured agent questions via ACP form elicitation #114

Description

@lnittman

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 Other answer 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

Berd asking a two-question structured form in the composer area: a question stepper, single-select options with descriptions, an optional custom answer, a decline action, and the sidebar attention badge on the backgrounded session

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 direct cursor-agent --print --output-format json provider, 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions