Skip to content
arpan404Public

About

Multi-agent coding environment: one interface for your local coding-agent CLIs across desktop, web and mobile

Resources

Stars

4 stars

Watchers

0 watching

Forks

Latest commit

 

History

8,828 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ace

A multi-agent coding environment. ace drives the coding-agent CLIs you already have installed (Claude Code, Codex, OpenCode, Cursor, Antigravity, Pi) and gives them one interface on desktop, in the browser and on your phone.

Status: early development. The local daemon can store events and serve snapshots and replay over WebSocket. Provider execution and clients are still to come.

How it fits together

  • Daemon runs on the machine that has your code and your logged-in agent CLIs. It owns every agent process, the event log, git worktrees and terminals.
  • Clients (desktop app, web app, mobile app) are views over the daemon's event log. They can connect locally or from another device.
  • Protocol: every provider is translated into one canonical model. Agents form a tree, status is derived from the whole tree, and tool calls, approvals and background tasks are typed. See docs/adr and docs/research/providers.

Each agent CLI owns its credentials. ace can start its login or hand a pasted API key directly to its supported credential mechanism over stdin; ace never saves the key. See the authentication policy.

Repository layout

Path Purpose
apps/relay Self-hosted WebSocket relay with encrypted outbound host/client streams
packages/secure-channel Portable Noise XX handshake, ordered transport and static identity
apps/daemon Local SQLite event store and authenticated WebSocket server
apps/ios Native SwiftUI/JavaScriptCore spike; Phase 1 held by ADR 0074
apps/web React web client; the same bundle runs in the desktop app
apps/desktop Electron shell: daemon supervision, notifications, in-app browser
packages/projection Pure shared event folds for thread and sidebar views
packages/git Local Git worktrees, checkpoints, diffs and safe restore
packages/orchestrator Multi-provider fan-out, races, pipelines and coordinator lanes
packages/review Local diff comments, persistent anchors and structured agent fixes
packages/protocol Canonical protocol: Zod schemas and types, no runtime logic
packages/agent-registry Official ACP catalog, approved local installations and source profiles
packages/provider-kit Supervised provider processes, JSON-RPC, SSE and local CLI discovery
packages/workspace Workspace file listing, reads, search and change subscriptions
packages/files Streamed transfers, atomic workspace mutations, trash and artifacts
tools/recorder Records raw provider sessions as fixtures for adapter contract tests
tools/dev The development process runner behind bun run dev
docs/adr Architecture decision records
docs/research Primary-source research behind the decisions

The agent browser and computer tool contract documents scoped MCP calls, navigation waits and control handback.

The source-control draft workflow documents editable commit and PR text generated through the user's own CLI, source revisions and cancellation.

The headless CLI exposes thread and delegated-task control.

Agents can publish HTML visualizations through dedicated MCP tools. Pages replay with the thread and run in an offline sandbox. Claude Code and Codex sessions receive the bundled visualize skill.

The generated protocol reference covers WebSocket messages, canonical events and built-in MCP tools. Regenerate it with bun run docs:protocol.

Development

Prerequisites

  • Bun 1.4.4+ (package manager, script runner and the daemon runtime) and Node 26+ (release builds and tooling).
  • macOS: the Xcode Command Line Tools (xcode-select --install) for git, cc and swiftc (native addons and the screen helper). Full Xcode only for the iOS Simulator.
  • Optional: the Android SDK (ANDROID_HOME) for emulators; Rust (cargo) to build the Windows or Linux screen helper: Rust 1.87+ for Linux (rust-version in native/screen-helper-linux/Cargo.toml; rustup update stable), 1.82+ for Windows.
  • The provider CLIs you want to use, installed and logged in on their own (claude, codex, opencode, agent, …). the CLI owns credential storage.
bun install
bun run check   # merge gate only: includes tests

Commands

Every development command runs its processes side by side with prefixed logs (daemon │, web │, desktop │). Ctrl-C stops all of them; a second Ctrl-C kills them.

Command What runs
bun run dev The daemon in watch mode, the web Vite server, and Electron on the Vite URL (renderer HMR; main restarts)
bun run dev:web The daemon and the web app in your browser; prints a #token= link for the dev daemon
bun run dev:fake The web app against the in-page fake daemon. No daemon, no providers
bun run dev:desktop:fake Electron against the fake daemon
bun run daemon Only the daemon, in watch mode
bun run doctor The daemon's doctor checks against the dev data dir
bun run desktop:build An unsigned (ad-hoc signed) local app for this machine: macOS .app and dmg in apps/desktop/dist/release
bun run desktop:package The full platform package (see Packaging)
bun run desktop:e2e Playwright-for-Electron smoke test against the fake daemon (ACE_E2E_ELECTRON=1)
bun run release:doctor What this Mac has set up for a release: Developer ID, notarization, GitHub CLI (releasing)
bun run release:build <v> A release for this Mac's architecture, signed, notarized and verified, staged under dist/releases/v<v>
bun run release:publish <v> The staged release as a GitHub release, which installed apps update from
bun run smoke:real Headless Chromium tour against a protected copy of owner data; options and fixture mode

Dev data is isolated and persistent. The dev daemon uses ACE_HOME=~/.ace/dev on port 4343, and Electron keeps its window state, sessions, settings and logs in ~/.ace/dev-electron. Every checkout and worktree shares this home, so dev threads and settings survive across branches, and none of it touches ~/.ace or an installed app. Set ACE_DEV_SEED=1 to copy the fake daemon's demo threads into an empty dev store before the daemon starts (ACE_DEV_SEED=1 bun run dev). Reset everything with rm -rf ~/.ace/dev ~/.ace/dev-electron; set ACE_DEV_DIR for a throwaway home elsewhere.

Pointing the app at another daemon. bun run dev attaches to the dev daemon and never spawns one. The packaged app reuses a daemon already serving ACE_HOME (the CLI, or the login service from ace service install) and only starts its bundled daemon when none answers. To use a daemon on another machine, start the app with ACE_DAEMON_URL=wss://host:port/ and ACE_DAEMON_TOKEN=<paired device token> (or ACE_DAEMON_TOKEN_FILE) and ACE_DAEMON_DEVICE_ID=<paired device ID>; use the credentials issued when pairing this device, rather than the host token printed by ace token. In the browser build, enter the address, paired-device token and paired device ID on the connection screen.

Terminals and native calls. The daemon runs on Bun: terminals use Bun's own PTY (Bun.spawn({ terminal })) and C or Win32 calls go through bun:ffi, so the daemon ships no node-pty or koffi. node-pty stays a development dependency of @ace/terminal, loaded only when tests open a terminal on Node.

Troubleshooting

  • Electron starts as plain Node (Cannot read properties of undefined (reading 'setPath')): your shell exports ELECTRON_RUN_AS_NODE=1 (some Electron-based terminals and tools do). The dev scripts strip it; unset it when you launch Electron yourself.
  • Port 4343 or 5173 is busy: set ACE_DEV_DAEMON_PORT / ACE_DEV_WEB_PORT.
  • "Cannot acquire daemon lock": another dev daemon owns ~/.ace/dev (perhaps from another worktree). Stop it, or use ACE_DEV_DIR=/tmp/ace-dev-2.
  • The desktop window shows the connection screen: the daemon had not published ~/.ace/dev/daemon-endpoint within 15 seconds. The window reloads by itself once the daemon is up; check the daemon │ lines meanwhile.
  • Screen helper skipped during a build: the Swift (macOS) or Rust (Windows, Linux) toolchain is missing. The app works without it; screen and computer use stay off. On Linux a Rust older than 1.87 fails the desktop build instead of skipping the helper; update Rust and build again.

bun run typecheck uses incremental declaration builds and checks the original package programs, root test tooling, and browser-only client runtime. One native compiler runs at a time, with at most two project builders and two CPU threads. bun run --filter @ace/protocol typecheck checks a workspace and its dependencies. Use bun run typecheck:clean to remove the caches. See incremental typechecking for the design and cache rules. CI also runs bun run typecheck:full, checking every original program from source with fresh build info as an independent safety net for declaration inference.

Tests run in separate unit and process projects with bounded concurrency. They run on Bun, the daemon's runtime; the web and client-react jsdom projects and a few Node-only suites follow in a second pass on Node (node on PATH). See process test reliability for the real-I/O suite inventory, shared fixtures and validation record. The owner requires tests to run only at merge; development verification uses the permitted static checks.

The daemon prints its URL and token-file path. See startup and degraded services for readiness and service diagnostics. Remote access is on by default and serves the local network; a saved choice wins. See remote access for LAN/Tailscale pairing, device scopes and the ace CLI. See store and sync for configuration, the development creator, the command port, and replay behavior.

Local generic ACP launch and registry wire APIs are described in agent registry. Arbitrary agents retain unknown authentication and limited visibility; compatibility profiles are source-based until separately approved recordings establish behavior.

Remote access relay setup and APIs are described in encrypted relay.

Packaging

apps/desktop is the Electron shell (ADR 0054). bun run desktop:package builds one architecture, the host's, for the platform it runs on. --arch arm64|x64 may name it and must match the host: native code is built for the host, so release CI runs once per architecture on a matching runner. The build stops, listing each problem, if a required native piece is missing or any staged binary is built for another architecture.

  • macOS: dmg and zip (the zip is what Squirrel.Mac updates from). Signed with the Developer ID in the keychain (CSC_NAME picks one; CSC_LINK in CI) and notarized with whichever notarytool credentials are set: APPLE_KEYCHAIN_PROFILE, APPLE_API_KEY with APPLE_API_KEY_ID and APPLE_API_ISSUER, or APPLE_ID with APPLE_APP_SPECIFIC_PASSWORD and APPLE_TEAM_ID. --unsigned builds the same package ad-hoc signed. The screen helper ships as Contents/Helpers/AceScreenHelper.app (dev.ace.screen-helper), signed by native/screen-helper/build.sh and left untouched by the app's signing; its manifest is Contents/Resources/screen-helper-manifest.json. A full package signs the helper with the Developer ID Application identity named by ACE_SCREEN_SIGN_IDENTITY (or CSC_NAME) and a secure timestamp, and fails without one. That identity must already be in a keychain on the search list when the package command starts: the helper is signed during the build, before electron-builder imports CSC_LINK into its own temporary keychain. In CI, import the certificate first (security create-keychain, security import … -T /usr/bin/codesign, security set-key-partition-list, security list-keychains -s), then run bun run desktop:package --full.
  • Windows: NSIS, with an "Open in ace" folder entry in Explorer. Windows runs no local daemon yet; it connects to a remote one.
  • Linux: AppImage, deb and tar.gz (ADR 0093). Launch at login writes ~/.config/autostart/dev.ace.app.desktop. An AppImage or extracted tar.gz installs nothing, so its first launch adds dev.ace.app.desktop and the app icon under ~/.local/share (the app list and ace:// links), and the sandbox setup it offers installs /etc/apparmor.d/ace-desktop-user-<uid> and ace-chromium. Deleting the AppImage or the folder removes none of these, nor the ace command in ~/.ace/bin or ace's data in ~/.ace. To remove them: turn off Launch at login first (or delete the autostart entry), delete ~/.local/share/applications/dev.ace.app.desktop and ~/.local/share/icons/hicolor/*/apps/ace-desktop.png, and unload each profile with sudo apparmor_parser -R /etc/apparmor.d/<name> before deleting its file (keep ace-chromium while a standalone daemon or the deb uses ace's Chrome). Delete ~/.ace only to erase ace's data.

Each package carries the daemon bundle from tools/release (Resources/daemon), the pinned Bun runtime it runs on (Resources/runtime, the same one as the standalone archive), the staged runtime packages, rg from @vscode/ripgrep, and the platform's screen helper. Electron's runAsNode fuse is off. A full package also carries the update feed (app-update.yml), and electron-builder writes latest*.yml beside it: the app updates itself from GitHub releases (ADR 0091), and the bundled ace update hands updates to the app. ACE_RELEASE_PUBLIC_KEY_FILE embeds the release authority's Ed25519 key in the bundled daemon for standalone installs (ADR 0041).

License

Apache-2.0. See LICENSE and NOTICE.

About

Multi-agent coding environment: one interface for your local coding-agent CLIs across desktop, web and mobile

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages