Blolabel
← Notes
event 8 min read

Apple's onscreen awareness needs the app to declare a persistent identifier; phoneshell gets a MAC address and a raw pointer baked into one instead

WWDC26 session 343 shows a developer attaching a persistent EntityIdentifier to whatever is on screen so Siri can resolve "play the third one" without a word of pixel or tree parsing. That cooperation does not exist in the ordinary, unmodified consumer apps phoneshell drives, and its memory.py file quotes, from a real run, exactly what shows up instead: an identifier with a Bluetooth MAC address and a raw memory pointer baked into it, which has to be detected and stripped before two sightings of the same screen can be recognized as the same screen at all.

Apple's WWDC26 session 343, "Explore advanced App Intents features for Siri and Apple Intelligence," presented by Antonio Cancio of the App Intents team, covers onscreen awareness: the mechanism that lets Siri connect what is visible on a screen to entities and actions it understands. Without it, the session states, Siri has no way to resolve a reference like "play the third one" or know which artist is meant if the artist's name is not itself visible. The session's code examples show four ways a developer opts a screen into this: attaching an NSUserActivity with an appEntityIdentifier for a screen dedicated to one primary item; a per-view .appEntityIdentifier annotation for a view representing one entity among several; a collection annotation, .appEntityIdentifier(forSelectionType:), for lists, which fetches identifiers lazily and keeps working even after a selected row scrolls out of the view hierarchy; and UIKit and AppKit equivalents, AppEntityAnnotatable and UICollectionViewAppIntentsDataSource. Every one of these requires the identifier to be persistent, and the session separately stresses implementing fast display-representation queries, so Siri can resolve an on-screen entity without loading its full content, warning that without this Siri may ask for clarification or give up.

Abstract technical illustration on a dark grid: on the left, a clean labelled token travels from a screen shape directly into a recognition node, representing a persistent identifier an app declares on purpose; on the right, a messy string of mixed characters travels from an identical screen shape toward a filter node that strips several of its segments before a shorter, cleaned token continues on to the same kind of recognition node, cool blues and slate greys with one amber accent marking the filter node, no icons or text

What Apple's onscreen awareness assumes the app will do

The design Apple describes puts the entire burden of stable identity on the app's own code. A developer who wants Siri to ground a reference to a song, a playlist, or a conversation must supply an EntityIdentifier that refers to the same underlying item every time it is shown, across launches, across scroll positions, across however the surrounding UI happens to be laid out that day. The session's sample code pairs a SongEntity or AlbumEntity type with a stable identifier string the app already uses internally, not with anything derived from the view hierarchy or the screen's rendered content. This works precisely because the app knows its own data model and is choosing, at build time, to expose a piece of it through a documented API. The mechanism has no fallback for an app that declines to participate: the session does not describe any way for Siri to infer an entity's identity from an app that has not adopted these annotations.

Opt-in surface (WWDC26 session 343)Screen scenarioWhat makes the identifier persistent
NSUserActivity.appEntityIdentifiera screen dedicated to one primary itemattached to the activity itself, not derived from the view hierarchy
.appEntityIdentifier (per-view annotation)a view representing one entity among several on screentags that one view directly, independent of where it sits
.appEntityIdentifier(forSelectionType:) (collection annotation)listsfetched lazily, keeps working after a selected row scrolls out of the view hierarchy
AppEntityAnnotatable / UICollectionViewAppIntentsDataSourceUIKit and AppKit screensmirrors the SwiftUI annotations for non-SwiftUI code

Source: Apple, WWDC26 session 343, "Explore advanced App Intents features for Siri and Apple Intelligence," presented by Antonio Cancio, read 30 October 2026.

What phoneshell gets from an app that never opted in

phoneshell drives ordinary, unmodified consumer iOS apps, none of which were built with onscreen awareness or any equivalent agent-facing API in mind. Its own grounding problem, deciding whether a screen the agent is looking at now is the same screen it saw before, is solved entirely from what WebDriverAgent's accessibility tree happens to expose, and memory.py's own comments document exactly how unreliable that is as a source of stable identity. The file quotes two real identifiers pulled from a live run of iOS Settings:

com.apple.settings.followUpGroupAsItem...group.account.61932825-AFFA-4F26-...
com.apple.settings.connectedHeadphone.38:C4:3A:26:96:EE-0x85a8cf0f0

The comment accompanying them is direct about what is wrong: the first contains a UUID, the second a Bluetooth MAC address and a raw memory pointer, both of which "survive within one launch and change on the next, which silently turns every revisit into a screen the agent has never seen." Where Apple's mechanism asks the app to hand over an identifier that means "this exact song" forever, iOS Settings, with no obligation to do any such thing, hands phoneshell an identifier that means "this exact Bluetooth session, at this exact address in memory, right now." memory.py answers this not by requesting better identifiers, which it has no way to do, but with a regex table, _ID_NOISE, that pattern-matches and strips UUIDs, MAC addresses, and similar instance-specific fragments before an identifier is allowed anywhere near a screen fingerprint.

Declared identity, versus identity recovered from noise Apple onscreen awareness (WWDC26 #343) app declares EntityIdentifier at build time tied to the app's own internal data model persistent by construction, by design no fallback if the app does not opt in NSUserActivity, per-view and collection annotations phoneshell memory.py, unmodified apps whatever WebDriverAgent's tree exposes e.g. 38:C4:3A:26:96:EE-0x85a8cf0f0 (quoted, Settings) contains a MAC address and a raw pointer changes on every relaunch, by accident _ID_NOISE regex table strips it before use Apple's mechanism is a protocol between a cooperating app and Siri; phoneshell's problem is grounding an app that was never asked to cooperate. Neither identifier string was designed for an agent to key a cache on. One is deliberately stable; the other is accidentally unstable. Sources: developer.apple.com/videos/play/wwdc2026/343/; phoneshell/memory.py, read 30 October 2026. memory.py's fingerprint pipeline for one real identifier WebDriverAgent tree raw accessibility id, read fresh each visit connectedHeadphone. 38:C4:3A:26:96:EE- 0x85a8cf0f0 _ID_NOISE table memory.py's regex list strips 38:C4:3A:26:96:EE strips 0x85a8cf0f0 also strips bare UUIDs, e.g. 61932825-AFFA-4F26 cleaned id instance noise removed, only the stable prefix left, e.g. connectedHeadphone screen fingerprint matched against prior visits Without this stripping step, the MAC address and pointer alone would make every relaunch of this screen look new. Source: phoneshell/memory.py, read 30 October 2026.

What it means for grounding on iOS, with and without app cooperation

Check it yourself

# the real identifiers phoneshell quotes from a live iOS Settings run
grep -n "followUpGroupAsItem\|connectedHeadphone" phoneshell/memory.py

# the regex table that strips UUIDs, MAC addresses and similar noise
grep -n "_ID_NOISE" -A 10 phoneshell/memory.py

# confirm memory.py's match key is the screen fingerprint, computed after noise stripping
sed -n '1,24p' phoneshell/memory.py

# Apple's session page and its onscreen awareness chapter
open "https://developer.apple.com/videos/play/wwdc2026/343/"

# the specific annotation APIs named in the session
#   NSUserActivity.appEntityIdentifier, .appEntityIdentifier(forSelectionType:),
#   AppEntityAnnotatable, UICollectionViewAppIntentsDataSource

What would prove this wrong

We claim Apple's onscreen awareness APIs, as shown in WWDC26 session 343, require the hosting app to declare a persistent entity identifier at build time, with no mechanism shown for Siri to infer stable identity from an app that has not adopted them; that is checkable against the session itself and would be false if Apple's own documentation describes a fallback path we have not found. We also claim the two identifier strings quoted above are real output from a live run against iOS Settings, not constructed examples; that is checkable directly in memory.py's own comments, dated to this repository's history. We will revisit this piece if a future iOS release ships onscreen awareness support that works without app-side annotation, or if phoneshell's own identifier-noise table needs new patterns for an app we have not yet seen, by 30 April 2027.

Sources