8.5 KiB
name, version, description, tags, requires
| name | version | description | tags | requires | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| bare-os-super-developer | 1.0.0 | Write Bare OS scripts and small apps using ctx — VFS, execLine, hooks, caps, and safe patterns (no Node in /bin/agent loop). |
|
|
bare-os-super-developer — Scripts, apps, and ctx
When to use
Use this skill when you (or the user) need to author or debug Bare OS JavaScript that runs inside the guest (kernel init, /bin/* utilities, kernel.ext.d, user .mjs run via run_js_script**, or Pear/booter-hosted scripts). It complements repo docs: treat **developer-guide/02-the-context-object.md** and **packages/bare-os-booter/lib/bare-os-ctx.d.ts as the canonical deep dives; this file is the fast mental model.
Core model
- Entrypoints — Kernel:
async function start(ctx)in/boot/init.js(or your image). Commands:async function run(ctx, argv)**where**argv[0]is the invoked name (e.g.agent). You must setctx.exitCode(number) before returning on failure paths. ctxis not Node — There is no fullprocess**, no**require('node:fs')**. The booter assembles**ctx**as the narrow syscall surface:**vfs**,**env**,**execLine**,**runBinCommand**, optional**httpFetch**,**bare, identity helpers, diagnostics, etc. See the mermaid overview in Chapter 2 of the developer guide./bin/agentis special — The agent bundle usesrun_js_script**for guest JS and a frozen tool surface; do not assume**node**exists. For general in-guest scripting, prefer**ctx.vfs**+**ctx.execLine**/**ctx.runBinCommand**and optional**ctx.bare.*modules when enabled.
Writing scripts (run(ctx, argv))
- Argv —
argvis a string array;argv[0]is how you were invoked (symlink name matters for multi-call binaries). - Stdout — Prefer
ctx.console.log**/**ctx.console.error**(session-aware). For binary or captured stdout,**ctx.bareOsBinWritemay exist when the shell captures pipeline output. - Shell a subprocess —
await ctx.execLine('some shell line', { signal, timeoutMs })**returns a string (see booter**raceWithAbortAndTimeout**). Heavy work:**await ctx.runBinCommand(['/bin/grep', …], opts)for same resolution as the interactive shell. - Filesystem —
await ctx.vfs.readFile(path)**→**Uint8Array**;**await ctx.vfs.writeFile(path, buf, opts?)**. Decode with**ctx.b4a.toString(buf)**or**TextDecoder**. Always use absolute paths under**/home**,**/tmp**,**/mnt**,**/bin, etc., per policy. - Environment —
ctx.env**is mutable shell state (also**ctx.vfs.env**). After**execLine**,**ctx.env.BARE_OS_EXIT_STATUSreflects last exit code when the booter sets it. - Exit — Set
ctx.exitCode = 1**(or other code) on error;**0**on success.**ctx.requestBooterExit(code)**ends the whole session from builtins like**exit.
Building “apps” (long-lived behaviour)
Think in layers the stock OS already uses:
| Layer | Mechanism | Notes |
|---|---|---|
| Init | **bareOsRegisterBootStepHook**, initd units |
Boot-order DAG (stock: **bare-os-www** before **bare-holesail** so **bare-www-*** reaches loopback HTTP; **bare-openssh** + login stack ensure **bare-ssh-*** in **~/.holesail/state.json**); pair **registerKernelShutdownHook** / initd disposers for teardown. |
| Virtual files | **bareOsRegisterVirtualFile(name, reader, opts?)** |
Serves **/run/bare-os/virtual/<name>**; gated by runtime caps. |
| IPC | **ctx.bareOsIpc** when present |
**push/take**, JSON helpers, fanout, duplex bridge — bounded; audit when **BARE_OS_IPC_AUDIT=1**. |
| Kernel extensions | bareOsRegisterKernelExtensionRecord**, **bareOsRunImageScript** under **/lib/bare-os/extensions/ |
Trusted image paths only. |
| Sandboxed user JS | **bareOsSandboxRunScript(source, argv?, opts?)** |
Restricted **ctx**; disable with **BARE_OS_SANDBOX_SCRIPT=0**. |
| Pear / host | **bareOsPearIpcEmit**, **bareOsPearIpcRequest**, mirror/export hints |
Host must cooperate; return **{ ok, hint }** patterns. |
Before touching sensitive ctx** methods in hardened images, call **ctx.bareOsIsCtxMethodAllowed?.(name)** when boot policy **BARE_OS_BOOT_POLICY_ALLOWED_CTX_METHODS is set.
ctx field map (cheat sheet)
Always read live truth for capability bits: read_proc_file** on **/proc/bare_os/features** and **/proc/bare_os/capabilities.json** — do not infer from man pages alone (see **bare-os-kernel-proc skill).
Files, drives, process
ctx.vfs**—**readFile**,**writeFile**,**mkdir**,**readdir**,**stat/lstat**,**chmod**, … Path routing: system vs personal Hyperdrive;**ctx.drive**vs**ctx.personalDrivefor advanced use.ctx.env**,**ctx.drive**,**ctx.personalDrive**,**ctx.disk— Session identity and mounts.ctx.execLine**,**ctx.runBinCommand— Shell and/binexecution with shared policy (timeouts, abort).
Bytes, console, session
ctx.b4a— Buffer/string helpers for Hyperdrive payloads.ctx.console**,**ctx.readLine**,**ctx.writeScreen**— REPL session (**readLinemay be Fish-backed when enabled).ctx.exitCode**,**ctx.requestBooterExit**,**ctx.registerKernelShutdownHook
Bare OS introspection & policy
ctx.bareOsCtxApiVersion**,**ctx.bareOsRuntimeCaps(frozen)ctx.bareOsAdvertisedKernelCapabilityWords**,**ctx.bareOsSeedKernelCapabilityWords**—**>>> 0when testing bits.ctx.bareOsGetResourceStatus**,**ctx.bareOsReadProcMetricsLive**,**ctx.bareOsReadBareTopSnapshotctx.bareOsRegisterVirtualFile**,**ctx.bareOsInvalidateVirtualFile**,**ctx.bareOsUpdateVirtualFileMetactx.bareOsEmitIpcAudit**,**ctx.bareOsEvaluatePeerAdmission**,**ctx.bareOsEmitMirrorDriveHint
Optional / host-dependent
ctx.httpFetch**— Same allow/deny policy as**curl**/**wget**; every host for**web_fetchmust be allowlisted.ctx.bare**— Frozen map of vendored modules (**b4a**,**protomux**, …) when**BARE_OS_BARE_MODULESallows.ctx.bareOsHostStats**,**ctx.bareOsChat***,**ctx.bareOsPearIpc*— Present only when wired by the booter/host.
For the full list and semantics, open developer-guide/02-the-context-object.md** in the repo (or **read_file on a mounted checkout).
Minimal script template (guest)
/**
* @param {Record<string, unknown>} ctx
* @param {string[]} argv
*/
export async function run(ctx, argv) {
const argv0 = argv[0] || 'script'
const vfs = ctx.vfs
if (!vfs?.readFile) {
ctx.console.error(argv0 + ': no vfs')
ctx.exitCode = 1
return
}
try {
const buf = await vfs.readFile('/proc/bare_os/features.json')
const t =
ctx.b4a && typeof ctx.b4a.toString === 'function'
? ctx.b4a.toString(buf)
: new TextDecoder().decode(buf)
ctx.console.log(t.slice(0, 500))
} catch (e) {
ctx.console.error(argv0 + ': ' + (e && e.message ? e.message : String(e)))
ctx.exitCode = 1
}
}
Save under /home/.../my-tool.mjs** and run by absolute path (or register under **/bin** on the image). Do not rely on **node in the guest.
Agent-specific note
When helping inside /bin/agent, the model uses tools (read_file, run_js_script, …) backed by the same personal/system VFS as the rest of the guest. run_js_script** writes a temp **.mjs** under **~/.agent/** and executes it like a **/bin** script — the script body should use the same **ctx** patterns above when the harness passes **ctx.
Checklist before shipping
read_proc_file**/**get_system_info— confirm needed features and caps exist this session.- Paths — absolute, no
..escape from allowed roots. - Timeouts — pass
AbortSignal**/**timeoutMs**to**execLine**/**readLinefor network or slow FS. - Teardown — unregister hooks, clear intervals, dispose IPC fanout subscribers.
- Secrets — never log
~/.agent/config.json**or keys; redact in**MEMORY.md.
Output format (when this skill was used)
- What you read — which
ctx**fields or**/procfiles grounded the answer. - Plan — file paths, entrypoint (
runvsstart), and exit semantics. - Risks — policy gates, missing caps, host-only APIs.