flowaway goldenbody is an OS-like webpage built with vanilla js and a node server.
This is copied directly from the dev docs in the settings app
Apps live under /systemfiles/runtime/apps/<app-folder>. Every app must include an
entry.json file and an executable JS file named by jsFile.
id- unique app identifier.jsFile- entry script file relative to the app folder.label- display name for the app.iconFile- icon asset path relative to the app folder.pngEnabled- boolean flag to rendericonFileas a PNG image.hiddenDragstrip- boolean flag to hide the drag/resize strip on the app window.-
If you don't want an element to be able to be dragged in your iframe, do
undraggableElement.addEventListener('pointerdown', (event) => event.stopPropagation()); hiddenTitlebar- boolean flag to hide the titlebar on the app window. Only works for iframe apps.createShortcutUponInstallation- boolean flag to create a desktop shortcut when the app is installed.-
startupPos- (Iframe Apps Only) optional object controlling the initial window placement/size. Use{ x, y, width, height, maximize, minimize }to position and size the window when the app is first launched (each property is optional). For example,"startupPos": { "x": 120, "y": 90, "width": 800, "height": 520 }will open the app at those coordinates and dimensions. If omitted, the runtime chooses a sensible default or cascades windows.maximizeandminimizeare boolean flags to start the app maximized or minimized. -
requestAdminPerm-truefor full admin mode,falsefor sandboxed iframe mode. -
openfileCapability- optional list of VFS file/folder patterns or capabilities used by File Explorer to determine if a file extension can be opened by this app. (extension is the .something behind a file), (VFS aka. cloud storage) enableDebugging- boolean flag to enable debugging features for the app.cmdorcommands- array of command objects for the app.headless- boolean flag to indicate if the app runs in headless mode (no entry shown in the UI).functionName- name of the globally exported launch function. (admin app only)globalVarObjectString- name of the global object for app instances. (admin app only)-
allAppArrayString- array name under the global object for tracking instances. (admin app only) cmfandcmfl1- app button context menu hooks. (admin app only)
Non iframe headless apps can choose to not have a window, but if it is an iframe app, it will still have a window, but it will not show on the taskbar and will not have a start menu entry.
You can make it appear to be headless by setting "startupPos": { "minimize": true } in the entry.json, which will make it start minimized and not show.
Headless apps can be used for background tasks, services, file operations, or other non-interactive functionality.
These icon fields are used by start menu, taskbar, and runtime window rendering logic in startMenu.js,
goldenbody.js, and runtimeWindowSystem.js. They determine whether the icon is rendered as
text or PNG.
{ "id": "myApp", "label": "My App", "jsFile": "script.js", "iconFile": "icon.png", "pngEnabled": true, "requestAdminPerm": false, "openfileCapability": [".txt", ".md"], "enableDebugging": true, "headless": false }
When requestAdminPerm is false, the app runs inside a sandboxed iframe using
untrustedIframePatch.js. That iframe has:
sandbox="allow-scripts allow-pointer-lock"- No direct access to DOM APIs like file inputs, localStorage, sessionStorage, IndexedDB, caches, or fullscreen exit APIs.
- Only the exposed runtime API surface available through
window.__goldenbodyAPI.
An app with requestAdminPerm: true is treated as an admin-style app only when the runtime can verify a
matching key.
The loader reads:
<app-folder>/jsKey.txtsystemfiles/userprofile/jsApiKey.txt
Only if both exist and match will the runtime load the app script directly with full privileges. If the key is missing or invalid, the app is skipped or replaced by a placeholder launcher.
This means admin apps are developer-mode apps: they can behave like system apps, but they still need a user-supplied API key to run. (system apps has those keys too, but they are written when ur acc is created)
Admin apps should be designed differently from iframe apps:
- They can access the runtime directly once verified.
- They are not limited by the sandboxed APIs.
-
They still must be installed under
/systemfiles/runtime/apps/<folder>with a matchingjsKey.txt.
If you want to build a full system-style app, use requestAdminPerm: true and make sure your
jsKey.txt is valid.
{ "id": "myAdminApp", "label": "My Admin App", "jsFile": "app.js", "iconFile": "icon.png", "pngEnabled": true, "requestAdminPerm": true, "functionName": "myAdminAppLauncher", "globalVarObjectString": "myAdminAppGlobals", "allAppArrayString": "instances", "cmf": "", "cmfl1": "", "headless": false }
The Settings app stores window.protectedGlobals.appPerms in
/systemfiles/userprofile/appPermissions.json. For sandboxed apps this controls:
storage- allow, deny, or ask for write access.notification- allow, deny, or ask for notifications.launchApp- allow, deny, or ask for launching other apps.
Admin apps with valid keys are trusted differently, because they are expected to run with user-level privilege when the key is verified.
The iframe launcher created in appLoader.js (see createIframeContainerAppFunction)
registers a global function named by entryObj.functionName. Its signature is:
window[entryObj.functionName] = async function(path, verify, argObj, posX = 50, posY = 50) { ... }
Pass structured input via argObj. The loader injects window.__args into the iframe, so the app can read it. For example, if you launch an app with:
// launch an app and pass args await __goldenbodyAPI.launchApp('myApp', [{ view: 'recent', id: 42 }, { obj2: 'favorites' }]);
// inside iframe script const args = window.__args; // [{ view: 'recent', id: 42 }, { obj2: 'favorites' }]
To make an app run a worker in the background, provide headlessJsFile. The loader in
appLoader.js will start the worker automatically once the app is discovered, and it stores it in
window.protectedGlobals.workers[entryObj.id].
{ "id": "watcherApp", "label": "Watcher App", "headless": true, "headlessJsFile": "headlessWorker.js", "iconFile": "icon.txt", "jsFile": "script.js" }
The background worker is created with
new Worker(url, { name: entryObj.headlessJsFile, source: entryObj.id }), so it can live independently
from the iframe. This pattern is used for long-running helper workers, polling loops, or OS-like background
services.
The worker is able to launch its gui through postMessage({ type: 'launchApp' }) to the main runtime.
HeadlessJsFile can also exist if an app is not headless, it will still be launched as a worker in the background.
The worker is not allowed to interact with anything in the VFS, it can only complete communication by sharing a server with the main app instance and use the 3rd party server as a bridge.
It may also choose to use minimized or 0 by 0 windows at startup to stimulate a background service, but the service requires a user interation (launch the app in file explorer by opening a file or terminal) to start.
Admin apps can build their window looks through window.protectedGlobals.apptools, which is initialized
by initapptools.js. The usual flow is:
- Create an app instance with
window.protectedGlobals.apptools.api.createAppInstance({...}). -
Register the instance with
window.protectedGlobals.apptools.api.trackInstance(instance, appId)so maximize/minimize/show/hide/close state is tracked by the runtime.
"use strict";window.myadminapp = () => { // necessary for the runtime to track this app instance const appId = "myAdminApp"; let pos = window.protectedGlobals.getNextWindowXY(); const instance = window.protectedGlobals.apptools.api.createAppInstance({ appId, posX, posY, width: appWidth, height: appHeight, maximize: windowMaximize, minimize: windowMinimize, hiddenDragstrip: false }); window.protectedGlobals.apptools.api.trackInstance(instance, appId);
// vars u prob need let appwindow = instance.rootElement; let dragTarget = instance.titlebarElement; };
For admin apps, appLoader.js validates the app entry object and only injects the script after the
runtime confirms that the app folder has a matching jsKey.txt and
systemfiles/userprofile/jsApiKey.txt.
The following section covers the terminal, CLI commands, and worker runtime. This is separate from the normal iframe app API.
App commands are declared in the cmd array or the commands array. The runtime normalizes
them to lowercase letters only and strips anything else, so a name like WorkerTest becomes
workertest. The terminal command runner reads those entries and launches the matching script as a
worker.
{ "id": "demoApp", "label": "Demo App", "jsFile": "script.js", "iconFile": "icon.txt", "cmd": [ { "name": "workerTest", "src": "workerTest.js", "receive_onkill_handler": true }, { "name": "doThing", "src": "doThing.js" } ] }This is the same pattern used by testIframeApp/entry.json. The terminal app supports invoking it as:
demoApp workerTest --mode=fast --count=3 # or workerTest
When the command is backed by a JS file, the runtime reads the file, creates a worker, passes the argument object as
self.args / self._startArgs, and then calls the worker with a runtime
start message. The arguments are parsed from the terminal command line as JSON or key/value pairs when
possible.
receive_onkill_handler tells the runtime to treat onkill as graceful shutdown logic and
wait for the worker to handle it before terminating the process. If you omit it, the runtime terminates more
aggressively.
Two new runtime APIs are available to worker scripts:
Returns an object with two string properties: relative and full. Use
relative when showing paths to the user (preserves app-relative view). Use full when
resolving or writing files in the VFS.
const cwd = api.cwd(); // cwd.relative -> './data' (user-facing) // cwd.full -> '/systemfiles/runtime/apps/myapp/data' (absolute VFS path)
Workers can prompt the user inline via the terminal. The options object supports:
prefill- a string that will be placed into the terminal input for inline editing.-
multiline- boolean; whentruethe prompt is intended for multi-line text (Shift+Enter inserts newlines).
const edited = await api.prompt('Edit file contents', { prefill: existingText, multiline: true }); // 'edited' contains the final string the user submitted.
Note: the runtime preserves the original argument string shown to the user (relative paths) while resolving absolute
paths internally. Do not rely on the worker receiving an appRoot value; the runtime supplies cwd info
only.
Workers receive a runtime API object named self.api and a few helper globals. The exact implementation
is created in the terminal worker bootstrap and mirrors the same protections used by the sandboxed iframe patches.
-
self.argsandself._startArgs- the startup argument object/array passed when the worker is spawned. self.api.readFile(path, options)- read a file from the VFS.self.api.writeFile(path, content, options)- write text or binary content.self.api.readFolder(path, options)- read folder entries.self.api.writeFolder(path, options)- create a folder.self.api.fileExists(path)andself.api.folderExists(path)- existence checks.self.api.deleteFile(path),self.api.deleteFolder(path)- delete paths.-
self.api.renameFile(path, newName)andself.api.renameFolder(path, newName)- rename paths. -
self.api.pasteFile(destination, clipboard, options)andself.api.pasteFolder(destination, clipboard, options)- copy or move items. self.api.launchApp(appId, args)- launch another app from the worker.-
self.api.writeline(...args)- print a terminal-style line, including optional text color, size, and font. -
self.api.prompt(message, options)- show a prompt and await the response throughpromptResponse. self.api.getStartArgs()- return the original startup arguments object.
self.api.writeline() returns a handle object you can update in place instead of writing a completely
new line. The handle exposes .update(...args) and .rewriteLine(...args), and it also keeps
the original DOM element at .element.
const status = await api.writeline('Downloading...', '#ffcc66', 14, 'ui-monospace, SFMono-Regular, Menlo, Monaco, monospace'); status.update('Downloading... 25%', '#3ddc97', 14); await new Promise((resolve) => setTimeout(resolve, 1000)); status.rewriteLine('Downloading... 100%', '#3ddc97', 16, 'ui-monospace, SFMono-Regular, Menlo, Monaco, monospace');
The first argument can be a string and the optional arguments are the same as terminal styling:
(text, color, size, font). This is the easiest way to make progress indicators or status rows that
update live without spamming the terminal output.
Workers also see a guarded network surface: fetch, XMLHttpRequest, and
WebSocket are replaced so they fail when the runtime blocks network access. The runtime relays the
current Wi-Fi/user network policy via networkToggle / allowNetwork and the worker updates
its local policy from the broadcast state.
Incoming runtime messages include start, networkToggle, allowNetwork,
onkill, promptResponse, and apiResult. Outgoing messages can use
postMessage({ type: 'log' }), postMessage({ type: 'done' }),
postMessage({ type: 'api' }), and the terminal line helpers to render output or request file actions.
Sandboxed apps should call window.__goldenbodyAPI. Every method returns a promise, so await it in async
code.
API summary:
readFile(pathOrHandle, options)- read a file from the VFS as text, binary data, or a stream.writeFile(pathOrHandle, contents, options)- write text or binary content to a file.readFolder(pathOrHandle, options)- list the contents of a folder, with optional detail metadata.writeFolder(pathOrHandle, options)- create a folder in the VFS.deleteFile(pathOrHandle, options)- delete a file.deleteFolder(pathOrHandle, options)- delete a folder.renameFile(pathOrHandle, newName, options)- rename a file.renameFolder(pathOrHandle, newName, options)- rename a folder.pasteFile(destinationOrHandle, clipboard, options)- copy or move a file payload into a destination.pasteFolder(destinationOrHandle, clipboard, options)- copy or move a folder payload into a destination.folderExists(pathOrHandle, options)- check whether a path is a folder.fileExists(pathOrHandle, options)- check whether a path is a file.showOpenFilePicker(options)- let the user pick a file or folder and return a permission handle.showSaveFilePicker(options)- let the user choose a save target and return a handle.showDirectoryPicker(options)- let the user pick a directory and return a handle.closeWindow()- request the runtime to close the current instance window.getBounds()- get the current app window bounds as an object with x, y, width, and height.setBounds(bounds)- resize or reposition the current app window, including maximize/minimize states.setInstanceTitle(title)- update the title of the current instance.setDragThreshold({ px })- change the pointer drag threshold for the current instance.setDragstripHeight({ percent || px })- change the titlebar/dragstrip height for the current instance.setTitlebarVisibility(visible)- show or hide the titlebar for the current instance.message(message, toInstance)- send a message to another instance or broadcast to all instances.messageToWorker(message)- relay a message to the app worker for this instance.getCurInstanceNum()- get the current instance index.getLiveInstanceIndex()- get the number of active instances for this app.getInstanceTitle(instanceIndex)- read the title of a specific app instance.launchApp(appId, [arg1, arg2, ...])- start another app from this iframe app.getTheme()- return the current UI theme asdarkorlight.setTheme(theme)- change the current app theme todarkorlightorauto.setAskUserBeforeClose(value)- enable or disable the close-confirmation prompt for this app.Observer(callback, type)- watch runtime postMessages of a given type.observer.disconnect()- stop an existing message observer.FShandle({ path, key })- lightweight handle wrapper used to reuse a permissioned VFS path/key pair.
Examples:
// object form
await window.__goldenbodyAPI.setBounds({ x: 120, y: 90, width: 900, height: 640 });
// maximize the window
await window.__goldenbodyAPI.setBounds({ maximize: true });
// minimize or restore
await window.__goldenbodyAPI.setBounds({ minimize: true });
// switch the app to dark mode
await window.__goldenbodyAPI.setTheme('dark');
// switch it back to light mode
await window.__goldenbodyAPI.setTheme('light');
// hide the titlebar for a fullscreen-style app
await window.__goldenbodyAPI.setTitlebarVisibility(false);
// show it again later
await window.__goldenbodyAPI.setTitlebarVisibility(true);
Note: observer.disconnect() and FShandle({ path, key }) are convenience items that were
introduced in the runtime surface, and they are still part of the API even though the examples above focus on the
most common app-window and theme calls.
These methods send a message to the host frame and return a promise.
This section teaches the full VFS surface available to app authors. Read it end-to-end if you haven't written apps here before — it covers the primitives, picker handles, permissions, common pitfalls, and concrete examples.
The runtime exposes a promise-based VFS on window.__goldenbodyAPI for sandboxed apps and on
self.api for workers. Admin apps can call window.protectedGlobals.* directly when
verified. The core FS operations are:
readFile(pathOrHandle, options)readFolder(pathOrHandle, options)writeFile(pathOrHandle, contents, options)writeFolder(pathOrHandle, options)deleteFile(pathOrHandle),deleteFolder(pathOrHandle)renameFile(pathOrHandle, newName),renameFolder(pathOrHandle, newName)-
pasteFile(destination, clipboard, options),pasteFolder(destination, clipboard, options) fileExists(pathOrHandle),folderExists(pathOrHandle)-
Picker helpers:
showOpenFilePicker(),showSaveFilePicker(),showDirectoryPicker()
- Sandbox iframe apps: call window.__goldenbodyAPI.* (promises).
- Workers: call
self.api.*.
- Admin apps (verified with keys): may call
window.protectedGlobals.* directly.
Every file/folder argument can be either a plain VFS string like /root/path/file.txt or a handle object
produced by the runtime pickers. A handle is shaped like:
{ kind: 'file'|'directory', path: '/root/whatever', key: 'uuid-permission-key', name: 'prettyname.txt' }Use strings for simple read-only operations against known paths. Use handles when you need persistent write permission to a user-selected target — keep the handle object and pass it back to subsequent calls.
A handle in this platform is not a browser FileSystemHandle and it is not a special object you need to
open or close. It is a small runtime record shaped like:
{ path: '/some/path.txt', key: 'uuid-key' }
The path field tells the runtime which VFS path to use. The key field is the permission
token created when the user picked that file or folder. You keep this object and pass it back to later FS calls
whenever you want to keep using the same picked target.
Important: this is a custom runtime capability object, not a native browser filesystem handle. A
picked directory handle does not become a special “directory context” object that automatically applies to every
child file. For child-file operations inside a picked folder, you still build a child path with the same key, such
as { path: folderHandle.path + '/notes.txt', key: folderHandle.key }.
There are two common patterns:
-
Plain path: use a normal string such as
/root/demo/notes.txtwhen the target is already known and you are not using a picker token. This is the simplest pattern for paths you already know. -
Handle object: use the object returned by
showOpenFilePicker,showSaveFilePicker, orshowDirectoryPickerwhen you want to keep editing the same picked target after the picker closes. The runtime uses the savedpathplus the savedkeyfor future calls. This is the pattern you want for writes and edits to a picked file or folder. For a picked folder, you must usually append the child file name tofolderHandle.pathand reusefolderHandle.key.
Signature: readFile(pathOrHandle, options). Options (mutually exclusive except direct):
{ text: true }— returns the file as UTF-8 text (string).{ buffer: true }— returns an ArrayBuffer.{ stream: true }— returns a ReadableStream for incremental reads.{ direct: true }— return raw response value.
Example (simple):
const { fileSize, fileContent } = await window.__goldenbodyAPI.readFile('/root/doc.txt', { text: true }); console.log('size', fileSize, 'contents', fileContent);Example (streaming large files):
const stream = await window.__goldenbodyAPI.readFile('/root/big.bin', { stream: true }); const reader = stream.getReader(); let received = 0; while (true) { const { done, value } = await reader.read(); if (done) break; received += value.byteLength; // process chunk } console.log('received', received);Signature: writeFile(pathOrHandle, contents, options). Important options:
{ replace: true|false }— whether to replace the target (default true). If set false it will append the contents.-
{ stream: true }— caller supplies a ReadableStream or Blob; runtime will convert to bytes and upload. { retrytimeout: ms }— per-chunk timeout used for retries (default set by runtime).{ password: '...' }— forwarded for server-side protected writes when supported.
The runtime uploads large files in ~10MB chunks with robust retry logic. Example:
// small text write await window.__goldenbodyAPI.writeFile('/root/notes.txt', 'hello world', { replace: true });
// write using a picked handle await window.__goldenbodyAPI.writeFile(savedHandle, fileBytes, { replace: true });
Signature: readFolder(pathOrHandle, { detail: false, directoryDetail: false }). When
detail: true the runtime returns entries with { path, type }. Example:
const names = await window.__goldenbodyAPI.readFolder('/root/projects'); const detailed = await window.__goldenbodyAPI.readFolder('/root/projects', { detail: true });Signature: writeFolder(pathOrHandle, options). Use to create a new folder. Example:
await window.__goldenbodyAPI.writeFolder('/root/projects/new-app'); // or with a picked folder handle (reuses permission) await window.__goldenbodyAPI.writeFolder(folderHandle);fileExists(pathOrHandle)/folderExists(pathOrHandle)— resolves boolean.deleteFile(pathOrHandle),deleteFolder(pathOrHandle)— remove targets.-
renameFile(pathOrHandle, newName),renameFolder(pathOrHandle, newName)— rename entries.
These APIs are used to copy or move clipboard-style payloads into a destination folder. The
clipboard array contains objects like
{ path: '/root/source/thing.txt', kind: 'file' }. Example:
await window.__goldenbodyAPI.pasteFile('/root/dest', { path: '/root/source/template.txt', kind: 'file' }); // use options: { move: true } to move instead of copy await window.__goldenbodyAPI.pasteFolder(destHandle, { path: '/root/source/template.txt', kind: 'file' }, { move: false });
Read-like operations such as readFile, readFolder, fileExists, and
folderExists do not require the write permission gate. Write-like operations that change files,
folders, or storage usage, such as writeFile, deleteFile, renameFile, and
similar actions, are checked against the saved permission key for the picked target.
Picker helpers return handle objects you should store when you want continued permission to write. Typical flow:
// pick a file to open const handle = await window.__goldenbodyAPI.showOpenFilePicker(); const text = await window.__goldenbodyAPI.readFile(handle, { text: true });
// keep 'handle' to write later without re-picking await window.__goldenbodyAPI.writeFile(handle, updatedText, { replace: true });
Results from external pickers include:
{ kind: 'file' | 'directory', path, key, name }If the picker path is not authorized with a valid key, writes do not go to the external path.
First pick a directory. Then build a child path inside that directory and reuse the same key from the
folder handle.
const folderHandle = await window.__goldenbodyAPI.showDirectoryPicker(); const childFilePath = folderHandle.path + '/notes.txt';
await window.__goldenbodyAPI.writeFile( { path: childFilePath, key: folderHandle.key }, 'hello from the picked folder', { text: true } );
The important detail is that the folder handle object is not the file itself and it is not a native directory
context object. It describes a directory, and you create the real child file path by appending the file name to that
directory path while reusing the same key from the folder handle. In other words, a picked directory is
effectively a saved { path, key } pair, not a live browser directory handle.
If you want to edit a file the user picked, keep the picker result and reuse it for later read/write calls.
const pickedFile = await window.__goldenbodyAPI.showOpenFilePicker(); const currentText = await window.__goldenbodyAPI.readFile(pickedFile, { text: true });
await window.__goldenbodyAPI.writeFile( pickedFile, currentText + '\n\nappended by the app', { text: true } );
The same handle object can be passed to readFile, writeFile, deleteFile, and
the other file APIs. You do not need to re-pick the file for each operation as long as you keep the object around.
When you call showDirectoryPicker, the returned object is a folder handle that can be reused for all
subsequent operations against that folder. The important part is that you keep the returned object and use it as the
first argument whenever you want to operate inside that directory.
const folderHandle = await window.__goldenbodyAPI.showDirectoryPicker();// read the folder contents const listing = await window.__goldenbodyAPI.readFolder(folderHandle, { detail: true }); console.log(listing);
// check whether a child exists const childExists = await window.__goldenbodyAPI.fileExists({ path: folderHandle.path + '/notes.txt', key: folderHandle.key }); console.log(childExists);
// write a new file inside that picked folder await window.__goldenbodyAPI.writeFile( { path: folderHandle.path + '/notes.txt', key: folderHandle.key }, 'created via picked folder handle', { text: true } );
// rename an existing child inside that folder await window.__goldenbodyAPI.renameFile( { path: folderHandle.path + '/notes.txt', key: folderHandle.key }, 'renamed.txt' );
// delete a child inside that folder await window.__goldenbodyAPI.deleteFile({ path: folderHandle.path + '/renamed.txt', key: folderHandle.key });
You can also use the same handle for a directory-level operation such as creating a subfolder, listing children, or checking whether the directory itself exists.
const folderHandle = await window.__goldenbodyAPI.showDirectoryPicker(); const exists = await window.__goldenbodyAPI.folderExists(folderHandle);if (!exists) { await window.__goldenbodyAPI.writeFolder(folderHandle); }
const children = await window.__goldenbodyAPI.readFolder(folderHandle); console.log(children);
When a user chooses "Open with" from the File Explorer (rather than using the runtime pickers), the runtime injects an immediate handle into sandboxed iframe apps so the app can operate on the opened file without showing a picker. The iframe patch sets two helpers for this flow:
window.__path__- the VFS path of the file the user opened.window.__filehandle__- an internal permission key string for that file.-
window.userPickedFileHandle- a convenience{ path, key }handle created from the above values (available inside the iframe after load).
Because this is a runtime-provided handle (not a picker promise), you can use it directly. Example:
// read the file that the user opened via Explorer if (window.userPickedFileHandle) { const text = await window.__goldenbodyAPI.readFile( window.userPickedFileHandle, { text: true } ); console.log('opened file contents:', text); }// write back to the same file if (window.userPickedFileHandle) { await window.__goldenbodyAPI.writeFile( window.userPickedFileHandle, 'updated content', { text: true } ); }
// if you need the raw path or key you can also inspect: // window.path (string) and window.filehandle (permission key)
The runtime exposes a special shared path prefix /__public. Sandboxed apps and workers are allowed to
access paths under /__public without a picker key (the runtime treats /__public as an
application-visible shared area). Use it for non-sensitive shared assets, caches, or inter-app data; avoid storing
secrets or personal data there.
const saveHandle = await window.__goldenbodyAPI.showSaveFilePicker({ suggestedName: 'hello.txt' });await window.__goldenbodyAPI.writeFile( saveHandle, 'hello world', { text: true } );
const contents = await window.__goldenbodyAPI.readFile( saveHandle, { text: true } );
console.log(contents);
const folderHandle = await window.__goldenbodyAPI.showDirectoryPicker(); const folderExists = await window.__goldenbodyAPI.folderExists(folderHandle);
if (!folderExists) {
await window.__goldenbodyAPI.writeFolder(folderHandle);
}
const listing = await window.__goldenbodyAPI.readFolder(
folderHandle,
{ detail: true }
);
console.log(listing);
await window.__goldenbodyAPI.renameFolder(folderHandle, 'new-name');
const targetFolder = '/root/demo'; const clipboard = { path: '/root/demo/template.txt', kind: 'file' };
await window.__goldenbodyAPI.pasteFile(
targetFolder,
clipboard
);
- Read and write APIs throw on permanent errors; catch and show friendly messages.
- For large files prefer streaming reads and let the runtime handle chunked uploads when writing.
- Keep picker handles if you need persistent permission; treat the handle as your token.
-
When writing into a picked folder, append the child filename to
folderHandle.pathand reusefolderHandle.key.
- Decide whether you need write access. If yes, call a picker and keep the returned handle.
- Use
readFileto load templates or existing data. - Use
writeFileto save changes; prefer small writes or rely on runtime chunking for big files. - Test the app as sandboxed first; convert to admin mode only when you understand key management.
All of the examples above use the same API surface the runtime provides to workers and iframes — use the variant for
your execution context (self.api in workers, window.__goldenbodyAPI in iframes, or
window.protectedGlobals in admin apps).
There are no hidden files or directories anywhere in cloud storage. You can edit systemfiles to change
how the client behaves. If you break it, you can restore the system tree from the login page and remove broken
non-system apps there. A copy of broken files will also be stored in your cloud storage.
- Requirements: Node.js (latest recommended, v24+). IDK if bun works... prob not.
- Install libraries/dependencies the server (aka. the rammerhead server) needs via npm install:
npm install- Because of how the proxy is set up, the 1st time you start the server you need to run
npm run build- Run server:
node src/server.js- you can also run with:
npm start-
You need to make an account named ServerAdmin as that is the server admin account. Its password is used to ban IPs in http(s)://your-url.ext/moderation (localhost: http://localhost:8080/moderation)
-
THE BACKEND IS BASED ON ""aka (copied from)"" RAMMERHEAD SINCE THE PURPOSE OF THIS THING USED TO BE A PROXY:
-
Configure Rammerhead
src/config.jsto override defaults. -
If you want external access,
cloudflaredis a good option to host it. -
Just so yall know you can run this server in about 10 minutes after you get a new rpi or any device including an android phone. If you need longer than that there must be some stuff u did wrong!
-!!!IMPORTANT!!! if you are hosting on termux change config.js to this
const enableWorkers = false; on line 7 of config.js
For project-related questions: a1462978843@outlook.com, alt email: playminecraft183@outlook.com
