SDK reference

vos.app & events

Metadata about the running instance — its name, id, private sandbox path and the permissions actually granted — plus the two events VibeOS dispatches into your window.

window.vos.app1 methodno permission needed

app.getInfo

app.getInfo

none — always available
getInfo(): Promise<{
  name: string;
  id: string;
  closeBehavior: "close" | "minimize";
  sandboxPath: string;
  permissions: {
    hasRead: boolean;
    hasWrite: boolean;
    hasAi: boolean;
    hasNet: boolean;
    network: string[];
  };
}>

returns metadata for the running instance

The one capability every app has without declaring anything. It is also the correct way to discover your sandbox directory, and calling it lazily creates that directory if it does not exist yet — so call it during boot before your first write.

javascript
const info = await window.vos.app.getInfo();

// {
//   name: "Markdown Notes",
//   id: "markdown-notes",
//   closeBehavior: "close",
//   sandboxPath: "home/.apps/markdown-notes",
//   permissions: {
//     hasRead: true, hasWrite: true, hasAi: false, hasNet: true,
//     network: ["https://api.openlibrary.org/"]
//   }
// }

The info object

FieldTypeDescription
name*stringThe app's display name as installed.
id*stringStable identifier for this installed app. Useful as a storage key.
closeBehavior*"close" | "minimize"What the window does when the user closes it, as declared in your manifest.
sandboxPath*stringHome-relative path to your private directory, e.g. home/.apps/<appId>. Created on demand the first time you ask for it.
permissions.hasReadbooleanWhether filesystem reads are available at all.
permissions.hasWritebooleanWhether filesystem writes are available.
permissions.hasAibooleanWhether window.vos.ai may be used.
permissions.hasNetbooleanWhether window.vos.net may be used.
permissions.networkstring[]The network origin patterns the user approved, as declared.

These are the real, installed permissions

The values come from the grant the user approved — not from the manifest embedded in your HTML. If a user revokes an origin, permissions.network reflects that on the next call.

Adapting to permissions

A well-behaved app never assumes it got what it asked for. Users can decline directories and revoke network origins, and older installs may predate a permission you added later. Read the granted capabilities once at boot and shape the UI around them.

javascript
const { permissions, sandboxPath } = await window.vos.app.getInfo();

// Build the UI around what was actually granted, not what you asked for.
if (permissions.hasAi) enableSummariseButton();
if (!permissions.hasWrite) enterReadOnlyMode();
if (permissions.hasNet) showSyncPanel();

// Always prefer the reported sandbox path over a hard-coded one.
const dataDir = sandboxPath;
  • Hide controls you cannot fulfil rather than letting them fail with an error.
  • If your update needs a new permission, users are re-prompted on upgrade — until they accept, the old grant applies.
  • Full details in permissions.

Window events

VibeOS dispatches exactly two events into your document.

EventTypeDetailWhen
vos-readyEventnoneOnce, immediately after window.vos is installed. Does not replay.
vos-fs-changeCustomEvent{ affectedPath?: string }Whenever the host observes a filesystem change, debounced by roughly 200 ms.

vos-ready

javascript
// Fired once on window as soon as window.vos exists. No detail payload.
if (window.vos) start();
else window.addEventListener("vos-ready", start, { once: true });

vos-fs-change

javascript
// A CustomEvent whose detail may name the path that changed.
window.addEventListener("vos-fs-change", (event) => {
  const path = event.detail && event.detail.affectedPath;
  if (!path || path.startsWith(myDir)) reload();
});

// Equivalent, and usually nicer, through the fs helpers:
window.vos.fs.watch(myDir, () => reload());

Prefer fs.watch

fs.watch is built on this event and adds path filtering, debouncing and an unsubscribe function. Use the raw event only when you want the unfiltered stream.

There are no theme, resize, focus or close events, and no API for opening windows, showing notifications, reading the clipboard or changing permissions. Use standard web platform events — resize, visibilitychange, prefers-color-scheme — for those needs.

Lifecycle & close

Your window can be closed or minimised at any moment, and you cannot intercept it. closeBehavior: "minimize" keeps the document alive in the background — useful for players and timers — while "close" discards it entirely.

javascript
// Save eagerly — you cannot block or intercept a window close.
window.addEventListener("visibilitychange", () => {
  if (document.visibilityState === "hidden") flushPendingSave();
});

window.addEventListener("pagehide", flushPendingSave);
  • Save on a short debounce, not on close — a pending write may never run.
  • Keep everything you need to restore state in a file under sandboxPath; in-memory state does not survive a close.
  • Choose minimize only when background continuation genuinely benefits the user — it keeps consuming resources.