Files
bare-operating-system/developer-guide/01-two-runtimes-host-vs-image.md
T
Raven Scott 7171618c74
Release rolling / release (push) Successful in 9m59s
Update Docs
2026-08-12 21:10:14 -04:00

108 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Chapter 1 — Two runtimes: host (Pear/Node) vs in-image (`AsyncFunction`)
If you only remember one thing from this guide, remember this: **Bare OS runs two different kinds of JavaScript**, and they follow different rules.
---
## The confusion in one sentence
You might paste a file into your home directory on the personal Hyperdrive that starts with `import fs from 'node:fs'` and expect it to run like a Node script. **It will not.** That file is loaded as a **string** and executed with the JavaScript **`AsyncFunction`** constructor—not as an ES module. There is no module graph, no `import` resolution, and no automatic `node_modules` on the drive.
The **booter** and **seeder** Pear packages, by contrast, are normal **ESM** projects: they use `import`, npm dependencies, and Pear bundling. They run on the **host** and _host_ the environment that evaluates in-image code.
When the **`bare-os`** npm module is available on that host, the booter may attach a read-only **`ctx.bareOsHostStats`** snapshot (**`loadavg`**, **`cpus`**, **`networkInterfaces`**, …) and write **`/proc/bare_os/host_os.json`** (**schema 2**, including **`bare-os` 3.9+** and optional **`bare-posix`** fields)—still **not** a general “run Node in the image” escape hatch; see [Chapter 2](02-the-context-object.md).
---
## Mental model: who loads whom
```mermaid
flowchart TB
subgraph host [Host process Pear or Node]
booterPkg[bare-os-booter package]
seederPkg[bare-os-seeder package]
esm[import and node_modules]
end
subgraph hyper [Hyperdrives]
sys[System drive]
pers[Personal drive]
end
subgraph evalLayer [Evaluated inside booter VM]
kernel["start ctx from boot/init.js"]
binutil["run ctx argv from bin/*"]
userscript["run ctx argv from home script.js"]
end
booterPkg --> esm
booterPkg --> sys
booterPkg --> pers
booterPkg -->|runKernelFromSource| kernel
booterPkg -->|runBinCommand| binutil
booterPkg -->|runBinCommand| userscript
```
- **Host** code lives under `packages/bare-os-booter/`, `packages/bare-os-seeder/`, etc. It is **trusted** in the sense that you built or installed it; it opens Corestore, Hyperswarm, Hyperdrive, and constructs `ctx`.
- **In-image** code is **bytes on a drive** (`/boot/init.js`, `/bin/cat`, `~/mytool.js`). The booter reads those bytes as UTF-8 strings and passes them to `new AsyncFunction(...)` (see [`kernel-runner.js`](../packages/bare-os-booter/lib/kernel-runner.js)).
---
## In-image execution (the `AsyncFunction` contract)
Two entry shapes matter:
- **`async function start(ctx)`** — `/boot/init.js` on the **system** drive — `ctx``runKernelFromSource` wraps the source and calls `start(ctx)`
- **`async function run(ctx, argv)`** (optional for user scripts) — `/bin/*` always; or a `*.js` file resolved from the shell — `ctx`, `argv` (string array) — `runScriptFromSource` runs the file body, then **awaits** `run(ctx, argv)` if defined
The booter **injects** `ctx` and `argv`. Kernel **`start`** is required; for shell scripts, top-level statements may stand alone, or you may **define** **`run`** like **`/bin`** utilities. Top-level `import` is invalid in that evaluated string because the engine is not loading an ES module—it is compiling a function body.
Shebang lines (`#!/usr/bin/env bare`) are stripped before compile ([`stripShebang`](../packages/bare-os-booter/lib/kernel-runner.js)) so the first token the parser sees is valid JavaScript.
---
## Host execution (Pear / Node packages)
When you edit `packages/bare-os-booter/index.js`, you are writing **normal** JavaScript for Node or Bare under Pear:
- Use `import Hyperdrive from 'hyperdrive'`.
- Add dependencies in `package.json`.
- Use async I/O against real host APIs.
**Web Encoding globals:** some Bare/Pear builds do **not** define global `TextEncoder` / `TextDecoder`. Booter and in-image code should use **`b4a`** for UTF-8 instead (e.g. `b4a.from(str, 'utf8')`, `b4a.toString(buf, 'utf8')`), matching [`curl-cli.js`](../packages/bare-os-booter/lib/curl-cli.js). Relying on `new TextEncoder()` in booter `lib/*.js` can break at runtime (for example when statting or reading pseudo files under `/proc` or `/sys`).
This code **creates** `ctx` and passes it into the kernel. It does **not** run inside the simulated `/bin` environment unless you explicitly call `runBinCommand(ctx, argv)` with the same `ctx` the shell uses.
---
## Trust: system drive vs personal drive
- The **system** drive is the **replicated OS image**: `/boot`, `/bin`, `/etc`, `/share`. You should treat its contents as **integrity-checked by replication** from peers you chose to trust (same discovery key / topic as the rest of the project).
- The **personal** drive holds `$HOME`, `/.bare`, user files, crontab, etc. It is **writable** by the session. User scripts you write live here by default.
A script you place in `~/exploit.js` is **your** code; the booter will still `AsyncFunction`-evaluate it with full `ctx` power. That is convenient and dangerous—see [Chapter 9](09-security-and-trust.md).
---
## Host source policy (Bare-first)
Pear-bundled **booter** and **seeder** runtime sources under `packages/bare-os-booter/lib/` and `packages/bare-os-seeder/lib/` must stay resolvable on **Bare** as well as Node: CI runs [`scripts/verify-pear-no-static-node-import.mjs`](../scripts/verify-pear-no-static-node-import.mjs), which rejects **`from 'node:…'`** imports, **`require('node:…')`**, and **`import('node:…')`** in those trees (with path-based exceptions). Use **`#host-fs`**, `**#host-path**`, and `**#host-fs-promises`** from package `imports` instead of bare **`fs`** / **`path`** specifiers. The only deliberate **`node:module`** usage today lives in **`bare-os-boot-manifest-sig.node.js`** (Node default entry for boot manifest verification); the **`bare`** export uses **`bare-os-boot-manifest-sig.bare.js`**. For guest-visible behavior, prefer Holepunch `**bare-*`** modules per [Node → Bare module map](node-to-bare-modules.md).
---
## When to use which runtime
- Add a new **`/bin`** command shipped with the OS image — **In-image** pattern: coreutils `src/*.js` + build (Chapter 6)
- One-off automation in your home directory — **In-image** script (top-level and/or optional `run`); no `import` (Chapters 45)
- Change how networking, HDMS, or the REPL works — **Host** booter package (ESM)
- Publish or replicate the system image — **Host** seeder package
---
## See also
- [Chapter 2 — The context object](02-the-context-object.md)
- [Handbook — Booter runtime](../handbook/04-the-booter-runtime.md)
- [Handbook — Kernel and binaries](../handbook/06-kernel-and-binaries.md)
---
[← Developer guide home](README.md) · [Context object →](02-the-context-object.md)