Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ Thumbs.db
# Tauri build artifacts (handled in src-tauri/.gitignore but also here for safety)
src-tauri/target

# Tauri sidecar binaries (built via scripts/build-sidecars.sh)
src-tauri/binaries/

# Test coverage
coverage

Expand Down
78 changes: 60 additions & 18 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Ada is an AI Code Agent Manager - a Tauri 2 desktop application for managing mul
## Development Commands

```bash
# Start development (frontend + Tauri)
# Start development (frontend + Tauri + daemon)
bun run tauri:dev

# Build for production
Expand All @@ -33,6 +33,10 @@ bun run build # TypeScript check + Vite build
# Linting
bun run lint

# Sidecar binaries (ada-cli, ada-daemon)
bun run build:sidecars # Build with smart caching
bun run build:sidecars:force # Force rebuild

# Rust checks (from src-tauri/)
cargo check
cargo build
Expand All @@ -41,13 +45,43 @@ cargo test

## Architecture

Ada uses a **daemon-based architecture** for terminal management:

```
┌─────────────────┐ IPC ┌─────────────────┐
│ Ada Desktop │◄────────────►│ Ada Daemon │
│ (Tauri App) │ │ (Background) │
└─────────────────┘ └────────┬────────┘
│ PTY
┌─────────────────┐
│ AI Agents │
└─────────────────┘
```

### Sidecar Binaries

- **ada-daemon** - Background process managing PTY sessions, persists across app restarts
- **ada-cli** - Command-line tool for daemon management (`ada-cli daemon start/stop/status/logs`)

Sidecars are built via `scripts/build-sidecars.sh` and bundled in `src-tauri/binaries/`.

### Backend (src-tauri/src/)

- **state.rs** - Central `AppState` with thread-safe `RwLock<HashMap>` storage for projects, terminals, PTY handles, and clients
- **project/** - Project CRUD operations, settings, git initialization on creation
- **terminal/** - PTY spawning via `portable-pty`, terminal lifecycle, output buffering (max 1000 chunks)
- **git/** - Branch management and worktree support for branch isolation
- **clients/** - AI client configurations (Claude Code, OpenCode, Codex) with installation detection via `which`
- **daemon/** - Daemon server, IPC protocol, PTY session management, tray icon
- `server.rs` - TCP server for IPC, session lifecycle
- `protocol.rs` - Request/response/event types for daemon communication
- `session.rs` - Individual PTY session management
- `shell.rs` - Shell/PTY spawning and I/O
- `tray.rs` - System tray icon and menu
- **cli/** - CLI implementation for daemon management
- `daemon.rs` - start/stop/status/restart/logs commands
- `paths.rs` - Data directory and file path resolution
- **state.rs** - Central `AppState` with thread-safe storage for projects, terminals, clients
- **project/** - Project CRUD operations, settings, git initialization
- **terminal/** - Terminal types, status enums, command specs
- **git/** - Branch management and worktree support
- **clients/** - AI client configurations with installation detection via `which`

### Frontend (src/)

Expand All @@ -59,17 +93,18 @@ cargo test
### Data Flow

1. Frontend calls `invoke("command_name", { params })` via Tauri IPC
2. Rust command handlers in `*/commands.rs` process requests
3. State changes persisted to `~/.local/share/ada/` as JSON files
4. Events emitted via `app_handle.emit()` for terminal output, status changes
2. Tauri backend forwards terminal operations to daemon via TCP IPC
3. Daemon manages PTY sessions and streams output back
4. Events flow: Daemon → Tauri → Frontend via event system
5. State persisted to `~/.local/share/ada/` (or `ada-dev/` in dev mode)

### Key Patterns

- All backend operations are Tauri commands (async, return `Result<T, Error>`)
- Terminal output streams via Tauri events (`terminal-output`, `terminal-closed`)
- Worktrees created automatically when spawning terminals on specific branches
- Projects must be git repos with at least one commit
- Terminal history preserved across app restarts (PTY handles are not)
- Daemon runs independently from the Tauri app (survives app restarts)
- All terminal operations go through the daemon
- IPC uses JSON-over-TCP with newline-delimited messages
- Daemon writes PID and port files for discovery
- Terminal history preserved in daemon even when app is closed

## Path Aliases

Expand All @@ -84,12 +119,19 @@ bun run tauri:build:signed
```

This runs `scripts/build-signed.sh` which:
1. Builds the Tauri app in release mode
2. Ad-hoc signs the .app bundle with `codesign`
3. Recreates the DMG with the signed app
1. Builds sidecar binaries (ada-cli, ada-daemon)
2. Builds the Tauri app in release mode
3. Signs all components individually (sidecars, main binary, frameworks)
4. Signs the .app bundle with hardened runtime
5. Creates a DMG installer

**Output locations:**
- App: `src-tauri/target/release/bundle/macos/Ada.app`
- DMG: `src-tauri/target/release/bundle/dmg/Ada_<version>_<arch>.dmg`

**Note:** Ad-hoc signing removes "app is damaged" errors but recipients may still need to right-click → Open on first launch, or run `xattr -cr /Applications/Ada.app`. For full Gatekeeper clearance without warnings, you need an Apple Developer certificate ($99/year) and notarization.
**Using a real certificate:**
```bash
CODESIGN_IDENTITY="Developer ID Application: Your Name (TEAMID)" bun run tauri:build:signed
```

**Note:** Ad-hoc signing (default) removes "app is damaged" errors but recipients may still need to right-click → Open on first launch, or run `xattr -cr /Applications/Ada.app`. For full Gatekeeper clearance without warnings, you need an Apple Developer certificate ($99/year) and notarization.
202 changes: 183 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,210 @@

![Ada](screenshots/ada.png)

Ada is a desktop application for managing multiple AI coding agents with integrated terminal support and git worktree workflows.
Ada is an AI Code Agent Manager - a desktop application for managing multiple AI coding agents (Claude Code, OpenCode, Codex) with integrated terminal support and git worktree workflows.

## Features

- **Multi-Agent Support** - Manage Claude Code, OpenCode, and Codex agents from a single interface
- **Integrated Terminals** - Built-in terminal emulation with xterm.js for each agent session
- **Git Worktree Workflows** - Automatic worktree creation for branch isolation, keeping agents working in parallel without conflicts
- **Project Management** - Organize and switch between multiple projects with persistent settings
- **Session History** - Terminal output preserved across app restarts
- **Multi-Agent Support**: Manage Claude Code, OpenCode, Codex, and other AI coding agents from a single interface
- **Integrated Terminals**: Built-in terminal emulator with xterm.js for each agent session
- **Git Worktree Integration**: Automatic worktree creation for branch-isolated development
- **Persistent Sessions**: Terminal sessions survive app restarts via daemon architecture
- **System Tray**: Daemon runs in background with system tray icon for quick access
- **Project Management**: Organize and switch between multiple projects with persistent settings

## Tech Stack

- **Frontend:** React 19, TypeScript, Vite, Tailwind CSS v4
- **Backend:** Rust with Tauri 2
- **UI:** Radix UI + shadcn/ui
- **State:** Zustand
- **Routing:** TanStack Router
- **Terminal:** xterm.js with portable-pty
- **Frontend**: React 19 + TypeScript + Vite 7 + Tailwind CSS v4
- **Backend**: Rust with Tauri 2
- **UI**: Radix UI components + shadcn/ui patterns
- **State**: Zustand
- **Routing**: TanStack Router
- **Terminal**: xterm.js

## Architecture

Ada uses a daemon-based architecture for terminal management:

```
┌─────────────────┐ IPC ┌─────────────────┐
│ Ada Desktop │◄────────────►│ Ada Daemon │
│ (Tauri App) │ │ (Background) │
└─────────────────┘ └────────┬────────┘
│ PTY
┌─────────────────┐
│ AI Agents │
│ (Claude, etc.) │
└─────────────────┘
```

### Components

| Component | Description |
|-----------|-------------|
| **Ada Desktop** | Main Tauri application with React frontend |
| **Ada Daemon** | Background process managing PTY sessions, persists across app restarts |
| **Ada CLI** | Command-line tool for daemon management |

### Why a Daemon?

The daemon architecture provides:
- **Session Persistence**: Terminal sessions survive app restarts
- **Background Processing**: Agent sessions continue running when the app is closed
- **System Integration**: Tray icon for quick access and status monitoring
- **Resource Isolation**: PTY processes are managed independently from the UI

## Development

### Prerequisites

- [Rust](https://rustup.rs/) (latest stable)
- [Bun](https://bun.sh/) (or npm/yarn/pnpm)
- One or more AI coding agents installed (Claude Code, OpenCode, or Codex)

### Setup

```bash
# Install dependencies
bun install

# Start development (frontend + Tauri)
# Start development (builds sidecars, starts frontend + Tauri)
bun run tauri:dev
```

# Build for production
bun run tauri:build
### Development Commands

```bash
# Start development (frontend + Tauri + daemon)
bun run tauri:dev

# Frontend only (Vite dev server on :5173)
bun run dev

# Build frontend
bun run build

# Lint
bun run lint

# Build sidecar binaries only
bun run build:sidecars
bun run build:sidecars:force # Force rebuild
```

## Requirements
### Rust Commands

- [Bun](https://bun.sh/) (or Node.js)
- [Rust](https://rustup.rs/)
- One or more AI coding agents installed (Claude Code, OpenCode, or Codex)
Run from `src-tauri/` directory:

```bash
cargo check # Type check
cargo build # Debug build
cargo build --release # Release build
cargo test # Run tests
```

## Building for Distribution

### Standard Build

```bash
bun run tauri:build
```

### Signed Build (macOS)

For distribution, use the signed build which properly signs all components:

```bash
bun run tauri:build:signed
```

This script:
1. Builds sidecar binaries (ada-cli, ada-daemon)
2. Builds the Tauri app in release mode
3. Signs all components individually (sidecars, main binary, frameworks)
4. Signs the .app bundle
5. Creates a DMG installer

**Output locations:**
- App: `src-tauri/target/release/bundle/macos/Ada.app`
- DMG: `src-tauri/target/release/bundle/dmg/Ada_<version>_<arch>.dmg`

### Using a Real Certificate

For full Gatekeeper clearance (no warnings for users), set your Apple Developer certificate:

```bash
CODESIGN_IDENTITY="Developer ID Application: Your Name (TEAMID)" bun run tauri:build:signed
```

**Note:** Ad-hoc signing (default) removes "app is damaged" errors but recipients may still need to right-click → Open on first launch, or run:
```bash
xattr -cr /Applications/Ada.app
```

## CLI Usage

The `ada-cli` tool manages the daemon. After building, the CLI is available at `src-tauri/target/release/ada-cli` (or `debug` for dev builds).

### Daemon Management

```bash
# Start daemon (runs in background)
ada-cli daemon start

# Start in foreground (for debugging)
ada-cli daemon start --foreground

# Check daemon status
ada-cli daemon status

# Stop daemon
ada-cli daemon stop

# Restart daemon
ada-cli daemon restart

# View logs
ada-cli daemon logs
ada-cli daemon logs -f # Follow mode (like tail -f)
ada-cli daemon logs -n 100 # Show last 100 lines
```

### Development Mode

Use `--dev` flag for separate data directory (useful when developing):

```bash
ada-cli --dev daemon start
ada-cli --dev daemon status
```

## Data Locations

| Mode | Data Directory |
|------|----------------|
| Production | `~/.local/share/ada/` |
| Development | `~/.local/share/ada-dev/` |

Contents:
- `projects.json` - Project configurations
- `clients.json` - AI client configurations
- `daemon.pid` - Daemon process ID
- `daemon.port` - Daemon IPC port
- `logs/` - Log files

## Environment Variables

| Variable | Description |
|----------|-------------|
| `ADA_DEV_MODE` | Enable development mode (`1` = enabled) |
| `ADA_LOG_LEVEL` | Log level (trace, debug, info, warn, error) |
| `ADA_LOG_STDERR` | Log to stderr instead of file (`1` = enabled) |
| `ADA_LOG_DIR` | Custom log directory |
| `ADA_LOG_DISABLE` | Disable logging (`1` = disabled) |
| `CODESIGN_IDENTITY` | macOS code signing identity |

## Screenshots

Expand Down
2 changes: 1 addition & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import tseslint from 'typescript-eslint'
import { defineConfig, globalIgnores } from 'eslint/config'

export default defineConfig([
globalIgnores(['dist', 'src-tauri']),
globalIgnores(['dist', 'src-tauri', '.worktrees']),
{
files: ['**/*.{ts,tsx}'],
extends: [
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
"tauri": "tauri",
"tauri:dev": "tauri dev",
"tauri:build": "tauri build",
"tauri:build:signed": "./scripts/build-signed.sh"
"tauri:build:signed": "./scripts/build-signed.sh",
"build:sidecars": "./scripts/build-sidecars.sh",
"build:sidecars:force": "./scripts/build-sidecars.sh --force"
},
"dependencies": {
"@radix-ui/react-alert-dialog": "^1.1.15",
Expand Down
Loading