12 KiB
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)
-
/lib/bare(system image, primary) —bare-os-bare-libsbuilds one IIFE per manifest row intokernel/lib/bare/bundles/(mirrored on the seeded Hyperdrive). It also copiesbare-module-manifest.jsonintokernel/lib/bare/.manifest.jsonlists successful bundles; stale**bundles/*.js** files are pruned on each successful build. At boot, drive bundles run first (unlessBARE_OS_BARE_DRIVE_BUNDLES=0). -
Pear booter (
bare-module-manifest.data.mjs) — The stock booter package shipspackages/bare-os-booter/lib/ctx/bare-module-manifest.json(normative JSON, edited or synced from the catalog) and a generated siblingbare-module-manifest.data.mjsthatexport defaultthe same object. Underpear run,import.meta.urlispear://…;bare-fscannot openpear:URLs passed asURLinstances because normalization usesbare-url.fileURLToPath(file:only). ThereforeloadBareModuleManifest()reads the embedded.data.mjson Pear so the manifest stays in the traced module graph. Onfile:dev checkouts it prefers the JSON on disk (live edits) and falls back to the embedded copy if the file is missing. Regenerate.data.mjswithnpm run sync:bare-manifestornode scripts/generate-bare-module-manifest-data.mjs; CI runsnpm run verify:manifest-data. -
ctx.bare(host fallback) — UnlessBARE_OS_BARE_HOST_IMPORTS=0, the booter then**import()**s manifest packages still missing after drive merge. Underpear run(booterimport.meta.urlispear:),bundle: truerows are skipped for hostimport()(keys come from**/lib/bare/bundles/***only; avoids bare-module**MODULE_NOT_FOUND/ referrer** errors for npm names likeholesail). Underfile:dev trees,bundle: truemay 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-localctx.bare(no Pear hostnode_modulesparticipation). Disable allctx.barewithBARE_OS_BARE_MODULES=0. For narrow harnesses, session env may setBARE_OS_BARE_HOST_SKIP_CTX_KEYS(comma-separatedctxKeylist to skip) orBARE_OS_BARE_HOST_ONLY_CTX_KEYS(allowlist — only those keys are host-imported). Manifest rows may include optionaltier(corevs extended) andrisk(low,medium,high) for distributor policy; the build honorstierviaBARE_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).
- The full mirror (discoverability) — A local checkout of Holepunch repos (for example
holepunchto_reposunder your Pear tooling tree) lists on the order of 150+ repositories whose names start withbare-. Many are native addons, platform-specific (mobile, GUI, FFmpeg, …), or developer tools. The manifest can list them forctx.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:
npm run gen:bare-catalog npm run sync:bare-manifest npm installThis refreshes
docs/bare-holepunch-catalog.json(everyholepunchto/bare-*repo plus npmlatest, minusscripts/bare-catalog-overrides.json), then merges published packages intobare-module-manifest.jsonand replaces booteroptionalDependenciesfrom that catalog (anything notincludedInBooteris dropped).sync:bare-manifestrewritesentriesonly and preserves the curated top-levelpearEntriesarray (pear-build,pear-bundle,pear-ref,bare-bundle-compile,bare-bundle-evaluate).packages/bare-os-bare-libs/build.mjsresolves package.json#importswith hostplatform/bareconditions so new Holepunch modules (Bluetooth, native UI, …) bundle without a Node-onlydefault. CI runsnpm run gen:bare-catalog:checkso the committed catalog’sentries(andsource) stay in sync with live npm/GitHub.scripts/bare-ctx-import-overrides.jsonadjusts a few packages forctx.bare/ esbuild: namespace exports (export: *),bare-node-runtime/globalas a side-effect entry, etc. Edit this when npm packages have no default export or need a subpath. -
Add or remove a
ctx.bareentry by hand — Edit the manifest and booterdependencies/optionalDependenciesas needed. Thebundlefield in the manifest is legacy metadata;bare-os-bare-libsattempts every row. Prefer the catalog + sync path for**bare-*** rows soctxKeyand semver ranges stay consistent. -
Refresh
/lib/bareon the image — From the repo root:npm run build -w bare-os-bare-libsOptional
BARE_OS_BUNDLE_TIER=corebuilds only manifest rows with"tier": "core"(default tier when omitted). Useallor 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 afile:URL). Checkmanifest.json→bundleStatsafter a build for how many IIFEs succeeded vs stub-only. -
Node vs Pear/Bare — On Node,
buildBareCtxObjectFromHostskips manifest rows withnativeHint: trueso 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-booterbeforepear runso hoistednode_modulesresolve like npm (see PEAR-RUN.md). After any manifest or catalog edit, runnpm run sync:bare-manifestbeforepear stagesobare-module-manifest.data.mjsmatches the JSON. -
Local Holepunch clone inventory — After editing the manifest or before a release, run
npm run audit:holepunch-clonesto refreshdocs/audit/holepunch-clone-sync-report.jsonagainstBARE_OS_HOLEPUNCH_CLONES_ROOT. To fail CI when selected clones lagorigin/main, list their directory names indocs/audit/holepunch-drift-repos.jsonand setBARE_OS_HOLEPUNCH_DRIFT_CHECK=1(see scripts/README.md). -
mirror-drive(Holepunch) audit — The stock VFS union and/mirror/*overlays remain the supported read-mostly composition path. The upstreammirror-drivepackage 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. SeeBARE_OS_VFS_UNION_PREFIXESin the environment appendix andctx.bareOsEmitMirrorDriveHintabove.
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-style messaging. Well-known channel strings are listed in packages/bare-os-booter/lib/tools/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).
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 / 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. 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
pearEntriesinbare-module-manifest.json(pear-build,pear-bundle,pear-ref,bare-bundle-compile, …). - Static host imports under
pear://viabare-os-ctx-pear-host.js(see HDMS manager pattern — no dynamicimport("pkg")from guest bundles). /bin/pear:help,info,list,init,stage,release,seed(build/bundlealiasstage).
Guest workflow (no host Pear CLI required for release):
pear init && pear stage && pear release . && pear seed .
appstore install my-app pear://0.<length>.<key> --yes
appstore launch my-app
Full operator guide: 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 - Chapter 2 — The context object
- Handbook — Booter runtime
packages/bare-os-bare-libs/README.md