Skip to content

App add-ons: show and grant agent powers in the UI - #1888

Open
fujibee wants to merge 12 commits into
mainfrom
addon-agent-ui
Open

fujibee wants to merge 12 commits into
mainfrom
addon-agent-ui

Conversation

@fujibee

@fujibee fujibee commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

What

The app side of add-on agent powers: what an add-on may do with agents is shown where the user decides, and listed afterwards. It builds on the host operations from #1861, which is now on main.

  • Install dialog: an "agents" block saying what the requested powers mean.
  • Add-on pane: a powers card that asks for the team powers (join, send, spawn) before the pane runs; Settings lists the grants and can revoke them. Remembered powers are replayed on reopen only when every declared power was saved for exactly that team.
  • Sidebar: add-on members carry a badge.
  • Settings: a members/agents list per add-on, with a prompt about members left behind by a removed add-on.
  • Add-on kit: helpers for team.join, messages.send, agents.models and the agent operations.
  • Claude Code trust: when an add-on may start agents, the powers card offers a checkbox to trust ~/agmsg-agents (off by default), through the read-only addon_agents_folder_trust and the single-flag addon_trust_agents_folder. A failed read is shown with its reason instead of being hidden.
  • Placement: agents.spawn takes an optional order (a whole number from 0 to 99) and the window is told which pane asked. The first agent opens to the right of the asking pane, later ones form a column ordered by order (smaller is higher), whatever the arrival order. The tab is named after its panes ("Chess · black · white"). All 9 locales are updated.

Process spawns

  • The UI adds no process starts of its own. Opening the pane or Settings runs no script; Settings reads the member state only when it opens or on Refresh.
  • Starting agents is the add-on's call: a chess game start is 2 spawns and then 1 send per move. Each spawn's cost is App add-ons: join a team, send messages and start agents #1861's.
  • The trust checkbox: 1 read when the powers card is shown, 1 write when applied (config file only, no child process).
  • agents.models: once per CLI type when the add-on's setup opens (the host caches the Codex answer for the run).

Checked

  • tsc --noEmit clean; vitest run: 45 files, 528 tests pass; cargo test --lib addons::agents: 32 pass (the placement fields are covered). The CI gate scripts (check-enforced-assertions, check-errexit-status-reads, check-unguarded-env-reads) are at their baselines and check-private-names is clean on this head.
  • A real run on this Mac, on App add-ons: join a team, send messages and start agents #1861 95e08f9f plus this branch (a debug build with its own identifier and a side install, not the live one): claude haiku as white against codex as black, started from the chess add-on. Both sides moved by themselves for 10 plies, all legal; the first turn notice was typed into white after its first idle. Startup turns, measured from the players' own records over 3 runs at a load of 3 to 6: claude haiku 22.2, 22.5 and 20.0 s, codex 8.5, 8.0 and 11.8 s.

Not checked

  • Windows (WebView2) and Linux.
  • The new look in a real window (the Start button states, the countdown), a game played to the end, and the sidebar delivery marker. The Mac that ran the check had a locked screen, so the page was suspended at times; while the window is hidden the notice flush waits (a separate follow-up).

@fujibee
fujibee force-pushed the addon-agent-ui branch 3 times, most recently from 2fe10b3 to bc4b6ae Compare November 5, 2026 03:30
Add team:join, messages:send and agents:spawn to the permission rows,
reword "What it cannot do" as what the add-on itself cannot do, and add a
second block when an add-on can message or start agents: they keep their
own permissions, plus the permission mode and the working-folder rule for
agents:spawn. All nine locales.
An add-on that declares team:join (and messages:send / agents:spawn) gets one
card for its team after the messages card, with the same note that agents keep
their own permissions. Allow is remembered per team, once per add-on, through
the existing saved-grant path and replayed on open. Settings lists and revokes
the three new grants.
A member that only has the app-addon type shows an add-on badge and no
longer offers to start a terminal for it.
…ed ones

Settings -> Add-ons lists the members and agents add-ons made with their
state. An agent that may still be running after the app stopped shows its pid
and waits for the person (open new, or leave it); a joined or failed one can be
opened. Read when the tab opens and on Refresh, never on a timer.
Thin wrappers that send exactly the frame fields protocol.d.ts names, with
sample answers so a pane that uses them can be built in a plain browser.
… agents

The agents:spawn grant card shows an opt-in box, unticked by default,
with one line saying it writes a single setting to Claude Code's config.
The state (trusted, not trusted, config not found) is read once when the
card shows; the box is offered only while the folder is not trusted. A
ticked box calls the trust command after the consent is saved; a failure
is shown and the grant stands. Strings in all nine locales.
…ust box and pid display

A failed read of the folder-trust state was shown as "config not found", hiding a malformed or unreadable config. Only the host's ConfigNotFound value now means missing; any other error is shown with its message, and the grant is not held back.

The trust box starts unticked each time the powers card appears, instead of keeping a ticked state from an earlier open. A member state whose pid is null no longer prints an empty pid.
Reopening a pane grants the team and sets each remembered power again when all the powers the add-on declares were saved for exactly this team; otherwise the card asks. The decision moves out of the pane host so a test can show the card is not asked twice, and that a missing power, another team or a failing power asks.
…it sits

agents.spawn takes an optional order (a whole number from 0 to 99); the open request now carries the asking pane and that order, and the entry keeps them so a retry opens the terminal in the same place. A member has none.
An agent asked for by an add-on pane used to open in a tab of its own. It now opens in the asking pane's tab: the first to its right, the rest in a column under each other, ordered by the order the add-on gave (smaller is higher) whatever order they arrive in. The add-on names no side or position; the app decides. With no such pane open the agent still gets its own tab.
@fujibee
fujibee changed the base branch from addon-agent-powers to main November 6, 2026 07:17
…nder, and sort unordered agents last

Two agents whose spawns finished before the next render both read the rendered panes for their siblings, saw none, and each opened to the right of the asking pane, giving three columns instead of the asker on the left and the players stacked on the right. The agents already placed beside an asking pane are now remembered synchronously (createAskedPlacer), and the tree update is applied to the latest tree when React runs it.

An agent with an order also ignored the unordered agents already there when looking for the place below it, so an ordered agent could land under an unordered one. Agents are now sorted by order with the unordered ones last, and a new one goes above the first that sorts after it.

The tests open both agents before the update is applied, in both arrival orders, and mix ordered and unordered arrivals.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant