# Jumping Beans native iMessage entry prototype

This directory is a build-oriented native iMessage App Extension source
prototype for the Jumping Beans allowable-actions/chains thesis. It is kept
isolated from the web engine and does not pretend that a static HTTPS page is
an iMessage app.

The prototype demonstrates a real Messages extension flow:

1. Open Jumping Beans from the Messages app drawer.
2. Review the carried-in offer and its provenance.
3. Select one allowable next action: **Compare**, **Adapt presentation**, or
   **Preview handoff**.
4. Review and approve the exact action, offer, provenance, and boundary fields.
5. Create an `MSMessage` with an `MSMessageTemplateLayout` fallback and a
   native `MSMessageLiveLayout` for transcript presentation.
6. Call `MSConversation.insert(_:)` to stage the message in the composer. The
   person still taps Messages' Send button; the extension never auto-sends.

## Important boundary

This is a native iMessage surface, not a WebMCP runtime. The extension does
not call `document.modelContext`, discover partner tools, open a mobile HTTPS
share, use `URLSession`, use `WKWebView`, or claim that WebMCP runs inside
Messages. The sample offer carries explicit web-journey provenance so the
message can say where it came from without implying that Messages verified or
invoked that source.

`MSMessage.url` uses the `jumpingbeans://` app-local payload scheme only to
identify the staged message when a recipient opens it. It is not a network
handoff and contains no credentials, profile data, or partner operation.

## Host setup in Xcode

Xcode is required to build and run an iMessage App Extension. This host has
Swift command-line tools but no full Xcode installation, so no `.xcodeproj` or
compiled app is claimed here.

1. In Xcode, create a new **iOS App** named `JumpingBeansMessages` using Swift
   and UIKit. Use a development team and a unique bundle identifier.
2. Add a target with **File → New → Target → Messages Extension**. Name the
   extension `JumpingBeansMessagesExtension` and keep **Embed in Application**
   enabled.
3. Replace the generated extension controller with
   `MessagesViewController.swift` and add `NativeActionModel.swift` to the
   extension target. Do not add either file to the host app target.
4. In the extension target's Build Settings, set the deployment target to
   iOS 16.0 or later, and link `UIKit.framework` and `Messages.framework`.
5. Use this directory's `Info.plist` as the extension target's plist, or copy
   its `NSExtension` dictionary into the generated plist. Xcode expands
   `$(PRODUCT_MODULE_NAME)` during the build.
6. Select the host app scheme, choose an iOS Simulator or a signed test iPhone,
   and build/run. The host app only exists to install the extension; the
   extension's UI is opened from Messages.

## Manual demo / test

1. Open **Messages** and enter a conversation on the simulator/device.
2. Tap the app-drawer button beside the composer, then choose **Jumping
   Beans**. This is the native extension entry point.
3. Select each action and confirm that the boundary copy changes. Observe that
   the offer always retains `Petsupply`, `WebMCP offer tool`, its origin,
   observed time, and “not independently verified” status.
4. Turn on all four approval switches. The stage button must remain disabled
   until every exact field is approved.
5. Tap **Stage native message**. Verify that the message appears in the
   Messages composer and that the extension reports that Send remains a human
   action. Do not tap Send if testing the no-send boundary.
6. If you do tap Send, open the native message bubble. The live layout should
   reopen the extension in transcript presentation; if live presentation is
   unavailable, Messages uses the template fallback.
7. Confirm that no browser opens, no network request is made, and no order,
   payment, account change, partner write, or saved Jumping Beans memory is
   created by this prototype.

## Local checks available on this host

From `products/jumping-beans`:

```bash
node experiments/native-imessage-entry/validate.mjs
```

The check validates the plist, parses the Swift sources with `swiftc -parse`,
and checks the native API and boundary markers. It cannot type-check
`UIKit`/`Messages` or build the extension without the full Xcode SDK.
