239 lines
16 KiB
Markdown
239 lines
16 KiB
Markdown
# n_OS_tr
|
||
|
||
**A privacy-preserving, ephemeral operating system whose identity and configuration live on [Nostr](https://nostr.com).**
|
||
|
||
You boot n_OS_tr. It asks for a 12-word mnemonic (or generates one for you). From that mnemonic it deterministically derives every key the system needs — your personal identity, your relay keys, your blob-store keys, your mesh identity — using the standard [NIP-06](https://github.com/nostr-protocol/nips/blob/master/06.md) derivation scheme. Your preferences, dotfiles, bookmarks, and personal configuration are then loaded from Nostr relays, decrypted with your own key, and projected into your home directory on a RAM-backed filesystem. Nothing is saved to disk. You don't even need storage on your computer, and part of the intention of this project is that you don't have any.
|
||
|
||
When you power off, **everything disappears**. There is no local trace that you were ever on this machine.
|
||
|
||
The next time you boot — on the same machine, a different machine, a Pi in your pocket — you type the same 12 words and your environment materializes again.
|
||
|
||
---
|
||
|
||
## Status
|
||
|
||
- **Phase 2 Slice B+C: live.** Base ISO with [`fips`](https://github.com/) mesh daemon, [`c-relay`](https://github.com/) Nostr relay, [`ginxsom`](https://github.com/) Blossom blob server, nginx reverse proxy, first-boot provisioning, and smoke test are all green. See [`plans/slice_bc_fips_crelay.md`](plans/slice_bc_fips_crelay.md).
|
||
- **Phase 3 (identity + config): planned.** Mnemonic-driven identity subsystem and Nostr-as-home-directory are in design. See [`plans/identity_subsystem.md`](plans/identity_subsystem.md) and [`plans/nostr_config_projection.md`](plans/nostr_config_projection.md).
|
||
- **Phase 4 (Pi flavor and GUI): scoped.** Pi Zero 2 W live image and an optional amd64 GUI flavor come after the identity/config work stabilizes.
|
||
|
||
---
|
||
|
||
## The core idea in three sentences
|
||
|
||
1. **One mnemonic = your whole identity.** A single BIP-39 seed phrase deterministically generates every key the OS and its apps need, via [NIP-06](https://github.com/nostr-protocol/nips/blob/master/06.md) (`m/44'/1237'/{index}'/0/0`).
|
||
2. **All config lives on Nostr.** Replaceable events signed by your main key hold your dotfiles, preferences, and per-app state, encrypted to yourself with [NIP-44](https://github.com/nostr-protocol/nips/blob/master/44.md).
|
||
3. **The OS is ephemeral.** Root filesystem is an overlay on tmpfs. Shutdown wipes memory. No persistent local state by default — not even `machine-id`, Wi-Fi credentials, or shell history.
|
||
|
||
---
|
||
|
||
## The key tree
|
||
|
||
Every key in the system is deterministically derived from your single 12-word mnemonic. Each role gets its own index on the NIP-06 derivation path:
|
||
|
||
| Index | Role | Used by |
|
||
|-------|----------------------|------------------------------------------------------------|
|
||
| `0` | Main account | Your public Nostr identity (profile, posts, social graph) |
|
||
| `1` | Throwaway / test | Experimental account, scratch work, testing |
|
||
| `2` | c-relay admin | Admin key for your local [`c-relay`](includes/c-relay/) personal Nostr relay |
|
||
| `3` | ginxsom server | Server key for your local [`ginxsom`](includes/ginxsom/) Blossom blob store |
|
||
| `4` | fips node | Mesh node identity for the [`fips`](includes/fips/) daemon (also yields your fips IPv6) |
|
||
| `5`+ | Reserved future uses | New apps request an index from the identity agent at install time |
|
||
|
||
An app never sees the mnemonic or the seed. It asks the local **identity agent** for "the key assigned to role X", and the agent derives and returns it (or signs on its behalf via [NIP-46](https://github.com/nostr-protocol/nips/blob/master/46.md)). Details in [`plans/identity_subsystem.md`](plans/identity_subsystem.md).
|
||
|
||
The derivation method itself is not invented — it's standard NIP-06 and matches the reference implementation in [`/home/user/lt/client/www/tools.html`](../client/www/tools.html) (`nostr-tools.nip06.privateKeyFromSeedWords(mnemonic, "", index, 0, 0)`).
|
||
|
||
**Crypto core.** All mnemonic handling, key derivation, event signing, NIP-44 encryption, and NIP-46 signer/bunker flows are implemented by the vendored [`includes/nostr_core_lib`](includes/nostr_core_lib/) library — a C implementation of the relevant NIPs already unit-tested in [`includes/nostr_core_lib/tests`](includes/nostr_core_lib/tests/). The identity agent and config projection services are thin wrappers around its API; n_OS_tr does not reimplement any Nostr crypto itself.
|
||
|
||
**Language and toolchain.** Every n_OS_tr binary we ship (identity-agent, TUI, config-loader, config-writer, smoketest helpers) is **C99, statically linked against musl libc**, built inside Alpine Docker — the same pattern [`includes/nostr_core_lib`](includes/nostr_core_lib/), [`includes/ginxsom`](includes/ginxsom/), and [`includes/c-relay`](includes/c-relay/) already use. Output is self-contained static ELFs (`ldd` reports "not a dynamic executable"), identical toolchain across amd64 and arm64, no Python or Node.js at runtime. Details in [`plans/tui_login.md §0.1`](plans/tui_login.md#01-toolchain-alpine--musl-dev-built-in-docker).
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
M[12-word BIP-39 mnemonic<br/>user enters or generates at boot]
|
||
M --> S[BIP-32 seed]
|
||
S --> D0[Index 0<br/>main account]
|
||
S --> D1[Index 1<br/>throwaway]
|
||
S --> D2[Index 2<br/>c-relay admin]
|
||
S --> D3[Index 3<br/>ginxsom]
|
||
S --> D4[Index 4<br/>fips node]
|
||
S --> DN[Index 5..N<br/>future roles]
|
||
```
|
||
|
||
---
|
||
|
||
## The privacy contract
|
||
|
||
n_OS_tr makes a small number of hard promises to the user. These are non-negotiable; they're enforced by the image build and audited by the smoke test. The full list is in [`plans/threat_model.md`](plans/threat_model.md).
|
||
|
||
The short version:
|
||
|
||
- **Your mnemonic never touches disk.** Not swap, not logs, not journal, not `~/.bash_history`, not crash dumps.
|
||
- **The root filesystem is ephemeral.** Every boot is a clean slate; shutdown leaves no recoverable trace on the boot media.
|
||
- **No cross-boot fingerprint.** `machine-id`, MAC address, hostname, and Wi-Fi credentials do not persist by default.
|
||
- **No on-disk logs.** systemd-journald runs in volatile mode. User app caches are tmpfs-backed.
|
||
- **Your config is encrypted on Nostr to yourself.** Relay operators see ciphertext and metadata only. Run your own [`c-relay`](includes/c-relay/) to keep even the metadata local.
|
||
- **Identity can be walked away from.** Power off, remove the USB/SD, destroy it if you want — the only recoverable identity is the one you carry in your head or on paper.
|
||
|
||
---
|
||
|
||
## Architecture at a glance
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph boot[Boot sequence]
|
||
direction TB
|
||
B1[Kernel + initramfs]
|
||
B2[tmpfs overlay root<br/>= ephemeral]
|
||
B3[privacy-hardener<br/>MAC rand, swap off,<br/>volatile journald,<br/>fresh machine-id]
|
||
B4[identity-agent<br/>prompt for 12 words<br/>or generate new]
|
||
B5[network-bootstrap<br/>Wi-Fi / Ethernet /<br/>fips mesh]
|
||
B6[config-loader<br/>Nostr replaceable events<br/>projected to ~/]
|
||
B7[user shell or GUI]
|
||
B1 --> B2 --> B3 --> B4 --> B5 --> B6 --> B7
|
||
end
|
||
|
||
subgraph core[Core subsystems]
|
||
ID[identity-agent<br/>NIP-06 derivation<br/>NIP-46 signer]
|
||
CFG[config projection<br/>NIP-44 encrypted]
|
||
HARD[privacy-hardener<br/>+ shutdown-wiper]
|
||
end
|
||
|
||
subgraph opt[Optional user services]
|
||
FIPS[fips mesh daemon]
|
||
CREL[c-relay personal relay]
|
||
GINX[ginxsom + nginx blob store]
|
||
end
|
||
|
||
B4 --- ID
|
||
B6 --- CFG
|
||
B3 --- HARD
|
||
B7 -.optional.-> FIPS
|
||
B7 -.optional.-> CREL
|
||
B7 -.optional.-> GINX
|
||
```
|
||
|
||
The "core subsystems" (identity, config, hardening) define the product. Everything else — fips, c-relay, ginxsom, nginx, the GUI, the Pi HAT drivers — is optional user-facing infrastructure layered on top.
|
||
|
||
---
|
||
|
||
## Form factors
|
||
|
||
n_OS_tr is one product, delivered as multiple image flavors that all share the same core subsystems.
|
||
|
||
| Flavor | Status | Use case |
|
||
|-------------------------------------|-----------------|------------------------------------------------------------------------------------------|
|
||
| **amd64 live ISO (text console)** | Live (Phase 2) | Boot any x86_64 laptop/desktop from USB, get a privacy-preserving session. |
|
||
| **amd64 live ISO with GUI** | Planned | Adds a minimal window manager for users who want graphical apps on the same session. |
|
||
| **Raspberry Pi Zero 2 W live image**| Planned | Pocket-sized hardware token + mesh node; Waveshare LCD HAT as the mnemonic-entry UI. |
|
||
| **Other Pi models (Pi 4, CM4)** | Possible later | Same stack, larger form factor with HDMI-GUI capable. |
|
||
|
||
The design goal is that a user who knows their 12 words can sit down in front of any of these, boot, type their phrase, and have the same configuration materialize. See [`plans/iso_architecture.md`](plans/iso_architecture.md) for the amd64 build details today and the companion project [`raspberry_pi_zero_nostr`](../raspberry_pi_zero_nostr) for current Pi exploration work that will fold into the monorepo later.
|
||
|
||
---
|
||
|
||
## Current service stack (Phase 2)
|
||
|
||
The live Phase 2 Slice B+C ISO ships these services and components out of the box. They are *infrastructure for advanced users*, not the core product — the core product is identity + config, which is Phase 3.
|
||
|
||
All first-party components are organized under [`includes/`](includes/) as git submodules and are pulled with `git submodule update --init --recursive`.
|
||
|
||
| Service / Component | Role |
|
||
|--------------------------------------------------------------------------------|--------------------------------------------------------------------------|
|
||
| [`n_OS_tr-firstboot`](iso/config/includes.chroot/usr/local/sbin/n_OS_tr-firstboot) | Generates ephemeral service keypairs, issues self-signed TLS, configures fips interface |
|
||
| [`fips`](includes/fips/) | Nostr-addressed mesh networking daemon (virtual IPv6, mesh routing) |
|
||
| [`c-relay`](includes/c-relay/) | High-performance C Nostr relay running locally |
|
||
| [`ginxsom`](includes/ginxsom/) | Blossom blob server, served via nginx reverse proxy |
|
||
| [`nt`](includes/nostr_terminal/) | Nostr Terminal (TUI) client for reading/writing notes, DMs, and follows |
|
||
| [`otp`](includes/otp/) | One-time pad encryption tool with hardware RNG support |
|
||
| [`didactyl`](includes/didactyl/) | Nostr-native AI agent with a skill-based architecture |
|
||
| [`nginx`](iso/config/includes.chroot/etc/nginx/sites-available/n_OS_tr.conf) | TLS-terminating reverse proxy for relay and blob endpoints |
|
||
| [`n_OS_tr-smoketest`](iso/config/includes.chroot/usr/local/bin/n_OS_tr-smoketest) | End-to-end health check (21 checks, currently all green) |
|
||
|
||
When Phase 3 lands, these services become **opt-in keys at NIP-06 indices 2, 3, 4** — they inherit deterministic identities from the user's mnemonic instead of generating fresh keys on first boot.
|
||
|
||
---
|
||
|
||
## Planning documents
|
||
|
||
Read these in order for the full picture:
|
||
|
||
1. [`README.md`](README.md) — this file. Vision and structure.
|
||
2. [`plans/threat_model.md`](plans/threat_model.md) — the privacy contract. What we defend, what we don't, forbidden behaviors.
|
||
3. [`plans/identity_subsystem.md`](plans/identity_subsystem.md) — how the 12-word mnemonic becomes every key in the system.
|
||
4. [`plans/nostr_config_projection.md`](plans/nostr_config_projection.md) — how Nostr events become your home directory.
|
||
5. [`plans/iso_architecture.md`](plans/iso_architecture.md) — the current amd64 live-build architecture.
|
||
6. [`plans/slice_bc_fips_crelay.md`](plans/slice_bc_fips_crelay.md) — Phase 2 Slice B+C implementation notes (shipped).
|
||
7. [`plans/network_boot.md`](plans/network_boot.md) — research and notes on network-boot delivery options.
|
||
|
||
---
|
||
|
||
## Running the current ISO
|
||
|
||
For practical "how do I build and boot it" instructions see [`docs/RUNNING.md`](docs/RUNNING.md).
|
||
|
||
TL;DR:
|
||
|
||
```bash
|
||
# Build
|
||
./build.sh --clean
|
||
|
||
# Run locally in a VM (headless serial)
|
||
HEADLESS=1 ./scripts/run-iso.sh
|
||
|
||
# Or flash to USB and boot real hardware
|
||
sudo dd if=iso/live-image-amd64.hybrid.iso of=/dev/sdX bs=4M status=progress
|
||
```
|
||
|
||
Once booted, run [`n_OS_tr-smoketest`](iso/config/includes.chroot/usr/local/bin/n_OS_tr-smoketest) for an end-to-end health check.
|
||
|
||
---
|
||
|
||
## Developer notes
|
||
|
||
- Historical Debian live-build reference material (tutorials, package discovery, GUI/splash options, minimization, persistence) has been moved to [`docs/debian_live_notes.md`](docs/debian_live_notes.md). Nothing in there is authoritative for the product — it's a cheatsheet we built up while bootstrapping the ISO.
|
||
- The amd64 live image is built with [`live-build`](live-build/) via [`build.sh`](build.sh). The ISO itself is produced at `iso/live-image-amd64.hybrid.iso`.
|
||
- Service artifacts staged into the ISO come from submodules under [`includes/`](includes/): [`fips`](includes/fips/) (mesh daemon), [`c-relay`](includes/c-relay/) (Nostr relay), [`ginxsom`](includes/ginxsom/) (Blossom server), and [`nostr_core_lib`](includes/nostr_core_lib/) (the C Nostr library used as the crypto core for identity and config projection).
|
||
|
||
---
|
||
|
||
## Licensing and contributing
|
||
|
||
TBD. The product principle is: **you should always be able to build and run this from source, verify it matches the shipped image, and run it on your own hardware with no external dependencies.** Anything that violates that principle does not belong in the product.
|
||
|
||
---
|
||
|
||
## Why this exists
|
||
|
||
Operating systems today are identity sinks. They remember your SSIDs, your login history, your hostnames, your keys, your clipboard, your browsing state. When a machine changes hands — sold, seized, borrowed, stolen — those traces go with it.
|
||
|
||
At the same time, Nostr gives us something new: **a place to keep identity and preferences that is not tied to any particular computer, account, server, or company**. Your keys are just math. Your preferences are just signed events. Any machine that can do elliptic-curve crypto can reconstitute your setup.
|
||
|
||
n_OS_tr puts those two facts together. The computer is disposable. The identity and configuration are portable. And the glue between them — the mnemonic, the derivation scheme, the config projection — is open, standard, and auditable.
|
||
|
||
That's the product.
|
||
|
||
## Virtual Consoles (Multi-Terminal)
|
||
|
||
n_OS_tr uses Linux virtual consoles to provide multiple independent terminals without a GUI:
|
||
|
||
| TTY | Keystroke | Purpose |
|
||
|-----|-----------|---------|
|
||
| tty1 | `Ctrl+Alt+F1` | 🔐 **Signer** — mnemonic entry, status display, signing approval prompts |
|
||
| tty2 | `Ctrl+Alt+F2` | ⚙️ **Services** — post-unlock service selection menu |
|
||
| tty3–tty6 | `Ctrl+Alt+F3`..`F6` | **Shell** — standard login prompts for admin commands |
|
||
|
||
Each terminal has a distinct background color tint and banner so you always know where you are:
|
||
- **tty1** (red tint): `🔐 n_OS_tr SIGNER · TTY1`
|
||
- **tty2** (blue tint): `⚙️ n_OS_tr SERVICES · TTY2`
|
||
- **tty3–tty6** (default): login banner shows `n_OS_tr · SHELL · ttyN`
|
||
|
||
### Boot flow
|
||
|
||
1. Boot lands on **tty1** with the `nsigner` mnemonic prompt
|
||
2. Enter or generate your 12-word BIP-39 mnemonic on tty1
|
||
3. Switch to **tty2** (`Ctrl+Alt+F2`) — it auto-detects the signer is ready and shows the service menu
|
||
4. Toggle services (c-relay, ginxsom, fips, nginx) and apply
|
||
5. Switch to **tty3** (`Ctrl+Alt+F3`) for a working shell at any time
|
||
|
||
Signing approval prompts appear on tty1. When a service requests a signature, switch back to tty1 to approve or deny.
|