Skip to content

electron_standalone_app_plan

github-actions[bot] edited this page Sep 20, 2026 · 1 revision

Runloop — Plan

A plan for packaging coding-agent-loop as a downloadable Mac app that runs the agent and workspace servers automatically—no browser or manual server startup required.


Overview

Today the app runs in a browser: users start the Go agent server (and optionally the workspace server), then open the frontend. This plan describes a standalone Electron app for Runloop that:

  • Bundles the agent server and workspace server as binaries inside the app.
  • Starts both servers automatically when the user launches the app.
  • Opens a single window loading the existing React UI, which talks to localhost.
  • Stops both servers when the user quits the app.
  • Produces a shareable Mac package (e.g. .dmg) that users can download and run.

Scope: Mac only (Apple Silicon primary; Intel/universal optional). Distribution is a single downloadable artifact (e.g. via GitHub Releases).


Architecture

┌─────────────────────────────────────────────────────────────────┐
│                     Electron App (user double-clicks)             │
├─────────────────────────────────────────────────────────────────┤
│  Main Process (Node)                                              │
│    1. Check ports 45678 / 45679 availability                      │
│    2. Spawn workspace-server (bundled binary) → port 45679        │
│    3. Spawn agent-server (bundled binary)       → port 45678      │
│    4. Poll /health on both until ready                            │
│    5. Create BrowserWindow → load http://127.0.0.1:45678          │
│    6. On quit: kill both child processes                          │
├─────────────────────────────────────────────────────────────────┤
│  Renderer (existing React frontend)                               │
│    - API base URL: http://127.0.0.1:45678                         │
│    - Workspace API URL: http://127.0.0.1:45679                    │
└─────────────────────────────────────────────────────────────────┘
  • Servers run on the user's machine as child processes of the Electron app.
  • Binaries live inside the app bundle (e.g. MyApp.app/Contents/Resources/).
  • No Docker or extra runtime required; the app is self-contained.

Implementation Plan

Phase 1: Electron shell and server lifecycle — ✅ COMPLETED

Step Task Notes
1.1 Add desktop/ package with Electron + electron-builder Done. package.json and main.js initialized.
1.2 Implement server spawn in main process Done. Uses obscure ports 45678/45679.
1.3 Port Availability Check Done. Uses detect-port to prevent conflicts.
1.4 Health-check and window launch Done. Polls /health endpoints with timeout.
1.5 Cleanup on quit Done. Kills children on quit/close.

Phase 2: Go binaries and config — ✅ COMPLETED

Step Task Notes
2.1 Build agent server for Mac Done. Compiled for darwin/arm64.
2.2 Build workspace server for Mac Done. Compiled for darwin/arm64.
2.3 Workspace config and data dir Done. Uses app.getPath('userData').
2.4 Agent config Done. Configured to talk to workspace on 45679.

Phase 3: Frontend and API URLs — ✅ COMPLETED

Step Task Notes
3.1 Build frontend for Electron Done. Built with VITE_API_BASE_URL pointing to 45678/45679.
3.2 Serve frontend from agent server Done. Frontend files moved to agent_go/static/.
3.3 (Future) Dynamic port Deferred as fixed obscure ports are working well.

Phase 4: Local Packaging & Verification (No Signing) — ✅ COMPLETED

Step Task Notes
4.1 electron-builder config Target mac (dmg/zip). Include both Go binaries in extraResources. Point app at agent’s static dir.
4.2 Local Build Script Created desktop/dev-setup.sh to build binaries and setup environment.
4.3 Verify Standalone App ✅ Verified. Fixed hardcoded paths in workspace and agent servers.
4.4 Verify Port Conflict Handling Verified logic in desktop/main.js.

Phase 4.5: Hardening & Polishing — ✅ COMPLETED

Step Task Notes
4.5.1 Fix hardcoded paths ensure agent/workspace accept flags for all paths (DB, logs, docs, data, mcp-config). Done for workspace/root.go (data-dir) and agent.
4.5.2 Verify read-only filesystem compatibility ✅ Done. Agent/Workspace now write to userData (db, logs, data). Default config is copied to userData.
4.5.3 Bundle static assets ✅ Done via extraResources in package.json.

Phase 5: Production Release (Mac) — ✅ COMPLETED

Step Task Notes
5.1 Code Signing Skipped for local build. Requires Apple Developer ID identity. npm run dist produces a functional but unsigned .dmg.
5.2 Notarization Skipped (requires signing). Users will need to right-click -> Open to bypass Gatekeeper on first launch.
5.3 CI/CD Pipeline ✅ Done. GitHub Action .github/workflows/desktop-release.yml created and verified. Automatically builds DMG/ZIP on tag push.
5.4 Distribution Artifacts created automatically in GitHub Releases. Version synced from git tag.

Current Blockers & Active Tasks (Feb 16, 2026)

1. v1.21.0 Release — ✅ COMPLETED

  • Status: Released.
  • Notes: Dynamic ports implemented. Frontend sync features refined. Binaries built and packaged.

Phase 6: Documentation and UX — ✅ COMPLETED (Initial)

Step Task Notes
6.1 README / install instructions Done. Updated desktop/README.md with build and run instructions.
6.2 In-app messaging Polished error dialogs for startup failures (e.g. port conflicts).
6.3 CDP Connectivity Helper Add a UI status/button to help users connect to their local Chrome via --remote-debugging-port=9222.
6.4 Logs and debugging Done. Updated main.js to pipe stdout/stderr from agent/workspace processes to userData/logs/agent.log and userData/logs/workspace.log.

Phase 7: Production Hardening (In Progress)

These steps are recommended for a commercial or wide public release to ensure robustness and security.

Step Task Details
7.1 Dynamic Port Allocation ✅ Done. Implemented in v1.21.0. Servers bind to port 0 (dynamic), Electron parses the assigned port from stdout, and injects it into the frontend via IPC. No more port conflicts or hardcoded ports.
7.2 IPC Authentication Critical for security. Generate a random session token in Electron on startup. Pass it to Go processes as an env var. Require this token in an Authorization header for all API requests to prevent unauthorized access from other local software/scripts.
7.3 Zombie Process Prevention Reliability. Implement a "parent heartbeat" or PID monitoring in the Go servers. If the Electron parent process dies unexpectedly (crash/force quit), the Go servers should automatically shut down to prevent orphaned background processes.
7.4 Auto-Update Integrate electron-updater to pull new releases from GitHub.

Project Status Summary (Feb 16, 2026)

The standalone Electron application has been successfully packaged and released as v1.21.0.

Artifacts Generated

  • DMG: Runloop-1.21.0-arm64.dmg
  • ZIP: Runloop-1.21.0-arm64-mac.zip

Key Achievements

  • Dynamic Port Allocation: Servers now bind to random free ports provided by the OS, eliminating port conflicts with other running instances or services.
  • Zero-Dependency Startup: Spawns agent-server and workspace-server sidecar binaries automatically on launch.
  • Filesystem Persistence: Configured Go servers to use app.getPath('userData') for databases, logs, and search indices.
  • Integrated Frontend: Frontend is served directly via the agent-server.
  • Reliable Dev Mode: npm start (with DEV_URL) correctly connects to external backends on standard ports (8000/8081) while packaged app uses internal dynamic ports.

Next Steps (Post-v1.21.0)

  • Code Signing: To distribute outside of local environments, the build process needs an Apple Developer ID.
  • Universal Build: Configure electron-builder to produce universal binaries (arm64 + x64) for broader Mac compatibility.
  • Security Hardening: Implement Phase 7.2 (IPC Authentication) to secure the local API.

Directory / artifact layout (conceptual)

coding-agent-loop/
  desktop/                    # New: Electron app
    package.json              # electron, electron-builder, main script
    main.js                   # Main process: spawn servers, health check, window, cleanup
    preload.js                # Optional: expose API base URL to renderer
    resources/                # Dev: place Go binaries here for local run
  agent_go/
    cmd/server/               # Agent server (build → agent-server for Mac)
    static/                   # Built frontend (Vite build output)
  workspace/                  # Workspace server (build → workspace-server for Mac)
  frontend/                   # Build with VITE_API_BASE_URL etc. for Electron

Packaged app (simplified):

MyApp.app/
  Contents/
    MacOS/Electron
    Resources/
      app.asar (or unpacked)   # Electron app code
      agent-server            # Go binary
      workspace-server        # Go binary

Alternatives considered

  • Docker: Run agent and workspace via docker compose from the Electron app. Possible, but requires users to have Docker installed; not chosen for “download and run” simplicity.
  • Hosted backend: No local servers; app talks to cloud API. Not in scope for this plan; would be a different product.
  • Windows / Linux: Out of scope for this plan; can be added later using the same pattern (build Go for each OS, electron-builder targets).

Success criteria

  • User downloads a single Mac artifact (e.g. .dmg) from a release page.
  • User opens the app; agent and workspace start automatically; window shows the existing UI.
  • No browser, Docker, or manual server startup required.
  • User quits the app; both servers stop; no lingering processes.
  • (With signing/notarization) App opens without Gatekeeper blocking it.

References

  • Current browser-based setup: Go server serves frontend from ./static/; frontend uses VITE_API_BASE_URL and VITE_WORKSPACE_API_URL (see frontend/src/services/api.ts).
  • Workspace server: workspace/, typically port 8081; docker-compose in repo root.
  • Agent server: agent_go/cmd/server/server.go; static files from ./static/.

Clone this wiki locally