Repository navigation
Show running and waiting agents on the Lock Screen and in the Dynamic Island, from a new Live Activity switch - #1071
Merged
Merged
Conversation
sak0a
force-pushed
the
port/ios-widget-extension
branch
from
October 31, 2026 14:05
0cdfbf0 to
4160521
Compare
sak0a
force-pushed
the
port/agent-live-activity
branch
from
October 31, 2026 14:15
5a8fe1c to
3bced6a
Compare
sak0a
changed the base branch from
port/ios-widget-extension
to
port/subscription-usage-widget
October 31, 2026 14:15
sak0a
force-pushed
the
port/subscription-usage-widget
branch
from
October 31, 2026 14:42
214c6ec to
e7a2680
Compare
sak0a
force-pushed
the
port/agent-live-activity
branch
from
October 31, 2026 14:48
3bced6a to
5863ccb
Compare
… Island, from a new Live Activity switch The phone app can now keep one Live Activity card for agent work. It is off by default; Settings > Inbox > Alerts has a new Live Activity switch whose text says the card stays current only while Ryco runs and that task titles show on a locked phone. The card counts what runs, what waits on you, and results from the last 15 minutes, with up to five threads on the Lock Screen and three in the expanded Dynamic Island, each opening its thread. It uses the shared agent activity summary, fed by the Inbox as Home builds it. It starts only in the foreground with work running or waiting, updates when what it shows changes (a second of changes becomes one update), ends once nothing runs or waits and stays 15 minutes with its results, and ends at once on sign-out, an account switch or when the switch goes off. Once Ryco is suspended it reads "Out of date" after 10 minutes. Phase 1 sends nothing anywhere: no push token, no APNs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…en no machine answers - Before a card starts, any Ryco card that already ended and still shows its results is dismissed at once, so work that starts again within those 15 minutes no longer puts a second card beside it. Sign-out, an account switch and turning the switch off now end every Ryco card, results cards included. - The sign-in screen ends every card once the app is idle, when the switch was ever on, with a small lazily loaded module: a sign-out while Ryco was closed no longer leaves task titles on the Lock Screen. - A card ends once no machine has been live for the 10-minute stale window while Ryco runs; coming back to the foreground gives the machines that window again. - The content state is checked as Swift encodes it (JSONEncoder escapes every slash): the module trims rows above 4,096 bytes, and the app keeps its JSON within 3,584. The content state moved to a Foundation-only file so a Mac test can measure it. - Home and the Live Activity read the Inbox through one hook (useInboxSource), so the card also counts messages queued on this phone and woken threads already seen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sak0a
force-pushed
the
port/agent-live-activity
branch
from
October 31, 2026 14:56
5863ccb to
56441f2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What Changed
Built on #1070 (the subscription usage widget, merged). Built on #1069 and #1055 (both merged; the two #1055 commits this branch used to carry are dropped). Stacking on #1070 resolves the keep-both overlaps in
RycoWidgetsBundle.swift,widgetExtension.test.ts,withIosWidgetExtension.test.ts,AppAccessGate.tsxandmobileStartupImports.test.tshere. The shared Inbox hook (useInboxSource) now reads main'suseListedEnvironmentsWorkspaceData, as Home does since #1025. After rebasing onto main with #1070 merged, all 2,863 mobile tests pass, and so doesbun run check.summarizeAgentActivity(Summarize running and waiting agents in one shared rule, for the phone's Live Activity #1055), fed by the Inbox as Home builds it: both read it through one hook (useInboxSource: machines, threads, messages queued on this phone, woken threads already seen), so the card never disagrees with the list it opens. Only machines that are connected with a current shell count.decideAgentActivity):pushType: nil), no APNs, no Hub. Titles stay in iOS's activity store on the phone. The app keeps the content state's JSON within 3,584 bytes, and the module checks it again as Swift encodes it (4,096 bytes, ActivityKit's limit); rows are dropped before the counts.AgentActivityAttributes.swiftandAgentActivityContentState.swift(Foundation only) are shared by the app module and the extension; the attributes carry only a version. The widgets module getsactivitiesEnabled,startAgentActivity,updateAgentActivity,endAgentActivity,listAgentActivitiesanddismissAgentActivities. The extension renders the card (AgentActivityWidget.swift). The app's Info.plist getsNSSupportsLiveActivities.Why
Phase 1 of the Live Activity port from T3 Code (one card, foreground-only start, 10 minute stale date, 15 minute results) and Synara (the card ends once everything has settled). Remote counts through the Hub (LA3) need Hub work, a paid Apple team and a device, so they are a later phase.
Validation
bun run check:changed: passes (format, lint, fullbun typecheck, all 2,772 mobile tests, and the related client-runtime, desktop, web and ryco-cli tests).agentActivityModel.test.ts(11): starts only in the foreground when on, signed in and something runs; no update for the same state; the stale date is now + 600,000 ms; a nearly stale card is refreshed in front; the end on settle carries a 15 minute dismissal; sign-out or switching it off ends it at once; two cards become one; a stale leftover ends, a live one is adopted; 5 rows of the longest titles stay under 4 KB, and an oversized state drops rows, not counts; the Inbox rows carry state, request kind, resting, delegated and liveness.liveActivityRuntime.test.ts(7, fake timers): nothing until the switch is on; changes within a second become one update; the end after settling; no start in the background, a start on coming back; sign-out and an account switch end every card; leftovers; a card iOS refused is not retried until the next foreground.LiveActivitySettings.test.tsx(3): no row without the extension; off by default, with the required wording; the iOS Settings hint.mobileStartupImports.test.ts: nothing undersrc/liveActivitybut the bridge is on the launch path.withIosWidgetExtension.test.ts:NSSupportsLiveActivitieson the app, and the new sources in the extension.expo prebuildinto a scratch folder,xcodebuild(Debug, ad-hoc signing). The build succeeds with the ActivityKit calls in the app's module; the appex containsAgentActivityWidgetand links no React or Hermes; the app's Info.plist hasNSSupportsLiveActivities => true.Review
An independent review found no privacy or network problem. Fixed in
5a8fe1cb0:listAgentActivitiesleaves ended cards out, so work that started again within those minutes started a second card. The module getsdismissAgentActivities(endedOnly), and the runtime calls it withtrueright before every start, so an ended card is gone (dismissal.immediate) before the next one. Sign-out, an account switch and turning the switch off now call it withfalse: every Ryco card ends at once, also a results card the old code left for 15 minutes. Tests:liveActivityRuntime.test.ts("removes a card still showing its results before work that starts again gets one"; fails without the call), and the sign-out, account-switch and switch-off tests now expect every card to go.LockedLiveActivityBridgeon the sign-in screen, when the switch was ever on, loadsendLiveActivities.tsonce the app is idle and ends every card. Tests:endLiveActivities.test.ts;mobileStartupImports.test.tschecks it stays off the launch path and loads neither the runtime nor the Inbox. Note: a phone that launches offline with only a Hub account is also locked for a moment, so it ends the card too; a new one starts once work runs and Ryco is in front.unknownSinceMs), and the card ends at once after the 10-minute stale window. Coming back to the foreground starts the window again, so a resumed app gets time to reconnect instead of replacing its card. Tests:agentActivityModel.test.ts("stays while machines may still answer…") andliveActivityRuntime.test.ts("ends the card once no machine was live…", which also covers the foreground restart); both fail without the rule.JSONEncoderescapes every slash, and every row has a link. The content state moved toAgentActivityContentState.swift(Foundation only;AgentActivityAttributeskeeps typealiases), withfitted(): rows go from the end until it encodes within 4,096 bytes, and a state that does not fit even without rows is refused. Start, update and end all go through it. The app's budget is now 3,584 bytes. Tests:agentActivityModel.test.ts("keeps a margin under 4 KB…"; fails with the old 4,096 budget), and a Mac Swift harness (test/activityState/main.swift, run bywidgetExtension.test.ts): the longest five rows the app sends stay under 4,096 bytes as Swift encodes them, and a 3.4 KB state of slashes (about 5.4 KB in Swift) is trimmed to fit with its counts. It fails iffitted()does not trim. ActivityKit's own encoding is private;JSONEncoderis the closest measure I have.useInboxSource(machines, workspace data filtered to Home's machines, messages queued on this phone, woken threads seen), used byHomeScreenand the feed, so the card counts a queued message and a seen woken thread as Home does. Only Home's search and machine filter stay out. Not covered by a new test: it is hook wiring, and the mobile runner cannot run effects; Home's own behavior is unchanged.AppAccessGate.tsxnow has both PRs adding a bridge on the sign-in screen as well (keep both).bun run check:changedpass. Rebuilt once for the iOS Simulator (expo prebuildinto a scratch folder,xcodebuildDebug, ad-hoc signing): the build succeeds, the app's module hasdismissAgentActivities, the appex hasAgentActivityContentStateand links no React or Hermes; scratch deleted. Not verified on a simulator or device: thatend(nil, dismissalPolicy: .immediate)on an already ended card removes it at once (Apple documents ending with an immediate policy; I could not run a card here), and ActivityKit's real encoded size.🤖 Generated with Claude Code