Structured View (Web Dashboard)

The structured view is the default rendering for AI coding agents in the web dashboard and the native TUI. Instead of a terminal pane (PTY bytes through xterm.js), it renders the agent’s structured state directly: plan, tool-call cards, diffs, and approvals. It is mobile-first and scales the same components into a richer multi-pane desktop layout.

It speaks the Agent Client Protocol (ACP), a JSON-RPC standard for editor-agent communication. aoe is the client; the agent (Claude Code, Gemini, Codex, etc.) is the server. Any ACP-capable agent uses the structured view by default; a session can opt into the terminal view instead, per session, and you can switch at any time. Agents with no ACP adapter always run in the terminal view.

The structured view rendering an agent’s plan, tool-call cards, and a pending approval

In this section

  • Interface: the TUI and web surfaces, keybinds, composer, queued prompts, and timeline grouping.
  • Modes, approvals & model controls: permission modes, YOLO, approval cards, notifications, and the model / reasoning-effort selectors.
  • Troubleshooting: the security summary plus a field guide to each failure mode and its fix.

Contributors: see Structured View Internals for worker lifecycle, watchdogs, persistence, and profiles.

Supported agents

aoe ships an ACP registry entry for each tool whose ACP server we’ve verified. For those tools the web wizard shows a per-session Use structured view toggle (on by default), under the wizard’s More options disclosure. Tools not in the set, and custom agents without an ACP command, have no toggle and always run in the terminal view.

Agent ACP adapter Install Auth
claude claude-agent-acp (Zed, recent version required) npm install -g @agentclientprotocol/claude-agent-acp@latest claude login, or ANTHROPIC_API_KEY
codex codex-acp (ACP) npm install -g @agentclientprotocol/codex-acp@latest OPENAI_API_KEY, or ChatGPT login (local-only)
opencode opencode acp (native, ≥1.16.0 recommended) curl -fsSL https://opencode.ai/install | bash opencode auth / provider env
gemini (deprecated) gemini --acp (native) npm install -g @google/gemini-cli GEMINI_API_KEY, OAuth, or Vertex
vibe vibe-acp (native) see mistral-vibe Mistral API key
pi pi-acp (adapter) npm install -g pi-acp (plus @earendil-works/pi-coding-agent) pi-acp --terminal-login, or provider env
omp omp acp (native) curl -fsSL https://omp.sh/install | sh provider environment or OMP login
kimi kimi acp (native) curl -fsSL https://code.kimi.com/kimi-code/install.sh | bash kimi login, or provider env
prime-agent prime-agent --mode acp (native) curl -fsSL https://app.primeintellect.ai/prime-agent/install.sh | sh /login once, or provider env
aoe-agent in-tree (Vercel AI SDK 7) not yet packaged; needs a local build of acp-worker/aoe-agent (#3553) provider env vars

Gemini CLI is deprecated upstream for individual accounts since 2026-06-18. Enterprise and API-key authentication remain valid; Antigravity CLI is the replacement for consumer accounts.

The npm install -g commands above are optional: aoe acp doctor --fix installs the claude / codex / pi adapters into the data dir for you, one adapter at a time (see Requirements). Run it, or install them globally yourself.

Tools not yet wired into the registry (aider, cursor, copilot, droid, hermes, kiro) always run in the terminal view. A custom agent can opt in two ways. Set an explicit ACP launch command via agent_acp_cmd (see Configuration); or, if the custom agent only wraps a supported one (for example a Claude wrapper that overrides profile/oauth locations), map it to that base with agent_detect_as (my-claude = "claude") and it inherits the base’s ACP adapter automatically, with no agent_acp_cmd needed. An inheriting agent runs through the base adapter, so it renders exactly like the base agent; its profile/oauth overrides ride the session’s extra_env / environment the same as any other agent. This also lights up the “Switch to structured view” action for an existing terminal session of that agent.

Each built-in adapter receives only the provider variables it is known to read from the environment that runs aoe serve:

Adapter Forwarded
claude ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, CLAUDE_CONFIG_DIR
codex CODEX_API_KEY, OPENAI_API_KEY, OPENAI_BASE_URL, CODEX_HOME
opencode ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, GOOGLE_API_KEY, GEMINI_API_KEY, OPENROUTER_API_KEY, OPENCODE_API_KEY
gemini GEMINI_API_KEY, GOOGLE_API_KEY, GOOGLE_GENAI_USE_VERTEXAI, GOOGLE_APPLICATION_CREDENTIALS, GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_LOCATION
aoe-agent ANTHROPIC_API_KEY, OPENAI_API_KEY, OPENAI_BASE_URL, GOOGLE_GENERATIVE_AI_API_KEY

vibe, pi, omp, kimi, and prime-agent have no ambient provider allowlist yet. Custom adapters also receive no ambient provider credentials. Until their variables are verified, give them auth through the per-session extra_env field or environment in your config, or set session.inherit_host_environment = true to forward your whole aoe serve environment to non-sandboxed agents. In a sandboxed session the per-adapter provider keys above still cross the container boundary (forwarded as docker exec -e flags), but inherit_host_environment does not; give a sandboxed not-yet-verified adapter its auth through sandbox.environment. Three ambient allowlist entries are host-only and never cross: CLAUDE_CONFIG_DIR, CODEX_HOME, and GOOGLE_APPLICATION_CREDENTIALS name paths on your machine that do not exist inside the container, and each agent’s config dir is already bind-mounted at its canonical container location. Values explicitly supplied through provider_env are not part of that ambient filtering.

Feature matrix

Each feature fires for any ACP agent, only when the agent’s profile opts in, or claude-only.

Feature Claude Codex OpenCode Gemini Other ACP
Streaming text, tool-call cards, approvals
Mode picker depends depends depends
Slash-command palette depends depends
Usage / context-window display depends depends
/clear boundary divider /clear /new /new none none
TodoWrite / Skill / ExitPlanMode / ScheduleWakeup cards
Subagent indentation unverified
Session resume across aoe serve restart depends depends depends

Codex/opencode/gemini support is built from adapter docs and code reading rather than hands-on walkthroughs, so some tool aliases may need adjustment; file an issue with the observed tool.kind + tool.name. opencode ≥1.16.0 is recommended: it classifies apply_patch as edit and task as think, populates external_directory permission context, and emits clean read-tool content. Older opencode still works but falls back to generic tool cards, verbose read text, and blind permission prompts. Mode picker, slash palette, and usage display depend on the adapter advertising the matching channels; when it doesn’t, the UI stays empty rather than showing stale state. Codex currently does not advertise a Plan-mode channel, so AoE does not render a Codex Plan switch. How profiles gate these is covered in Structured View Internals.

Quickstart

The web new-session wizard is the primary path; no CLI needed.

  1. Run aoe serve and open the dashboard.
  2. Click New session, pick your project and agent, and launch. Structured view is on by default; to confirm or change it, expand More options and leave Use structured view on.
  3. Open the session: you see the structured plan and tool-call cards instead of a terminal.

The CLI is the optional path for scripting or headless launches. Unlike the wizard, aoe add defaults to the terminal view (matching the TUI):

aoe acp doctor                              # confirm prerequisites
aoe add . --cmd claude --structured-view    # structured view for an ACP tool
aoe add . --agent codex --model gpt-5       # pick an ACP agent + model (implies structured view)

--agent for an uninstalled adapter errors with an install hint; --structured-view (no --agent) falls back to the terminal view with a warning so the command still succeeds.

Requirements

  • Node.js 22+ on PATH (the structured view spawns an ACP agent subprocess; aoe-agent declares engines.node: >=22.0.0).
  • For Claude Code, a claude login session.

If Node is missing or too old, the session falls back to the terminal view with an actionable warning. Verify with aoe acp doctor:

aoe acp doctor                                  # reports Node + each configured agent's reachability
aoe acp doctor --fix                            # download bundled Node if missing, then install claude-agent-acp
aoe acp doctor --fix --adapter codex-acp        # install a specific adapter instead
aoe acp doctor --fix --all-adapters            # install all three

--fix installs a pinned npm adapter under $AOE_DATA_DIR/acp-worker/adapters/<adapter>/ with the bundled Node’s own npm; no npm install -g and no sudo, at a version aoe pins per release. Each adapter is a separate several-hundred-MB tree (claude-agent-acp ~304 MB, codex-acp ~336 MB, pi-acp ~7 MB), so --fix installs only claude-agent-acp unless you ask for more.

An adapter already on your PATH normally wins, so a manual global install keeps working. The exception is a PATH copy below the version floor aoe requires: rather than spawn a binary the agent handshake would reject, aoe uses the pinned bundled copy and logs the substitution. doctor --fix tells you when your PATH copy is the stale one.

It exits 1 if Node is missing, 2 if some agents are unreachable, else 0. Pass --json for machine-readable output. Install the native CLIs (opencode / gemini / vibe / omp / kimi / prime-agent) through their own channels.

Choosing the view per session

  • Web wizard: defaults to the structured view; turn off Use structured view to get the terminal view.
  • CLI / TUI: default to the terminal view. From the CLI, opt in with --structured-view or --agent; in the TUI new-session dialog, toggle the Structured field (shown for ACP-capable tools).
  • Either way, an existing active session can switch views: the web sidebar’s right-click menu (Switch to terminal / Switch to structured view) or the TUI’s right-click context menu (needs a running aoe serve daemon; archived, trashed, and still-creating rows are excluded until they leave that state). Both surfaces confirm first. The worktree, open files, and commits are always preserved. For a claude session the conversation is kept in both directions: the terminal resumes it with claude --resume, and switching back to structured view reloads it via the ACP adapter. Every other agent restarts fresh on the target surface, resetting the in-memory conversation.

Non-ACP tools always run in the terminal view, with no toggle.

Launch command and session naming

--cmd <tool> resolves through session.agent_command_override the same as terminal sessions, so an override like opencode = "opencode-plannotator" makes --cmd opencode launch opencode-plannotator acp (the required ACP args are preserved). Adapter-backed agents such as Claude use session.agent_acp_cmd for a full command swap instead. The wizard shows the resolved launch command read-only.

aoe add does not prompt for a name by default: it uses --title, else the worktree branch name, else a generated name. Pass -i/--interactive for the same name prompt the TUI and wizard show. Set per-agent defaults for web-created sessions under [acp.acp_defaults.<agent>]:

When a structured view session keeps its generated civilization name (no --title, no branch name), AoE auto-renames it from its first turn using the session’s own agent in one-shot mode (claude -p, codex exec, opencode run, gemini -p, omp -p). This is on by default and controlled by session.smart_rename. It renames the title only, never the worktree directory (the running agent holds it), and never touches a session you named yourself. Sandboxed sessions, agents with no one-shot mode, and command-overridden agents keep the generated name. See Configuration: Session.

The rename waits for the first turn to finish and titles from the whole transcript, your prompt and the agent’s response, so the title reflects what the turn did (and the one-shot never races the live agent for the provider API).

To name with a different agent than the session’s own (e.g. a cheaper or more obedient title model), set session.smart_rename_agent to any installed one-shot-capable agent; leave it empty to use the session’s agent. The same setting also picks the agent for the conversation-summary one-shot. If the automatic rename never lands (the one-shot timed out or returned unusable output), right-click the session in the sidebar and pick “Auto-name now” to re-run it; the action is offered only while the session is still default-named. “Auto-name now” runs on demand even when session.smart_rename is off, so you can name a session by hand without enabling automatic renaming. The native TUI has the same on-demand action on a still-default-named session, via the v key or the command palette (“Auto-name now”).

The sidebar shows where each session stands: an Auto-name chip (sparkle) marks a session that is still default-named and will be renamed on its first message, and a Naming… chip (pulsing dot) shows while the one-shot title call is in flight. The chips disappear once the session is renamed or if it is not eligible.

Two chips flag a session that has parked itself but is still alive, so an agent waiting on background work does not read as a dead idle session. A countdown shows when the agent scheduled a wakeup (a ScheduleWakeup call or a /loop run) and ticks down to the fire time. A 👁 monitoring badge shows when the agent armed a Monitor (a background watch, for example waiting for a build or cargo clippy to finish); it has no fixed end time, so it stays put while the monitor keeps re-invoking the agent and clears once you send the session a new prompt.

[acp.acp_defaults.opencode]
model = "openai/gpt-5.5"
effort = "high"           # default thinking level
mode = "plan"             # default mode, applied when the agent advertises one

# Per-model thinking: overrides `effort` when that model is the resolved model.
[acp.acp_defaults.opencode.effort_by_model]
"openai/gpt-5.5" = "high"
"anthropic/opus" = "low"

model is forwarded when the worker starts. effort and mode are applied through the agent’s ACP config options (thought_level and mode) once advertised; a value the agent does not advertise is skipped with a warning rather than failing the session. effort_by_model takes precedence over the flat effort when the resolved model matches a key. These defaults are also editable per agent from the web dashboard settings (Structured view tab, Structured View Defaults), where the dropdowns are populated from whatever each agent last advertised.

The [acp] block holds the structured view’s global tuning knobs (timeouts, concurrency, watchdog grace). See Structured View Internals for the full list.

Agent artifacts

Each session gets a managed artifact directory, exposed to the agent as AOE_ARTIFACT_DIR (bind-mounted at /aoe/artifacts inside a sandbox). A screenshot or status file the agent writes there is served over an authenticated, session-scoped route and opens in the dashboard: transcript links open the file in a new tab, and markdown images render inline. Files written elsewhere (an arbitrary /tmp path, for example) cannot be served and render as plain, non-clickable text. To make a generated artifact viewable, write it under $AOE_ARTIFACT_DIR.

Cross-machine attach

Set AOE_DAEMON_URL (and optionally AOE_DAEMON_TOKEN) to point at a remote aoe serve:

AOE_DAEMON_URL=https://aoe.example.com AOE_DAEMON_TOKEN= aoe   # remote session picker
aoe acp attach <session_id> --daemon-url https://aoe.example.com

When AOE_DAEMON_URL is set, the TUI swaps the local home view for a remote session picker, and aoe serve --status / the aoe acp * verbs retarget to the remote. Local-only operations (tmux attach, aoe stop, file edit) aren’t available against a remote; use the web dashboard or SSH into the host. Unset the variable to fall back to local introspection.

Headless CLI verbs

Every structured-view operation has a matching aoe acp <verb> against the same daemon:

Verb What it does
aoe acp history <id> Dump the persisted transcript
aoe acp status <id> Print highest/lowest seq and the daemon source
aoe acp prompt <id> <text> Send a prompt (- reads stdin)
aoe acp approve <id> <nonce> [--always|--deny] Resolve a pending approval
aoe acp cancel <id> Cancel the in-flight prompt
aoe acp tail <id> Stream broadcast frames as JSON lines
aoe acp attach <id> Open the TUI structured view for this session
aoe acp stop / kill / restart / logs / switch-agent Worker management
aoe ps --acp List workers with their ACP columns (BUILD, MODEL, CWD, SOCKET); add --dead to include dead and orphaned ones. Replaces the removed aoe acp ps

Every verb requires a running aoe serve daemon and exits with a hint if none is found. Start one with aoe serve --daemon (localhost) or aoe serve --daemon --remote (Tailscale/Cloudflare), or set AOE_DAEMON_URL. The CLI does not spawn a daemon on your behalf, so the localhost-vs-tunnel choice stays explicit.