NIP-5D · workshop path

Build your first napplet.

Start with the maintained template. Run it inside a real host shell. Leave with a verified, single-purpose Nostr app.

45 minutes Node.js 20+ Deno 2 Alpha
00

Understand the split

Your napplet draws the UI. The shell holds authority.

A napplet is a small web app in a sandboxed iframe. It asks its host for identity, relays, signing, storage, and other capabilities through typed messages.

Napplet UI + product logic
Untrusted and sandboxed
Host shell Keys + relays + policy
Trusted by the user
Today’s host: Paja

Paja runs your app inside the Kehto runtime and shows interfaces, permissions, signer state, and every protocol envelope.

01

Prepare your machine

Install the app toolchain and the local host.

Node.js 20+
Current LTS is fine.
pnpm 10
Package manager.
Git
Used by the scaffold.
Deno 2
Runs the Kehto host CLI.
Chromium browser
Chrome, Brave, or Edge.

Check the basics

corepack enable
corepack prepare pnpm@10.8.0 --activate

node --version     # v20 or newer
pnpm --version     # v10
git --version

Install Deno and the Kehto host

# macOS or Linux
curl -fsSL https://deno.land/install.sh | sh

# Windows PowerShell
irm https://deno.land/install.ps1 | iex

Open a new terminal, then install and check Kehto:

deno install --global --allow-all --name kehto npm:@kehto/cli
deno --version
kehto --help

Install the napplet CLI

# macOS or Linux
curl -fsSL https://napplet.run/install.sh | sh

# then check it
napplet guide
# Windows PowerShell
irm https://napplet.run/install.ps1 | iex
napplet guide

The installer downloads a standalone binary and verifies its checksum. Deno is not required.

02

Create the project

Use the maintained starter. Let the CLI own metadata.

napplet create my-napplet
cd my-napplet
napplet init
napplet skills install --to codex
pnpm install

During napplet init, choose a short name, a clear title, the closest archetype, and the workshop relay and Blossom server supplied by your facilitator.

Keep the generated structure

Edit the app surfaces in src/. Keep the Vite, single-file, conformance, and .napplet/config.json wiring intact.

03

Build one small thing

Napplets should be focused. Pick one job.

There are four valid ways in. Today we are taking the agentic path with the installed skills.

Boilerplate Packages Protocol

Prompt your coding agent

Use the installed napplet skills to build a one-screen note composer. Autosave the draft through shell storage, show the connected pubkey, and publish through the outbox. Keep the existing scaffold and verify the result.

Prefer @napplet/sdk. Normal Nostr reads and writes go through outbox. Persistent state goes through storage. The shell—not your app—signs and talks to relays.

The boundary in four lines

const draft = await window.napplet.storage.getItem('draft');
await window.napplet.storage.setItem('draft', text);

const pubkey = await window.napplet.identity.getPublicKey();
await window.napplet.outbox.publish(eventTemplate);
04

Run inside Paja

A raw Vite tab is not a napplet host.

kehto paja --target-url http://127.0.0.1:5173 \
  -- pnpm vite --host 127.0.0.1

Open the printed Paja runtime URL, not the Vite target URL. Paja keeps hot reload while hosting the app in a real sandboxed Kehto iframe.

If kehto cannot be spawned

Open a new terminal and run kehto --help. If it is still missing, add ~/.deno/bin to PATH, then retry the Paja command.

  • Use a NIP-07 signer when you have one available.
  • Otherwise select the Dev signer for disposable signing.
  • Use Interfaces to test a missing capability.
  • Use ACL to grant or deny an operation.
  • Watch Messages to see each request and response.
The Dev signer is a fallback

Its ephemeral identity has no follows, relay history, or web of trust. Napplets that depend on that context may look empty or remain unavailable. Paja prompts before every sign or publish operation, whichever signer you choose.

05

Verify the artifact

Build, test the sandbox contract, then inspect the plan.

pnpm verify
pnpm test:conformance
napplet debug
napplet deploy --dry-run

You are done when all four pass and Paja can exercise the app without errors.

Workshop finish line

A single-purpose napplet, hosted in Paja, responsive at small sizes, and clean under conformance. Publishing is a separate step.

06

Keep the boundary clean

If the shell owns it, ask the shell.

  • Never place an nsec in source, config, prompts, or shell history.
  • No direct WebSocket, relay pool, or window.nostr.
  • No browser localStorage; use the storage interface.
  • No direct external assets or fetch by default; use the resource interface.
  • Declare only capabilities the napplet cannot work without.
  • Handle absent optional interfaces without crashing.
07

Read the source material

Short path first. Protocol details when needed.