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)whereargv[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, norequire('node:fs'). The booter assemblesctxas the narrow syscall surface:vfs,env,execLine,runBinCommand, optionalhttpFetch,bare, identity helpers, diagnostics, etc. See the mermaid overview in Chapter 2 of the developer guide./bin/agentis special — The agent bundle usesrun_js_scriptfor guest JS and a frozen tool surface; do not assumenodeexists. For general in-guest scripting, preferctx.vfs+ctx.execLine/ctx.runBinCommandand 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 booterraceWithAbortAndTimeout). 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 withctx.b4a.toString(buf)orTextDecoder. Always use absolute paths under/home,/tmp,/mnt,/bin, etc., per policy. - Environment —
ctx.envis mutable shell state (alsoctx.vfs.env). AfterexecLine,ctx.env.BARE_OS_EXIT_STATUSreflects last exit code when the booter sets it. - Exit — Set
ctx.exitCode = 1(or other code) on error;0on success.ctx.requestBooterExit(code)ends the whole session from builtins likeexit.
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.drivevsctx.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—**>>> 0** when 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 ascurl/wget; every host forweb_fetchmust be allowlisted.ctx.bare— Frozen map of vendored modules (b4a,protomux, …) whenBARE_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/timeoutMstoexecLine/readLinefor network or slow FS. - Teardown — unregister hooks, clear intervals, dispose IPC fanout subscribers.
- Secrets — never log
~/.agent/config.jsonor keys; redact inMEMORY.md.
Output format (when this skill was used)
- What you read — which
ctxfields or/procfiles grounded the answer. - Plan — file paths, entrypoint (
runvsstart), and exit semantics. - Risks — policy gates, missing caps, host-only APIs.