Hosts
A host is the program that runs the engine and shows the page. There are two: the VS Code extension (apps/vscode) and the Electron desktop app (apps/desktop). Everything else is shared: the services in packages/core and packages/agent, the controller, the protocol, the indexer and the UI bundle. What is host code is only what the editor or the app does that the other can't.
What every host provides
| Duty | VS Code | Desktop app | Shared piece it stands on |
|---|---|---|---|
| Storage directory, first folder, trust, a logger | extension.ts |
workspace.ts, trust.ts, logger.ts |
The options of GraphService and SessionService |
| The file list | graph/files.ts: git ls-files in a work tree, else workspace.findFiles |
listFilesOnDisk: git, else a walk |
@orbit-code/indexer/listFiles |
| File events | graph/watcher.ts: VS Code's file system watchers |
watcher.ts: one recursive fs.watch |
ChangeBatcher in core |
| The indexer worker | build.mjs copies dist/indexer.mjs |
The same, unpacked from the asar | @orbit-code/indexer |
| A page for the UI under the panel's CSP, with a transport | panel/orbitPanel.ts: a webview panel |
page.ts (the orbit://app/ scheme), window.ts, the preload |
webview.js; HostBridge in the page |
| Dialogs, notifications, the browser, editor tabs | controller.ts (PanelController) |
workspace.ts (Workspace), notifications.ts |
HostUi in packages/core/src/controller.ts |
| File requests from the card and the sheet | fileActions.ts: workspace edits, documents, diff editors |
files.ts: the disk, behind the same revision check |
FileHost, fileHelpers.ts in core |
| Settings under the same trust rules | config.ts and package.json |
settings.ts: settings.json in user data |
normalizeSettings and applySettings in core |
| Status while the page is out of sight | statusBar.ts, permission notifications |
tray.ts (tray, dock badge), notifications.ts |
summarizeSessions in agent |
The controller is OrbitController in packages/core/src/controller.ts. A host gives it a HostUi, a FileHost and, once there is one, a WebviewTransport, and sends { type: 'host', capabilities } for what it can't do: the desktop app sets tabs: false, so the file card hides "Open in a tab" and transcript links open the editor sheet.
VS Code
apps/vscode is the extension imshaikot.orbit-code. Its package.json is the extension manifest.
- Activation on
onStartupFinished.activate()buildsGraphService(storage fromstorageUri,dist/indexer.mjs, the first folder, the file lister),SessionServiceoverClaudeCliBackend, the controller, the watcher, the status bar item and the activity bar launcher, pushes them all into the context's subscriptions, and registers the commands. In development mode it opens the panel by itself, andORBIT_REINDEX=1reindexes. - Commands are the
orbit.*entries incontributes.commands: Open, Ask Claude…, Stop Claude, New Claude Conversation, Reindex Workspace.orbit.prompttakes the prompt text as an argument and returns whether it was accepted, which the smoke test relies on. - Settings are
orbit.maxFilesandorbit.claude.*, read once byreadSettings(), checked bynormalizeSettings, and applied byapplySettingson change (a new path or extra arguments probe the CLI again; a new model, effort or mode applies from the next prompt).claude.path,claude.extraArgsandclaude.permissionModeare machine-scoped and listed inrestrictedConfigurations, so a repository's.vscode/settings.jsoncan't set them. - Workspace trust is
limited: the graph works in an untrusted workspace, and sessions stay unavailable until it is trusted. - The panel is a webview panel with scripts enabled,
retainContextWhenHidden(so the WebGL context and layout survive tab switches; the frame loop parks instead) andlocalResourceRootsofdist/only. Its HTML carries the nonce'd CSP and one script. Creating the panel collapses the side bar, and so do Orbit Code: Open and the activity bar icon for a panel already open. - The activity bar entry is a view container with one empty view whose becoming visible hands the side bar back to the Explorer and opens the panel.
- The status bar shows how many turns run, or wait for approval, while the panel is hidden or closed; a click opens it. A permission request while the panel is hidden becomes a warning notification with Allow, the request's "don't ask again" choice and Deny.
- Logs go to the Orbit output channel, on disk under VS Code's logs directory as
Orbit.log. Webview errors and log calls arrive prefixed[webview]. - Storage is
<workspaceStorage>/imshaikot.orbit-code/orbit-v1/.
The desktop app
apps/desktop composes the same services for each open folder in Electron's main process, one Workspace per folder in its own BrowserWindow.
Module (src/main/) |
Owns |
|---|---|
main.ts |
App lifecycle: launch arguments (--folder, --reindex, --disable-workspace-trust), the single-instance lock, a window per folder (an empty window takes the next folder opened), the menu, the trust dialog, recent folders reopened at launch, the indexer's path under app.asar.unpacked |
workspace.ts |
Workspace, the desktop's HostUi: the services, the controller attached to its window, the watcher flushed when a turn ends; pickFiles is the open dialog, openExternal the system browser for http(s) only |
window.ts |
OrbitWindow, the WebviewTransport: messages accepted only from its own top frame on orbit://app/, ready re-armed on every load, visibility on show, hide, minimise and restore, no navigation or new windows |
page.ts |
The privileged orbit scheme: the page with a fresh nonce and the panel's CSP (as a header and a meta tag), webview.js and its map, and nothing else |
../preload/preload.ts |
Exposes one object with one function, window.orbitHost.postMessage, and delivers host messages as window message events |
files.ts |
DesktopFileHost: the same file requests on the disk, with the same revisions; delete through the system trash and refused otherwise; no tabs |
watcher.ts |
A recursive fs.watch into ChangeBatcher |
settings.ts, trust.ts, recent.ts |
JSON files in user data; the settings file is watched and applied with applySettings |
notifications.ts, tray.ts, shellPath.ts |
Permission notifications (with buttons on macOS), the tray and badge count, the login shell's PATH for an app started from the GUI |
logger.ts |
<userData>/logs/orbit.log, rotated past 5 MB, with the same lines the extension writes |
Invariants the desktop keeps: the window is sandboxed, context-isolated and without Node; the scheme serves the page and its script only; settings come from user data only, never from a folder; trust gates Claude per folder; delete is to the trash or not at all; typed arrays cross the IPC intact (the smoke's relaunch step proves a saved layout is reused). Electron 44.3.0 and electron-builder 26.15.3 are pinned; both CI workflows skip Electron's binary download except in the desktop jobs.
apps/desktop/README.md covers running it, its settings, where it keeps things and packaging.
Adding an editor
An editor app hands the shared host its facts and the shared UI a page; nothing else is rewritten. The checklist:
- Scaffold
apps/<editor>(see The monorepo) with a runtime tag of its own, and add that runtime to the boundary check's table. - Supply each duty in the table above.
apps/vscodeis the reference for every one, and the desktop app for a host that embeds Chromium with Node beside it. - Serve
webview.jsin a page under the same CSP, definewindow.orbitHost.postMessagebefore the script runs, and deliver host messages as windowmessageevents. - Implement
HostUi,FileHostandWebviewTransport, and send thehostcapabilities message for what the editor can't do. - Targets:
build(depending on^build, so the webview and indexer are built),package, an end-to-end check, andnx-release-publish; apublish:<registry>tag and a release group; jobs inci.ymlandrelease.yml.
By editor: VS Code's family (Cursor, Windsurf, VSCodium, Positron) needs no new app, since the same .vsix is published to Open VSX. An editor that can't host a page (JetBrains through a JCEF tool window, Zed, Neovim) would start a local server app running the engine in one Node process, speaking the protocol over a WebSocket or stdio, and open its page.