| name | nmp |
| description | Build, review, debug, test, or plan applications and protocol modules that use the Nostr Multi-Platform (NMP) Rust, Swift, or Kotlin public facade. Use for live queries, write intents and receipts, identity/signers, diagnostics, NMPContent/NMPUI, NIP-02/NIP-22/NIP-29 helpers, lifecycle and recovery, practical feature recipes, protocol extension, and consumer-facing API verification. Do not use this as authority for unverified internals or future VISION contracts. |
NMP application development
Use NMP as an embeddable engine with two app-facing nouns: a live query and a write intent observed through a receipt. Keep navigation, ordering, moderation, presentation, account UX, and product policy in the app.
Establish current truth first
Verified-Revision: fa8ff8752826cb67376e97cf68fdf8423be575bd
This is the audited revision of the declared product/source authorities, not the skill package's own commit. A newer checkout is not automatically stale when only skill files changed; the bundled validator proves whether any declared source drifted.
- Find the NMP repo root and read
README.md, docs/known-gaps.md, and docs/architecture/supported-surface.md when present.
- Record
git rev-parse HEAD. If the checkout differs from the verified revision, inspect the current facade files listed in Source map before naming APIs.
- Identify the consumer tier: direct Rust (
nmp), Swift (NMP), Kotlin/JVM (com.nmp.sdk), or optional content/UI packages. Never substitute an internal crate or raw generated UniFFI type for its supported wrapper.
- Check Current surface and gaps. Treat
docs/VISION.md as the north star, not proof that a public method exists.
If asked to modify the NMP repository, follow its AGENTS.md: capture an issue first, use an isolated worktree and PR, update every affected projection, and test the touched surface.
Route the task
- Architecture, ownership, lifecycle, or implementation plans: Application workflow
- Concrete feed, profile, group, follow, publishing, offline, and debugging shapes: Practical recipes
- Filters, bindings, demand, rows, evidence, or pagination: Queries
- Publish, receipts, durability, accounts, local or remote signers: Writes and identity
- Restart, sign-out, reset, reconnect, teardown, or resource pressure: Lifecycle and recovery
- Relay proof screens, acquisition state, or debugging: Diagnostics
- Rust/Swift/Kotlin setup, call maps, and test commands: Platforms
- NMPContent, NMPUI, NIP-02, NIP-22, or NIP-29 helpers: Content and protocols
- Adding or reviewing a protocol module or governed cross-platform surface: Protocol authoring
- Test strategy, falsifiers, restart proof, or live smoke verification: Verification
- Exact implementation authority: Source map
- Maintaining or forward-testing this skill: Evaluation protocol and raw prompts
For a requested deliverable, copy and fill the appropriate reusable asset instead of inventing another format: application plan, protocol-module plan, feature review, or verification record.
Non-negotiable guardrails
- Do not claim global
synced, completeness, or authoritative emptiness. Report rows, per-source evidence, and explicit shortfalls.
- Do not build a second authoritative event cache or optimistic pending-row mirror in app state. Accumulate the delivered row stream for presentation state.
- Keep query ownership explicit. Swift observation is eager and cancelable; Kotlin
Flow is cold and each collection subscribes unless the app shares it.
- A publish call is not convergence. Retain and observe the receipt; persist its id when restart reattachment matters.
- Do not expose secret keys in logs, fixtures, screenshots, or source. The bundled file account stores are explicitly insecure development conveniences, not Keychain/Keystore providers.
- Do not promise write cancellation, app-controlled retries, typed pending-row metadata, populated query
AuthPhase, native maxRelays, or secure native signer persistence: those are not current cross-platform public capabilities. Receipt RetryEligible is evidence from NMP's engine-owned durable scheduler, not an app retry door. No tier exposes any application-configurable worker/task/thread capacity: #704 removed it entirely.
- Treat governed sign-only as a cancellable operation, not a write. It freezes the active author, validates the exact signed result, and creates no pending row, receipt, route, relay attempt, storage fact, or publication claim. A pending external Rust signer resolves through NMP's opaque
PendingSignerSender; do not expose or depend on its internal channel.
- There is no application-visible worker/task ceiling or capacity refusal for ordinary operations: logical waits run as async tasks on one shared engine-owned runtime, while private physical bounds use cancellable backpressure. The only genuine infrastructure outcomes are
EngineStartFailed { component, reason } when the engine cannot be constructed and ObservationUnavailable { reason } when an ordinary or windowed observe cannot open its initial canonical projection after store degradation. Relay connection/worker failure remains acquisition evidence and never constructs ObservationUnavailable. Direct Rust uses the owning EngineError variant, raw UniFFI uses FfiError, and Swift/Kotlin map them to the corresponding NMPError. Never relabel either outcome as a timeout or panic.
- Treat NIP-11 as an explicit engine-owned one-shot, not a relay stream or an app-owned cache. One engine admits at most 8 distinct HTTP/DNS/body flights; excess callers suspend cancellably in their own futures and same-relay callers share one completion, with no public capacity refusal. Service closure, credentialed-URL refusal, HTTP failure, size refusal, and invalid JSON are distinct acquisition facts. A stale-on-error snapshot preserves the last-good document and carries the refresh error separately. Reducer advertisement evidence exists only for relays in the current read plan; diagnostic freshness is derived from the engine clock and the cited document deadline. Relay advertisement never becomes behavioral capability proof.
Completion gate
Before presenting code or a plan:
- Verify every named type, method, throwing boundary, and error case in the current supported facade.
- State platform-specific gaps that affect the design.
- Show deterministic query/content/signer/engine teardown and explicit receipt-consumption ownership. Swift/Kotlin receipts have no observer-detach handle: cancelling the app task/collector ends consumption, not the native bridge or write obligation.
- Include the exact build/test commands for the chosen tier.
- Separate what the app owns from what NMP owns.
- For runnable work, test the running consumer path; compilation alone is not proof of relay, signer, receipt, or lifecycle behavior.