Build an app

Building a .vibe app

A .vibe app is a single JSON manifest that bundles your metadata and inline HTML. It needs no hosting and runs as a native-feeling window inside VibeOS.

Anatomy of a manifest

Everything lives in one JSON object. The html field holds a complete HTML document — your markup, CSS and JavaScript — that VibeOS renders inside a sandboxed window. Here's a complete, valid example:

json
{
  "vibe": 1,
  "name": "Markdown Notes",
  "iconEmoji": "📝",
  "iconBg": "linear-gradient(135deg,#10b981,#0ea5e9)",
  "iconImage": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg…",
  "description": "A fast, distraction-free markdown notepad that saves to your Home directory.",
  "version": "1.0.0",
  "author": "Jane Developer",
  "genre": "productivity",
  "width": 900,
  "height": 640,
  "closeBehavior": "close",
  "fileExtensions": ["md", "markdown"],
  "permissions": {
    "read": ["home"],
    "write": ["home"],
    "ai": true,
    "network": ["https://api.openlibrary.org/", "https://covers.openlibrary.org/"]
  },
  "screenshots": [
    { "url": "https://example.com/shot1.png", "caption": "Editing a note" }
  ],
  "html": "<!doctype html><html><head><meta charset=\"utf-8\"><style>body{font-family:system-ui;margin:0;padding:24px;background:#0f172a;color:#e2e8f0}</style></head><body><h1>My Notes</h1><textarea style=\"width:100%;height:80vh\"></textarea></body></html>"
}

One file, no external runtime

The runtime is a sandboxed browser window with no external network access for core logic. You cannot load scripts, styles, or libraries from external URLs. CSS and Javascript must be entered inline within the html field (single HTML string with embedded CSS/JS). System capabilities such as the filesystem and AI are reached exclusively through the window.vos SDK.

Field reference

Fields marked with * are required. Anything else is optional and falls back to a sensible default.

FieldTypeDescription
vibe*1Format version. Always the literal number 1.
name*stringDisplay name, 2–60 characters.
iconEmoji*stringAn emoji used as the app icon.
iconBg*stringBackground behind the icon — any CSS color or gradient, e.g. linear-gradient(135deg,#10b981,#0ea5e9).
iconImagestringApp icon embedded as a base64 data URI, e.g. data:image/png;base64,…. Overrides iconEmoji when present. Must be a data URI — external URLs are ignored; the host then falls back to iconEmoji over iconBg. Use a small square PNG or WebP (64–128px, under ~3 MB encoded).
description*stringWhat the app does, 10–2000 characters. Shown on the listing.
html*stringThe full inline HTML document that renders inside the app window.
versionstringSemver, e.g. 1.0.0. Defaults to 1.0.0.
widthnumberInitial window width in px (240–3840). Default 900.
heightnumberInitial window height in px (180–2160). Default 640.
closeBehavior"close" | "minimize"What happens when the user closes the window.
fileExtensionsstring[]Extensions this app can open, e.g. ["md"]. Enables double-click to open.
authorstringDeveloper or studio name.
genrestringCategory slug used to place the app in the catalog.
screenshots{ url, caption? }[]Up to 8 screenshots shown on the app listing.
appCenterIdstringStable identifier linking updates to an existing App Center listing.
permissions{ read?: string[]; write?: string[]; ai?: boolean; network?: string[] }Filesystem, AI, and network capabilities. See the section below.

Permissions

Filesystem permissions

The filesystem is directory-scoped: your app declares the Home-relative directories it wants to read and/or write. The host re-checks every filesystem call against the installed grant, so an app can never widen its own scope at runtime.

json
{
  "permissions": {
    "read":  ["home/Documents", "home/Pictures"],
    "write": ["home/Documents"]
  }
}

Declaring capabilities

The presence of read / write (even an empty array []) declares the filesystem capability. An empty array means sandbox-only access at home/.apps/<appId>/. The user is prompted to approve the requested directories at install time, and re-prompted on upgrades that widen the scope.

AI permissions

The ai flag gates access to the AI gateway. Set it to true to enable AI chat and other model-powered features through window.vos.ai. The host rejects every AI call when this flag is missing or false.

json
{
  "permissions": {
    "ai": true
  }
}

AI access requires the ai permission

To use the AI gateway (window.vos.ai.chat), set "ai": true inside permissions. AI requests run through VibeOS, so no API keys are required — see the SDK reference.

App metadata (window.vos.app.getInfo) is the only capability that needs no permission — it's available to every app with no declaration and no install-time prompt.

Network permissions

By default a .vibe app has no network access — the host injects a strict connect-src CSP and the browser blocks every outbound request. To call an external API, list its https:// origin (with an optional path prefix) in permissions.network. Each entry covers the origin and any URL beginning with that prefix.

json
{
  "permissions": {
    "network": [
      "https://api.openlibrary.org/",
      "https://covers.openlibrary.org/"
    ]
  }
}
  • https://api.example.com — the entire origin.
  • https://api.example.com/v1/ — origin plus path prefix.
  • Only https:// is allowed. Up to 32 entries.

Use window.vos.net.fetch for requests

Direct fetch() still hits CORS for most APIs. Use window.vos.net.fetch(url, init) — it routes through the VibeOS host, re-validates the URL against this list, and returns { status, headers, body | bodyBase64 }. See the SDK reference.

Users approve the requested origins at install time and can revoke individual entries from Web Apps → app details → Permissions after install.

The HTML runtime

Inside the window your document runs as a normal web page, with a few VibeOS specifics:

  • The document is sandboxed — it can't reach other apps or the host desktop directly.
  • System capabilities (Home filesystem, AI chat, app info) are reached through the global window.vos SDK object — wait for the vos-ready event, then see the SDK reference.
  • Use the window width/height as a design target, but make your layout responsive — users can resize.

Next steps

When your manifest is ready, paste it into the submit form as a draft, then follow the submission & review process.