This file provides guidance to Claude Code when working with this repository. Full architecture details are in AGENTS.md and docs/architecture.md. Full project rules are in .claude/PROJECT_RULES.md.
apps/desktop/ # Electron shell: main process, preload, loads web build output
apps/web/ # Standalone React UI (Vite + React Router + Zustand)
packages/agent-core/ # Core business logic, types, storage, MCP tools (@anastomotic_ai/agent-core, ESM)
# Dev
pnpm dev # Desktop app (web dev server + Electron)
pnpm dev:web # Web UI only (localhost:5173)
pnpm dev:clean # Dev with CLEAN_START=1 (clears stored data)
# Build
pnpm build # All workspaces
pnpm build:web # Web UI only
pnpm build:desktop # Desktop (builds web first)
pnpm clean # Clean build outputs and node_modules
# Typecheck / Lint / Format
pnpm typecheck && pnpm lint:eslint && pnpm format:check
pnpm format # Prettier auto-fix (write mode)
# Tests — always workspace-scoped (no root-level test commands)
pnpm -F @anastomotic/web test:unit # Web unit tests
pnpm -F @anastomotic/web test:integration # Web integration tests
pnpm -F @anastomotic/desktop test:unit # Desktop main-process unit tests
pnpm -F @anastomotic/desktop test:integration # Desktop integration tests
pnpm -F @anastomotic/desktop test:e2e:native # Playwright E2E tests (serial, Electron)
pnpm -F @anastomotic_ai/agent-core test # Agent-core tests
# Run a single test file
pnpm -F @anastomotic/desktop vitest run --config vitest.unit.config.ts path/to/file.unit.test.ts
# Environment variables for dev/testing
# CLEAN_START=1 — clear all stored data on start
# E2E_SKIP_AUTH=1 — skip onboarding flow
# E2E_MOCK_TASK_EVENTS=1 — mock task eventsReact UI (apps/web)
↓ window.anastomotic.* calls
Preload (contextBridge) — apps/desktop/src/preload/index.ts
↓ ipcRenderer.invoke / ipcRenderer.on
Main Process — apps/desktop/src/main/ipc/handlers.ts
↓ agent-core factories (TaskManager, Storage, etc.)
↑ IPC events → taskStore subscriptions in renderer
- Handler in
apps/desktop/src/main/ipc/handlers.ts - Expose via
contextBridgeinapps/desktop/src/preload/index.ts - Typed wrapper in
apps/web/src/client/lib/anastomotic.ts - Consume from components or
apps/web/src/client/stores/taskStore.ts pnpm typecheckto verify the full chain
Never skip a step — all 4 must be done together.
- ESM package (
"type": "module") — all internal imports must use.jsextensions - Shared types:
packages/agent-core/src/common/types/ - Factories are the public API:
createTaskManager,createStorage,createPermissionHandler, etc. - Do not use internal classes directly; use factories
- DB:
anastomotic.db(prod) /anastomotic-dev.db(dev), in Electron user-data directory - Current schema version: 6 (in
packages/agent-core/src/storage/migrations/index.ts) - To add a migration: create
vXXX-description.ts, import + add to themigrationsarray, bumpCURRENT_VERSION - Never modify released migration files — always add a new one
The packaged app ships Node.js v20.18.1. When spawning npx/node in the main process,
prepend bundledPaths.binDir to PATH — otherwise processes fail with exit code 127 on
machines without system Node.js. See docs/architecture.md.
| Alias | Resolves to |
|---|---|
@/* (web only) |
apps/web/src/client/* |
@main/* (desktop only) |
apps/desktop/src/main/* |
@anastomotic_ai/agent-core |
packages/agent-core/src/index.ts |
@anastomotic_ai/agent-core/common |
packages/agent-core/src/common.ts |
Desktop does not have an @/* alias — UI code lives in apps/web.
- No
require()in agent-core — it is ESM; useimport .jsextensions required on all imports within agent-core- Image assets must use ES module imports (
import logo from '/assets/logo.png'), never absolute paths — they break in the packaged app - Always use braces for
if/else/for/while(enforced by ESLintcurlyrule) - No nested ternaries — use mapper objects or if/else
- No root-level test scripts — always use
-F @anastomotic/web,-F @anastomotic/desktop, or-F @anastomotic_ai/agent-core - Reuse UI components — check
apps/web/src/client/components/ui/before creating new ones - New files must be < 200 lines — split into logical modules if needed (exceptions: generated files, migrations)
- No
console.login production code — use the app's existing logger
Do not delete, comment out, or disable existing functionality unless the task explicitly requires removal. If unsure, ask before removing. This applies to: exported functions, components, types, IPC handlers, UI elements, routes, and config entries.
- Always pull
mainbefore branching:git checkout main && git pull origin main - Branch naming:
feat/ENG-XXX-short-descriptionorfix/ENG-XXX-short-description - Conventional commits:
feat(scope):,fix(scope):,refactor(scope):,chore(scope): - Never force-push a branch that has an open PR
# 1. Install deps if any package.json changed
git diff --name-only | grep "package\.json" && pnpm install
# 2. Typecheck → Lint → Format → Build
pnpm typecheck && pnpm lint:eslint && pnpm format:check && pnpm build
# 3. Tests — only workspaces with changed files
pnpm -F @anastomotic/web test:unit # if apps/web changed
pnpm -F @anastomotic/desktop test:unit # if apps/desktop changed
pnpm -F @anastomotic_ai/agent-core test # if packages/agent-core changedDo not push if any step fails.
Tailwind CSS + shadcn/ui, CSS variables for theming (no hardcoded colors), DM Sans font,
Framer Motion for animations via apps/web/src/client/lib/animations.ts.