cmux NEXT: Needs you list and the Needs your input pill
Summary
Agents keep writing "still waiting on you" because an open ask has nowhere to live once it scrolls away. This adds Needs you: one pinned list of every open ask, behind a count badge in the agent chat header. It covers approvals, decisions, verify-this asks and held agent-pair messages, from this chat, the Chief, its subagents and every other agent chat.
Each row shows:
- the ask on one line;
- who asked (the agent's mark, or the Chief's orb, plus the chat that started a subagent);
- its kind and age;
- one-click answers (Allow / Deny, or one of up to four choices), drawn the way Claude's permission card draws its options: numbered rows in one column, the first one ready;
- Go to source, which opens the asking chat at the ask's turn;
- Ask about this, a side question (
_acpmux/ask) to a read-only copy of the asking chat, seeded with "What is going on here?".
An ask leaves the list as soon as it's answered anywhere: its card, the Feed, the CLI, another pane or a phone.
Needs your input pill (from Leo's Claude Code desktop screenshot):
- While any ask is open, the floating Jump to latest button becomes a pill: the blue dot, "Needs your input" (or "Needs your input · N"), and a chevron.
- It's a little bigger than Claude's: 34px, in the composer's surface and edge tokens.
- A press goes to this chat's ask first, then cycles through the asks open in other chats.
- With nothing open, it's the plain button again.
- It reads the same Needs you list, not a signal of its own.
One mark. The blue dot is now the one "needs you" mark. It replaces two ad-hoc glyphs: the agent sidebar's amber status.needsinput and the Chief dock's waiting-card glyph. The badge and the pill wear it too. Its color is the window sidebar's unread dot (Palette.notificationBlue), fixed on every theme like the Messages blue. check-system-blue warns about the literal; that's deliberate.
No parallel store. Everything comes from what acpmux already reports (design and contract: plans/cmux-next/needs-you.md):
- Asks (
needsYou/asks.ts): pending permission requests in every watched chat._acpmux/permission_pendingadds an ask.- A change to a chat's
pendingPermissions, or an answer (permission_decision/permission_resolved), rereads_acpmux/infopending. That's whatacpmux pendingand the Feed bridge read. - A count of zero clears the chat at once.
- Reads are fenced per chat, so a slow read never revives an answered ask or drops a new one.
- Waiting chats. A chat that waits with no readable ask (e.g. on another computer) shows as one item, from its session
indicator/pendingPermissions(#21808's needs-me signal). - Held messages come from the open chat's agent-pair rows (#21975).
- Ids. Items use the Feed's dedupe key,
acpmux:<permissionId>, so the Feed and pet notices can share them.
Agents. acpmux pending --json now gives each request a needsYou link, cmux://needs-you/<permissionId>. The acpmux skill tells agents to put that link in a reply instead of restating the ask. The pane draws the link as a chip that opens the list on that ask.
Debug Settings, both on by default; new agent tabs read them:
agentPane.debug.needsYou: pinned, compact or off;agentPane.debug.needsYouPill.
The gallery's agent-pane host gains documentAttributes, so variants can render those choices.
Related: #21851 (New Tab's Needs you card) and #21945 (sidebar needs-you tray) show the same idea elsewhere. This list doesn't replace them.
Owned areas. None of the listed owned files are touched (newtab/, Composer, pickers, Inspector, Chief approval code). The ChiefDock.tsx change is a one-line glyph swap.
Testing
Added tests:
webviews/test/agent-pane-needs-you.test.tsx(15 tests):- each kind and its one-click answers;
- waiting-chat and archived handling;
- held pairs and Resume;
- the subagent
via; - answer params per harness (a permission by option; a Claude question by text);
- link parsing;
- the pill's visit order and cycling, and its labels;
- the mode attribute;
- the side-question prompt;
- JSDOM panel answer / refuse / hide / compact.
webviews/test/agent-pane-needs-you-asks.test.ts(7 tests): AskTracker adds, a count of zero clears, an answer rereads, matching counts don't read, reads date asks, stale-read fencing, failed reads keep what's held, purge.AgentPaneNeedsYouTunablesTests.swift: defaults set no attribute, the other choices set theirs, and both toggles are listed.
Each test imports only new code, so it fails on the base.
Run so far:
- Both bun test files passed locally (22 pass) before cosmic-gray started refusing local
bun test. Later edits, including the review fixes and their tests, ran in CI on this head. vp check --no-fmt --no-lint(types) passes, andvp fmt/vp lintare clean on the changed files.check-layers,check-type-scaleandcheck-text-focus-ringspass.check-system-bluewarns (above).prepush-gate.pyreports no new violations.rustfmt --checkis clean onstandard.rs.- I looked at the gallery entry (
agent-pane.needs-you) in a local gallery dev server, in dark and light: the list, the badge and pill, one ask, and the off state.
Not run:
- No Mac app build and no Swift or Rust build here (cosmic-gray rule). The Swift tunable test and the acpmux change compile only in CI.
- The live app is not dogfooded. In the app, held messages are listed only for the open chat. The Chief's Home page has no Jump to latest button, so it has no pill yet. Both are noted in the plan.
Review fixes (abaef19)
An independent review of a627fcf found six issues; all are fixed and the re-review passed.
- Answering an ask in another chat now opens that chat first, then answers. The open (attach) brings the chat into the pane's scope on the click's scope credit and records the question's keys, so
permission_respondand question answers are accepted. No relay change. - A new ask no longer drops a read in flight: asks are dated, and a read only removes asks it predates.
permission_requestalso rereads. _acpmux/infois reread only when a chat's reported count changes or an ask is made or answered.- Grouped permissions (
groupId) are not listed one by one; the chat shows as one waiting item that opens its card. - A refused answer shows as failed instead of leaving the row sending.
- A chat with held messages and an input marker shows once.
- The pill makes one move per press: scroll to this chat's ask, or go to the next chat.
Known limits, for a follow-up:
- An Allow or a question answer must reach the host within 1.5s of the click (
answerWindow). Opening a large or remote chat can take longer; then the answer is refused safely, the chat is open on its card, and the row shows the failure. Deny is unaffected. - A chat holding both a grouped and an ungrouped ask lists only the ungrouped one; the grouped one is on the chat's card.
Review fix: a chat on another computer is never read (1f22414 red, 2324168 / 959265c green)
An independent review failed 037c733 on a cross-daemon read. The design says another computer's chat shows only as an input item and is never read, but:
- an SSH or Cloud peer's chat is in the local daemon's watch with
peerand itspendingPermissions(acpmuxhub/peers.rsremote_summary); - the page reread any chat with a count above zero (
needsYou/asks.ts) throughchat.asks.pending; - the host sent
_acpmux/info {sessionId: <bare id>}to the pane's own socket, and acpmux forwards a request for a peer's session to that peer (server/peer_forward.rs;_acpmux/infoisn't excluded). So the peer's asks came back and were drawn with Allow and Deny.
Fixed in two layers, with no acpmux change:
- Page (
needsYou/asks.ts,model.ts): the tracker never reads a session whose summary names apeer. It holds no ask for it, including one from a relayedpermission_pending, and drops any read still in flight. The list draws such a chat as oneinputitem with no answers. - Host (
AgentPanePendingAsks):- The read names the chat
local/<id>(acpmux qualifies ids with/:session_identity.rs).hub.resolvematches that against its own sessions first. - An id already qualified as
local/isn't prefixed twice. An id with any other/is never sent and answers null. - acpmux peer names are any session name, so a peer could be named
local, and its rows are keyedlocal/<id>. For that case the host also refuses any reply that names apeer: every forwarded reply carries one (peer_forward.rs), and a daemon's own_acpmux/infodetail never does. - The page still keys the reply on its own unqualified id, because the host returns only
pending.
- The read names the chat
- Doc (
plans/cmux-next/needs-you.md): the host read is described as what the code does: one plain connection to the pane's own acpmux socket, with no person proof, naminglocal/<id>. The doc no longer says "person-proven". - Base merge e70b6d2 (feat-cmux-next f90fbd9b7db9): the branch had started to conflict in
AgentPageProvider.call, because base now matches the scrollAnchor ops by name (#23232). The resolution keeps base's check and thechat.asks.pendingline.
Red, then green (fleet):
- webviews
test/agent-pane-needs-you-asks.test.ts:- red:
cmux-ci run --class light --script scripts/ci/run-webviews-tests.sh --ref 1f22414 --key pv-needs-peer-red-1f22414ba6 --env CMUX_WEB_TEST_FILES=test/agent-pane-needs-you-asks.test.tsfailed: 15 pass, 1 fail. "a chat on another computer is never read..." expected reads["near"]and got["far", "near"]. - green: the same with both needs-you test files, at 2324168 (key
pv-needs-peer-green-232416889d) and at the head 959265c (keypv-needs-peer-green-959265ca16): both files PASS.
- red:
- Swift
AgentPanePendingAsksTests(scripts/ci/package-test-lane.sh suite Packages/macOS/CmuxNext AgentPanePendingAsksTests):- The CmuxNext test target doesn't compile on this base. First it broke at
PageEnginePolicyTests.swift:43(fixed on base by #23281). Now it breaks atRemoteChildSessionsTests.swift:14: the fake lacksisReadOnly. That's a base red, with open fixes #23362, #23363 and #23369. So the runs on the PR's own SHAs gave no verdict (keyspv-needs-peer-swift-red-1f22414ba6,-green-232416889d,-red-5f212140d5,-green-959265ca16). - For a verdict, each SHA below was rerun with only that one-line base fix added (
var isReadOnly: Bool { false }on the fake), on scratch branches since deleted:- red, the PR head with the host fix reverted (key
pv-needs-peer-swift-scr-nofix-9e3730cddc): 8 tests, 4 issues. The host sents-1, notlocal/s-1. A mirrored peer chat's asks came back forpeer-mirrorandpeer-chat. The reads were["peer-chat", "own", "local/own", "build-host/peer-chat"]. - red, 5f21214 (the peer-reply test, before the refusal; key
pv-needs-peer-swift-scr-peerreply-e43207a5b6): 9 tests, 1 issue.aReplyForwardedFromAPeerIsRefusedgot that peer's asks. - green, the head 959265c (key
pv-needs-peer-swift-scr-fixed-37a855f4c6): 9 tests in 1 suite passed.
- red, the PR head with the host fix reverted (key
- The CmuxNext test target doesn't compile on this base. First it broke at
cmux-ci compile-check --app: passed at 2324168 (61 s) and at the head 959265c (43 s).
Observed / Not run
- Observed: the fleet runs above.
scripts/web-lint.shandprepush-gate.pypassed before each push. - Not run:
- no live two-machine check (a real SSH or Cloud peer with a pending ask in this pane); the forward path was read in acpmux source, not exercised;
- the Swift suite never compiled on the PR's own SHAs (base red above);
- no acpmux Rust tests (no Rust changed).
Changelog
Added: A Needs you badge in the agent chat header lists every approval and question your agents and the Chief are waiting on, with one-click answers, and Jump to latest becomes a "Needs your input" pill while any are open.
Proof
Gallery entry agent-pane.needs-you, captured in dark and light by the Linux Chromium gallery advisory run.
- Before: the
beforevariant, with both toggles off. - After: the
list,badge-and-pill,pill-one-ask,ask-about-this,compactandemptyvariants.
Captures of this head: gallery advisory run 39524014238 (artifact gallery-advisory-22646-abaef19…), shown in the HQ feed card.
Checklist
- Behavior changes have added or updated tests
- Localization: 24 new
needsYou.*keys in all 21 pane locales (non-English marked needs_review). The sample prompt to the agent is markedl10n-allow.
Agent session: cosmic-gray