Skip to content
kernlizePublic

About

a kernl for running untrusted applets, distributed without permission, over decentralized protocols.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation


kernl

An opinionated shell for sandboxed applets, built on kehto.

The person at the keyboard is the only principal that matters.

status: alpha package coverage: 100% slop gate: 100 (clean) agent readiness: 90 license: MIT

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. Read docs/alpha-status.md before relying on anything, and note that the badges are measured by pnpm check and an agent-readiness scan, not live CI.

The kernl preview shell in its tiled layout: the Notes and Pulse sample applets side by side, Notes granted network access and Pulse not, each listing actions such as Publish a note (no prompt), Update your profile and Delete a note (ask first), with the guard indicator reading strict and no events.

What it is

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.

What it does

  • Runs applets in a sealed frame. Verified bytes run in a srcdoc frame with sandbox="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 (https only, 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=1 runs 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).

The full guard panel in the preview: the strict, balanced and relaxed profiles with strict selected, all eleven protections in plain words with their strict limits and whether each is built into the toolkit, added by kernl or both, saying which limits refuse a request, which only report it, and that quarantine drops the message that crossed the limit, and an empty recent-events log.

Packages

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.

Layout

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

Run it

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 packages

Then 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/.

Write an applet

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.

Check it

pnpm check

That 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.

How behaviour is specified

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 window

The 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.

Documentation

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

Relationship to the ecosystem

  • 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.md D-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.

Contributing

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.

License

MIT

About

a kernl for running untrusted applets, distributed without permission, over decentralized protocols.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages