next: cmux://agent links open the agent session, input focused
Summary
Agent commits, PRs and leases now carry a link back to the session that made them (manaflow-ai/cmuxterm-hq#2555, tool in cmuxterm-hq#2556). This PR lets cmux NEXT open that link. cmux://agent/<harness>/<session>?host=<machine>&name=<callsign> is one more DeepLink target. It goes through the same link.open path as every other link: the OS URL handler, the palette, cmux link open and MCP.
- Opening it reveals the tab this app already shows that session in. That's either the agent chat tab that adopted
harness:session, or a terminal whose agent hooks reported that session id. The terminals come from the machines this app is connected to. - It never creates a tab, resumes or launches a harness, connects to a host, or types anything. So the link is an address, not a credential: you reach a session only if your app could already reach it.
hostandnameare display hints only, kept when they're 1โ64 char tokens, and they play no part in resolution. - When the user opens it, the tab is revealed with
.raise, so the revealed session's input has the keyboard: the agent chat page's composer claims focus when its window takes focus (composerFocus.ts), and a terminal's surface takes it on selection. Talking to the agent is then one keystroke away. A background open (Cmd held, or automation) uses.bringForward, the same intent every other link target uses. - Debug Settings โ "Agent links" (
links.agentLinks, in AgentPaneTunables), on by default. Off refuses these links with a localized message. plans/cmux-next/links.json, the Markdown page's link matcher and agent chat replies (replyHref.ts) all know the new host. Dots-only sessions and hints are refused, matching the web fallback (#22088).- CmuxNextApp doesn't grow (check-app-size). The candidate walk lives in CmuxNextDaemon (
WorkspaceModel.agentHarnessSessions), and three unused App lines were removed (a logger,runningCount, animport os).
Unknown sessions get the existing "gone" refusal. A card for sessions on machines this app isn't connected to comes later.
Testing
Tests/CmuxNextActionsTests/DeepLinkAgentTests.swift: parse/format round trip; rejection of 1 or 3 segments, bad tokens, fragments and other schemes; malformed hints dropped; existing link kinds unchanged; tab matching (adopted chat first, harness mismatch skipped, unknown harness matched on session); and the daemon'sharnessSessionstuples. The red commits 385d9134 and 7ed47659 come before the implementation.LinkExportTestscovers the new kind inlinks.json.Tests/CmuxNextAppTests/TypeAheadQueueTests.swift(red commit a12fbf6f first): an earlier size trim droppedTypeAheadQueue.Wire.startedNs, so queued keys never expired. It's restored, and the test checks that text older than 2 s is dropped.- Review fixes at 76e48e08 (red commits da30996c and 6f383dcc first): an exited terminal and a disconnected machine's terminals are no candidates (
WorkspaceAgentSessionsTests,DaemonStore.reachableAgentHarnessSessions), and a chat tab that switched away from the outside chat it adopted no longer answers for it (AgentTabHarnessOnCreateTests.switchingChatsReleasesTheAdoption). Swift tests for red and green: dispatchedcmux-next.ymlon next-batch/leo-agent-provenance-red (run 39358338412) and next-batch/leo-agent-provenance (run 39358342365); results added below when they finish. -
- Nothing was compiled locally (no heavy Swift builds on this Mac), so CI's CmuxNext lanes are the first compile and run. Focus relies on the existing
revealTab(.raise)path and isn't dogfooded yet.
- Nothing was compiled locally (no heavy Swift builds on this Mac), so CI's CmuxNext lanes are the first compile and run. Focus relies on the existing
Proof
Not UI: link routing and parsing only; no layout or visual change. The one visible effect is that cmux://agent/... links in Markdown and agent replies draw as links, like the existing cmux://session/... links.
Review: PASS at 2de43467 (correctness-first reviewer subagent, read-only). It confirmed the startedNs restore matches cmux-focus-core and that the new test fails without it; no AgentFocus references remain; the overload labels are unambiguous; the size check passes (83246 = base). Its note about real machine names in examples is fixed in 0825459b (test strings and the links.json example only).
Changelog
Added: cmux://agent links open the agent session they name, with its input focused, when this Mac can already reach it
๐ค Generated with Claude Code