- ADE is a local-first desktop application for orchestrating coding agents, missions, lanes, PR workflows, and proof/artifact capture.
- The main product lives in
apps/desktopand is built with Electron, React, and TypeScript. - The ADE CLI lives in
apps/ade-cliand shares core services with the desktop app. - State is primarily stored under
.ade/inside the active project, with runtime metadata in SQLite and machine-local files under.ade/secrets,.ade/cache, and.ade/artifacts.
docs/playbooks/ship-lane.md— autonomous PR-to-merge driver (automate → finalize → poll-fix loop). Any agent CLI can follow it directly; Claude Code wraps it as/shipLane.
- Preserve existing desktop app patterns before introducing new abstractions.
- Prefer fixing the underlying service or shared type rather than layering renderer-only workarounds on top.
- Keep IPC contracts, preload types, shared types, and renderer usage in sync whenever an interface changes.
- For ADE CLI changes, verify both headless mode and the desktop socket-backed ADE RPC path.
- For computer-use changes, treat policy enforcement and artifact ownership as hard requirements, not prompt guidance.
- Desktop checks:
npm --prefix apps/desktop run typechecknpm --prefix apps/desktop run testnpm --prefix apps/desktop run buildnpm --prefix apps/desktop run lint
- ADE CLI checks:
npm --prefix apps/ade-cli run typechecknpm --prefix apps/ade-cli run testnpm --prefix apps/ade-cli run build
- Run the smallest relevant subset first when iterating, then finish with the broader checks that cover the touched surfaces.
- Use "lane" for ADE worktrees/branches.
- Use "mission" for orchestrated multi-step work.
- Use "computer use" for screenshot/video/GUI/browser proof flows.
- Prefer direct, operational language over marketing phrasing.
- Keep user-facing copy concrete and stateful: say what changed, what is blocked, and what the next action is.
- Use sentence case for headings and labels unless the existing UI pattern is intentionally uppercase.
- Do not reframe ADE as a docs site, Mintlify project, or generic template app.
- Do not store secrets in plaintext project files when an encrypted store already exists.
- Do not leave policy enforcement in prompts alone when a code path can enforce it directly.
Release flows live behind asc (installed at /opt/homebrew/bin/asc). There's no manual IPA/cert shuffling — prefer the CLI end-to-end and consult the asc-* skills (asc-xcode-build, asc-testflight-orchestration, asc-release-flow, asc-signing-setup, asc-submission-health). Auth is keychain-backed (asc doctor to verify) with the API key at ~/.apple/asc/keys/AuthKey_*.p8 and ~/.asc/config.json.
iOS signing gotchas (don't repeat these):
- The iOS project uses automatic signing (
CODE_SIGN_STYLE = Automatic,DEVELOPMENT_TEAM = VQ372F39G6).apps/ios/ExportOptions.plistships withsigningStyle = manual+ named profiles for CI/archive determinism, but local ad-hoc exports needsigningStyle = automaticinstead (drop the per-bundle profile map). asc signing fetchonly downloads provisioning profiles and the.cer— it does not include the private key. Don't expect it to make local signing work on its own.- Local exports need the App Store Connect API key passed to
xcodebuildso it can create/fetch missing Distribution assets on demand. Add these flags (in addition to-allowProvisioningUpdates):(Pull the current values from-authenticationKeyPath ~/.apple/asc/keys/AuthKey_WRRA7YU7RA.p8 \ -authenticationKeyID WRRA7YU7RA \ -authenticationKeyIssuerID 4d523a6c-e68c-49b2-8560-34e59786d8e3~/.asc/config.jsonrather than hard-coding.) This works even when the local keychain has only the Development cert, because xcodebuild provisions the Distribution cert via ASC. - For the full flow,
asc publish testflight --app <APP_ID> --project apps/ios/ADE.xcodeproj --scheme ADE --version <x.y.z> --build-number <N> --export-options <auto-plist> --group "<Beta Group>" --waitdoes archive + export + upload + distribute in one shot. - After upload,
processingState = VALIDalone isn't enough for TestFlight distribution — you also needusesNonExemptEncryptionanswered (asc builds update --build-id <ID> --uses-non-exempt-encryption=false) and the build assigned to a beta group (asc publish testflight --build <ID> --group "<Group>").
Desktop release:
- Tag a commit on
mainwithvX.Y.Zand push the tag..github/workflows/release.ymltriggers, runs therelease-core.ymljob, and publishes a draft GitHub Release with.dmg,.zip, blockmap, andlatest-mac.ymlassets. The workflow requires the tagged commit to be an ancestor oforigin/main. - Draft releases stay unpublished until you flip them (
gh release edit vX.Y.Z --draft=falseor the UI). Don't publish silently. - Main is protected by a ruleset: admin bypass is required for direct pushes, and the "strict required status checks" rule makes GitHub's "Merge pull request" button reject merges that use a non-linear history (even when the branch already contains
main).gh pr merge --adminhits the same block; merging locally and pushing (admin bypass) is the fallback.
- Node.js 22.x is required (
node:sqliteis used as the primary database engine). - Each app under
apps/has its own independentnode_modulesandpackage-lock.json(no npm workspaces). - Validation commands are documented in the "Validation" section above.
- The desktop test suite (265 test files) is large; CI shards it. For local iteration, run targeted tests (e.g.
npm --prefix apps/desktop run test:unit) or a single file rather than the full suite.
- To inspect ADE desktop parity locally with Codex Computer Use, launch the dev app from the worktree with
npm run devinapps/desktop. - Treat the Electron process spawned by that command as the source of truth, even if the window title or bundle branding says "ADE". In Codex Computer Use, call
list_apps/get_app_stateand prefer theElectronapp entry (App=com.github.Electron) over the installedADEapp entry (App=com.ade.desktop). - Confirm the Codex Computer Use app state shows an ADE window whose HTML content URL contains
localhost:5173. That is the local dev Electron surface. - The first
Electronwindow exposed to Codex Computer Use may be DevTools (Developer Tools - http://localhost:5173/). PressCmd+\`` in theElectron` app to cycle to the main ADE window before interacting with the app. - On first launch, the dev app may open to
localhost:5173/#/projectwith no project selected. Open the recentADE /Users/admin/Projects/ADEproject inside that dev window before comparing desktop parity. - Do not use Safari as the desktop parity reference. ADE desktop parity should be checked against the Electron app surface unless the task explicitly asks for renderer-only Vite behavior.
- Keep the dev terminal logs visible while inspecting. Useful confirmation lines include
dev launcher using http://localhost:5173,DevTools listening on ws://127.0.0.1:9222,window.loading_url, andrenderer.route_change.
- When the user wants the ADE iOS app paired to desktop, run the desktop dev app from the active lane's
apps/desktop, but setADE_PROJECT_ROOTto the ADE project root the phone should sync with. For this local setup, that is commonlyADE_PROJECT_ROOT=/Users/arul/ADE npm run dev, even when the code under test is in/Users/arul/ADE/.ade/worktrees/.... - Do not interact with an already-open Xcode GUI window unless the user explicitly says it is the ADE iOS project. Other projects may be open. Prefer
xcodebuildandxcrun simctlfor building, installing, launching, and inspecting the simulator. - The desktop sync PIN can be read or configured through the dev Electron preload once the
localhost:5173page is running. Use the CDP endpoint printed by the dev app (http://127.0.0.1:9222/json/list) and evaluatewindow.ade.sync.getStatus()to verifypairingPinConfigured,pairingPin, the sync port, andconnectedPeers. - A successful simulator pairing is not just the Settings screen showing "Connected". Also verify desktop
connectedPeers > 0, inspect the simulator database underxcrun simctl get_app_container <UDID> com.ade.ios data, and check recent simulator logs forincoming message failed,FOREIGN KEY, or changeset errors. - If pairing reaches WebSocket but the phone reports
FOREIGN KEY constraint failedwhile applyingchangeset_batch, treat it as an iOS sync/materialization bug until disproven. Desktop CRR tables may not enforce the same foreign keys as the iOS SQLite schema, so valid remote CRDT batches can arrive in an order that local foreign-key checks reject.
- Set
ADE_DISABLE_HARDWARE_ACCEL=1— the VM has no real GPU, and without this the app crashes onWebGL1 blocklisted. node-ptyships only macOS/Windows prebuilds. Afternpm install, runnpm --prefix apps/desktop run rebuild:nativeto compilepty.nodefor Electron on Linux. Then manually compile the spawn-helper:cd apps/desktop/node_modules/node-pty && g++ -o build/Release/spawn-helper src/unix/spawn-helper.cc.- The
npm run devscript has a race condition:predevclearsdist/, then tsup + Electron start in parallel, so the first Electron launch fails with "Cannot find module main.cjs" and auto-restarts. To avoid this, pre-build first (npm run build) then run the dev launcher directly:node scripts/normalize-runtime-binaries.cjs && node scripts/ensure-electron.cjs && node scripts/dev.cjs. - Alternatively, start Vite and Electron separately for more control:
npx vite --port 5173 --strictPort --force &thenVITE_DEV_SERVER_URL=http://localhost:5173 npx electron . --no-sandbox. cr-sqliteextension binaries are only available for macOS. On Linux the app logsdb.crsqlite_unavailableas a warning and continues without CRDT sync — this is non-blocking for development.- The
ADE_PROJECT_ROOT=/workspaceenv var tells the main process to auto-open a project at startup. However, there is a timing race: the renderer's initialgetProject()call may return null before the async project switch completes, causing the welcome screen to appear even though the backend loaded the project. A workaround is to open the project manually via the "Open a project" button in the top bar. - Computer-use features (screenshot, video capture, GUI automation) are macOS-only (
screencapture,osascript). On Linux these gracefully degrade — the app returnsblocked_by_capability. electron-builderconfig only defines amactarget. Distributable Linux builds (deb/AppImage) are not configured, but dev mode works fine.