workbooks docs

Workbooks Browser (desktop)

The Workbooks Browser is the Tauri desktop shell. Its frontend is one Svelte codebase that talks to the OS, the runtime, and the embedded kernel through a single seam — the Host (the Dock membrane). A target (desktop / web / mobile) is a routing config over that one seam, not a code fork.

Truth lives in desktop/src/lib/platform/ (the Host seam), desktop/src-tauri/src/ (the local provider commands), and desktop/src/lib/sdk/ (the Browser SDK). See host vs loaded and the Dock for the why; /learn/the-seam for the deep page.

The Host seam (one contract, three providers)

The UI calls exactly one thing — the Tauri invoke(cmd, args) seam, generalized as the Host. Every capability is fulfilled by one of three providers; the UI never knows which.

providerfulfils via:SRC:
localOS via Tauri (desktop) / browser-native (web)desktop/src-tauri/src/lib.rs:109 (the #[tauri::command] set)
runtimea shared server over RCP (HTTP + WS)desktop/src/lib/engine-api/gen.ts, desktop/src/lib/rcp/
kernelthe embedded oql.wasm, in-process, offlinedesktop/src-tauri/src/kernel.rs:42 (call/2)

A target is a routing config mapping capability group → provider. Per-target mapping (desktop/docs/platform-model.md:35-40):

capability groupdesktopweb pagemobile
fs / window / terminallocal (OS)local (browser)/n.alocal
keychain / secretslocal (OS)runtime / WebCryptolocal
agent / chat / data / syncruntimeruntimeruntime
weave / validate / outlinekernelkernelkernel

Honest caveat: one contract does not mean every capability exists everywhere. The web build has no PTY; the Host reports it unavailable and the UI degrades (desktop/docs/platform-model.md:48-52).

Embedded kernel commands (provider: kernel)

oql.wasm (the SAME component the Elixir runtime loads, ~414 KB) is compiled into the shell and run via wasmtime with an empty WASI context — so the app weaves / tangles / validates a workbook LOCALLY, with no server and no Docker. This is what makes the browser workbook-native and offline-first.

commandkernel exportreturns:SRC:
weaverenderResult<String>desktop/src-tauri/src/lib.rs:67
tangletangle-planResult<String>desktop/src-tauri/src/lib.rs:72
validatevalidateResult<String>desktop/src-tauri/src/lib.rs:77
lintlintResult<String>desktop/src-tauri/src/lib.rs:82
outlineparse-headlinesResult<String>desktop/src-tauri/src/lib.rs:87

The WIT world is pure string → string; the compiled artifact imports WASI 0.2 but is given no preopens, so render never touches the filesystem (desktop/src-tauri/src/kernel.rs:7-9).

Runtime discovery (provider: runtime)

The shell CONNECTS to an already-running runtime; it does not auto-start the heavy engine on launch (desktop/src-tauri/src/lib.rs:246-253). runtime_url reads the local discovery file and returns the localhost URL + per-boot bearer token + state (up / down).

fieldmeaning
url<scheme>://127.0.0.1:<port> or ""
tokenper-boot bearer, or ""
stateup when discovery present, else down

Connection is brokered over RCP. The route → posture resolver is framework- agnostic and ships with router adapters (desktop/src/lib/rcp/routing.ts:11; adapters in desktop/src/lib/rcp/adapters/). Postures: public, gated_data, gated_route (desktop/src/lib/rcp/routing.ts:14). See /learn/nexus and RCP wb-uxn.

Daemon / engine control (provider: local)

Local supervision + the first-run install wizard. n/a on the web build.

commanddoes
daemon_statusdiscovery + /health snapshot
daemon_up / _downstart / stop the local engine
daemon_restartrestart the local engine
engine_detectprobe OS support (krunvm / brew / APFS)
engine_install_backendinstall the VM backend
engine_boot_localboot a local engine container
engine_probehealth-check a candidate engine
engine_connect_cloudattach to a cloud engine
engine_disconnect_clouddetach the cloud engine

A live poll emits a daemon-state event; the tray menu surfaces "Engine: …" status and a start/restart action (desktop/src-tauri/src/lib.rs:254-296).

Offline-first boot

The native split (desktop/src-tauri/src/lib.rs:7-10):

  • NATIVE (work offline) — fs / doc / tab / workspace / bookmark / theme / terminal.

  • RUNTIME (graceful when down) — agent / chat / network / publish, over the control-plane at the discovered URL.

The app boots without the engine; engine state shows in the titlebar/tray, never as a blocking gate. Closing the window HIDES it; the daemon + tray keep running (desktop/src-tauri/src/lib.rs:258-265).

local provider command surface

The full registered #[tauri::command] set, grouped, from the generate_handler! block. Each group's handlers live in the named module.

groupcommandsmodule
kernel / discoveryweave tangle validate lint outline runtime_urllib.rs
daemon / enginedaemon_status daemon_up daemon_down daemon_restart engine_detect engine_install_backend engine_boot_local engine_probe engine_connect_cloud engine_disconnect_clouddaemon.rs
tabstab_list tab_open tab_focus tab_close tab_set_dirtytabs.rs
filesystemfs_tree_walk fs_dir_read fs_read_file fs_write_file fs_reveal fs_rename fs_delete fs_mkdir fs_create_file fs_watch_start fs_watch_stop config_watch_startfs.rs / fs_ops.rs
workbooks / memoryworkbook_spec_read memory_source_resolveworkbooks.rs
packagespackage_list package_get_active package_load package_create package_import_folder package_set_icon package_delete package_add_folder package_remove_folder package_set_active package_refresh_active package_set_layout package_set_view_mode package_set_subtree package_workbooks package_app_workbook package_move_intopackages.rs
workspacesworkspace_list workspace_get_active workspace_create workspace_set_active workspace_rename workspace_set_icon workspace_delete workspace_add_package workspace_remove_package workspace_set_subtreeworkspaces.rs
bookmarks/themes/etcbookmark_list bookmark_create bookmark_rename bookmark_delete bookmark_set_slot theme_* mcp_* plugins_*store.rs
agent settingsagent_settings_get agent_settings_setagent_settings.rs
keychainsecrets_push keys_* env_vars_* connections_*keychain.rs
identity / WorkOSidentity_load identity_generate identity_set_handle identity_set_workos workspace_package workos_sign_in workos_load_session workos_clear_sessionnetwork.rs
terminal (PTY)terminal_spawn terminal_write terminal_resize terminal_killterminal.rs
setupsetup_status setup_initialize_keychain setup_complete_first_run setup_save_model_keysetup.rs

Secrets are held in the OS keychain; PTY terminals and plugin:dialog are desktop-only. plugin:store (workspaces / tabs / bookmarks) is a local-domain KV backed by Tauri's store plugin (desktop/src-tauri/src/lib.rs:105).

Browser preview host (web, mock providers)

When the frontend runs in a plain browser, window.__TAURI_INTERNALS__.invoke is absent, so webHost.ts installs a stand-in (window.__WB_MOCK_INVOKE__) that answers every command from seed data. It is structured as the seed of a real WebHost, not a throwaway mock: domains are tagged mock (today's default), http (future RCP routing), local (future browser-native). Run it with cd desktop && bun run dev (port 5178).

Some commands are stateful in the mock (tabs, bookmarks, package_move_into, the ?onboarding=fresh flow) so flows are walkable in preview; package_move_into's real Rust command is tracked as wb-5fl.12 (desktop/src/lib/platform/webHost.ts:322-323).

The dock / extension model

The browser is itself extensible: a toolkit ships a UI, registers it as a dock panel, and drives the browser through the Browser SDK. The host stays primitives-only — it exposes seams; toolkits own behavior. This is "software built in workbooks" applied to the browser's own surface. See EXEC shapes.

Panel registration

registerToolkitPanel(m) maps \{ id, title, icon, entry \} onto dock.register. The panel's icon appears in the titlebar dock toolbar; clicking opens it in the right dock. DockHost.svelte renders the active panel.

entry formtrust rung:SRC:
\{ iframeSrc \}default — sandboxed iframedesktop/docs/browser-sdk.md:12-15
\{ component \}first-party / trusted, DOM-mounteddesktop/src/lib/components/DockHost.svelte:5-7

iframe panels inherit the theme via the wb-theme postMessage handshake — the same path WorkbookView uses (desktop/src/lib/components/DockHost.svelte:45-61).

The membrane (postMessage protocol)

A panel's iframe talks to the host over postMessage. The SDK is the only channel to the host.

messagedirectionshape:SRC:
wb-sdk-calltoolkit → host\{ id, method, args \}desktop/src/lib/sdk/protocol.ts:19
wb-sdk-replyhost → toolkit\{ id, ok, result?, error? \}desktop/src/lib/sdk/protocol.ts:25
wb-sdk-eventhost → toolkit\{ event, payload \}desktop/src/lib/sdk/protocol.ts:32
wb-themehost → toolkit\{ tokens \}desktop/docs/browser-sdk.md:18
wb-theme-readytoolkit → hosthandshakedesktop/docs/browser-sdk.md:19

Host dispatcher: desktop/src/lib/sdk/browserSdk.ts:33 (dispatchSdk). DockHost turns a thrown error into a wb-sdk-reply error (desktop/src/lib/components/DockHost.svelte:88-90).

The Browser SDK

A toolkit loading /browser-sdk.js gets window.workbooks.browser plus theme inheritance for free (desktop/static/browser-sdk.js:14 installs it; client is ~129 lines). Every call returns a Promise. The surface is exactly what the user can do in the UI — no raw fs / exec / network beyond what the host already brokers.

Method surface

The SDK_METHODS allow-list, kept in sync with the host dispatcher (desktop/src/lib/sdk/browserSdk.ts:33-89):

callreturnsdispatcher :SRC:
tabs.list()[\{id, path, title\}]browserSdk.ts:36
tabs.active()\{id, path, title\} or nullbrowserSdk.ts:38
tabs.open(path)\{ok\}browserSdk.ts:42
tabs.focus(id)\{ok\}browserSdk.ts:45
tabs.close(id)\{ok\}browserSdk.ts:48
bookmarks.list()[\{id, title, path\}]browserSdk.ts:53
bookmarks.add(title, path)\{ok\}browserSdk.ts:55
bookmarks.remove(id)\{ok\}browserSdk.ts:58
workspace.active()\{id, name\} or nullbrowserSdk.ts:63
workspace.list()[\{id, name\}]browserSdk.ts:67
package.active()\{name\} or nullbrowserSdk.ts:69
viewer.current()\{path, title\} of the focused doc, or nullbrowserSdk.ts:75
nexus.active()\{name, url, mode\} of the connected runtimebrowserSdk.ts:79
theme.tokens()the current token mapbrowserSdk.ts:83

browser.call(method, args) is a forward-compat escape hatch; an unknown method throws (desktop/src/lib/sdk/browserSdk.ts:86-87).

Events

browser.on(name, fn). Names (SdkEventName): tab-changed, workbook-opened, theme-changed. This makes "open a workbook → the dock toolkit reacts" a one-liner (desktop/docs/browser-sdk.md:62-65).

Security model

  • iframe panels are sandboxed; the SDK is the only channel to the host.

  • The method surface reuses existing UI commands, so a panel grants no capability the user lacks — no fs/exec/network beyond what the host brokers.

  • DOM-mounted (\{ component \}) panels bypass the iframe boundary; reserved for first-party/trusted panels only.

The UI is itself a workbook

The north star is that the app's own UI becomes a workbook: one frontend build, where a target is just a host routing config + runtime endpoint an agent can author — "publish anywhere" = choose a preset + a runtime URL (desktop/docs/platform-model.md:103-115).

Today's reality, stated plainly: the browser is workbook-native (renders the format locally) and workbook-extensible (toolkits drive it via the SDK). The shell itself is still hand-authored Svelte talking to the Host seam; the typed Host interface / WIT component and the agent-authored target-config are explicitly future decisions (desktop/docs/platform-model.md:80-87). Do not read "the UI is a workbook" as present-tense.

See also