Audited all 143 plan files across the 10 plans/ folders. Each plan now carries a Status header (shipped | in-progress | queued | abandoned) backed by codebase evidence, and every folder has a README.md index grouping plans by status. Shipped plans were moved into a per-folder plans/archive/ (via git mv, history preserved) so each plans/ folder surfaces only live work: shipped (archived): 122 in-progress: 8 queued: 7 abandoned: 4 docs/plans/ is the frozen legacy folder; its plans were stamped and indexed in place (48 of 52 archived) but it remains closed to new plans. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016hpUivtmq4pgzqRbY6MYrA
5.0 KiB
Napplet inter-applet communication (NAP-INC / NAP-INTENT) — design notes
Status: queued — Explicitly deferred; no
MESSAGINGcapability exists inNappletCapabilityand the prerequisites (multi-applet hosting, archetype registry) are unbuilt. Audited 2026-06-30.
Date: 2026-06-20
Status: Deferred — design only. Prereqs not yet built (see below).
Parent: amethyst/plans/2026-06-19-napplet-sandbox-host.md
Why this is deferred (not just "next")
Inter-applet messaging is the one napplet capability that needs new architecture, not just a new broker op + gateway. Two hard prerequisites are missing today:
- Multiple applets running at once.
NappletHostActivityis declaredlaunchMode="singleTask"and hosts exactly one applet. True live A↔B messaging (the full NAP-INC request/result transport) requires either multi-applet hosting (several iframes in one host, or several host processes) plus a routing layer — none of which exists. - An archetype / handler registry. NAP-INTENT dispatches by archetype
(
note,feed,profile, …) to a default-handler napplet. OurNappletManifesthas nohandles/archetype declaration and there is no "which napplet is the default handler for X" registry.
Both are sizeable subsystems. Shipping a half-version would also risk forking the wire format from upstream while it is still being defined.
Upstream model (napplet/naps survey, 2026-06-20)
Inter-applet is split into two shell-mediated specs (applets never reach each other directly — every message crosses the shell/broker):
- NAP-INC (
inc) — the transport. Messages are{ type: "domain.action", id, … }, request/result correlated byid. Addressing is direct (napplet→napplet) or archetype-mediated by the runtime. - NAP-INTENT (
intent) — invoke a napplet by archetype via default-handler dispatch (shell.supports("intent")). The shell launches the handler; napplets cannot invoke directly. - NAP-1…5 — concrete protocols on top of NAP-INC:
profile:*(NAP-1),stream:*(NAP-2),chat:*(NAP-3),note:open(NAP-4),feed:*(NAP-5). Producer/consumer model.
Discovery is capability-probe based: shell.supports("inc"),
shell.supports("inc", "NAP-N").
How it would map onto our boundary
The broker model fits "shell-mediated" naturally — every message would cross
NappletBrokerService exactly like every other capability, gated by the ledger.
The pieces:
- Capability. Add
NappletCapability.MESSAGINGmapped from NAP domainsinc/intent(default-deny like every other domain). Consent is a link grant ("Applet A may message / open Applet B"), distinct from per-op consent. - Protocol. New
NappletRequest/NappletResponsevariants underMESSAGING, shaped to mirror NAP-INC (type = "domain.action",idcorrelation) so we don't fork the wire format. - Addressing. Direct by napplet coordinate first; archetype dispatch only after the registry (below) exists.
Two viable implementation shapes (pick at build time)
- NAP-INTENT, direct coordinate —
napplet.intent({ target, payload })→ consent → broker resolvestargetto a manifest inLocalCache→ launches it via aNappletIntentLaunchergateway, passing an initial payload the target reads on startup (napplet.intent/onIntent). Fits the single-applet model (you switch to the target). No simultaneous hosting needed. Lowest lift; most aligned with NAP-INTENT. Result-return across the switch is awkward (fire-and- forget, or a callback event). - NAP-INC brokered mailbox —
napplet.sendTo(coordinate, msg)/pollMessages()with broker-persisted per-napplet inboxes, consent per link. Works with no simultaneous hosting and is fully unit-testable, but it is async fire-and-collect, not the request/result transport upstream describes.
Full live NAP-INC (simultaneous A↔B, request/result) needs the multi-applet hosting prereq regardless.
Prerequisites to build first
- Multi-applet hosting — either N iframes in one
NappletHostActivitywith per-iframe origin isolation + routing, or a host-per-applet process model and a cross-process router in the broker. Decide the model before coding NAP-INC. - Archetype registry — a manifest
handles/archetype tag (align with upstream naps), an index over installed napplets, and a user-set default handler per archetype (mirror NIP-89 handler selection, which Amethyst already models for app recommendations). - Link-consent UX — distinct from capability consent: "Allow Chess to open Wallet?", revocable per pair in a permissions screen.
Recommendation
When picked up: start with NAP-INTENT direct-coordinate (smallest, aligned,
no new hosting), build the archetype registry next (unlocks default-handler
dispatch + reuses NIP-89 patterns), and only then tackle live NAP-INC once
multi-applet hosting lands. Keep the wire type/id shape identical to upstream
NAP-INC throughout to avoid a fork.