Skip to content

cmux NEXT: agents mark the tab where you must act (cmux attention request, tab-attention-v1) - #24286

Merged
teamleaderleo merged 6 commits into
feat-cmux-nextfrom
sp-attn-a
Oct 23, 2026
Merged

teamleaderleo merged 6 commits into
feat-cmux-nextfrom
sp-attn-a

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Leo-ask: ask-12231fbe5e

Leo: "idk where things are man i dont see anything other than the current workspace which is you and you have a cmux next github brwoser tab open (we need to have cmux expose this harder if it isn't already/hve better instructions)"

What happened: an agent needed Leo to confirm GitHub sudo in a browser tab it had opened (in a workspace 42 rows down the sidebar) and told him a raw ws_… id he could not see or search.

This is slice A of the "needs you here" surface: the daemon state, CLI and MCP path. The app styling, notification with Show, the "Go to what needs me" palette command and the agent instructions follow in their own PRs.

What changes

  • tab.update takes attention: a one-line reason (1-200 characters, no control characters) or null to clear. The daemon stores {reason, at_ms} on the tab record (tab_state.attention_json, an additive column), and every client sees it as the tab's extra.attention. Capability tab-attention-v1.
  • CLI: cmux attention request --tab <tab_…> --reason <text> and cmux attention clear --tab <tab_…>. Both send tab.update {attention}, so CLI, MCP (tab_update with attention, generated from the catalog) and the app share one mutation path.
  • It never moves focus. A test checks that the active surface stays the same.
  • Clearing:
    • the agent's clear;
    • a browser tab whose page goes to a different URL, for both frontend-rendered (WebKit/CEF) and CDP browsers; a title-only change keeps the mark;
    • the tab's close. The mark is dropped when the tab row is tombstoned, so a reopened tab (which keeps its id) does not ask again.
    • Terminal tabs keep the mark until the agent clears it or the tab closes.
  • The agent guide (cmux docs, "Show your work…") tells agents to mark the tab and to name workspaces and tabs by their titles, never by a ws_ or tab_ id.

Tests

  • state/tab_attention_tests.rs:
    • mark, list, keep across another field, clear;
    • bad values are rejected;
    • focus does not move;
    • navigation clears the mark, a title change or the same URL does not;
    • close plus reopen leaves no mark.
  • tab_state_store unit tests: migration, clear on close, reason validation.
  • CLI: attention_request_and_clear_send_tab_update, plus the transport-path coverage cases (which check the plan against the catalog).

Not in this PR

App styling (the existing blue needs-you treatment on the tab and its workspace row), the Needs you list entry, the system notification with Show, the palette command, and the MCP server instructions text.

No capture: daemon/CLI only; no native UI changes in this PR.

Agent session: cosmic-gray

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Agents can now mark the tab where the person must act (confirm, log in, approve, pick), instead of pointing them at an opaque ws_/tab_ id for a tab far down the sidebar.

  • tab.update takes attention, a one-line reason or null to clear; the daemon stores it on the tab record and every client sees it as extra.attention under tab-attention-v1. Reasons with control characters, U+2028, or U+2029 are refused.
  • New CLI commands cmux attention request --tab <tab_…> --reason <text> and cmux attention clear --tab <tab_…> both send tab.update — the same mutation path CLI, MCP (tab_update), and the app share.
  • The mark never moves focus.
  • A mark records the page it was set on, so a navigation clears only a mark set on another page, and the clear is decided in its own commit: a mark an agent sets on the new page survives a late or repeated clear for an older page. It clears on the agent's clear, a browser tab's navigation to another URL (a title-only change keeps it), or the tab's close; reopening a closed tab does not re-ask. The CDP event thread detects URL changes over target-info, frame, and same-document navigation alike and always asks on its first event.
  • cmux docs now tells agents to mark the tab and to name tabs and workspaces by their titles, never by id.

App styling, the needs-you list entry, system notification with Show, and the palette command follow in later PRs.

Written for commit 12f9a15. Summary will update on new commits.

View guided diff Turn on auto-fix

…-attention-v1)

`cmux attention request --tab <tab_…> --reason <text>` and `cmux attention
clear --tab <tab_…>` send `tab.update {attention}` (MCP tab_update with
attention). The daemon keeps `{reason, at_ms}` on the tab record and every
client sees it as the tab's extra.attention. It never moves focus. The mark
clears on the agent's clear, when a browser tab's page goes to another URL
(frontend-rendered and CDP browsers), or when the tab closes, so a reopened
tab does not ask again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray
@teamleaderleo teamleaderleo added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 22, 2026
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 22, 2026 07:39 — with GitHub Actions Inactive
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 12f9a15: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr24286 -f ref=sp-attn-a -f platform=macos -f backend_mode=local

red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 44fc3d3 to compare; do not merge until green; see lane-rules

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-rfo6q created for this PR by the cmux coordinator.

@blacksmith-sh

blacksmith-sh Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Found 8 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmp8flduogh/summary-fail.json (live):/summary-fail.json (live): View Logs
/tmp/tmpn1vv9q4z/summary-missing.json (live):/summary-missing.json (live): View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
View Logs
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs
test_base_passes (main.NoticesPairTests.test_base_passes)/
test_base_passes (main.NoticesPairTests.test_base_passes)
View Logs
test_targets_outside_the_app_go_to_the_mac_canary (main.SwiftCanaryFleetCoverage.te
st_targets_outside_the_app_go_to_the_mac_canary)/
test_targets_outside_the_app_go_to_the_mac_canary (main.SwiftCanaryFleetCoverage.te
st_targets_outside_the_app_go_to_the_mac_canary)
View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

- The CDP event thread now compares the page URL against the one it last
  saw after target-info, frame and same-document navigation, so a mark
  clears even when another setter moved the URL first. Test added.
- clippy: slice::from_ref; rustfmt the eprintln.
- CLI test asserts the real 'not an id' message.
- Bad-value test uses short idempotency keys.
- The reason limit is 200 UTF-8 bytes, matching the catalog's max_length.
- Help no longer names palette UI this PR does not ship.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 22, 2026 08:07 — with GitHub Actions Inactive
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (claude sonnet, correctness first): SHIP at a6e4474

Independent re-review by a different model (Claude Sonnet; the lane runs Opus), after the BLOCK at 78947df. Read-only checks: git diff, grep, rustfmt --check, sync-resource-api.py --check (exit 0).

Previous BLOCK items, all fixed:

  1. cli/command/state/tests.rs:642 asserts .contains("not an id"), the message Selector::parse("ws_1") returns.
  2. rustfmt passes for every changed .rs file, state/tabs.rs included.
  3. clippy cloned_ref_to_slice_refs: fresh_upserts(..., std::slice::from_ref(&tab)).
  4. CDP clear on every URL change: clear_attention_if_page_changed runs after TargetInfoChanged, FrameNavigated and NavigatedWithinDocument, comparing browser.url() with the URL the event thread last saw. A navigate-hold change made on another thread is picked up at the next of those events. New test in browser/tests/navigation_barriers.rs.
  5. The bad-value test uses short idempotency keys (attention-bad-{index}).
  6. The reason limit is 200 UTF-8 bytes in the store's check, the catalog (catalog_validation.rs:347 counts bytes), the spec and the help.
  7. The help no longer names the palette UI, which this PR does not ship.
  8. All 7 SDK descriptors carry the same catalog hash.

worker.rs: the per-thread seen_url borrows cleanly. The state and registry locks are taken one after the other, never nested, after the URL and title guards are released, so there is no lock-order risk. Screencast frames never call it. The DB read happens only when the URL differs, and the commit only when the tab holds a mark.

Non-blocking:

  • The CDP test passes Weak::new(). It proves the URL tracking, not the daemon clear. The clear is covered end to end on the frontend-browser path (tab_attention_tests.rs).
  • If an agent navigates a tab and marks it before the CDP navigation event lands, that event clears the mark. Agents should mark after the page loads; the skills PR (agents: name tabs by title, mark the tab the person must act in (skills, MCP instructions) #24299) says to mark the page the person must act on.
  • The god-file ratchet files grow by a few lines.

@teamleaderleo teamleaderleo added the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Oct 22, 2026
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 22, 2026 16:32 — with GitHub Actions Inactive
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next guards / nightly-guards / workflow-guard-tests / release-notary is red on 14 of 14 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

…, in its commit

Review (codex xhigh) BLOCK at 53b2f38:
- The CDP worker seeded its last-seen URL from the first event, so a mark set
  before the worker saw the old page survived a navigation whose URL moved
  first.
- The navigation clear read the mark, then cleared it in a later commit, so a
  mark an agent set on the new page in between was dropped.

A browser tab's mark now records the page it was set on (attention_json.page,
not shown in extra.attention). The clear runs one conditional UPDATE in its
commit: it drops the mark only when the mark's page differs from the page the
tab is on, so a late or repeated clear for the new page keeps that page's mark,
and the worker's first event always asks. The worker's seen URL now only skips
the read for a page it already asked about.

Also: the Rust SDK's TabUpdateOptions gains attention (set and clear), and a
reason with U+2028 or U+2029 is refused as more than one line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 23, 2026 04:35 — with GitHub Actions Inactive
… SDK refuses a multi-line reason

The navigation clear now decides in its commit against the tab's current page: a late
callback for a page the tab already left clears nothing, so a mark the agent set on the
new page stays when two navigations overlap. The Rust SDK refuses what the daemon
refuses (a control character, U+2028 or U+2029). The worker's page-change check takes
its clear as a closure, so its test proves the clear is asked once per page.

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray
@cursor

cursor Bot commented Oct 23, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 23, 2026 09:00 — with GitHub Actions Inactive
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

rust workspaces / plan (changed Cargo workspaces) is red on 14 of 15 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

rust workspaces / rust workspaces is red on 14 of 15 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex xhigh, correctness first): SHIP at 12f9a15

No findings.

Independent review by a different model (Codex gpt-6.1-sol at xhigh on cmux16, diff-only, read-only sandbox). It checked that each finding of the earlier BLOCK at a3d0d8c is fixed: a stale navigation clear now checks the current page, the SDK refuses a multi-line reason, and the worker test records each clear.

Checks at this head:

  • Fleet: cmux-tui fmt, clippy and the attention tests pass (cmux-ci step a15ee8ac00f420e8883e1b99).
  • Reds that fail the same way on feat-cmux-next: rust workspaces (Every Cargo workspace is listed / Every planned workspace passed), Guard status, release-notary, and cmux-next checks. The SDK rust package job fails only on rustdoc for [::1] in bindings/rust/src/generated/types.rs:2612, which is also on base; its fmt, tests and clippy pass.

@teamleaderleo
teamleaderleo merged commit 7e71621 into feat-cmux-next Oct 23, 2026
176 of 185 checks passed
@teamleaderleo
teamleaderleo deleted the sp-attn-a branch October 23, 2026 09:29
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

lawrencecchen added a commit that referenced this pull request Oct 25, 2026
…umn too, as the migration does

tab_marked_unread_column_is_added_and_an_empty_row_is_dropped failed with "SQL logic error": 7e71621
(#24286, tab-attention-v1) made every tab_state update write attention_json, and the fixture table had only the
marked_unread column. The fixture now runs add_tab_attention_column after add_tab_marked_unread_column.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 27, 2026
… why

tab-attention-v1 (the daemon half is #24286): the tab record's
extra.attention {reason, at_ms} becomes TabModel.attention, and
showsUnread reads it, so the tab's blue dot, the screen bar, the sidebar
tab list and the pane's blue ring all show it with no new drawing. The
workspace row gets its manual dot and shows the reason as its text line.
Going into the pane (a click or a key) or Dismiss Highlight hides the
ring; the dot stays until the agent clears the mark, the page changes or
the tab closes, and a new request rings again. Mark as Read on the tab
also drops the mark.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray
teamleaderleo added a commit that referenced this pull request Oct 28, 2026
… why

tab-attention-v1 (the daemon half is #24286): the tab record's
extra.attention {reason, at_ms} becomes TabModel.attention, and
showsUnread reads it, so the tab's blue dot, the screen bar, the sidebar
tab list and the pane's blue ring all show it with no new drawing. The
workspace row gets its manual dot and shows the reason as its text line.
Going into the pane (a click or a key) or Dismiss Highlight hides the
ring; the dot stays until the agent clears the mark, the page changes or
the tab closes, and a new request rings again. Mark as Read on the tab
also drops the mark.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray
teamleaderleo added a commit that referenced this pull request Oct 28, 2026
… why

tab-attention-v1 (the daemon half is #24286): the tab record's
extra.attention {reason, at_ms} becomes TabModel.attention, and
showsUnread reads it, so the tab's blue dot, the screen bar, the sidebar
tab list and the pane's blue ring all show it with no new drawing. The
workspace row gets its manual dot and shows the reason as its text line.
Going into the pane (a click or a key) or Dismiss Highlight hides the
ring; the dot stays until the agent clears the mark, the page changes or
the tab closes, and a new request rings again. Mark as Read on the tab
also drops the mark.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray
teamleaderleo added a commit that referenced this pull request Oct 28, 2026
… why

tab-attention-v1 (the daemon half is #24286): the tab record's
extra.attention {reason, at_ms} becomes TabModel.attention, and
showsUnread reads it, so the tab's blue dot, the screen bar, the sidebar
tab list and the pane's blue ring all show it with no new drawing. The
workspace row gets its manual dot and shows the reason as its text line.
Going into the pane (a click or a key) or Dismiss Highlight hides the
ring; the dot stays until the agent clears the mark, the page changes or
the tab closes, and a new request rings again. Mark as Read on the tab
also drops the mark.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray
teamleaderleo added a commit that referenced this pull request Oct 29, 2026
… why

tab-attention-v1 (the daemon half is #24286): the tab record's
extra.attention {reason, at_ms} becomes TabModel.attention, and
showsUnread reads it, so the tab's blue dot, the screen bar, the sidebar
tab list and the pane's blue ring all show it with no new drawing. The
workspace row gets its manual dot and shows the reason as its text line.
Going into the pane (a click or a key) or Dismiss Highlight hides the
ring; the dot stays until the agent clears the mark, the page changes or
the tab closes, and a new request rings again. Mark as Read on the tab
also drops the mark.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray
cmux-bot Bot pushed a commit that referenced this pull request Oct 30, 2026
…nd why (carries #24311) (#27962)

* cmux NEXT: a tab an agent needs you in shows the unread dot, ring and why

tab-attention-v1 (the daemon half is #24286): the tab record's
extra.attention {reason, at_ms} becomes TabModel.attention, and
showsUnread reads it, so the tab's blue dot, the screen bar, the sidebar
tab list and the pane's blue ring all show it with no new drawing. The
workspace row gets its manual dot and shows the reason as its text line.
Going into the pane (a click or a key) or Dismiss Highlight hides the
ring; the dot stays until the agent clears the mark, the page changes or
the tab closes, and a new request rings again. Mark as Read on the tab
also drops the mark.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* SidebarMapping: keep newestUnread's doc comment on newestUnread

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Attention ring: going into a remote marked tab hides its ring too

interacted(_:tabID:) found tabs on this Mac's daemon only, while attentionMarks
rings marked tabs on every machine, so a click or a key in a Cloud or SSH tab
never dismissed its ring. A tab found on another machine now gets the ring's
dismissal, which is this app's own state; its notifications and Mark as Unread
keep their daemon's own paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Attention ring: resolve a click or key on the window's own machine; reject a bad at_ms

A tab on another machine can share an id with one here (a forked machine keeps its
tab ids). Interactions now find the tab in the workspace the window shows, on the
machine that owns it, and the hidden-ring state lives on the tab's own model, so
one machine's click or Dismiss Highlight never hides another's ring. A mark whose
at_ms is missing, negative, fractional or not a number is no mark.

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Attention ring: typing in another machine's terminal clears no workspace mark here; tests prove the redraw and the untouched local tab

noteTyping's workspace Mark as Unread clear now runs only for a window that shows
this Mac's workspace (or none), so a key in a remote terminal never clears a local
workspace whose tab shares the id. The ring test checks that hiding the ring wakes
its observers, and the two-machine test checks that a click on the remote tab leaves
the local tab's Mark as Unread alone.

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* TabAttentionTests: the observation flag is nonisolated (onChange is a Sendable closure)

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Test remote attention rings through a delayed strip click

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* Keep delayed strip clicks on their originating machine

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* Pass the strip fixture readiness condition explicitly

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* Test attention ownership through workspace replacement and menu reads

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* Bind attention reads to their owner and show clears immediately

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* Guard attention clears and ring generations

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* Make attention clears conditional and monotonic

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* Document revision guarded attention clears

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* Persist attention clear revisions across remarks

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* Fix decimal encoding for guarded attention clears

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* fix: import wire decimal parser

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* fix: preflight attention clear capability

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* fix: read nullable attention revision

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* fix: preserve explicit attention targets

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* style: format tab update SDK

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* fix: scope remote highlight dismissal and validate revisions

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* test: read SQLite timestamps as signed integers

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* fix: scope highlight dismissal to its machine and pinned owner

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* fix: serialize machine-scoped highlight debug state

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* fix: provide scheduler in attention test fixtures

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* fix: reject malformed guarded attention timestamps

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* fix: keep attention input ownership lookup indexed

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* test: import attention fixture scheduler module

Agent-Session: https://cmux.com/deeplink/agent?id=aid-493104335f660a57687e

* fix: guard shared attention interactions by owner request identity

Integrate the shared native request-ID contract from 9171431 and cecd056 while retaining machine-scoped dismissal state and client-local attention generation. Clear only the captured owner token and require the capability on the actual sending connection after handoff.

Regressions cover coalesced same-clock replacements, stale native mouse release, and legacy transport refusal. Fleet runtime validation is pending the backend-containing integration tree from #27497; no runtime result is claimed. Static verification: nine checks pass; unchanged localization inputs exceed existing debt. Swift #26809 and structural dogfood holds remain.

* fix(attention): an older daemon's mark hides its ring on entry and Dismiss Highlight

A mark without a request id (a daemon before tab-attention-request-id-v1)
stayed ringed until the agent cleared it: going in and Dismiss Highlight
skipped it. Hiding the ring is this client's view state, keyed by the
client-local attention generation, so it now applies to those marks too.
A press whose mark was replaced since is still dropped: a mark without a
request id compares the generation captured at the press. The owner clear
still needs the id.

Fixes the review BLOCK at c27c81c on #24311.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

* fix(attention): a remote workspace or tab menu runs every targeted row on its own machine

Review BLOCK at 23ffe95 on #27962: only Dismiss Highlight and Mark Tab
Unread carried the owner machine, so a remote menu's other rows routed to
the first daemon holding the same id. Every menu row that names the
right-clicked object now carries its machine, and menu validation checks
the row against that machine, as the run does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

* fix(attention): a remote workspace menu's rename field renames it on its own machine

Review at 44d1031 on #27962: the menu's rows were scoped to the
workspace's machine but the identity header's rename field built its own
invocation without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

* fix(attention): a remote tab's menu rows resolve their pane on the tab's machine

Box review BLOCK at 06e3510 on #27962: with the menu's machine on the
invocation, routing went to the remote daemon but ActionScope.pane and
AppActionContext.paneController still found the first pane holding a
same-id tab on any machine, so Reload Tab could reach this Mac's tab. Both
now look only on the target's machine when the invocation names one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

* fix(attention): name the pane in ActionScope's pane lookup closure (compile)

Box review at 8c0b5f5: $0 inside a closure nested in one with a
named parameter does not compile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

* fix(attention): Move Tab keeps the remote tab model it was given

Box review BLOCK at 3e011c0 on #27962: movingTabs looked the tab up
again by id across every machine, so with a same-id tab on this Mac shown,
Move Tab to New Workspace or Window could move this Mac's tab. It now
finds the pane of that very tab model on its own machine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

* Revert "fix(attention): Move Tab keeps the remote tab model it was given"

This reverts commit ad63a5f.

Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

* Revert "fix(attention): name the pane in ActionScope's pane lookup closure (compile)"

This reverts commit 3e011c0.

Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

* Revert "fix(attention): a remote tab's menu rows resolve their pane on the tab's machine"

This reverts commit 8c0b5f5.

Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

* Revert "fix(attention): a remote workspace menu's rename field renames it on its own machine"

This reverts commit a9a4b8b.

Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

* Revert "fix(attention): a remote workspace or tab menu runs every targeted row on its own machine"

This reverts commit 44d1031.

Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

* fix(attention): a machine-scoped menu row validates against its machine

The one part of the reverted 44d1031 that fixed this PR's own code: menu
validation rebuilt the invocation without targetMachineID, so a scoped
row's title and enablement were checked against a same-id object on
another machine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

* fix(attention): opening a marked tab hides its ring

Sol review BLOCK at 5825e87 on #27962 (P2): jump to unread or a
banner click opens the tab with the .open trigger, which dismissAttention
ignored, so the ring stayed after the person went in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

* refactor(attention): TabInteractionTarget lives in CmuxNextDaemon (app-type guardrail)

The type holds only daemon models (TabModel, DaemonStore) and its mark
check; nested in NotificationCenterService it grew a CmuxNextApp file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8bf8af53d779b9f5acad

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Nov 2, 2026
) (#32213)

* cmux NEXT: a tab an agent needs you in shows the unread dot, ring and why

tab-attention-v1 (the daemon half is #24286): the tab record's
extra.attention {reason, at_ms} becomes TabModel.attention, and
showsUnread reads it, so the tab's blue dot, the screen bar, the sidebar
tab list and the pane's blue ring all show it with no new drawing. The
workspace row gets its manual dot and shows the reason as its text line.
Going into the pane (a click or a key) or Dismiss Highlight hides the
ring; the dot stays until the agent clears the mark, the page changes or
the tab closes, and a new request rings again. Mark as Read on the tab
also drops the mark.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* SidebarMapping: keep newestUnread's doc comment on newestUnread

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* cmux NEXT: Go to What Needs Me, and marked tabs in Needs you

A tab an agent marked with `cmux attention request` (tab-attention-v1) now
shows in two places, each by the agent's reason, the workspace and the tab
title, never an id:

- Needs you: a `kind: "tab"` item. AgentPaneAttentionTabs pushes the marked
  tabs to every agent page (`attentionTabs` host event); its Go to calls
  `chat.attention.open {tabId}`, which shows only a listed tab through the
  App's user jump (revealTab). No answers and no side question.
- The palette's Go to What Needs Me (`attention.goTo`): a page of the marked
  tabs, newest first; Return goes through the same Go to. No default key.

AttentionTabsWatch observes the store and updates the list; nothing polls.
Strings localized in every catalog locale.

Leo: "idk where things are man i dont see anything other than the current
workspace which is you and you have a cmux next github brwoser tab open (we
need to have cmux expose this harder if it isn't already/hve better
instructions)"

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* AttentionPalettePage: key the action page by ActionID

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* cmux NEXT: a banner with Show for a tab an agent marked

When an agent marks a tab with `cmux attention request` (tab-attention-v1),
the app posts one system banner per request: "Workspace › Tab", "Needs you",
the agent's reason. Show (or a click) goes to the tab through the same Go to
as Needs you and the palette; posting it moves nothing. It follows
notifications.* like an agent's notification (desktop mode, muted
workspaces, quiet hours, sound), marks made before launch post nothing, and
a cleared mark takes its banner back.

Leo: "idk where things are man i dont see anything other than the current
workspace which is you and you have a cmux next github brwoser tab open (we
need to have cmux expose this harder if it isn't already/hve better
instructions)"

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Go to What Needs Me: an agent's run opens no palette

attention.goTo is a focus action, so an agent-origin `cmux action run
attention.goTo` now refuses unless focus was requested, as Search Tabs does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* DesktopNotifier: Mark as Read's doc comment back on its function

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Regenerate the action exports and docs shortcuts for attention.goTo

Regenerated on the fleet (scripts/cmux-next/regenerate-action-exports.sh,
steps 3ee6d476 and c491d7ee) and with web/scripts/export-docs-shortcuts.ts.
They also pick up the base's stale entries for home.*Conversation* and
neverHibernateSite. The defaults snapshot is bot-only (#21946), so it is left
to the base autofix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Regenerate actions.md for attention.goTo after the base merge

Fleet step df753c55 (regenerate-action-exports.sh at 1c2a8dc); action-surfaces.json
and the docs shortcuts were already fresh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Attention ring: going into a remote marked tab hides its ring too

interacted(_:tabID:) found tabs on this Mac's daemon only, while attentionMarks
rings marked tabs on every machine, so a click or a key in a Cloud or SSH tab
never dismissed its ring. A tab found on another machine now gets the ring's
dismissal, which is this app's own state; its notifications and Mark as Unread
keep their daemon's own paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* AttentionTabsWatch: AppServices owns the watch, and letting it go cancels its loop

The observation task was never stored, so once AppServices was freed its stream
waited forever on a closure that read nothing. The watch is now an object that
AppServices keeps; its deinit cancels the task, which ends the stream.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* AttentionTabsWatch: nonisolated deinit (cx-t7hu)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Attention ring: resolve a click or key on the window's own machine; reject a bad at_ms

A tab on another machine can share an id with one here (a forked machine keeps its
tab ids). Interactions now find the tab in the workspace the window shows, on the
machine that owns it, and the hidden-ring state lives on the tab's own model, so
one machine's click or Dismiss Highlight never hides another's ring. A mark whose
at_ms is missing, negative, fractional or not a number is no mark.

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Needs you: a page's Go to needs the person's gesture; an open palette page follows the marks

chat.attention.open shows a tab, which moves the person's focus: it now spends the
pane's one-use user gesture like other focus-moving page calls, so page script alone
cannot show a tab. Go to What Needs Me reads the marked tabs at each load and reloads
when they change, so a cleared mark's row leaves an open page and a new one appears.

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Needs you: rows name their machine; a bad atMs is no row; test the open page's reload

Tabs on two machines can share an id, so a marked tab's row key is now its machine
and its tab id, and Go to shows that machine's tab only (revealTab(_:onMachine:)).
The page drops an item whose atMs is not a whole nonnegative number, as the host
does. A test drives the real palette: an open Go to What Needs Me page keeps its
query and page across a change, gains a new mark's row and loses a cleared one's.

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Needs you banner: read the muted workspace and the viewed pane on the row's own machine

A marked tab's row key now names its machine. The banner's policy inputs (is the
pane viewed, is its workspace muted) look the tab up on that machine, not by a
bare id that another machine's tab may share.

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Attention ring: typing in another machine's terminal clears no workspace mark here; tests prove the redraw and the untouched local tab

noteTyping's workspace Mark as Unread clear now runs only for a window that shows
this Mac's workspace (or none), so a key in a remote terminal never clears a local
workspace whose tab shares the id. The ring test checks that hiding the ring wakes
its observers, and the two-machine test checks that a click on the remote tab leaves
the local tab's Mark as Unread alone.

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Needs you banner: test that muted is read on the row's own machine

Two machines' tabs share an id in workspaces of their own. Muting one machine's
workspace silences only that machine's tab's banner. The banner's policy inputs
move into attentionArrival(_:) so the test reads what the policy decides on.

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* TabAttentionTests: the observation flag is nonisolated (onChange is a Sendable closure)

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Needs you: a row key fits the page's limit however long the machine id; test Go to's lookup on two machines

A row key is now a 16-hex digest of its machine's id, '/', and its tab id, so it
stays within chat.attention.open's 256-byte limit. Go to finds the key's machine
among the connected daemons (AttentionTabsWatch.locate) and reveals the tab there.
The test connects an SSH machine whose tab shares this Mac's tab id and checks that
each row's key finds its own machine's tab.

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Needs you banner: Show opens only the banner's own live request; policy finds the row's machine by its key

A banner's Show (or click) now opens the tab only while that banner's request
(its at_ms and row key) is still a live mark, so a banner from an earlier launch
or one a newer request replaced opens nothing. The policy lookup uses the row
key's machine digest (AttentionTabsWatch.locate). The Show test uses the real
machine-qualified key and covers a replaced and a cleared request.

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Needs you: Go to refuses a tab whose workspace id another machine's workspace also has

Windows find a workspace by its id alone and prefer this Mac's. A remote row whose
workspace id this Mac's workspace also has (a cloned machine's state) now refuses
rather than show this Mac's tab. The two-machine test drives the bound Go to.

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* Needs you banner: only a banner this launch posted can Show

A banner left in Notification Center by an earlier launch keeps its id after a
restart, and its request may still be the live mark. Show now also requires that
this launch posted the banner and has not withdrawn it. A test restarts the
service with a live mark and checks the old banner opens nothing.

Leo-ask: ask-12231fbe5e

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16037-16c2-7a73-b063-2e37ed40b9c4&host=cosmic-gray

* cmux NEXT: repair needs-you banner on current base

Rebase the stale attention-banner branch onto current feat-cmux-next while preserving machine-bound tab routing, gesture-gated Go to, and Needs you UI coverage.

Agent-Session: https://cmux.com/deeplink/agent?id=aid-cb9fc69664e9708a30ec

Sidebar-Look: no visual change

* Merge current-base needs-you repair tree

Agent-Session: https://cmux.com/deeplink/agent?id=aid-cb9fc69664e9708a30ec

Sidebar-Look: no visual change

* Harden needs-you notification lifecycle

Sidebar-Look: no visual change
Agent-Session: https://cmux.com/deeplink/agent?id=aid-cb9fc69664e9708a30ec

* Inject attention state and keep row requests generation-bound

Move attention observation, palette rows, and banner identity into AgentPane; keep system notification integration in the existing app service. Exercise stale-generation refusal, bounded keys, sound policy, and startup withdrawal.

Sidebar-Look: no visual change
Agent-Session: https://cmux.com/deeplink/agent?id=aid-cb9fc69664e9708a30ec

* fix(next): use current tab attention capability API

Repairs the exact-head review compile finding in Mark as Read. Swift syntax and prepush gate pass; native compilation remains on fleet.

Sidebar-Look: no visual change
Agent-Session: https://cmux.com/deeplink/agent?id=aid-cb9fc69664e9708a30ec

* fix(next): allow attention page operation

Expose chat.attention.open through the page host allowlist so marked-tab Go to requests reach the injected routing handler.

Sidebar-Look: no visual change
Agent-Session: https://cmux.com/deeplink/agent?id=aid-cb9fc69664e9708a30ec

* fix(next): baseline attention snapshots by machine

Establish each daemon's quiet baseline only after its live tree and current session snapshot arrive. Rebaseline replaced stores and replayed streams without suppressing ready machines. Qualify remote workspace mute and sound settings while preserving existing local keys; use the same keys for writers, banners, rings and sidebar indicators.

Add regressions for late snapshot ordering, empty baselines, offline remotes, reconnect/replay, store replacement and cloned workspace IDs. Static gate and web lint pass. Native red/green evidence remains pending the Swift dependency hold.

Sidebar-Look: no visual change
Agent-Session: https://cmux.com/deeplink/agent?id=aid-cb9fc69664e9708a30ec

* fix(next): respect typing quiet period for tab attention

Record typing by machine and tab, and pass its age into attention policy so banner and sound suppression matches normal notifications without leaking across cloned tab IDs. Add coverage for both machine directions and expiry. Native red/green remains blocked by Swift dependency 26809; static gate and web lint pass.

Sidebar-Look: no visual change
Agent-Session: https://cmux.com/deeplink/agent?id=aid-cb9fc69664e9708a30ec

* fix(next): restore xcstrings catalog version

Agent-Session: https://cmux.com/deeplink/agent?id=aid-cb9fc69664e9708a30ec

* fix(next): remove invalid notification key enum initializer

Agent-Session: https://cmux.com/deeplink/agent?id=aid-cb9fc69664e9708a30ec

* fix(next): retain attention requests through reconnect readiness

Capture the quiet request baseline when the session snapshot is applied, before subsequent deltas or tree readiness can coalesce in observation. Classify live post-snapshot requests once per machine/generation and let the notification lifecycle post deferred eligible requests even when it already saw their unready rows.

Regressions cover reconnect deltas before the tree with separate/coalesced observations, missing initial tab models, cleared pending requests, and replay. Native red/green remains unproven while Swift dependency 26809 is held. Static gate and web lint pass.

Sidebar-Look: no visual change
Agent-Session: https://cmux.com/deeplink/agent?id=aid-cb9fc69664e9708a30ec

* fix(next): select throwing workspace mute action binding

Agent-Session: https://cmux.com/deeplink/agent?id=aid-cb9fc69664e9708a30ec

* test(next): supply the app scheduler to attention SSH fixtures

The focused fleet run reached test compilation and identified three owned SSHMachineSession fixtures still using the pre-mainWork API. Pass each fixture its existing AppServices scheduler. Regression assertions remain unchanged.

Agent-Session: https://cmux.com/deeplink/agent?id=aid-cb9fc69664e9708a30ec

* cmux NEXT: marked tabs in Needs you

Agent-Session: https://cmux.com/deeplink/agent?id=aid-04743fa7d44d1f9b2454

* Bundle the attention palette string catalog

Agent-Session: https://cmux.com/deeplink/agent?id=aid-04743fa7d44d1f9b2454

* Own attention tabs in AppServices and route page events

Agent-Session: https://cmux.com/deeplink/agent?id=aid-04743fa7d44d1f9b2454

* Preserve current base documentation and needs-you fixtures

Agent-Session: https://cmux.com/deeplink/agent?id=aid-04743fa7d44d1f9b2454

* Bind attention navigation to owner-issued request tokens

Agent-Session: https://cmux.com/deeplink/agent?id=aid-04743fa7d44d1f9b2454

* fix(next): open marked tabs from Home inbox

Agent-Session: https://cmux.com/deeplink/agent?id=aid-32928e845232cc28d954

* fix(next): wire marked tab host events

Agent-Session: https://cmux.com/deeplink/agent?id=aid-32928e845232cc28d954

* fix(home): avoid selecting marked tabs after opening

Agent-Session: https://cmux.com/deeplink/agent?id=aid-32928e845232cc28d954

* fix(debug): restore palette renderer for named-window captures

Agent-Session: https://cmux.com/deeplink/agent?id=aid-32928e845232cc28d954

* test(home): reject fallback selection after a marked-tab open

Agent-Session: https://cmux.com/deeplink/agent?id=aid-32928e845232cc28d954

* Carry of #24345: drop the duplicate AgentPane import; regenerate cmux-app.d.ts after the base merge

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-1500aad3011a497e835c

* Attention banners: redact an incognito tab's banner; keep remote mutes saved before qualified keys

Review at 2794003 (codex gpt-6.1-sol) blocked on two findings:
- An attention banner from an incognito window's tab named its workspace,
  tab and reason in Notification Center. postAttention now resolves the
  tab's workspace and posts with incognito redaction.
- Remote workspace mutes saved by earlier builds under bare workspace ids
  were dropped on upgrade. A bare id still mutes a remote workspace while
  no workspace on this Mac has that id (NotificationWorkspaceKey.legacyRemoteKey),
  and toggling the workspace's mute clears it.

Tests: AttentionBannerTests.anIncognitoTabsBannerNamesNothing and
aRemoteMuteSavedBeforeQualifiedKeysStaysMuted (run in PR CI; this host has
no fleet client for a local compile check).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-1500aad3011a497e835c

* Notification keys: one machine-aware lookup for mute and sound; keep remote sound rules saved before qualified keys

Review at edaec4b (codex gpt-6.1-sol) blocked on remote workspace sound
rules saved under bare ids by earlier builds. NotificationWorkspaceKey.ruleKey
reads such a rule while only it exists and no workspace on this Mac has the
id, so it keeps applying and the settings edit it in place.

Ordinary notifications, the move-to-top check and attention marks now read
mute and sound through NotificationCenterService.notificationKeys, so a
remote workspace's qualified mute or sound rule (what the toggle and sound
settings write) applies to every banner, not just Needs you ones.

Test: AttentionBannerTests.aRemoteSoundRuleSavedBeforeQualifiedKeysStillApplies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-1500aad3011a497e835c

* Needs you: a marked tab's ask-about refusal throws a bare Error, as its neighbours do (pane-english)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-1500aad3011a497e835c

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch was previously deployed

4 inactive deployments
artifacts — 12f9a15f Deployed Oct 23, 2026 by teamleaderleo via publish tree-addressed cmux-tui #45345
sentry-dsyms — 12f9a15f Deployed Oct 23, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #45345
ci-routing-agent — 12f9a15f Deployed Oct 23, 2026 by github-actions[bot] via cmux-next macOS placement #31594
cmux-tui-merge-tree — 12f9a15f Deployed Oct 23, 2026 by teamleaderleo via publish the merge tree #5105
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant