---
title: Architecture
description: The apps and packages, and the boundary between Electron main and the renderer.
---

Vimputer has two halves. The editor is where you build layers, bindings, and
variables. The runtime receives Karabiner events and shows the HUD.

## Apps and packages

| Path | Owns |
| --- | --- |
| `apps/desktop` | Electron main, preload, renderer, plugin runtime, HUD |
| `apps/browser-extension` | Chrome extension for tab and web-app commands |
| `apps/macos-accessibility-helper` | Swift helper: menus, displays, windows, Accessibility permission |
| `apps/docs` | This site |
| `packages/schemas` | Zod contracts for config, actions, plugins, HUD, and RPC |
| `packages/config` | Config store, defaults, and Karabiner import |
| `packages/karabiner` | Generation into Karabiner profile JSON |
| `packages/plugin-sdk` | The plugin authoring API |
| `packages/integrations` | Node-safe discovery and parsing of local command sources |
| `packages/shortcuts` | Re-exports the OpenKeymap SDK for semantic commands |
| `packages/api` | The external automation API contract |
| `packages/cli` | The `vimputer` command-line tool |
| `packages/ui` | Shared renderer primitives |

Code that speaks the product's language stays in `apps/desktop`. A reusable
primitive, contract, parser, or compiler step goes in a package.

## Main and renderer

Electron main owns everything privileged: the filesystem, shell, Karabiner writes,
the runtime socket, plugin execution, and the Accessibility helper. The renderer
stays platform-agnostic and calls main over typed oRPC through preload and a
message port.

| State | Lives in |
| --- | --- |
| Data from main | TanStack Query |
| The working copy of the config | The renderer store, autosaved |
| Shareable view state (`?view=`, `?binding=`) | TanStack Router search params |
| Everything transient | Component state |

App hotkeys go through `@tanstack/react-hotkeys`. Keep preload thin and main's
procedures narrow.
