# Chapter 12 — Bare modules, `ctx.bare`, and the Pear ecosystem This chapter ties together **Holepunch `bare-*` packages**, the **Pear** host runtime, and how Bare OS exposes a **curated** subset to **in-image** scripts. --- ## Tiers of access (image, Pear embed, host, mirror) 1. **`/lib/bare` (system image, primary)** — **`bare-os-bare-libs`** builds **one IIFE per manifest row** into **`kernel/lib/bare/bundles/`** (mirrored on the seeded Hyperdrive). It also copies **`bare-module-manifest.json`** into **`kernel/lib/bare/`**. **`manifest.json`** lists successful bundles; stale `**bundles/*.js`** files are **pruned** on each successful build. At boot, drive bundles run **first** (unless **`BARE_OS_BARE_DRIVE_BUNDLES=0`**). 2. **Pear booter (`bare-module-manifest.data.mjs`)** — The stock booter package ships **`packages/bare-os-booter/lib/bare-module-manifest.json`** (normative JSON, edited or synced from the catalog) and a generated sibling **`bare-module-manifest.data.mjs`** that **`export default`** the same object. Under **`pear run`**, **`import.meta.url`** is **`pear://…`**; **`bare-fs`** cannot open **`pear:`** URLs passed as **`URL`** instances because normalization uses **`bare-url.fileURLToPath`** ( **`file:`** only). Therefore **`loadBareModuleManifest()`** reads the embedded **`.data.mjs`** on Pear so the manifest stays in the traced module graph. On **`file:`** dev checkouts it prefers the JSON on disk (live edits) and falls back to the embedded copy if the file is missing. Regenerate **`.data.mjs`** with **`npm run sync:bare-manifest`** or **`node scripts/generate-bare-module-manifest-data.mjs`**; CI runs **`npm run verify:manifest-data`**. 3. **`ctx.bare` (host fallback)** — Unless **`BARE_OS_BARE_HOST_IMPORTS=0`**, the booter then `**import()**`s manifest packages **still missing** after drive merge. Under **`pear run`** (booter **`import.meta.url`** is **`pear:`**), **`bundle: true`** rows are **skipped** for host **`import()`** (keys come from `**/lib/bare/bundles/***` only; avoids bare-module `**MODULE_NOT_FOUND` / referrer** errors for npm names like **`holesail`**). Under **`file:`** dev trees, **`bundle: true`** may still be host-imported when the drive bundle did not fill the key. Remaining host imports cover native or Bare-only packages that could not be bundled, or when the image is older than the manifest. Set `**BARE_OS_BARE_HOST_IMPORTS=0`** for a **fully image-local** `ctx.bare` (no Pear host `node_modules` participation). Disable all `ctx.bare` with **`BARE_OS_BARE_MODULES=0`**. For narrow harnesses, session env may set **`BARE_OS_BARE_HOST_SKIP_CTX_KEYS`** (comma-separated **`ctxKey`** list to skip) or **`BARE_OS_BARE_HOST_ONLY_CTX_KEYS`** (allowlist — only those keys are host-imported). Manifest rows may include optional **`tier`** (**`core`** vs extended) and **`risk`** (**`low`**, **`medium`**, **`high`**) for distributor policy; the build honors **`tier`** via **`BARE_OS_BUNDLE_TIER`**. **Boot cold path / stdlib budget:** the stock booter measures drive merge + host **`import()`** resolution for **`ctx.bare`** and sets **`BARE_OS_BOOT_BARE_STDLIB_RESOLUTION_MS`** before the guest starts. Operators may set **`BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB`** to log **`boot-perf.json`** / stderr warnings when resolution exceeds the budget; combine with **`BARE_OS_BUNDLE_TIER=core`** (or a smaller manifest) to shrink cold I/O. Use **`node scripts/kernel-microbench.mjs`** for regression-shaped timings (not a literal Pear cold boot). 4. **The full mirror (discoverability)** — A local checkout of Holepunch repos (for example **`holepunchto_repos`** under your Pear tooling tree) lists on the order of **150+** repositories whose names start with **`bare-`**. Many are **native addons**, **platform-specific** (mobile, GUI, FFmpeg, …), or **developer tools**. The **manifest** can list them for `ctx.bare`, but only rows that bundle cleanly become real drive IIFEs; the rest rely on host import or stubs until you trim the manifest. --- ## Maintenance workflow - **Holepunch catalog (maximal npm set)** — From the repo root: ```bash npm run gen:bare-catalog npm run sync:bare-manifest npm install ``` This refreshes **[`docs/bare-holepunch-catalog.json`](../docs/bare-holepunch-catalog.json)** (every **`holepunchto/bare-*`** repo plus npm **`latest`**, minus [`scripts/bare-catalog-overrides.json`](../scripts/bare-catalog-overrides.json)), then merges published packages into **[`bare-module-manifest.json`](../packages/bare-os-booter/lib/bare-module-manifest.json)** and **replaces** booter **`optionalDependencies`** from that catalog (anything not **`includedInBooter`** is dropped). **`sync:bare-manifest` rewrites `entries` only** and **preserves** the curated top-level **`pearEntries`** array (`pear-build`, `pear-bundle`, `pear-ref`, `bare-bundle-compile`, `bare-bundle-evaluate`). **`packages/bare-os-bare-libs/build.mjs`** resolves package.json **`#imports`** with host **`platform` / `bare`** conditions so new Holepunch modules (Bluetooth, native UI, …) bundle without a Node-only `default`. CI runs **`npm run gen:bare-catalog:check`** so the committed catalog’s **`entries`** (and **`source`**) stay in sync with live npm/GitHub. **[`scripts/bare-ctx-import-overrides.json`](../scripts/bare-ctx-import-overrides.json)** adjusts a few packages for **`ctx.bare`** / esbuild: namespace exports (**`export: *`**), **`bare-node-runtime/global`** as a side-effect entry, etc. Edit this when npm packages have no default export or need a subpath. - **Add or remove a `ctx.bare` entry by hand** — Edit the manifest and booter **`dependencies`** / **`optionalDependencies`** as needed. The **`bundle`** field in the manifest is **legacy metadata**; **`bare-os-bare-libs`** attempts **every** row. Prefer the catalog + sync path for `**bare-*`** rows so **`ctxKey`** and semver ranges stay consistent. - **Refresh `/lib/bare` on the image** — From the repo root: ```bash npm run build -w bare-os-bare-libs ``` Optional **`BARE_OS_BUNDLE_TIER=core`** builds only manifest rows with **`"tier": "core"`** (default tier when omitted). Use **`all`** or unset for the full catalog. Then re-run the seeder so **`kernel/lib/bare/`** is copied into the Hyperdrive (the seeder invokes this build automatically when running from a `file:` URL). Check **`manifest.json`** → **`bundleStats`** after a build for how many IIFEs succeeded vs stub-only. - **Node vs Pear/Bare** — On **Node**, **`buildBareCtxObjectFromHost`** skips manifest rows with **`nativeHint: true`** so optional Bare-native packages are not `**import()`**’d (avoids stray failures and unhandled rejections from addons). On **Pear/Bare**, the full manifest is loaded in parallel. - **Pear** — Continue to use **`node scripts/ensure-pear-node-modules.mjs packages/bare-os-booter`** before **`pear run`** so hoisted **`node_modules`** resolve like npm (see [PEAR-RUN.md](../docs/PEAR-RUN.md)). After any manifest or catalog edit, run **`npm run sync:bare-manifest`** before **`pear stage`** so **`bare-module-manifest.data.mjs`** matches the JSON. - **Local Holepunch clone inventory** — After editing the manifest or before a release, run **`npm run audit:holepunch-clones`** to refresh **[`docs/audit/holepunch-clone-sync-report.json`](../docs/audit/holepunch-clone-sync-report.json)** against **`BARE_OS_HOLEPUNCH_CLONES_ROOT`**. To fail CI when selected clones lag **`origin/main`**, list their directory names in **[`docs/audit/holepunch-drift-repos.json`](../docs/audit/holepunch-drift-repos.json)** and set **`BARE_OS_HOLEPUNCH_DRIFT_CHECK=1`** (see [scripts/README.md](../scripts/README.md)). - **`mirror-drive` (Holepunch) audit** — The stock VFS union and **`/mirror/*`** overlays remain the supported read-mostly composition path. The upstream **`mirror-drive`** package is a candidate for a future **env-gated** fast path (read-only layering); treat any integration as **parity-tested** against union semantics and document **fallback** when the package is absent. See **`BARE_OS_VFS_UNION_PREFIXES`** in the environment appendix and **`ctx.bareOsEmitMirrorDriveHint`** above. --- ## Runtime caps **`ctx.bareOsRuntimeCaps.features`** includes **`bareCtxModules`**, **`bareDriveBundles`**, and **`bareHostImportsForCtx`** so kernels can see whether host fallbacks are enabled. --- ## Pear IPC channel registry **`ctx.bareOsPearIpcEmit(channel, payload)`** is a host bridge for [pear-ipc](https://github.com/holepunchto/pear-ipc)-style messaging. Well-known **`channel`** strings are listed in **`packages/bare-os-booter/lib/bare-os-pear-ipc-registry.js`** and mirrored as JSON under **`/proc/bare_os/pear_ipc.json`** (and the flat **`/proc/bare_os_pear_ipc_registry`** alias) so operators and kernels share one vocabulary for reload, mirror, and telemetry hints. **`ctx.bareOsPearIpcRequest(channel, payload, { timeoutMs? })`** correlates **`bareOsIpcReqId`** on **`payload`** and awaits **`process.emit('bare-os:pear-ipc-response', { bareOsIpcReqId, result?, error? })`** on Node-style hosts. Use for request/response pairs alongside **`bareOsPearIpcEmit`**. **Mirror-drive hints:** **`ctx.bareOsEmitMirrorDriveHint({ label?, key? })`** emits **`bare-os:mirror-drive-hint`** for Holepunch-style snapshot workflows (see [kernel extensions](../docs/reference/kernel-extensions.md)). **Blind-peer style hint:** **`ctx.bareOsEmitBlindPeerHint(payload)`** forwards a **capped** JSON object on Pear IPC as **`bare_os_blind_peer_hint`** (topic/key material stays opaque strings; the guest does not verify blind-relay crypto). **Host-only eval probe:** **`ctx.bareOsHostCapability('bundleEvaluate')`** is **`true`** when the host advertises `**BARE_OS_HOST_BUNDLE_EVALUATE=1`**, documenting an optional **[`cross-worker`](https://github.com/holepunchto/cross-worker)** / **[`bare-bundle-evaluate`](https://github.com/holepunchto/bare-bundle-evaluate)** path. Actual evaluation still happens **outside** the guest VFS trust boundary. **Discord bots (`ctx.bare.discordJS`)** — The booter vendors **`bare-discord-js`** (official **discord.js** 14) and attaches it as **`ctx.bare.discordJS`**. Guest scripts have no `import`/`require`. Full how-to (Portal, `.env`, intents, slash catalog, initd, packing): **[Chapter 21 — Discord bots](21-discord-bots.md)**. Disable with **`BARE_OS_DISCORD=0`**. **`bare-fetch` content encodings (Capability word 6 doc alignment)** — When the host **`fetch`** implementation is Holepunch **`bare-fetch` 3**, **Content-Encoding** negotiation may include **`br`** and **`zstd`** in addition to **`gzip`** depending on platform support. Responses may expose **`type`** and **`Headers.getSetCookie()`** (forwarded by in-guest **`web_fetch`**). In-image scripts should not assume a fixed encoding list; treat **`Accept-Encoding`** as host-defined. SPDX license identifiers on catalog rows (when present) are **metadata for distributors**, not a runtime guarantee inside the guest. --- ## New: `ctx.pear` surface and `/bin/pear` (2026) A parallel **`ctx.pear`** surface exposes Pear-level development tooling to in-image scripts. - Populated from **`pearEntries`** in `bare-module-manifest.json` (`pear-build`, `pear-bundle`, `pear-ref`, `bare-bundle-compile`, …). - Static host imports under `pear://` via `bare-os-ctx-pear-host.js` (see HDMS manager pattern — no dynamic `import("pkg")` from guest bundles). - **`/bin/pear`**: `help`, `info`, `list`, `init`, `stage`, `release`, `seed` (`build`/`bundle` alias `stage`). **Guest workflow (no host Pear CLI required for release):** ```bash pear init && pear stage && pear release . && pear seed . appstore install my-app pear://0.. --yes appstore launch my-app ``` Full operator guide: **[docs/guides/guest-pear-and-appstore-workflow.md](../docs/guides/guest-pear-and-appstore-workflow.md)**. Design and audit: `docs/design/ctx-pear-surface-and-bare-audit-plan.md`, `docs/audit/ctx-bare-audit-notes.md`. --- ## See also - [Chapter 5 — Modules and `import`](05-modules-and-imports.md) - [Chapter 2 — The context object](02-the-context-object.md) - [Handbook — Booter runtime](../handbook/04-the-booter-runtime.md) - [`packages/bare-os-bare-libs/README.md`](../packages/bare-os-bare-libs/README.md) --- [← Kernel + Pear cookbook](11-kernel-pear-cookbook.md) · [Modules and import →](05-modules-and-imports.md)