ADR-0081: Milestone 24 SMS through the owner's iPhone¶
- Status: Proposed
- Date: 2026-08-26
- Related: engineering plan Section 29 and roadmap item B7; ADR-0034, ADR-0049, ADR-0061, ADR-0069
- Detailed design:
docs/plan/device-channel-and-sms.md
Context¶
Roadmap item B7 held the device channel and device-scoped tools behind "a concrete use case, after Milestones 12 and 14". On 2026-08-26 the owner supplied the use case: sending and reading SMS through the owner's own iPhone — the agent acting as the owner, not a CPaaS number acting as the agent. Milestone 12 is complete and delivers everything the slice stands on; the Milestone 14 dependency in B7's entry condition covered client attribution and the session-key resolver, and this design takes neither — its triage session is keyed per device and channel, not through the surface resolver. The roadmap rule requires the owner's authorization and a specification with gates to declare. This ADR is the authorization, and device-channel-and-sms.md is the specification, with twelve gates.
Proposed decisions¶
- Parallel workstream. Milestone 24 is authorized as a parallel
workstream on the ADR-0069 terms: its gates become green independently,
and the verified gate ceiling still advances only in numerical order,
so nothing here moves the ceiling past 15. The milestone touches three
shared files, named here rather than discovered in review: the devices
domain model (the
capabilitiesfield lands where Milestone 14's surface rows also live), and the two document widenings named in decision 6. - The device channel is push-wake with poll-back. One adapter: a
pending invocation row, a content-free APNs wake, authenticated fetch
and result post, a bounded wait resolving
tool.device_offline. No websocket, no suspension kind. device.sms.sendregisters from declared capabilities. The device's registration declares the capability; the registry exposes the tool withToolSource.DEVICEwhile the device is present and unrevoked. This is the third registration source the seam audit anticipated.- The compose-sheet tap is the approval. The tool classifies
ALLOWbecause iOS makes the owner's Send tap non-bypassable; a second in-app approval would duplicate, not add, control. Hardline rules still scan the outbound body before any invocation is written. - Ingest is best-effort and untrusted. The Shortcuts automation and App Intent forward incoming texts to a device-authenticated route; the content is device-originated untrusted input routed into a standing triage session; the design says plainly that iOS can silently disable the automation.
- Two explicit widenings. Milestone 12's closed trigger catalog grows a sixth content-free entry (the pending device invocation), and tool-system's registration closes at three sources instead of two. Both documents are amended by this change-set, not silently diverged from.
- Default off.
AGENT_DEVICE_CHANNEL_ENABLEDandAGENT_DEVICE_SMS_ENABLEDdefault off and change together at release validation. This follows the schedule and notification routers exactly. - Twelve gates extend the existing
devicearea. Registered at Milestone 24 against the design's hard-gates section.
Consequences¶
- The census grows from 353 to 365 registry entries; the
devicearea grows from six gates to eighteen. - The scope vocabulary does not grow; the new routes take
device.readanddevice.write. - The iOS client gains its first device-scoped capability, behind a default-off setting.
- B7's roadmap row narrows to presence-based routing and hand-off.
Alternatives considered¶
- A CPaaS number (Twilio-class): rejected by the owner; the point is the agent acting as the owner, and a second number is a different product.
- A websocket device transport: rejected for v1; push-wake reuses Milestone 12 delivery and adds no long-lived connection infrastructure.
- A waiting-on-device suspension kind: deferred; the bounded wait is honest about an unreachable phone, and the suspension kind is a later ADR if expiry rates demand it.
- Silent sends via Shortcuts automation: rejected; it would remove
the non-bypassable confirmation that justifies
ALLOW, and its reliability is unverifiable. - Treating ingest as a Surface: rejected; an incoming SMS sender is not a paired principal, and pairing-as-authentication cannot apply. The device seam, with forced untrusted output, is the honest home.