Developers

Developer overview

meith is an Electron desktop workbench backed by a local tool runtime. Everything routes through one validated registry.

The main process is the authority for state and side effects. The renderer, CLI, plugins, and agent runtime all reach application capabilities through the same validated ToolRegistry.

That design keeps the app consistent: opening a tab from the UI, running meith open, or letting an agent control a browser tab all go through the same tool definition, validation, permission, logging, and persistence path.

Packages

meith is a pnpm monorepo built from four packages.

PackageRole
@meith/sharedZod schemas and inferred types for app state, tabs, projects, tools, agents, plugins, logs, settings, IDs, and result helpers.
@meith/protocolTool contracts, tool descriptors, NDJSON protocol messages, naming helpers, and public plugin bridge types.
@meith/desktopElectron main/preload/renderer, services, tool registration, socket server, IPC, browser/terminal hosts, agents, plugins, storage, and packaging.
@meith/cliTerminal client that discovers a running runtime and calls tools over the local socket.

Authority model

The runtime is centered on packages/desktop/src/main/bootstrap.ts. bootstrap(userDataPath, options) wires the services, registers tools, starts the local socket server, writes config, publishes an instance record, hydrates state, and returns the service container.

text
Renderer IPC ─────┐
CLI socket ───────┤
Plugin bridge ────┤
Agent MCP bridge ─┼── ToolRegistry ── services ── app state / files / browser / processes
Internal calls ───┘

ToolRegistry.call() is the common choke point. It:

  • rejects unknown tools,
  • validates arguments with each tool's Zod schema,
  • asks PermissionService to authorize privileged calls,
  • applies timeout and cancellation handling,
  • passes an abort signal and optional event emitter to the tool,
  • normalizes returned values into a ToolResult,
  • logs and audits every call.

Services

The main services are created in bootstrap.ts:

  • AppStateService owns persisted app state and emits reactive state changes.
  • BrowserTabService owns browser/workspace tab records and delegates live web contents to a BrowserViewHost.
  • SpaceService creates, updates, switches, and closes workspaces.
  • ProjectService detects folders, opens projects into spaces, generates templates, prewarms generated projects, and starts project run commands.
  • WorkspaceFileService reads, writes, patches, searches, and diagnoses files inside trusted workspace boundaries.
  • DevServerService and TerminalService start and track managed processes, dev servers, and terminal sessions.
  • PluginHostService installs plugins, stores grants, and gates plugin bridge APIs.
  • AgentService stores sessions and messages, runs the configured adapter, and gates agent tool calls.
  • McpBridgeService exposes per-agent-session tools over a localhost MCP-style HTTP endpoint for external ACP agents.
  • PermissionService authorizes non-renderer privileged calls and writes audit entries.
  • StorageService exposes read-only storage introspection, and ToolSocketService exposes the registry over a local NDJSON socket.

Persistence

Runtime data lives under the user data path passed to bootstrap(). In normal use, discovery data lives under ~/.meith.

  • ~/.meith/config.json records the active runtime socket, app version, protocol version, user data path, instance path, and managed CLI launcher.
  • ~/.meith/instances/<pid>.json records live runtime instances so the CLI can list, target, or kill them.
  • <userData>/state.json stores spaces, projects, tabs, file edit events, plugins, and settings.
  • <userData>/logs.jsonl and <userData>/audit.jsonl store app logs and tool authorization records.
JsonStore writes bounded JSON atomically and runs migrations before schema validation. Corrupt state is backed up and reset to defaults instead of crashing the app.

Development modes

bash
# desktop app
pnpm dev

# renderer-only mock mode
pnpm dev:renderer

# headless main-process runtime
pnpm --filter @meith/desktop dev:headless

# full verification
pnpm check