Bridge API Design
The Bridge API is the sole communication channel between sandboxed apps and the VibeDepot shell. It’s exposed as window.vibeDepot in every app window.
Why a Bridge?
Section titled “Why a Bridge?”VibeDepot apps are web pages running in Electron BrowserWindows with context isolation. They have no access to Node.js, Electron APIs, or the filesystem. The Bridge exists to provide controlled access to platform capabilities:
- AI model calls — Apps can’t load AI SDKs directly (no Node.js). The Bridge routes calls through the main process.
- Persistent storage — Web storage (localStorage) is unreliable in Electron. The Bridge provides durable, app-scoped storage.
- System integration — Desktop notifications, external URL opening, and theme detection go through the Bridge.
- Security boundary — Every Bridge call passes through permission checks and input validation.
How It Works
Section titled “How It Works”The Bridge is implemented using Electron’s contextBridge.exposeInMainWorld():
App JavaScript Preload Script Main Process(renderer context) (isolated context) (Node.js) │ │ │ │ vibeDepot.ai │ │ │ .callAI(params) │ │ │ ─────────────────────>│ │ │ │ ipcRenderer │ │ │ .invoke('ai:call', │ │ │ params) │ │ │ ─────────────────────>│ │ │ │ Zod validate │ │ │ Check permission │ │ │ Call AI SDK │ │ response │ │ │ <─────────────────────│ │ Promise resolves │ │ │ <─────────────────────│ │- App calls a method on
window.vibeDepot(e.g.,vibeDepot.ai.callAI()). - Preload script translates the call into an Electron IPC
invokewith the appropriate channel name. - Main process handler receives the IPC call, validates parameters with Zod, checks permissions, and executes the logic.
- Response flows back through the same chain.
Four Namespaces
Section titled “Four Namespaces”The Bridge organizes functionality into four namespaces:
vibeDepot.ai
Section titled “vibeDepot.ai”AI model interaction. Supports blocking calls and streaming.
| Method | Description |
|---|---|
callAI(params) | Send messages to an AI model and get a response |
streamAI(params, onChunk) | Stream a response, receiving chunks in real-time |
getProvider() | Get the name of the currently selected provider |
getModel() | Get the currently selected model name |
listProviders() | List providers available to this app |
vibeDepot.storage
Section titled “vibeDepot.storage”Per-app key-value storage backed by JSON files.
| Method | Description |
|---|---|
set(key, value) | Store a JSON-serializable value |
get(key) | Retrieve a stored value |
delete(key) | Delete a key |
keys() | List all stored keys |
clear() | Clear all stored data |
vibeDepot.shell
Section titled “vibeDepot.shell”Shell integration and system access.
| Method | Description |
|---|---|
getAppInfo() | Get this app’s manifest |
getVersion() | Get the VibeDepot shell version |
openExternal(url) | Open a URL in the default browser |
notify(title, body) | Show a desktop notification |
setTitle(title) | Set the app window’s title |
theme() | Get the current theme ('light' or 'dark') |
vibeDepot.db
Section titled “vibeDepot.db”Per-app SQLite database with SQL allowlisting.
| Method | Description |
|---|---|
run(sql, params?) | Execute a write statement (INSERT, UPDATE, DELETE) |
query(sql, params?) | Execute a read query (SELECT) |
transaction(statements) | Execute multiple statements atomically |
Streaming
Section titled “Streaming”The streamAI() method uses a different IPC pattern than blocking calls:
- The preload sends
ai:streamviaipcRenderer.invoke. - The main process starts streaming from the AI provider.
- For each chunk, the main process sends
ai:stream:chunkviawebContents.send(). - On completion, it sends
ai:stream:end. - On error, it sends
ai:stream:error. - The preload’s
ipcRenderer.on()listeners forward chunks to theonChunkcallback. - Listeners are cleaned up automatically when the stream ends or errors.
Error Transport
Section titled “Error Transport”Errors cross the IPC boundary as serialized DxError objects:
- The main process catches an error and creates a
DxErrorwith a code, message, and suggestion. - The error is serialized to JSON using
toSerializable(). - The JSON is sent back through IPC.
- The preload script detects the serialized error and reconstructs a
DxErrorusingfromSerializable(). - The reconstructed error is thrown as a proper exception in the app’s context.
IPC Channel Naming
Section titled “IPC Channel Naming”All channels follow a domain:action pattern:
ai:call,ai:stream,ai:getProviderstorage:set,storage:get,storage:deleteshell:notify,shell:themedb:run,db:query,db:transaction
See the IPC Channels Reference for the complete list.
Next Steps
Section titled “Next Steps”- Bridge API Reference — Complete method signatures and examples
- Security Model — How the Bridge enforces security
- Permission System — How permissions gate Bridge access