Native iMessage cards, described by JSON, rendered by SwiftUI.
HermesShare is an open-source iMessage App Extension that turns structured JSON into rich,
interactive cards inside Messages — package tracking, flight boards, trip plans, polls, hotel
catalogs, dashboards, and more. An AI agent (or any backend) sends a HermesLayout document
per message; a fixed native renderer draws it on device.
Apple does not let apps download and execute arbitrary Swift or SwiftUI at runtime. Code that runs on iOS must be compiled, signed, and shipped inside an App Store–reviewed binary — you cannot push new UI logic over the air the way a web app loads JavaScript. That is why you cannot simply "send SwiftUI source" in an iMessage and have it render.
HermesShare works around that constraint the same way Scriptable and Widgy do: the app ships a fixed, Apple-signed renderer, and incoming messages carry declarative JSON that selects from a known vocabulary of native views. The JSON describes what to show (a flight board, a checklist, a map preview) — it never executes code. The extension interprets the tree and builds real SwiftUI. App Store legal, no web views in the bubble, no eval.
What you CAN'T do What HermesShare does
───────────────── ───────────────────
Download SwiftUI code → Send HermesLayout JSON
Run unsigned UI logic → Map JSON → signed renderer → native SwiftUI

Courier journey
Delivery arc, live timeline, door notification CTA

Flight boarding pass
Split-flap codes, boarding status, seat and baggage rows

Trip day plan
Osaka timeline with dinner option picker
| Problem | HermesShare |
|---|---|
| Long markdown walls in iMessage | Structured cards with native UI |
| Web-view mini-apps feel disconnected | Real MSMessageTemplateLayout bubbles |
| Apple blocks arbitrary runtime UI code | JSON + signed renderer (Scriptable model) |
| Agent replies are plain text | Tap-to-reply actions insert real messages back into the thread |
Real device captures from Messages.app — tap a bubble to expand the full card.

Agent checklist dashboard
Multi-section checklist with done/pending states (NYU enrollment re-check)

System health
Gauge cluster for uptime, latency, and error rate with deploy summary

Trip itinerary — flight board
Zipair NRT → SJC hero inside a multi-day travel plan

Hotel + flight timeline
Tokyo hotel stay block and chronological departure schedule

Travel checklist
Pre-departure todos — train QR, check-in, baggage

Flight boarding pass
BR 26 TPE → SFO — split-flap board, boarding status, seat/baggage, CTA

Courier journey
Package delivery arc, live timeline, notify-at-door action

Map preview
MapKit preview with Hermes courier, vehicle details, contact driver CTA

Trip day plan
Date badge, Osaka timeline, option picker to vote on dinner

Quick reply
One-tap RSVP chips for a group dinner invite

Photo catalog
Full-bleed Kyoto hotel cards with price pills and room gallery

Weather tonight
Drawn sky scene with temperature, location, and stat strip

Market pulse
Dual sparkline tiles for NVDA and TSLA positions

Game final
Lakers vs Celtics scoreboard with field-goal percentage bars
Agent / backend iMessage Device
───────────── ──────── ──────
HermesLayout JSON ──send──► MSMessage bubble ──tap──► HermesLayoutRenderer
(base64url in URL) (thumbnail + caption) (native SwiftUI tree)
- Schema —
HermesLayoutis a JSON document: metadata + recursiveHermesNodetree. - Transport — payload is base64url-encoded in
MSMessage.url(?p=...), via PhotoncustomizedMiniApp()with anhttps://URL. - Renderer — the signed app interprets each JSON node type and builds native SwiftUI (fixed vocabulary — no downloaded code, no runtime compilation).
- Actions —
hermesshare://action?...buttons insert reply messages into the thread.
Full JSON reference: docs/LAYOUT.md
Sending guide: docs/SENDING.md
HermesShare/
├── Shared/ Swift package — schema, Codable, renderer, samples
├── HermesShare/ Host app (debug harness for fast iteration)
├── HermesShareExtension/ iMessage App Extension (MessagesViewController)
├── docs/
│ ├── LAYOUT.md HermesLayout authoring guide
│ ├── SENDING.md Photon / transport instructions
│ └── screenshots/launch/ Product screenshots (this README)
├── scripts/ Thumbnail helper, batch send, screenshot tools
└── project.yml XcodeGen project definition
- macOS with Xcode 26+
- iOS 26+ device or Simulator
- XcodeGen:
brew install xcodegen - Apple Development signing identity (free account works for Simulator and sideloading)
git clone https://github.com/time-attack/HermesShare.git
cd HermesShare
xcodegen generate
open HermesShare.xcodeprojIn project.yml, set DEVELOPMENT_TEAM under settings.base to your Apple team ID, then
regenerate:
xcodegen generateOr set your team in Xcode → Signing & Capabilities for both HermesShare and HermesShareExtension.
# Pick a simulator UDID
xcrun simctl list devices available | grep iPhone
xcodebuild -project HermesShare.xcodeproj -scheme HermesShare \
-destination 'platform=iOS Simulator,id=YOUR_UDID' \
-derivedDataPath build/DD buildInstall and launch the host app, or run from Xcode (⌘R).
Open the HermesShare app in Simulator. Use the segmented control to flip between sample
layouts, or tap {} to paste/edit live JSON and watch it render with inline validation errors.
- Run/install HermesShare on Simulator (embeds the extension).
- Open Messages → any conversation → tap + → App Store icon → HermesShare.
- In Debug Simulator builds, a compose gallery inserts sample cards into the thread.
- Tap a bubble to expand; action buttons insert reply messages.
xcodebuild -project HermesShare.xcodeproj -scheme HermesShare \
-destination 'platform=iOS Simulator,id=YOUR_UDID' \
-derivedDataPath build/DD testCovers schema round-trip, transport encoding, routing logic, and render smoke tests.
See docs/SENDING.md for Photon setup. Minimal flow:
python3 scripts/make_thumbnail.py my-card.json thumb.jpg
# … host https tunnel …
node send_card_photon.mjs '<compact-json>' '+1…' 'https://…/card.json' thumb.jpgCopy scripts/send_card_photon.mjs into your Photon sidecar directory (or run from a folder
with npm install spectrum-ts), set HERMES_TEAM_ID, and send.
{
"version": 1,
"title": "Package Out for Delivery",
"subtitle": "Order #HS-48213",
"accentColorHex": "#34C759",
"root": {
"type": "vstack", "spacing": 12,
"children": [
{ "type": "statusBadge", "label": "Out for delivery", "colorHex": "#34C759" },
{ "type": "progressBar", "value": 0.78, "colorHex": "#34C759" },
{ "type": "keyValueRow", "key": "Carrier", "value": "UPS Ground" }
]
},
"actions": [
{ "id": "track", "label": "View full tracking", "systemImage": "location.fill",
"deepLinkURL": "hermesshare://action?id=track" }
]
}More examples live in Shared/Sources/HermesShared/HermesSampleLayouts.swift and
Shared/Tests/HermesSharedTests/Fixtures/.
Contributions welcome — especially new HermesNode types, renderer polish, and fixture cards.
Open an issue before large schema changes. See CONTRIBUTING.md.
MIT — use freely, attribution appreciated.
Built for Hermes agent-driven iMessage via Photon. Inspired by Scriptable and Widgy's declarative native UI model.