Files
com.vitorpamplona.amethyst/amethyst/plans/2026-06-20-napplet-inter-applet.md
Claude 6579b5f656 docs: audit, status-stamp, and index all module plans
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
2026-06-30 15:35:38 +00:00

5.0 KiB

Napplet inter-applet communication (NAP-INC / NAP-INTENT) — design notes

Status: queued — Explicitly deferred; no MESSAGING capability exists in NappletCapability and 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:

  1. Multiple applets running at once. NappletHostActivity is declared launchMode="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.
  2. An archetype / handler registry. NAP-INTENT dispatches by archetype (note, feed, profile, …) to a default-handler napplet. Our NappletManifest has no handles/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 by id. 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:

  1. Capability. Add NappletCapability.MESSAGING mapped from NAP domains inc / intent (default-deny like every other domain). Consent is a link grant ("Applet A may message / open Applet B"), distinct from per-op consent.
  2. Protocol. New NappletRequest/NappletResponse variants under MESSAGING, shaped to mirror NAP-INC (type = "domain.action", id correlation) so we don't fork the wire format.
  3. 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 coordinatenapplet.intent({ target, payload }) → consent → broker resolves target to a manifest in LocalCache → launches it via a NappletIntentLauncher gateway, 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 mailboxnapplet.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

  1. Multi-applet hosting — either N iframes in one NappletHostActivity with 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.
  2. 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).
  3. 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.