Protocol#

The UI and the core talk over two IPC channels: ohm:call for requests and ohm:event for pushes. The renderer sees exactly two functions:

window.ohmHost = {
  call(method: string, params?: unknown): Promise<unknown>;
  on(event: string, listener: (payload: unknown) => void): () => void;
};

No Node, no ipcRenderer, no engine types. apps/ui/src/host.ts wraps it in a typed HostBridge and returns null when the global is missing, so the UI can be opened in an ordinary browser and says so instead of crashing.

Only the registered UI page may call: the handler table is keyed by the UI's webContents id, and anything else is rejected with Unauthorized caller. Pages you browse cannot reach any of this.

CoreMethods maps each name to [params, result], and the handler table is typed to be total — adding a method is a compile error until it is implemented.

Methods#

Tabs and layout#

Method Purpose
tabs.list the current snapshot
tabs.create { url?, hidden? }
tabs.close / activate / hide / show / discard by id
tabs.navigate { id, input } — resolved as a URL or a search
tabs.back / forward / reload by id
layout.setContentRect where the page view should sit

Scripts and the console#

Method Purpose
scripts.root the scripts folder
scripts.list / read / write / create / delete / rename the file tree
scripts.run by path or inline source
scripts.stop terminate a run
scripts.runs run history
scripts.export / import / restoreExamples folders in and out
console.eval / console.reset the REPL session

Apps#

Method Purpose
apps.list / apps.refresh what is installed; a rescan of apps/
apps.setEnabled start or stop one — a stopped app is granted nothing
apps.uninstall move its folder to the trash
apps.run run one of its commands by title
apps.capabilities every capability, its risk, and the host functions it unlocks

AI, settings and models#

Method Purpose
ai.status / ai.test / ai.generate test never throws; it returns { ok, error, ms }
settings.get / saveProfile / deleteProfile / setActive profiles
settings.setHfToken / pickModelsDir credentials and the models folder
models.list / search / files / download / cancel / downloads / delete local and Hub models
config.get where the data, profile, scripts and models folders are, and why
config.setDir / pickDir move a folder from the next start; dir: null restores the default
config.restart relaunch so a folder change takes effect
webai.respond the renderer answering a web-model request

Projects#

Method Purpose
projects.list / create / get / update / setActive / active
links.add / update / remove
data.preview parse a dataset file
files.list / import / delete / url / read project documents
annotations.get / save annotation sidecars
projects.bundle / importBundle / exportFile / importFile portability

Items#

Method Purpose
items.list / get / save / delete any item kind
items.versions / items.version snapshot history
prompts.save / render / run
experiments.run / cancel / runs / getRun
graphs.compile / run
graphs.profiles / saveProfile / deleteProfile palettes
specs.markdown render, and optionally write docs/<name>.spec.md

Events#

Event Payload
tabs.changed the whole TabsSnapshot — there are no incremental tab events
scripts.changed the file tree
scripts.output { runId, stream, text } as it happens
scripts.status a run's lifecycle
settings.changed the settings, without secrets
models.progress / models.changed downloads and the local list
webai.request a web-model generation for the renderer to perform
projects.changed / project.updated
experiments.progress throttled progress for a run
apps.changed the installed apps, after a scan or a start/stop

What never crosses#

No secret has a method that returns it. The UI receives only hasApiKey per profile, plus hasHfToken and secureStorage booleans.