MDX Limo
Untitled

Electron Desktop Build Plan for Auctor Summary Build Electron v1 as a macOS-only desktop shell that keeps the current Next.js 16 app as the UI, keeps the FastAPI LangExtract backend, and adds a new local Claude Code runtime in the Electron main process. Follow Conductor’s runtime patterns, but adapt them to Electron by removing the Rust/socket layer. The Claude SDK host, auth probe, workspace init probe, session manager, tool approval gate, env assembly, and audit logging all live directly in Electron main. Run both runtimes during migration: Web / existing browser use case continues to use the current Mastra harness + SSE. Desktop / Electron use case uses the new Claude Code runtime + Electron IPC. Use system-installed Claude Code in v1. The app detects a logged-in claude on the operator machine and uses accountInfo() / mcpServerStatus() to verify readiness. Do not bundle Claude in v1. Keep the current workspace browser read-only from the UI, but point it at a new desktop-managed workspace root so Claude can write to it and the Next UI can inspect it. Target Architecture repo root ├── frontend/ Next.js 16 App Router UI and current Mastra harness ├── backend/ FastAPI LangExtract service (uv-managed) ├── desktop/ New Electron package │ ├── package.json │ ├── tsconfig.json │ ├── electron-builder.yml │ ├── src/ │ │ ├── main.ts │ │ ├── preload.ts │ │ ├── bootstrap/ │ │ ├── db/ │ │ ├── next/ │ │ ├── python/ │ │ ├── claude/ │ │ ├── ipc/ │ │ ├── workspace/ │ │ └── logging/ │ └── build/ ├── scripts/ │ ├── bootstrap-operator-machine.sh │ ├── copy-next-standalone.mjs │ └── verify-desktop-runtime.mjs └── pnpm-workspace.yaml Monorepo Setup Update pnpm-workspace.yaml to include frontend and desktop. Keep backend outside the pnpm workspace and continue managing it with uv. Add root scripts: pnpm dev:web → current Next dev server. pnpm dev:backend → current FastAPI dev server. pnpm dev:desktop → Electron main/preload watch mode. pnpm dev:all-desktop → run web, backend, and desktop together. pnpm build:web → Next production build. pnpm build:desktop → Electron package build. pnpm build:all-desktop → build web first, then desktop. Add desktop/package.json with: Runtime deps: electron, @anthropic-ai/claude-code, better-sqlite3, chokidar, wait-on. Build/dev deps: electron-builder, tsup, tsx, concurrently, electronmon or equivalent. Keep the Electron package isolated from frontend bundling. The BrowserWindow always loads a local Next server, never a second renderer bundle. Frontend Changes Required Modify frontend/next.config.mjs to add: output: 'standalone' outputFileTracingRoot pointing at the repo root Add a post-build copy step so .next/standalone, .next/static, and public/ are packaged together for Electron. Refactor the current agent UI runtime boundary in agent-provider.tsx: Extract the current SSE transport into a MastraHarnessAdapter. Add a new ElectronClaudeAdapter that talks to window.electron. Keep the internal UI event shape unchanged so message rendering, plan approval, question prompts, and activity cards survive the migration. Make the current workspace base path configurable in workspace.ts: Dev default stays frontend/.workspace-data/sites/consul. Desktop runtime uses AUCTOR_WORKSPACE_ROOT/sites/consul. Keep the Next-side filesystem read-only. Make env loading in env.ts desktop-safe: First check AUCTOR_ENV_PATH. Then check explicit Electron-provided env. Only fall back to repo-root .env.local in local dev. Add a desktop-aware onboarding/status surface in the existing Next UI: Claude status workspace status backend status imported env status last session / last error Electron Scaffolding desktop/src/main.ts Create the BrowserWindow. Spawn the packaged Next standalone server in production. Spawn the managed FastAPI sidecar in production. Initialize SQLite, settings store, file watcher, Claude runtime manager, and IPC handlers. Kill all child processes cleanly on quit. desktop/src/preload.ts Expose a strict window.electron API with typed channels only. No raw Node access in the renderer. desktop/src/db/ Use better-sqlite3 with DB path ~/Library/Application Support/com.auctor.desktop/auctor.db. Create tables for settings, sessions, session_events, tool_audit, and system_status. desktop/src/bootstrap/ Verify claude exists and is logged in. Verify python3.11 and uv exist. Ensure app data directories exist: ~/Library/Application Support/com.auctor.desktop/env ~/Library/Application Support/com.auctor.desktop/workspace ~/Library/Application Support/com.auctor.desktop/logs ~/Library/Application Support/com.auctor.desktop/runtime desktop/src/next/next-server.ts Dev: connect to http://127.0.0.1:3000. Prod: spawn node server.js from packaged .next/standalone. Inject AUCTOR_DESKTOP=1, AUCTOR_ENV_PATH, AUCTOR_WORKSPACE_ROOT, and AUCTOR_APP_DATA_DIR. desktop/src/python/python-sidecar.ts Dev: expect backend already running at 127.0.0.1:8000. Prod: use bundled backend source and create a managed app-data venv on first run with uv sync --frozen. Then run uv run uvicorn app.main:app --host 127.0.0.1 --port 8000. desktop/src/workspace/file-watcher.ts Watch AUCTOR_WORKSPACE_ROOT with chokidar. Emit workspace:file-changed to the renderer. Ignore .git, temp files, and editor swap files. Claude Runtime Design Implement desktop/src/claude/runtime-manager.ts as the direct Electron equivalent of Conductor’s sidecar manager. Resolve the Claude executable from: settings.claudePath if explicitly set. else which claude. Implement Conductor-style probes: verifyAuth() → empty async generator + queryResult.accountInfo() workspaceInit() → empty async generator + supportedCommands() + mcpServerStatus() Implement Conductor-style session lifecycle: Async generator input queue for interactive sessions. Session reuse when model/settings are unchanged. Idle sweep every 60 seconds. Auto-stop idle sessions after 30 minutes. Max 5 idle sessions retained. Implement Conductor-style env assembly in desktop/src/claude/env-assembly.ts: Layer 1: filtered shell environment Layer 2: Electron process.env Layer 3: app flags (CLAUDE_CODE_ENABLE_TASKS=true, desktop marker vars) Layer 4: imported platform env from desktop .env.local Layer 5: optional claude_env_vars override from SQLite Layer 6: optional GH_TOKEN Strip from inherited shell env before merge: ANTHROPIC_API_KEY ANTHROPIC_AUTH_TOKEN OPENAI_API_KEY CLAUDE_CODE_USE_BEDROCK CLAUDE_CODE_USE_VERTEX Use system Claude auth by default. Do not build an “Add Claude Code credential” flow in v1. The default onboarding is “log in with system Claude Code, then verify”. Configure SDK options: cwd → AUCTOR_WORKSPACE_ROOT pathToClaudeCodeExecutable → resolved system path permissionMode → default disallowedTools → ['AskUserQuestion', 'Bash'] additionalDirectories → workspace root only hooks → user-prompt checkpoint, stop checkpoint, stop auto-commit, post-tool-use audit append Implement canUseTool policy: Auto-allow read/query/navigation tools. Auto-allow Edit, Write, and MultiEdit only when the normalized target path resolves inside the workspace root. Require explicit operator approval for mcp__auctor__upload-to-cms. Reject any write outside the workspace root. Normalize Claude SDK stream events into the existing frontend event contract so the agent UI does not need a second rendering system. MCP Server Plan Add a desktop MCP server entry under desktop/src/claude/mcp-server.ts. Do not block this build on a full shared-package extraction. For v1, import the existing domain logic and tool executors from the frontend codebase directly. Expose the current tool surface from content-engine-tools.ts as Claude-facing MCP tools. Use the auctor MCP namespace and keep tool IDs stable. Log every MCP tool call to SQLite tool_audit. Publish-sensitive tools must route through the approval registry before allowing execution. Keep the existing Mastra harness available for the browser/SSE path during migration; do not delete or repurpose route.ts. Desktop Runtime Contract Add preload channels: desktop:get-status desktop:import-env desktop:verify-runtime claude:verify-auth claude:workspace-init claude:start-session claude:send-message claude:stop-session claude:get-sessions claude:respond-approval settings:get settings:set workspace:list workspace:read Add renderer events: agent:event agent:session-ended agent:approval-requested workspace:file-changed desktop:status-changed Keep the normalized agent:event payload aligned with the current frontend event processor: message_update message_end activity_start activity_tool_start activity_tool_end ask_question plan_approval_required error agent_end Onboarding and Operator Machine Setup Add scripts/bootstrap-operator-machine.sh that does the one-time machine prep: confirm Homebrew confirm Node LTS confirm claude confirm python3.11 confirm uv install missing tools if allowed create the desktop app-data directories Desktop first-run onboarding flow: verify system Claude install run accountInfo() probe import existing repo .env.local into app-data .env.local set or confirm workspace root initialize SQLite run workspace init probe show readiness summary Keep the current repo root .env.local as the dev source of truth. In packaged desktop builds, use the imported app-data .env.local. Build and Packaging Development: pnpm dev:web pnpm dev:backend pnpm dev:desktop pnpm dev:all-desktop runs all three Production build: build Next standalone copy static/public assets into standalone output compile Electron main/preload package backend source, pyproject.toml, and uv.lock build macOS dmg and zip with electron-builder Electron package includes: compiled main/preload .next/standalone .next/static public/ backend source + lockfile Do not package .env.local into the app bundle. Test Plan Unit tests: env assembly precedence workspace path normalization tool approval policy session reuse logic event normalization from Claude SDK → UI contract Integration tests: Claude auth probe succeeds against a logged-in system claude workspace init returns commands and MCP status first message starts a session second message reuses the session stop interrupts the session cleanly upload-to-cms pauses for approval and resumes correctly file watcher emits after Claude writes into the workspace Next standalone starts under Electron with desktop env overrides FastAPI managed venv starts and answers /health E2E tests: packaged macOS app launches to the dashboard agent window works in desktop mode workspace page reflects Claude-written files publish approval UI blocks until operator action quitting the app shuts down Claude child processes and Python cleanly Assumptions and Defaults v1 is macOS only. v1 uses system-installed Claude Code and detects an already logged-in account. v1 keeps the current Next.js UI and current Mastra harness available during migration. v1 uses a desktop-managed app-data workspace root and a desktop-managed .env.local copy. v1 uses SQLite for settings, sessions, and audit logs. v1 does not allow Claude’s Bash tool; file access comes from Claude file tools plus Auctor MCP tools. v1 follows Conductor’s proven patterns for probes, env layering, session reuse, idle sweeping, and approval gating, but implements them in-process in Electron main instead of through a Tauri sidecar/socket stack.

Untitled Document | MDX Limo