An opinionated shell for sandboxed applets, built on kehto.
The person at the keyboard is the only principal that matters.
Try the shell · Website · Docs · About · Why
Alpha. kernl is a first draft: the guard, the contracts, the composition over kehto and the shell are real and tested; private, legacy and ratchet messages work for accounts that can encrypt (ratchet sessions are experimental), and downloads, sharing and mail only hand off to apps on your device. The source is private and the packages are not released yet, neither as
@kernlize/*on npm nor as@kernl/*on JSR; the site and docs are public. Readdocs/alpha-status.mdbefore relying on anything, and note that the badges are measured bypnpm checkand an agent-readiness scan, not live CI.
kehto is an unopinionated set of packages for building a NIP-5D applet shell. It does not pick a relay library, a signer, a consent model, a layout or a deployment story. kernl picks all of them, and writes each choice down.
| kehto leaves open | kernl decides |
|---|---|
| Event layer | applesauce v7, and nothing else |
| Security posture | Every mitigation kehto offers, on by default, strict profile |
| Grants | Restrictive. Applets see what the user granted, even which account is signed in, keyed by verified artifact hash |
| Consent | Writes are shown as what they change, not as JSON |
| Messaging | Any reasonable private-message protocol, described truthfully, never ranked |
| Other protocols | Bridged to one identity layer and named by what they do: downloads, sharing, mail |
| Public voice | The website never names a protocol. Protocols are plumbing; the person is the point |
The full reasoning is in SOUL.md. Each concrete choice is in DECISIONS.md.
- Runs applets in a sealed frame. Verified bytes run in a
srcdocframe withsandbox="allow-scripts", a zero-network CSP, no WebRTC and a lock against frames of their own (D-014). A browser spec tries every way out; when the host page can reach a public STUN server, it asserts that it does and that the applet produces no such candidate (Security posture). - Shares your account only when you say so. An applet is not told which account is signed in until you grant "your account", and every network domain is a separate grant, keyed to the verified build (Identity and grants).
- Asks before it signs anything destructive. A write that replaces or erases part of your public record is shown as before → after and waits for your answer; routine writes are signed without a prompt (Consent).
- Guards by default. Eleven protections ship on in the strict profile: kernl drops oversized requests, bursts and requests over the smaller budget of an applet you are not using before they are handled, holds a hidden applet's requests until you can see it, and quarantines an applet that floods; kehto's runtime firewall refuses over-rate requests on top (Guard). The hosted shell boots strict and only you loosen it; an embedding host may choose the starting profile, which changes limits only.
- Messages across providers. One messenger over several private-message providers, each described by its properties and none ranked. Messages are an applet like any other, shipped with the shell; you put the providers in order, and when someone last wrote to you through a different one, the shell asks before it answers for you. Private, legacy and ratchet messages work in the live shell when you sign in with an account whose signer can encrypt (browser extension, remote signer, local account). Ratchet sessions are experimental: your correspondent needs an app that speaks them, and the session keys are kept on this device, locked by your account (Alpha status). Group sessions are experimental too: everyone in the group needs an app that speaks them, and the group's keys change as it talks and as people join or leave (Messaging).
- Bridges other networks. Web fetch works behind an SSRF policy (
httpsonly, private addresses blocked, redirects refused in the browser). Magnet links download inside the shell page over WebRTC, with a Downloads panel to pause, resume, remove and save, or go to an app on your device if you choose that in Settings (D-017). NZB downloads, sharing and mail hand the link to an app on your device after you confirm leaving kernl, because a browser page cannot open the raw TCP sockets their protocols need; kernl connects to nothing for them (Bridges). - A store, and applets that hand work to each other. The shell lists published applets with loose search and topic bubbles, and still opens any pasted address. When one applet asks another to open a profile or edit a note, the user picks which applet does it, once or always.
- Previews without an account.
/app/?preview=1runs the shell offline with the core's own consent rule, kernl's guard in strict and a store of three preview applets. Refusals before dispatch need kehto's runtime, so they happen only in the live shell (Run the shell).
| npm | JSR | Purpose | Docs |
|---|---|---|---|
@kernlize/guard |
@kernl/guard |
Ingress flood control, visibility gating, focus-aware firewall, CSP profile, nested-frame lock, mitigation descriptions. Pure. | guard |
@kernlize/messaging |
@kernl/messaging |
Provider contract, registry, composite direct-message adapter, three providers. Pure. | messaging |
@kernlize/bridges |
@kernl/bridges |
Locator parsing, bridge contract, registry, HTTP bridge with SSRF policy, backend interfaces, hand-off backends, in-page download backend. Pure. | bridges |
@kernlize/core |
@kernl/core |
Composition root over kehto and applesauce: adapters, applet resolution, mount plan, consent summaries, layouts and a replaceable window manager. | core |
Published packages have zero framework dependencies and never import nostr-tools directly. pnpm check:deps (scripts/check-dependency-rules.mjs) enforces both.
packages/guard @kernlize/guard pure
packages/messaging @kernlize/messaging pure
packages/bridges @kernlize/bridges pure
packages/core @kernlize/core kehto + applesauce composition
apps/web @kernlize/web Astro site at /, shell at /app/
docs @kernlize/docs VitePress at /docs/
features shared step support for the package features
tests/e2e Playwright browser suite
scripts build, audit and guard scripts
No install: open the preview. It runs the shell in your browser, offline, with the live shell's consent and guard behaviour, a store of preview applets and a throwaway account.
From source, for maintainers only during the alpha, because the repository is private (Node 22 or newer, pnpm 10 via corepack enable):
git clone https://github.com/kernlize/web.git kernl && cd kernl # maintainers only during alpha
pnpm install
pnpm build # the site imports the built packagesThen run each dev server in its own terminal:
pnpm site:dev # landing site and shell, http://localhost:4321/app/
pnpm docs:dev # documentation, http://localhost:5173/docs/In the shell, sign in with a browser extension, a remote signer or a local account, and paste an applet's address. pnpm docs:dev serves the Markdown pages only, not the generated API reference; pnpm site:build && pnpm site:preview builds the site, the docs and the API reference into .pages/ and serves them at http://127.0.0.1:4178/.
Applets are ordinary NIP-5D napplets; kernl changes the posture, not the wire format. Write an applet builds one, tests it against the guard, publishes it and opens it in the shell. Applets under kernl lists what an applet meets here and how to test against it.
pnpm checkThat runs, in order: build, type-check, features with 100% coverage, dependency rules, docs gate, site build, public-vocabulary scan, agent-readiness audit, slop gate. pnpm test:e2e adds the browser suite, which drives both the preview and the live shell; the live shell runs against relays and blob servers that exist only inside the test browser, so it needs no network. PLAYWRIGHT_BASE_URL=https://kernl.run pnpm exec playwright test runs the suite against the live site, and adding KERNL_PUBLIC_NETWORK=1 also opens the published applets listed in tests/e2e/shell-live-network.spec.ts over the public network. pnpm site:publish publishes.
Every behaviour is a Gherkin scenario before it is code. This is an excerpt from packages/guard/features/visibility.feature; the omitted scenarios are marked with # …:
Feature: Visibility gate
Hidden windows should not fetch or publish while the user cannot see them.
Their traffic waits and is drained when they return; control messages are
never held so a hidden window can still be closed or themed.
Background:
Given a guard visibility gate using the "strict" profile
# … two scenarios on what the gate believes about visibility
Scenario: hidden windows defer everything except control
When the guard gate marks window "w1" as "hidden"
Then the guard gate defers "relay:subscribe" for window "w1"
And the guard gate defers "resource:bytes" for window "w1"
And the guard gate does not defer "control" for window "w1"
# … seven more scenarios: visible windows, draining, the full queue, forgetting a windowThe scenarios specify the gate's own API. In the composed shell an applet's traffic travels over a port kehto owns; kernl's pipeline decides each envelope before the runtime sees it, and kehto holds a hidden window's requests until kernl releases them.
Features live in packages/*/features/ and run inside vitest through quickpickle. Coverage thresholds are 100% across statements, branches, functions and lines.
The docs are a product. Start at docs/index.md, or on the site at /docs/. Agents can read /llms.txt and /docs/llms.txt; every page has a Markdown twin, except the generated API reference, which is HTML only.
| Need | Page |
|---|---|
| Know what works and what does not | Alpha status |
| See what each release ships | Changelog |
| Run the shell locally | Run the shell |
| Write an applet and open it in kernl | Write an applet |
| Write an applet that runs well under kernl | Applets under kernl |
| Build a page that runs an applet | Embed kernl in a page |
| Embed the shell core in your own page | Embed kernl core |
| Understand the layering | Architecture |
| Understand what protects the user | Guard |
| Understand grants and identity | Identity and grants |
| Add a messaging provider | Add a messaging provider |
| Add a bridge backend | Add a bridge backend |
| Fix a failure | Troubleshooting |
| Look up an error reason | Error reasons |
| Browse the API | API reference |
| See why each choice was made | Decisions |
- kehto supplies the runtime, shell adapter, services, ACL, firewall and NIP-5D verification. kernl composes them and takes gaps upstream instead of forking; the first four (kehto/web #397–#400) are released and in use. See
DECISIONS.mdD-001 and D-020. - The applet format is NIP-5D with per-domain NAPs. Applet-side packages and the format's own site live at napplet.run.
- applesauce is the event layer.
Packages use @kernlize/* on npm and @kernl/* on JSR, with matching versions. See publishing for registry setup and release commands.
Read AGENTS.md. It is written for agents and applies to people. Branch per concern, specify behaviour before code, keep docs in the same PR, keep the slop gate at 100.
MIT

