Architecture Microkernel - nself-org/cli GitHub Wiki
nSelf is built as a microkernel. A thin core ships with the CLI plus a minimum service set; everything else is a plugin. The model is borrowed from the Linux kernel and its loadable modules: the kernel guarantees a small set of invariants, and modules extend the surface area without touching kernel internals.
Plugins are the product. The core exists to load, validate, and run them.
The kernel is the nself CLI binary plus the four required services (Postgres, Hasura, Auth, Nginx). Everything else is a plugin: messaging, AI, media, payments, search, observability, billing. Plugins ship as signed manifests. The CLI resolves, validates, and runs them through a single lifecycle.
This split keeps the core small enough to audit and stable enough to depend on, while letting features evolve at plugin pace. A plugin can ship in days; the kernel ships in months.
Every plugin declares itself in a 12-field YAML manifest. The schema is defined in ticket G1-T30 and enforced by the loader.
| Field | Type | Notes |
|---|---|---|
name |
slug | Lowercase, hyphenated. Must be unique in the registry |
version |
semver | MAJOR.MINOR.PATCH |
tier |
enum |
free, basic, or pro
|
bundle |
enum |
nChat, nClaw, nFamily, nTV, ClawDE, ɳSelf+, or none
|
language |
enum |
go, rust, ts, py, or flutter
|
services |
array | Each entry: {name, port, healthcheck, image}
|
tables |
array |
np_*-prefixed Postgres table schemas |
hasura_metadata |
path or inline | Track-table, permission, and relationship metadata |
dependencies |
array | Other plugin slugs this plugin requires |
requires_license |
bool | True for any tier: pro plugin |
signature |
base64 | Ed25519 signature of the manifest body |
description |
string | One-line summary used by nself plugin list
|
The signature field covers every other field. Any tampering invalidates the signature and the loader refuses to install.
A plugin moves through eight phases from request to running container.
-
Discovery. The CLI queries
plugins.nself.orgfor a manifest by slug. The registry returns the manifest plus the signed checksum of any artifacts. -
Validation. The loader verifies the Ed25519 signature against the ping_api public key. For
tier: proplugins, the loader checks the local license against the cached entitlement table. - Resolution. Dependencies are walked and topo-sorted. Version conflicts surface as install errors with the conflicting pair named.
- Download. Artifacts pull from OCI for container images, or from npm, cargo, or pip for SDK code. Checksums are verified after download.
-
Installation.
nself plugin install <name>writes plugin files into the project, updates the local plugin registry, and registers the plugin with the build system. - Configuration. Plugin env vars merge into the project env cascade. Ports are allocated from the reserved 38xx range when the plugin requires one.
-
Build.
nself buildreads installed manifests and emits matching entries in the generateddocker-compose.yml. Manifests never bypass the build step. -
Runtime.
nself startbrings services up. Healthchecks gate readiness. The loader continues to honor license revocation on a cached TTL during runtime.
The kernel guarantees five invariants. Plugins that violate any of them fail to load.
-
Table prefix. Plugin tables must use the
np_*prefix. The loader rejects any migration that creates a non-prefixed table. -
Bind address. Plugin services bind to
127.0.0.1. External traffic enters through Nginx only. - Signature. Pro plugins must carry a valid Ed25519 signature. The CLI loader refuses unsigned or tampered pro plugins, with no override.
- License revocation. License changes propagate within 24 hours through cached TTL. The system runs FAIL-OPEN for 7 days when ping.nself.org is unreachable, then fails closed.
-
Convention Wall. Multi-app isolation uses
source_account_id TEXT; Cloud multi-tenancy usestenant_id UUID. The two columns are never mixed in the same table. See Multi-Tenant Conventions.
These are non-negotiable. The doctor command (nself doctor --deep) checks each invariant on every install and on a daily scan.
The initial release uses HTTP plus JSON for all plugin-to-plugin and plugin-to-core communication. gRPC is a frequent question and the answer is the same one given for many binary-protocol decisions: not yet. We have no measured perf bottleneck that JSON-over-HTTP cannot meet, and gRPC adds a code-generation step, a protobuf schema registry, and a debugging surface that JSON does not.
gRPC is deferred to v1.2.0 or later, gated on a real perf measurement that justifies the move. Until then, plugins speak HTTP.
- Architecture — top-level system overview
-
Multi-Tenant Conventions —
source_account_idvstenant_id - Plugin Development — building a plugin from scratch