# Getting started

This page walks you from zero to a deployable napplet. The standalone `napplet` CLI provisions its own cached tooling and does not require host Node.js, npm, npx, or Deno, including for screenshots and conformance. You will need Node.js 20+ and a package manager to develop the generated Vite project or use the optional skills.sh CLI. To actually *run* a napplet you also need a host shell — see [running in a shell](#running-in-a-shell) at the end.

## 1. Install the CLI

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

```powershell
# Windows PowerShell
irm https://napplet.run/install.ps1 | iex
```

Each installer downloads the platform binary and verifies it against the release's `SHA256SUMS` before replacing `napplet`. The [`@napplet/cli`](https://napplet.run/docs/packages/cli.md) page documents the JSR/Deno alternative.

Run `napplet guide` at any point for the complete command sequence and links to the documentation for each stage.

## 2. Create the project

```bash
napplet create my-napplet
cd my-napplet
```

`napplet create` delegates to the maintained [`github.com/napplet/boilerplate`](https://github.com/napplet/boilerplate) template. The generator creates the project and derives only its package name; it does not own deployment name, title, or archetype metadata.

## 3. Initialize deployment metadata

```bash
napplet init
```

The wizard writes `.napplet/config.yaml` with the named-manifest d-tag, title, optional description, queryless `napplet:<archetype>/<intent>` convention metadata, relays, and Blossom servers. Automation can provide the same values explicitly:

```bash
napplet init --name my-napplet --title "My Napplet" \
  --archetype napplet:note/open \
  --relay wss://relay.example --server https://blossom.example
```

The CLI validates the documented `napplet:<archetype>/<intent>` shape and deploys the complete queryless convention identity.

At runtime, INC `emit` and intent `invoke/open` may accept `napplet:<archetype>/<intent>?name=value` developer input. Their bindings transpose query pairs to text payload fields before sending a queryless normalized identity. Subscriptions, manifest discovery, and handler routing do not parse queries and use exact equality.

## 4. Install agent skills

```bash
npx skills add napplet/web
```

The open [skills CLI](https://skills.sh) detects the coding agents on your machine (Claude Code, Codex, Cursor, Gemini CLI, Copilot, and many more) and installs the `napplet-*` skills where each agent reads them. Add `-g` for a global install, `--skill napplet-make` for a single skill, or `-a claude-code` to target one agent. See [Agent skills](https://napplet.run/docs/guide/agent-skills.md) for what each skill does.

## 5. Build and verify

```bash
pnpm install
# Ask your agent to build the napplet.
pnpm verify
pnpm test:conformance
```

## 6. Preview, then deploy

```bash
napplet deploy --dry-run
napplet deploy
```

The dry run resolves the same config, files, metadata, and manifest events without uploading or publishing. Configure a local or remote signer before the live deploy; see [`@napplet/cli`](https://napplet.run/docs/packages/cli.md#deploy).

Choose the Note Drafts path that matches how you want to learn:

- [Build a Note Drafts napplet from scratch](https://napplet.run/docs/guide/build-note-drafts-napplet.md) hand-wires
  every file so you can see the runtime boundary one piece at a time.
- [Build a Note Drafts napplet from boilerplate](https://napplet.run/docs/guide/build-note-drafts-napplet-from-boilerplate.md)
  starts from the generator, preserves its project substrate, and replaces the
  starter demo with the same note composer.
- [Build a Note Drafts napplet with an AI agent and the napplet skills](https://napplet.run/docs/guide/build-note-drafts-napplet-with-ai-agent-and-skills.md)
  shows the prompt, review loop, and verification commands for agent-assisted
  authoring.

All three create a small Nostr note composer that autosaves through `storage`, reads the shell-user pubkey through `identity`, publishes through `outbox`, and runs in Kehto/Paja.

## Retrofit an existing app manually

For a new napplet, prefer the generator above. It owns the package manager pin, Vite config, single-file build plumbing, scripts, conformance wiring, and starter layout. Use manual wiring only when you are adding napplet support to an existing app.

Install the napplet-side SDK:

```bash
npm install @napplet/sdk
```

And the build-time Vite plugin as a dev dependency, which generates the signed NIP-5A manifest event:

```bash
npm install -D @napplet/vite-plugin
```

```ts
// vite.config.ts
import { defineConfig } from 'vite';
import { nip5aManifest } from '@napplet/vite-plugin';

export default defineConfig({
  plugins: [nip5aManifest({ nappletType: 'my-napplet', artifactMode: 'single-file' })],
});
```

Mirror the boilerplate scripts so verification stays consistent:

```jsonc
{
  "scripts": {
    "build": "vite build",
    "type-check": "tsc --noEmit",
    "verify": "npm run type-check && npm run build",
    "test:conformance": "npm run build && napplet-conformance ./dist"
  }
}
```

## Build your first napplet

NIP-5D runtimes inject `window.napplet` before your code runs. Napplet code can use the injected namespace directly:

```ts
// main.ts
// Read kind 1 notes through the shell's outbox-aware routing
const { events } = await window.napplet.outbox.query(
  [{ kinds: [1], limit: 20 }],
  { timeoutMs: 3000 },
);
for (const result of events) console.log('Note:', result.event.content);

// Subscribe to live updates through the same outbox boundary const sub = window.napplet.outbox.subscribe([{ kinds: [1], limit: 20 }], {   timeoutMs: 3000, }); sub.on('event', (result) => console.log('New note:', result.event.content));

// Publish a note — the shell signs and fans it out; your napplet never sees the key
const published = await window.napplet.outbox.publish({
  kind: 1,
  content: 'Hello from my napplet!',
  tags: [],
  created_at: Math.floor(Date.now() / 1000),
});
if (!published.ok) throw new Error(published.error ?? 'publish failed');
```

Notice you never imported a signing library and never touched a relay socket. The runtime sends `outbox.query`, `outbox.subscribe`, and `outbox.publish` JSON envelopes; the shell does relay discovery, signing, fanout, and policy.

## Runtime injection vs. SDK

Runtimes and napplets use different packages.

| | [`@napplet/shim`](https://napplet.run/docs/packages/shim.md) | [`@napplet/sdk`](https://napplet.run/docs/packages/sdk.md) |
| --- | --- | --- |
| **Import style** | `import { installNappletGlobal } from '@napplet/shim'` | `import { outbox, inc, intent } from '@napplet/sdk'` |
| **Who uses it** | Host runtime before napplet scripts execute | Napplet application code |
| **What it does** | Injects selected `window.napplet.<domain>` objects | Named, typed exports that wrap injected domains |
| **Required?** | Required for runtimes that use these packages | Optional convenience for bundler users |

The **sdk** is an ergonomic, typed wrapper. Its methods delegate to `window.napplet.*` at call time and throw a clear error if the runtime did not inject the namespace or requested domain.

Typical napplet code imports only the SDK:

```ts
import { outbox, inc, intent, storage } from '@napplet/sdk';
```

If you're writing a vanilla napplet with no build step, you can skip the sdk and use the injected `window.napplet.*` namespace directly.

For cross-napplet intent, call `intent.invoke(uri, options?)` or `intent.open(uri, options?)` with a convention URI such as `napplet:profile/open?pubkey=abc123`. An `ok: true` result means the runtime accepted delivery responsibility; it does not mean the target has already handled anything. An `ok: false` result carries `error`. The target receives the delivery through `intent.onDelivery(handler)` as a separate push with a runtime-attested `sender`, independent of the source lifetime and without any NAP-INC dependency. This is non-normative orientation; the living [NAP-INTENT](https://github.com/napplet/naps/blob/master/naps/NAP-INTENT.md), [NAP-INC](https://github.com/napplet/naps/blob/master/naps/NAP-INC.md), and [web projection](https://github.com/napplet/naps/blob/master/projections/web.md) documents are authoritative.

## Running in a shell

A napplet only does something when hosted by a compatible **shell** — the trusted runtime that owns keys, relays, and storage and proxies your requests. The reference runtime is **Kehto**.

> **TIP**
>
> The reference shell/runtime is **Kehto**:
> [github.com/kehto/web](https://github.com/kehto/web).
> You can also find napplet projects under the
> [github.com/napplet](https://github.com/napplet) organization.
> For questions and coordination, join the
> [community group chat](https://armada.buzz/invite/naddr1qvzqqqyzz5pzpjk98hj7z978r9xc9d2ymagw6tga0lx0s06y8lhpy9twc2kp8uwdqqqqpwqpw5#BAACAwTDEKKhS9_iA_qOc1n4ljVt).

Next, read [Core concepts](https://napplet.run/docs/guide/concepts.md) to understand the envelope, NAPs, the sandbox model, identity, and storage scoping.

### Terminal and automation options

`napplet init` and `napplet deploy` guide you through missing settings in a terminal. Deployment previews and results use readable sections, and network deployments show upload and relay progress. For automation, add `-i` / `--non-interactive` and supply values through flags or configuration. CI and redirected streams never trigger prompts. Use `napplet deploy -i --json` for machine-readable results and `--no-color` for plain display. See the [CLI reference](https://napplet.run/docs/packages/cli.md) for all options.
