Repository navigation
Inbox mobile: the wire contract (C1) - #1775
Merged
Merged
Conversation
The pairing offer and QR link, the device token door and its allowlist, the LAN listener, the relay's routes, envelope and push payload, the surface bridge, the idempotency rule, and a curl exchange per route. No product code.
The relay switch is PUT .../carriage, kept in the device record, and a reconnect registers only devices with carriage on. Screen 1.3's tailnet list is the known computers plus a typed address (no discovery). The raw attachment route is gone: Share uses view. Section 9 now records the coordinator's rulings in place of the open questions.
1 task
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.
The story
The iPhone app, the Inbox's device door, the LAN listener, the relay Worker and the surface bridge need one frozen wire before two lanes build them in parallel. This PR adds that wire as
adr/implementation/inbox-mobile.md, in the style ofguide-share-hosting.md, matched to the Inbox's handlers as they are on main. It is step C1 of the mobile plan; no product code changes.What the file holds
POST /api/inbox/pairing(window route, window guards),plannotator://pair?v=1&name&tailnet&lan&fp&secret&code, and the tailnet publication on 8443.POST /api/inbox/device/pair(secret or six digits, answering atok_bearer),inbox/devices.jsonl, list and revoke, and/api/inbox/device/*as an explicit allowlist of 23 routes mapped onto the window's handlers, each with the request and answer it has today. It also names what the door never answers (/mcp, the bridge, control, settings, restart, project delete, decision retire and replace), the door's guards in order, and its error codes. A non-loopback Host (the tailnet) reaches the door and nothing else.inbox/tls/, its SHA-256 pinned by the phone and carried in the QR and in Bonjour_plannotator-inbox._tcpTXTv,fp.packages/core/crypto.ts's exact layout underK = HKDF-SHA256(S, device id, "plannotator-inbox relay key v1")), the relay secret derivation, the push plaintext and the APNs body, and what the relay stores and deletes.packages/core/inbox-surface-bridge.tsv1: seven messages to the surface and eight back, the asset scheme and the<base href>rewrite.idempotency_keyin the body of every phone command, the door's replay loginbox/device-commands.jsonl, and the relay commandidset to the same key.Plus one line in AGENTS.md's Inbox section pointing at the file.
Limits named once
An offer lives 10 minutes. Its six-digit code closes after 5 wrong tries. The relay's mailbox creation reuses guides.show's existing brake, with no new number. Apple's ceilings (a 4096-byte push body, four actions) are named where they apply. There are no other limits.
Review fixes (REVIEW-PLANNOTATOR-MOBILE-C1-2026-10-08, head c4a2f0e)
PUT /v1/mailboxes/:mbx/devices/:dev/carriage { on, cursor? }(device bearer, exchange 7.35). The state lives in the device record (carriage) and inhello. A reconnect registers only non-revoked devices with carriage on that the relay does not list, and a device that turned carriage off stays listed, so it is never registered again.DELETE .../devices/:devis the Inbox's alone, on revoke.host:portthe Inbox prints. This matches the render's own caption for 1.3 ("A tailnet cannot be listed from another app, so the tailnet row takes the address the Inbox prints"), so it is a reading of the record, not a change to it.view'stextto a file namedattachment.name. Exchanges 7.16 to 7.35 moved down one number.Also from the review's items, because each is one sentence: exchanges for the window's device list and revoke (7.36, 7.37), Edit as a re-save with the same annotation id,
Idempotent-Replayedas the replay signal, and the shell fetchingviewagain after an asset 404.Additions beyond the brief's lists, each needed to work (three)
GET healthon the door, as the phone's reachability probe for 9.2.POST revokeon the door, for "Remove this source".message_id,key,revisionandcontextin the push plaintext (the lock-screen Send needs the first three, and render 7.1 draws the context). The surface'sannotationmessage andfocusfield (4.3, 3.6) come with the bridge.Rulings written in (section 9 of the file; no open questions remain)
mailboxis out of the QR. The redemption's answer carries the relay.carriageroute, as above.ack { cursor }).opensslanddns-sd(avahi-publishon Linux) run as child processes, with no dependency.inbox.json. When another mapping holds it, the window says so and never overwrites it.What it leaves out
Workspaces (W0 to W2), FCM and Android, the iPad, mailbox deletion, retention sweeps, relay rates, attestation, request signing, re-authentication, and every computer-chore route.
Gates
bun run check:release-version: green (v0.28.8).bun run typecheck: green.gitleaks git . --config .gitleaks.toml --log-opts="origin/main..HEAD": no leaks.