Skip to Content
Architecture

Architecture

ShipCode is a Turborepo monorepo with multiple apps and shared packages.

Structure

apps/ web/ Marketing site (Next.js + Tailwind) desktop/ Electron + Vite + React 19 cli/ CLI tool (published as 'shipcode' on npm) docs/ This documentation (Nextra) packages/ pipeline/ Pipeline state machine shared/ Types, schemas, constants, design tokens agents/ Process manager, prompts, GitHub CLI db/ SQLite persistence (node:sqlite) git/ Git operations + worktree manager ui/ React components

Key Design Decisions

  • gh CLI over GitHub API — no OAuth, uses existing auth
  • Adversarial review — different model families catch different blind spots
  • PR is the human gate — fully autonomous until PR creation
  • Fork-point SHA for diffs — stable diffs even when base branch moves
  • node:sqlite — built-in Node.js SQLite, no native addon dependencies
  • Sandboxed Electron renderers — Chromium sandbox + context isolation around a narrow preload bridge

Desktop IPC Trust Boundary

Electron’s main process treats the registered channel name and the IpcMainInvokeEvent as trusted application-owned values. Every argument received from the renderer is untrusted, even though the preload bridge and TypeScript channel map constrain normal callers.

Before any invoke handler runs, the shared main-process boundary requires either no argument or one plain object containing only bounded primitive values, arrays, and plain objects. It rejects accessors, symbol properties, circular references, prototype-sensitive keys, non-finite numbers, unsupported object prototypes, and payloads outside these limits:

  • 1 MiB total input
  • 512 KiB per string
  • 20 nesting levels and 20,000 values
  • 10,000 array items and 1,000 properties per object
  • 256 bytes per property name

Transport validation is the first layer. Each handler still owns domain validation such as enum membership, project and thread existence, authorization, URL allowlists, and filesystem path safety. Failures are logged in full in the main process, while renderer-visible errors and IPC event metadata are reduced to one line and 280 characters.

Electron renderer boundary

ShipCode enables Electron’s Chromium sandbox before the app becomes ready and also opts the main and splash windows into sandboxing explicitly. The main renderer has Node.js integration disabled in the page, workers, and subframes; context isolation remains enabled; insecure mixed content and <webview> are disabled. The bundled preload remains the only renderer bridge and exposes the same frozen { invoke, on } API through contextBridge.

Defense in depth does not rely on sandboxing alone:

  • production uses a default-src 'none' Content Security Policy with explicit resource directives; development adds only the Vite server allowances;
  • main-window navigation is restricted to the exact bundled renderer file (or the Vite development origin);
  • renderer-created windows are denied, and HTTP(S) links are handed to the OS browser instead of inheriting ShipCode’s preload bridge;
  • focused main-process tests pin the security-sensitive BrowserWindow preferences, CSP, navigation rules, and preload bridge behavior.
Last updated on