diff --git a/docs/README.md b/docs/README.md index bb042f7..841801a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,79 +1,87 @@ ---- -title: "Documentation" -role: part -parent: null -order: 1 -description: "Project documentation index" ---- +# Agents Orchestrator — Documentation -# Agent Orchestrator Documentation +Multi-project AI agent dashboard with terminal, SSH, and multi-provider session management. +Built with Tauri 2.x (Rust) + Svelte 5 + Claude Agent SDK. -Agent Orchestrator (formerly Agents Orchestrator) is a multi-project AI agent orchestration dashboard built with Tauri 2.x, Svelte 5, and the Claude Agent SDK. It transforms a traditional terminal emulator into a mission control for running, monitoring, and coordinating multiple AI agent sessions across multiple codebases simultaneously. +> **Source of truth.** Before making changes, consult these docs. After making changes, update them. -The application has three major version milestones: +## Quick Navigation -- **v1** — A single-file Python GTK3+VTE terminal emulator with Claude Code session management. Production-stable, still shipped as `agor`. -- **v2** — A ground-up rewrite using Tauri 2.x (Rust backend) + Svelte 5 (frontend). Multi-pane terminal with structured agent sessions, subagent tree visualization, session persistence, multi-machine relay support, 17 themes, and comprehensive packaging. -- **v3 (Mission Control)** — A further redesign on top of v2's codebase. Replaces the free-form pane grid with a project-group dashboard. Adds multi-agent orchestration (4 management roles), inter-agent messaging (btmsg), task boards (bttask), session anchors, health monitoring, FTS5 search, plugin system, Landlock sandboxing, secrets management, and 704 automated tests. - -> **Important:** The `docs/` directory is the single source of truth for this project. Before making changes, consult the docs. After making changes, update the docs. - ---- +| Audience | Start Here | +|----------|-----------| +| New users | [Getting Started](getting-started/quickstart.md) | +| Contributors | [Dual-Repo Workflow](contributing/dual-repo-workflow.md), [Testing](contributing/testing.md) | +| Pro customers | [Pro Edition](pro/README.md), [Marketplace](pro/marketplace/README.md) | +| Plugin developers | [Plugin Development Guide](plugins/guide-developing.md) | ## Documentation Map -### Architecture & Design +### Getting Started -| Document | What It Covers | -|----------|---------------| -| [architecture.md](architecture.md) | End-to-end system architecture: Rust backend, Svelte frontend, sidecar layer, data model, layout system, data flow, IPC patterns | -| [decisions.md](decisions.md) | Architecture decisions log: rationale and dates for all major design choices | -| [multi-machine.md](multi-machine.md) | Multi-machine relay architecture: agor-core extraction, agor-relay binary, RemoteManager, WebSocket protocol, reconnection | +- [Quickstart](getting-started/quickstart.md) — install, build, first agent session -### Subsystem Guides +### Architecture -| Document | What It Covers | -|----------|---------------| -| [sidecar.md](sidecar.md) | Sidecar process lifecycle, multi-provider runners (Claude/Codex/Ollama), env var stripping, CLI detection, NDJSON protocol | -| [orchestration.md](orchestration.md) | Multi-agent orchestration: btmsg messaging, bttask kanban, Tier 1/2 agent roles, wake scheduler, system prompts | -| [production.md](production.md) | Production hardening: sidecar supervisor, Landlock sandbox, FTS5 search, plugin system, secrets management, notifications, health monitoring, audit logging | -| [provider-adapter/](provider-adapter/) | Multi-provider adapter pattern: architecture decisions, coupling analysis, implementation progress | +- [System Overview](architecture/overview.md) — components, data flow, IPC patterns +- [Data Model](architecture/data-model.md) — SQLite schemas, layout, keyboard shortcuts +- [Decisions](architecture/decisions.md) — architecture decision log with rationale +- [Phases](architecture/phases.md) — v2 implementation phases (P1-7 + multi-machine A-D) +- [Research Findings](architecture/findings.md) — SDK, performance, coupling analysis -### Implementation & Progress +### Agents & Orchestration -| Document | What It Covers | -|----------|---------------| -| [phases.md](phases.md) | v2 implementation phases (1-7 + multi-machine A-D + profiles/skills) with checklists | -| [progress/v3.md](progress/v3.md) | v3 session-by-session progress log (Phases 1-10 + production hardening) | -| [progress/v2.md](progress/v2.md) | v2 session-by-session progress log (recent sessions) | -| [progress/v2-archive.md](progress/v2-archive.md) | Archived v2 progress (2026-03-05 to 2026-03-06 early) | +- [Orchestration](agents/orchestration.md) — btmsg, bttask, 4 management roles, wake scheduler, session anchors +- [btmsg Reference](agents/ref-btmsg.md) — inter-agent messaging CLI and database schema +- [bttask Reference](agents/ref-bttask.md) — kanban task board CLI and operations -### Research & Analysis +### Providers -| Document | What It Covers | -|----------|---------------| -| [findings.md](findings.md) | All research: Claude Agent SDK, Tauri+xterm.js, terminal performance, adversarial review, provider coupling, codebase reuse, session anchors, multi-agent design, theme evolution, performance measurements | +- [Provider Reference](providers/ref-providers.md) — Claude, Codex, Ollama, Aider: models, capabilities, routing -### Release & Testing +### Sidecar -| Document | What It Covers | -|----------|---------------| -| [release-notes.md](release-notes.md) | v3.0 release notes: feature summary, breaking changes, test coverage, known limitations | -| [e2e-testing.md](e2e-testing.md) | E2E testing facility: WebDriverIO fixtures, test mode, LLM judge, CI integration, troubleshooting | +- [Sidecar Architecture](sidecar/architecture.md) — runners, NDJSON protocol, crash recovery, env stripping ---- +### Multi-Machine -## Quick Orientation +- [Relay Architecture](multi-machine/relay.md) — WebSocket server, TLS, SPKI pinning, reconnection -If you are new to this codebase, read the documents in this order: +### Production Hardening -1. **[architecture.md](architecture.md)** — Understand how the pieces fit together -2. **[decisions.md](decisions.md)** — Understand why things are built the way they are -3. **[sidecar.md](sidecar.md)** — Understand how agent sessions actually run -4. **[orchestration.md](orchestration.md)** — Understand multi-agent coordination -5. **[e2e-testing.md](e2e-testing.md)** — Understand how to test changes +- [Hardening](production/hardening.md) — sidecar supervisor, Landlock sandbox, WAL checkpoint, TLS relay +- [Features](production/features.md) — FTS5 search, plugin sandbox, secrets, notifications, audit, error classification -For research context, read [findings.md](findings.md). For implementation history, see [phases.md](phases.md) and [progress/](progress/). +### Configuration + +- [Settings Reference](config/ref-settings.md) — env vars, config files, databases, themes, per-project settings + +### Plugins + +- [Plugin Development Guide](plugins/guide-developing.md) — Web Worker sandbox API, manifest, publishing, examples + +### Contributing + +- [Dual-Repo Workflow](contributing/dual-repo-workflow.md) — community vs commercial repos, sync, leak prevention +- [Testing](contributing/testing.md) — E2E fixtures, test mode, LLM judge, CI integration + +### Pro Edition (Commercial) + +- [Pro Overview](pro/README.md) — feature list, plugin architecture, IPC pattern +- [Analytics Dashboard](pro/features/analytics.md) — cost/token/model tracking over time +- [Cost Intelligence](pro/features/cost-intelligence.md) — budget governor, smart model router +- [Knowledge Base](pro/features/knowledge-base.md) — persistent memory, codebase symbol graph +- [Git Integration](pro/features/git-integration.md) — context injection, branch policy +- [Marketplace](pro/marketplace/README.md) — 13 plugins (8 free + 5 paid), catalog, install/update + +### Release History + +- [Release Notes](release-notes.md) — v3.0 features, breaking changes, requirements + +### Progress Logs + +- [v3 Progress](progress/v3.md) — session-by-session development log +- [v2 Progress](progress/v2.md) +- [v2 Archive](progress/v2-archive.md) --- @@ -82,10 +90,23 @@ For research context, read [findings.md](findings.md). For implementation histor | Path | Purpose | |------|---------| | `src-tauri/src/` | Rust backend: commands, SQLite, btmsg, bttask, search, secrets, plugins | -| `agor-core/` | Shared Rust crate: PtyManager, SidecarManager, EventSink trait, Landlock sandbox | +| `agor-core/` | Shared Rust crate: PtyManager, SidecarManager, EventSink, Landlock sandbox | | `agor-relay/` | Standalone relay binary for remote machine support | +| `agor-pro/` | Commercial plugin crate (Pro edition features) | | `src/lib/` | Svelte 5 frontend: components, stores, adapters, utils, providers | -| `sidecar/` | Agent sidecar runners (Claude, Codex, Ollama) — compiled to ESM bundles | +| `src/lib/commercial/` | Pro edition Svelte components and IPC bridge | +| `sidecar/` | Agent sidecar runners (Claude, Codex, Ollama, Aider) — ESM bundles | | `tests/e2e/` | WebDriverIO E2E tests, fixtures, LLM judge | -| `ctx/` | Context manager CLI tool (SQLite-based, standalone) | -| `consult/` | Multi-model tribunal CLI (OpenRouter, standalone Python) | +| `tests/commercial/` | Pro edition tests (excluded from community builds) | +| `scripts/` | Build scripts, plugin scaffolding, test runner | +| `.githooks/` | Pre-push leak prevention hook | + +## Reading Order for New Contributors + +1. [Getting Started](getting-started/quickstart.md) — build and run +2. [System Overview](architecture/overview.md) — how the pieces fit +3. [Decisions](architecture/decisions.md) — why things are built this way +4. [Sidecar Architecture](sidecar/architecture.md) — how agent sessions run +5. [Orchestration](agents/orchestration.md) — multi-agent coordination +6. [Testing](contributing/testing.md) — how to test changes +7. [Dual-Repo Workflow](contributing/dual-repo-workflow.md) — how to contribute diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md new file mode 100644 index 0000000..68cd40a --- /dev/null +++ b/docs/architecture/overview.md @@ -0,0 +1,246 @@ +# System Architecture — Overview + +This document describes the end-to-end architecture of Agent Orchestrator (agor) — how the Rust backend, Svelte 5 frontend, and Node.js/Deno sidecar processes work together to provide a multi-project AI agent orchestration dashboard. + +--- + +## High-Level Overview + +Agent Orchestrator is a Tauri 2.x desktop application. Tauri provides a Rust backend process and a WebKit2GTK-based webview for the frontend. The application manages AI agent sessions by spawning sidecar child processes that communicate with AI provider APIs (Claude, Codex, Ollama). + +``` ++----------------------------------------------------------------+ +| Agent Orchestrator (Tauri 2.x) | +| | +| +------------------+ Tauri IPC +--------------------+ | +| | WebView | <-------------> | Rust Backend | | +| | (Svelte 5) | invoke/listen | | | +| | | | +-- PtyManager | | +| | +-- ProjectGrid | | +-- SidecarManager | | +| | +-- AgentPane | | +-- SessionDb | | +| | +-- TerminalPane | | +-- BtmsgDb | | +| | +-- StatusBar | | +-- SearchDb | | +| | +-- Stores | | +-- SecretsManager | | +| +------------------+ | +-- RemoteManager | | +| | +-- FileWatchers | | +| +--------------------+ | +| | | ++-------------------------------------------+--------------------+ + | stdio NDJSON + v + +-------------------+ + | Sidecar Processes | + | (Deno or Node.js) | + | | + | claude-runner.mjs | + | codex-runner.mjs | + | ollama-runner.mjs | + +-------------------+ +``` + +### Why Three Layers? + +1. **Rust backend** — Manages OS-level resources (PTY processes, file watchers, SQLite databases) with memory safety and low overhead. Exposes everything to the frontend via Tauri IPC commands and events. + +2. **Svelte 5 frontend** — Renders the UI with fine-grained reactivity (no VDOM). Svelte 5 runes (`$state`, `$derived`, `$effect`) provide signal-based reactivity comparable to Solid.js but with a larger ecosystem. + +3. **Sidecar processes** — The Claude Agent SDK, OpenAI Codex SDK, and Ollama API are all JavaScript/TypeScript libraries. They cannot run in Rust or in the WebKit2GTK webview (no Node.js APIs). The sidecar layer bridges this gap: Rust spawns a JS process, communicates via stdio NDJSON, and forwards structured messages to the frontend. + +--- + +## Rust Backend (`src-tauri/`) + +The Rust backend is the central coordinator. It owns all OS resources and database connections. + +### Cargo Workspace + +``` +agor/ ++-- Cargo.toml # Workspace root ++-- agor-core/ # Shared crate +| +-- src/ +| +-- lib.rs +| +-- pty.rs # PtyManager (portable-pty) +| +-- sidecar.rs # SidecarManager (multi-provider) +| +-- supervisor.rs # SidecarSupervisor (crash recovery) +| +-- sandbox.rs # Landlock sandbox +| +-- event.rs # EventSink trait ++-- agor-relay/ # Remote machine relay +| +-- src/main.rs # WebSocket server + token auth ++-- src-tauri/ # Tauri application + +-- src/ + +-- lib.rs # AppState + setup + handler registration + +-- commands/ # 16 domain command modules + +-- btmsg.rs # Inter-agent messaging (SQLite) + +-- bttask.rs # Task board (SQLite, shared btmsg.db) + +-- search.rs # FTS5 full-text search + +-- secrets.rs # System keyring (libsecret) + +-- plugins.rs # Plugin discovery + +-- notifications.rs # Desktop notifications + +-- session/ # SessionDb (sessions, layout, settings, agents, metrics, anchors) + +-- remote.rs # RemoteManager (WebSocket client) + +-- ctx.rs # Read-only ctx database access + +-- memora.rs # Read-only Memora database access + +-- telemetry.rs # OpenTelemetry tracing + +-- groups.rs # Project groups config + +-- watcher.rs # File watcher (notify crate) + +-- fs_watcher.rs # Per-project filesystem watcher (inotify) + +-- event_sink.rs # TauriEventSink implementation + +-- pty.rs # Thin re-export from agor-core + +-- sidecar.rs # Thin re-export from agor-core +``` + +The `agor-core` crate exists so that both the Tauri application and the standalone `agor-relay` binary can share PtyManager and SidecarManager code. The `EventSink` trait abstracts event emission — TauriEventSink wraps Tauri's AppHandle, while the relay uses a WebSocket-based EventSink. + +### AppState + +All backend state lives in `AppState`, initialized during Tauri setup: + +```rust +pub struct AppState { + pub pty_manager: Mutex, + pub sidecar_manager: Mutex, + pub session_db: Mutex, + pub remote_manager: Mutex, + pub telemetry: Option, +} +``` + +### Command Modules + +Tauri commands are organized into 16 domain modules under `commands/`: + +| Module | Commands | Purpose | +|--------|----------|---------| +| `pty` | spawn, write, resize, kill | Terminal management | +| `agent` | query, stop, ready, restart | Agent session lifecycle | +| `session` | session CRUD, layout, settings | Session persistence | +| `persistence` | agent state, messages | Agent session continuity | +| `knowledge` | ctx, memora queries | External knowledge bases | +| `claude` | profiles, skills | Claude-specific features | +| `groups` | load, save | Project group config | +| `files` | list_directory, read/write file | File browser | +| `watcher` | start, stop | File change monitoring | +| `remote` | 12 commands | Remote machine management | +| `bttask` | list, create, update, delete, comments | Task board | +| `search` | init, search, rebuild, index | FTS5 search | +| `secrets` | store, get, delete, list, has_keyring | Secrets management | +| `plugins` | discover, read_file | Plugin discovery | +| `notifications` | send_desktop | OS notifications | +| `misc` | test_mode, frontend_log | Utilities | + +--- + +## Svelte 5 Frontend (`src/`) + +The frontend uses Svelte 5 with runes for reactive state management. The UI follows a VSCode-inspired layout with a left icon rail, expandable drawer, project grid, and status bar. + +### Component Hierarchy + +``` +App.svelte [Root -- VSCode-style layout] ++-- CommandPalette.svelte [Ctrl+K overlay, 18+ commands] ++-- SearchOverlay.svelte [Ctrl+Shift+F, FTS5 Spotlight-style] ++-- NotificationCenter.svelte [Bell icon + dropdown] ++-- GlobalTabBar.svelte [Left icon rail, 2.75rem wide] ++-- [Sidebar Panel] [Expandable drawer, max 50%] +| +-- SettingsTab.svelte [Global settings + group/project CRUD] ++-- ProjectGrid.svelte [Flex + scroll-snap, adaptive count] +| +-- ProjectBox.svelte [Per-project container, 11 tab types] +| +-- ProjectHeader.svelte [Icon + name + status + badges] +| +-- AgentSession.svelte [Main Claude session wrapper] +| | +-- AgentPane.svelte [Structured message rendering] +| | +-- TeamAgentsPanel.svelte [Tier 1 subagent cards] +| +-- TerminalTabs.svelte [Shell/SSH/agent-preview tabs] +| | +-- TerminalPane.svelte [xterm.js + Canvas addon] +| | +-- AgentPreviewPane.svelte [Read-only agent activity] +| +-- DocsTab / ContextTab / FilesTab / SshTab / MemoriesTab +| +-- MetricsPanel / TaskBoardTab / ArchitectureTab / TestingTab ++-- StatusBar.svelte [Agent counts, burn rate, attention queue] +``` + +### Stores (Svelte 5 Runes) + +All store files use the `.svelte.ts` extension — required for Svelte 5 runes (`$state`, `$derived`, `$effect`). Files with plain `.ts` extension compile but fail at runtime with "rune_outside_svelte". + +| Store | Purpose | +|-------|---------| +| `workspace.svelte.ts` | Project groups, active group, tabs, focus | +| `agents.svelte.ts` | Agent sessions, messages, cost, parent/child hierarchy | +| `health.svelte.ts` | Per-project health tracking, attention scoring, burn rate | +| `conflicts.svelte.ts` | File overlap + external write detection | +| `anchors.svelte.ts` | Session anchor management (auto/pinned/promoted) | +| `notifications.svelte.ts` | Toast + history (6 types, unread badge) | +| `plugins.svelte.ts` | Plugin command registry, event bus | +| `theme.svelte.ts` | 17 themes, font restoration | +| `machines.svelte.ts` | Remote machine state | +| `wake-scheduler.svelte.ts` | Manager auto-wake (3 strategies, per-manager timers) | + +### Agent Dispatcher + +The agent dispatcher (`agent-dispatcher.ts`, ~260 lines) is the central router between sidecar events and the agent store. When the Rust backend emits a `sidecar-message` Tauri event, the dispatcher: + +1. Looks up the provider for the session (via `sessionProviderMap`) +2. Routes the raw message through the appropriate adapter (claude-messages.ts, codex-messages.ts, or ollama-messages.ts) via `message-adapters.ts` +3. Feeds the resulting `AgentMessage[]` into the agent store +4. Handles side effects: subagent pane spawning, session persistence, auto-anchoring, worktree detection, health tracking, conflict recording + +The dispatcher delegates to four extracted utility modules: +- `utils/session-persistence.ts` — session-project maps, persistSessionForProject +- `utils/subagent-router.ts` — spawn + route subagent panes +- `utils/auto-anchoring.ts` — triggerAutoAnchor on first compaction event +- `utils/worktree-detection.ts` — detectWorktreeFromCwd pure function + +--- + +## Data Flow: Agent Query Lifecycle + +``` +1. User types prompt in AgentPane +2. AgentPane calls agentBridge.queryAgent(options) +3. agent-bridge.ts invokes Tauri command 'agent_query' +4. Rust agent_query handler calls SidecarManager.query() +5. SidecarManager resolves provider runner (e.g., claude-runner.mjs) +6. SidecarManager writes QueryMessage as NDJSON to sidecar stdin +7. Sidecar runner calls provider SDK (e.g., Claude Agent SDK query()) +8. Provider SDK streams responses +9. Runner forwards each response as NDJSON to stdout +10. SidecarManager reads stdout line-by-line +11. SidecarManager emits Tauri event 'sidecar-message' with sessionId + data +12. Frontend agent-dispatcher.ts receives event +13. Dispatcher routes through message-adapters.ts -> provider-specific parser +14. Parser converts to AgentMessage[] +15. Dispatcher feeds messages into agents.svelte.ts store +16. AgentPane reactively re-renders via $derived bindings +``` + +--- + +## Configuration + +### Project Groups (`~/.config/agor/groups.json`) + +Human-editable JSON file defining project groups and their projects. Loaded at startup by `groups.rs`. Not hot-reloaded — changes require app restart or group switch. + +### SQLite Settings (`sessions.db` -> `settings` table) + +Key-value store for user preferences: theme, fonts, shell, CWD, provider settings. Accessed via `settings-bridge.ts` -> `settings_get`/`settings_set` Tauri commands. + +### Environment Variables + +| Variable | Purpose | +|----------|---------| +| `AGOR_TEST` | Enables test mode (disables watchers, wake scheduler) | +| `AGOR_TEST_DATA_DIR` | Redirects SQLite database storage | +| `AGOR_TEST_CONFIG_DIR` | Redirects groups.json config | +| `AGOR_OTLP_ENDPOINT` | Enables OpenTelemetry OTLP export | + +--- + +## Key Constraints + +1. **WebKit2GTK has no WebGL** — xterm.js must use the Canvas addon explicitly. Maximum 4 active xterm.js instances to avoid OOM. +2. **Svelte 5 runes require `.svelte.ts`** — Store files using `$state`/`$derived` must have the `.svelte.ts` extension. The compiler silently accepts `.ts` but runes fail at runtime. +3. **Single shared sidecar** — All agent sessions share one SidecarManager. Per-project isolation is via `cwd`, `claude_config_dir`, and `session_id` routing. Per-project sidecar pools deferred to v3.1. +4. **SQLite WAL mode** — Both databases use WAL with 5s busy_timeout for concurrent access from Rust backend + Python CLIs (btmsg/bttask). +5. **camelCase wire format** — Rust uses `#[serde(rename_all = "camelCase")]`. TypeScript interfaces must match. This was a source of bugs during development (see [findings.md](findings.md) for context). diff --git a/docs/config/ref-settings.md b/docs/config/ref-settings.md new file mode 100644 index 0000000..156ac1f --- /dev/null +++ b/docs/config/ref-settings.md @@ -0,0 +1,229 @@ +# Configuration Reference + +All configuration paths, environment variables, database files, and per-project +settings for Agents Orchestrator. + +## Environment variables + +### Core + +| Variable | Default | Description | +|----------|---------|-------------| +| `AGOR_TEST` | unset | Set to `1` to enable test mode. Disables file watchers, wake scheduler, and telemetry. | +| `AGOR_OTLP_ENDPOINT` | unset | OpenTelemetry OTLP/HTTP endpoint (e.g. `http://localhost:4318`). When unset, telemetry is console-only. | +| `AGOR_TEST_DATA_DIR` | unset | Override data directory in test mode. Isolates SQLite databases. | +| `AGOR_TEST_CONFIG_DIR` | unset | Override config directory in test mode. Isolates groups.json and plugins. | +| `AGOR_TEST_CTX_DIR` | unset | Override ctx database directory in test mode. | +| `AGOR_EDITION` | `community` | Set to `pro` to enable commercial features (used by vitest and CI). | + +### Provider-specific + +Provider environment variables (`CLAUDE_*`, `CODEX_*`, `OLLAMA_*`) are stripped +from the sidecar process environment to prevent cross-contamination. The +whitelist `CLAUDE_CODE_EXPERIMENTAL_*` is preserved. + +Variables the sidecar runner may read: + +| Variable | Provider | Description | +|----------|----------|-------------| +| `ANTHROPIC_API_KEY` | Claude | API key (used by Claude CLI internally) | +| `OPENAI_API_KEY` | Codex | API key for Codex SDK | +| `OPENROUTER_API_KEY` | Aider | API key for OpenRouter-routed models | +| `CLAUDE_CONFIG_DIR` | Claude | Override Claude config directory (multi-account) | +| `BTMSG_AGENT_ID` | All (Tier 1) | Injected for management agents to enable btmsg/bttask CLI | + +## Config files + +Base directory: `~/.config/agor/` + +### groups.json + +Primary configuration file. Defines project groups, projects, and management +agents. + +``` +~/.config/agor/groups.json +``` + +Schema: `GroupsFile` (see `src/lib/types/groups.ts`). + +Structure: + +```json +{ + "version": 1, + "groups": [ + { + "id": "group-id", + "name": "Group Name", + "projects": [ ... ], + "agents": [ ... ] + } + ], + "activeGroupId": "group-id" +} +``` + +Managed via the Settings tab in the UI or by editing the file directly. Changes +are picked up on next group load. + +### accounts.json (Pro edition) + +Commercial multi-account configuration. + +``` +~/.config/agor/accounts.json +``` + +Only present when `AGOR_EDITION=pro`. Not included in the community build. + +### plugins/ + +Plugin discovery directory. Each plugin is a subdirectory containing a +`plugin.json` manifest. + +``` +~/.config/agor/plugins/ + my-plugin/ + plugin.json + index.js +``` + +Plugins run in Web Worker sandboxes with permission-gated APIs. See +`src/lib/plugins/plugin-host.ts`. + +## Database files + +Base directory: `~/.local/share/agor/` + +All databases use SQLite WAL mode with 5-second busy timeout for concurrent +access. + +### sessions.db + +Session persistence, layout state, settings, session metrics, and anchors. + +``` +~/.local/share/agor/sessions.db +``` + +Tables: + +| Table | Description | +|-------|-------------| +| `sessions` | Session state (project_id, group_name, layout data) | +| `agent_messages` | Per-project message persistence | +| `project_agent_state` | SDK session ID, cost, status per project | +| `session_metrics` | Historical session data (tokens, turns, cost, model) | +| `session_anchors` | Preserved turns through compaction chains | +| `settings` | Key-value application settings | + +### btmsg.db + +Shared database for inter-agent messaging (btmsg) and task board (bttask). + +``` +~/.local/share/agor/btmsg.db +``` + +Created by the `btmsg` CLI on first `btmsg register`. Used concurrently by +Python CLIs and the Rust backend. + +Tables: + +| Table | Description | +|-------|-------------| +| `agents` | Registered agents (id, name, role, group_id, tier, model, status) | +| `messages` | Direct messages between agents | +| `channels` | Named broadcast channels | +| `channel_messages` | Messages posted to channels | +| `contacts` | ACL for agent-to-agent visibility | +| `heartbeats` | Agent liveness tracking | +| `dead_letter_queue` | Undeliverable messages | +| `audit_log` | Agent action audit trail | +| `seen_messages` | Per-message read tracking (session_id, message_id) | +| `tasks` | Kanban task board entries | +| `task_comments` | Comments on tasks | + +### search.db + +FTS5 full-text search index. + +``` +~/.local/share/agor/search.db +``` + +Virtual tables: + +| Table | Description | +|-------|-------------| +| `search_messages` | Indexed agent messages | +| `search_tasks` | Indexed task board entries | +| `search_btmsg` | Indexed btmsg messages | + +Rebuilt on demand via the search overlay (`Ctrl+Shift+F`). + +## Tauri configuration + +### src-tauri/tauri.conf.json + +Community edition Tauri config. Defines window properties, permissions, updater +endpoint, and bundle metadata. + +### src-tauri/tauri.conf.commercial.json + +Commercial edition overlay. Merged with the base config when building with +`--config src-tauri/tauri.conf.commercial.json`. Changes bundle identifier, +product name, and updater URL. + +## Theme settings + +17 themes in 3 groups, all mapping to the same 26 `--ctp-*` CSS custom +properties. + +| Group | Themes | +|-------|--------| +| Catppuccin | Mocha (default), Macchiato, Frappe, Latte | +| Editor | VSCode Dark+, Atom One Dark, Monokai, Dracula, Nord, Solarized Dark, GitHub Dark | +| Deep Dark | Tokyo Night, Gruvbox Dark, Ayu Dark, Poimandres, Vesper, Midnight | + +Settings keys (persisted in `sessions.db` settings table): + +| Key | Default | Description | +|-----|---------|-------------| +| `theme` | `mocha` | Active theme ID | +| `ui_font_family` | system sans-serif | UI element font | +| `ui_font_size` | `14` (px) | UI font size (feeds CSS `--ui-font-size`) | +| `term_font_family` | system monospace | Terminal font | +| `term_font_size` | `14` (px) | Terminal font size (feeds CSS `--term-font-size`) | +| `default_shell` | system default | Default shell for terminal panes | +| `default_cwd` | `~` | Default working directory | + +All font settings are restored from SQLite on startup via `initTheme()`. + +## Per-project settings + +These fields are set in `groups.json` per project entry (`ProjectConfig`): + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `provider` | `ProviderId` | `claude` | Agent provider | +| `model` | string | provider default | Model identifier override | +| `profile` | string | `default` | Claude profile name | +| `useWorktrees` | boolean | `false` | Git worktree isolation per session | +| `sandboxEnabled` | boolean | `false` | Landlock filesystem sandbox | +| `autonomousMode` | string | `restricted` | `restricted` or `autonomous` | +| `anchorBudgetScale` | string | `medium` | Anchor budget: `small` (2K), `medium` (6K), `large` (12K), `full` (20K) | +| `stallThresholdMin` | number | `15` | Minutes before idle agent is marked stalled (range 5--60) | + +### Agent-specific fields + +Set on `GroupAgentConfig` entries in the `agents` array: + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `role` | string | required | `manager`, `architect`, `tester`, or `reviewer` | +| `wakeIntervalMin` | number | `3` | Auto-wake check interval (Manager only) | +| `wakeStrategy` | string | `smart` | `persistent`, `on-demand`, or `smart` | +| `wakeThreshold` | number | `0.5` | Threshold for smart wake strategy (0.0--1.0) | +| `systemPrompt` | string | none | Custom system prompt appended to generated prompt | diff --git a/docs/getting-started/quickstart.md b/docs/getting-started/quickstart.md new file mode 100644 index 0000000..d7b27e0 --- /dev/null +++ b/docs/getting-started/quickstart.md @@ -0,0 +1,188 @@ +# Quickstart + +Get Agents Orchestrator (agor) running locally in under 10 minutes. + +## Prerequisites + +| Dependency | Version | Notes | +|------------|---------|-------| +| Node.js | 20+ | npm included | +| Rust | 1.77+ | Install via [rustup](https://rustup.rs/) | +| WebKit2GTK | 4.1 | Tauri 2.x rendering engine | +| System libs | -- | See below | + +### System libraries (Debian/Ubuntu) + +```bash +sudo apt install \ + libwebkit2gtk-4.1-dev \ + libgtk-3-dev \ + libappindicator3-dev \ + librsvg2-dev \ + libssl-dev \ + libsoup-3.0-dev \ + javascriptcoregtk-4.1 \ + patchelf +``` + +### Optional dependencies + +- **Claude Code CLI** -- Required for the Claude provider. Auto-detected at + `~/.local/bin/claude`, `~/.claude/local/claude`, `/usr/local/bin/claude`, or + `/usr/bin/claude`. +- **Deno** -- Preferred sidecar runtime (faster startup). Falls back to Node.js. +- **Ollama** -- Required for the Ollama provider. Must be running on + `localhost:11434`. + +## Clone and build + +```bash +git clone git@github.com:DexterFromLab/agent-orchestrator.git +cd agent-orchestrator + +npm install +npm run tauri dev +``` + +The dev server runs on port **9700**. Tauri opens a native window automatically. + +### Production build + +```bash +npm run tauri build +``` + +Output: `.deb` and AppImage in `src-tauri/target/release/bundle/`. + +## Project configuration + +Agor organizes work into **groups**, each containing one or more **projects** +(codebases) and optional **agents** (Tier 1 management roles). + +Configuration lives in `~/.config/agor/groups.json`. On first launch, agor +creates a default file. You can also create it manually: + +```json +{ + "version": 1, + "groups": [ + { + "id": "my-team", + "name": "My Team", + "projects": [ + { + "id": "backend", + "name": "Backend API", + "identifier": "backend-api", + "description": "REST API service", + "icon": "B", + "cwd": "/home/user/code/backend", + "profile": "default", + "enabled": true, + "provider": "claude" + }, + { + "id": "frontend", + "name": "Frontend App", + "identifier": "frontend-app", + "description": "Svelte web client", + "icon": "F", + "cwd": "/home/user/code/frontend", + "profile": "default", + "enabled": true, + "provider": "claude", + "model": "claude-sonnet-4-6" + } + ], + "agents": [ + { + "id": "mgr-1", + "name": "Manager", + "role": "manager", + "enabled": true, + "wakeIntervalMin": 3, + "wakeStrategy": "smart", + "wakeThreshold": 0.5 + } + ] + } + ], + "activeGroupId": "my-team" +} +``` + +### Key fields + +| Field | Required | Description | +|-------|----------|-------------| +| `id` | Yes | Unique identifier within the group | +| `cwd` | Yes | Absolute path to the project directory | +| `provider` | No | `claude` (default), `codex`, `ollama`, or `aider` | +| `model` | No | Model override; falls back to provider default | +| `profile` | No | Claude profile name from `~/.config/switcher/profiles/` | +| `useWorktrees` | No | Enable git worktree isolation per session | +| `sandboxEnabled` | No | Enable Landlock filesystem sandbox (Linux 5.13+) | +| `autonomousMode` | No | `restricted` (default) or `autonomous` | +| `anchorBudgetScale` | No | Anchor token budget: `small`, `medium`, `large`, `full` | +| `stallThresholdMin` | No | Minutes before idle agent is marked stalled (default 15) | + +## Creating your first agent session + +1. Launch agor (`npm run tauri dev` or the built binary). +2. The workspace shows your configured projects as cards in a grid. +3. Click a project card to focus it. The **Model** tab opens by default. +4. Type a prompt in the input area at the bottom and press Enter. +5. Agor spawns a sidecar process, connects to the provider, and streams + responses in real time. + +The agent session persists across tab switches. Closing the project card stops +the agent. + +## Keyboard shortcuts + +| Shortcut | Action | +|----------|--------| +| `Ctrl+B` | Toggle sidebar | +| `Ctrl+,` | Open settings | +| `Ctrl+Shift+F` | Full-text search overlay | +| `Ctrl+K` | Command palette | +| `Alt+1` -- `Alt+5` | Focus project 1--5 | +| `Escape` | Close sidebar / overlay / palette | + +## Running tests + +```bash +# All tests (vitest frontend + cargo backend) +npm run test:all + +# Frontend only +npm run test + +# Backend only +npm run test:cargo + +# E2E tests (requires built binary) +npm run test:all:e2e +``` + +## Directory layout + +``` +agent-orchestrator/ + agor-core/ # Shared Rust crate (PTY, sidecar, supervisor, sandbox) + agor-relay/ # Standalone relay binary (WebSocket server) + src-tauri/ # Tauri app (Rust backend) + src/ # Svelte 5 frontend + sidecar/ # Provider runner scripts (compiled to .mjs) + docs/ # Project documentation + tests/e2e/ # WebDriverIO E2E tests +``` + +## Next steps + +- [Configuration reference](../config/ref-settings.md) -- all env vars, config + files, and per-project settings. +- [Provider reference](../providers/ref-providers.md) -- Claude, Codex, Ollama, + Aider setup. +- [btmsg reference](../agents/ref-btmsg.md) -- inter-agent messaging. +- [bttask reference](../agents/ref-bttask.md) -- kanban task board. diff --git a/docs/pro/README.md b/docs/pro/README.md new file mode 100644 index 0000000..4d1103d --- /dev/null +++ b/docs/pro/README.md @@ -0,0 +1,110 @@ +# Agents Orchestrator Pro Edition + +> This documentation covers Pro edition features available in the agents-orchestrator/agents-orchestrator private repository. + +## Overview + +Agents Orchestrator Pro extends the open-source community edition with commercial features for teams and organizations that need deeper analytics, cost controls, persistent agent knowledge, and a plugin marketplace. Pro features are architecturally isolated from the community codebase, implemented as a Tauri plugin crate and a separate Svelte module tree. + +## Feature Summary + +| Feature | Description | Documentation | +|---------|-------------|---------------| +| Analytics Dashboard | Session cost trends, model usage breakdown, daily statistics | [analytics.md](features/analytics.md) | +| Budget Governor | Per-project monthly token budgets with soft/hard limits | [cost-intelligence.md](features/cost-intelligence.md) | +| Smart Model Router | Cost-aware model selection with routing profiles | [cost-intelligence.md](features/cost-intelligence.md) | +| Persistent Agent Memory | Per-project knowledge fragments with FTS5 search and TTL | [knowledge-base.md](features/knowledge-base.md) | +| Codebase Symbol Graph | Regex-based symbol extraction and caller lookup | [knowledge-base.md](features/knowledge-base.md) | +| Git Context Injection | Branch, commit, and diff context for agent prompts | [git-integration.md](features/git-integration.md) | +| Branch Policy | Session-level protection for sensitive branches | [git-integration.md](features/git-integration.md) | +| Plugin Marketplace | Curated plugin catalog with install/update lifecycle | [marketplace/README.md](marketplace/README.md) | + +## Architecture + +Pro features are separated from the community codebase at two layers: + +### Rust Backend: `agor-pro` Tauri Plugin Crate + +The `agor-pro` crate is a standalone Tauri plugin located at `crates/agor-pro/` in the private repository. It contains all Pro-specific Rust logic: SQLite tables, commands, and business rules. + +The crate exposes a single entry point: + +```rust +pub fn init() -> TauriPlugin { ... } +``` + +### Svelte Frontend: `src/lib/commercial/` + +Pro UI components live under `src/lib/commercial/` with their own adapters and stores. Community components never import from this path. The commercial module tree mirrors the community structure: + +``` +src/lib/commercial/ + adapters/ -- IPC bridges for pro commands + components/ -- Pro-specific UI (analytics, budgets, marketplace) + stores/ -- Pro-specific state +``` + +## Feature Flag + +Pro features are gated at both compile time and runtime. + +### Cargo Feature Flag + +The `pro` feature flag controls Rust compilation: + +```bash +# Community build (default) +cargo build -p bterminal + +# Pro build +cargo build -p bterminal --features pro +``` + +When `--features pro` is active, `lib.rs` registers the plugin: + +```rust +#[cfg(feature = "pro")] +app.handle().plugin(agor_pro::init()); +``` + +### Frontend Edition Flag + +The `AGOR_EDITION` environment variable controls frontend feature visibility: + +```bash +# Community build (default) +AGOR_EDITION=community npm run tauri build + +# Pro build +AGOR_EDITION=pro npm run tauri build +``` + +Svelte components check this at module level: + +```typescript +const isPro = import.meta.env.VITE_AGOR_EDITION === 'pro'; +``` + +## IPC Pattern + +All Pro commands follow the Tauri plugin IPC convention. Commands are namespaced under `plugin:agor-pro`: + +```typescript +import { invoke } from '@tauri-apps/api/core'; + +const summary = await invoke('plugin:agor-pro|pro_analytics_summary', { + period: 30, +}); +``` + +Command names use the `pro_` prefix consistently. Arguments are passed as a single object. Return types are JSON-serialized Rust structs with `#[serde(rename_all = "camelCase")]`. + +## Error Handling + +Pro commands return `Result` on the Rust side. The frontend adapters in `src/lib/commercial/adapters/` wrap `invoke()` calls and surface errors through the standard notification system. When the Pro plugin is not loaded (community build), invoke calls fail with a predictable `plugin not found` error that the adapters catch and handle silently. + +## Database + +Pro features use a dedicated SQLite database at `~/.local/share/bterminal/agor_pro.db` (WAL mode, 5s busy timeout). This keeps Pro data isolated from community tables. The `pro_budgets` and `pro_budget_log` tables are created on plugin init via migrations. + +Read-only access to community tables (e.g., `session_metrics` in `sessions.db`) is done through a separate read-only connection. diff --git a/docs/pro/features/analytics.md b/docs/pro/features/analytics.md new file mode 100644 index 0000000..4bc503a --- /dev/null +++ b/docs/pro/features/analytics.md @@ -0,0 +1,177 @@ +# Analytics Dashboard + +> This documentation covers Pro edition features available in the agents-orchestrator/agents-orchestrator private repository. + +## Overview + +The Analytics Dashboard provides historical cost and usage visibility across all projects. It reads from the community `session_metrics` table (no additional data collection required) and presents aggregated views through three commands and corresponding UI components. + +## Data Source + +All analytics are derived from the existing `session_metrics` table in `sessions.db`: + +```sql +-- Community table (read-only access from Pro plugin) +CREATE TABLE session_metrics ( + id INTEGER PRIMARY KEY, + project_id TEXT NOT NULL, + session_id TEXT NOT NULL, + started_at TEXT, + ended_at TEXT, + peak_tokens INTEGER, + turn_count INTEGER, + tool_call_count INTEGER, + cost_usd REAL, + model TEXT, + status TEXT, + error_message TEXT +); +``` + +The Pro plugin opens a read-only connection to `sessions.db` and queries this table. It never writes to community databases. + +## Commands + +### pro_analytics_summary + +Returns an aggregated summary for the specified period. + +**Arguments:** + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `period` | `u32` | Yes | Number of days to look back (7, 14, 30, or 90) | +| `projectId` | `String` | No | Filter to a single project. Omit for all projects. | + +**Response: `AnalyticsSummary`** + +```typescript +interface AnalyticsSummary { + totalCostUsd: number; + totalSessions: number; + totalTurns: number; + totalToolCalls: number; + avgCostPerSession: number; + avgTurnsPerSession: number; + peakTokensMax: number; + periodDays: number; + projectCount: number; +} +``` + +### pro_analytics_daily + +Returns per-day statistics for charting. + +**Arguments:** + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `period` | `u32` | Yes | Number of days (7, 14, 30, or 90) | +| `projectId` | `String` | No | Filter to a single project | + +**Response: `Vec`** + +```typescript +interface DailyStats { + date: string; // ISO 8601 date (YYYY-MM-DD) + costUsd: number; + sessionCount: number; + turnCount: number; + toolCallCount: number; +} +``` + +Days with no sessions are included with zero values to ensure continuous chart data. + +### pro_analytics_model_breakdown + +Returns usage grouped by model. + +**Arguments:** + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `period` | `u32` | Yes | Number of days (7, 14, 30, or 90) | +| `projectId` | `String` | No | Filter to a single project | + +**Response: `Vec`** + +```typescript +interface ModelBreakdown { + model: string; + sessionCount: number; + totalCostUsd: number; + avgCostPerSession: number; + totalTurns: number; + totalToolCalls: number; + pctOfTotalCost: number; // 0.0 to 100.0 +} +``` + +Results are sorted by `totalCostUsd` descending. + +## Period Selection + +The UI presents four period options: + +| Period | Label | Use Case | +|--------|-------|----------| +| 7 | Last 7 days | Recent activity check | +| 14 | Last 14 days | Sprint review | +| 30 | Last 30 days | Monthly cost review | +| 90 | Last 90 days | Quarterly trend analysis | + +The selected period is stored in the component state and defaults to 30 days. Changing the period triggers a fresh query (no client-side caching). + +## UI Components + +### AnalyticsDashboard.svelte + +Top-level Pro tab component. Contains: + +1. **Period selector** -- segmented button group (7/14/30/90). +2. **Summary cards** -- four stat cards showing total cost, sessions, avg cost/session, peak tokens. +3. **Daily cost chart** -- SVG bar chart rendered from `DailyStats[]`. +4. **Model breakdown table** -- sortable table from `ModelBreakdown[]`. + +### Daily Cost Chart + +The chart is a pure SVG element (no charting library). Implementation details: + +- Bars are sized relative to the maximum daily cost in the period. +- X-axis labels show abbreviated dates (e.g., "Mar 5"). +- Y-axis shows cost in USD with appropriate precision ($0.01 for small values, $1.00 for large). +- Hover tooltip shows exact cost, session count, and turn count for the day. +- Colors use `var(--ctp-blue)` for bars, `var(--ctp-surface1)` for gridlines. +- Responsive: adapts bar width to container via `container-type: inline-size`. + +### Model Breakdown Table + +Standard sortable table with columns: Model, Sessions, Cost, Avg Cost, Turns, Tools, % of Total. Default sort by cost descending. The `% of Total` column includes a proportional bar using `var(--ctp-sapphire)`. + +## IPC Examples + +```typescript +// Get 30-day summary across all projects +const summary = await invoke('plugin:agor-pro|pro_analytics_summary', { + period: 30, +}); + +// Get daily stats for a specific project +const daily = await invoke('plugin:agor-pro|pro_analytics_daily', { + period: 14, + projectId: 'my-project', +}); + +// Get model breakdown +const models = await invoke('plugin:agor-pro|pro_analytics_model_breakdown', { + period: 90, +}); +``` + +## Limitations + +- Analytics are computed on-demand from raw session_metrics rows. For large datasets (10,000+ sessions), queries may take 100-200ms. No materialized views or pre-aggregation. +- Historical data depends on community session_metrics persistence. If sessions.db is deleted or migrated, analytics history resets. +- Cost values are only available for providers that report cost (Claude, Codex). Ollama sessions show $0.00. diff --git a/docs/pro/features/cost-intelligence.md b/docs/pro/features/cost-intelligence.md new file mode 100644 index 0000000..d85f488 --- /dev/null +++ b/docs/pro/features/cost-intelligence.md @@ -0,0 +1,238 @@ +# Cost Intelligence + +> This documentation covers Pro edition features available in the agents-orchestrator/agents-orchestrator private repository. + +Cost Intelligence comprises two systems: the Budget Governor (hard cost controls) and the Smart Model Router (cost-aware model selection). Both operate at the per-project level and integrate with the agent launch pipeline. + +--- + +## Budget Governor + +### Purpose + +The Budget Governor enforces per-project monthly token budgets. It prevents runaway costs by warning at a soft limit and blocking agent launches at a hard limit. + +### Budget Configuration + +Each project can have a monthly budget with two thresholds: + +| Threshold | Default | Behavior | +|-----------|---------|----------| +| Soft limit | 80% of budget | Emits a warning notification. Agent proceeds. | +| Hard limit | 100% of budget | Blocks agent launch. Returns error to UI. | + +Budgets are denominated in USD. The governor tracks cumulative cost for the current calendar month by summing `cost_usd` from `session_metrics` and `pro_budget_log`. + +### Emergency Override + +When the hard limit is reached, the UI displays a confirmation dialog with the current spend and budget. The user can authorize an emergency override that allows the next session to proceed. Overrides are logged in `pro_budget_log` with `override = true`. Each override is single-use; subsequent launches require a new override. + +### SQLite Tables + +Both tables reside in `agor_pro.db`. + +```sql +CREATE TABLE pro_budgets ( + project_id TEXT PRIMARY KEY, + monthly_budget_usd REAL NOT NULL, + soft_limit_pct REAL NOT NULL DEFAULT 0.80, + hard_limit_pct REAL NOT NULL DEFAULT 1.00, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE TABLE pro_budget_log ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + project_id TEXT NOT NULL, + session_id TEXT NOT NULL, + cost_usd REAL NOT NULL, + cumulative_usd REAL NOT NULL, + month TEXT NOT NULL, -- YYYY-MM format + override INTEGER NOT NULL DEFAULT 0, + logged_at TEXT NOT NULL DEFAULT (datetime('now')) +); +``` + +### Commands + +#### pro_budget_set + +Creates or updates a budget for a project. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `projectId` | `String` | Yes | Project identifier | +| `monthlyBudgetUsd` | `f64` | Yes | Monthly budget in USD | +| `softLimitPct` | `f64` | No | Soft limit percentage (default 0.80) | +| `hardLimitPct` | `f64` | No | Hard limit percentage (default 1.00) | + +#### pro_budget_get + +Returns the budget configuration for a project. Returns `null` if no budget is set. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `projectId` | `String` | Yes | Project identifier | + +#### pro_budget_check + +Pre-dispatch hook. Checks whether the project can launch a new agent session. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `projectId` | `String` | Yes | Project identifier | + +**Response: `BudgetCheckResult`** + +```typescript +interface BudgetCheckResult { + allowed: boolean; + currentSpendUsd: number; + budgetUsd: number; + pctUsed: number; // 0.0 to 1.0 + softLimitReached: boolean; + hardLimitReached: boolean; + month: string; // YYYY-MM +} +``` + +#### pro_budget_log_usage + +Records cost for a completed session. Called by the agent dispatcher on session end. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `projectId` | `String` | Yes | Project identifier | +| `sessionId` | `String` | Yes | Session identifier | +| `costUsd` | `f64` | Yes | Session cost | +| `override` | `bool` | No | Whether this was an emergency override | + +#### pro_budget_reset + +Resets the cumulative spend for a project's current month. Deletes all `pro_budget_log` entries for the current month. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `projectId` | `String` | Yes | Project identifier | + +#### pro_budget_list + +Returns budgets and current spend for all projects. + +**Response: `Vec`** + +```typescript +interface ProjectBudgetStatus { + projectId: string; + monthlyBudgetUsd: number; + currentSpendUsd: number; + pctUsed: number; + softLimitReached: boolean; + hardLimitReached: boolean; +} +``` + +### Pre-Dispatch Integration + +The budget check is wired into the agent launch path: + +1. User triggers agent start in AgentPane. +2. `AgentSession.startQuery()` calls `pro_budget_check` before invoking the sidecar. +3. If `softLimitReached`: toast warning, agent proceeds. +4. If `hardLimitReached`: blocks launch, shows override dialog. +5. On override confirmation: calls `pro_budget_log_usage` with `override: true`, then proceeds. +6. On session completion: `agent-dispatcher` calls `pro_budget_log_usage` with actual cost. + +--- + +## Smart Model Router + +### Purpose + +The Smart Model Router recommends which model to use for a given agent session based on the project's routing profile and the agent's role. It does not force model selection -- it provides a recommendation that the user can accept or override. + +### Routing Profiles + +Three built-in profiles define model preferences: + +#### CostSaver + +Minimizes cost by preferring smaller models for routine tasks. + +| Role | Recommended Model | +|------|-------------------| +| Manager | claude-sonnet-4-5-20250514 | +| Architect | claude-sonnet-4-5-20250514 | +| Tester | claude-haiku-4-5-20250514 | +| Reviewer | claude-haiku-4-5-20250514 | +| Default (no role) | claude-sonnet-4-5-20250514 | + +#### QualityFirst + +Maximizes output quality by preferring the most capable model. + +| Role | Recommended Model | +|------|-------------------| +| Manager | claude-opus-4-5-20250514 | +| Architect | claude-opus-4-5-20250514 | +| Tester | claude-sonnet-4-5-20250514 | +| Reviewer | claude-sonnet-4-5-20250514 | +| Default (no role) | claude-opus-4-5-20250514 | + +#### Balanced + +Default profile. Balances cost and quality per role. + +| Role | Recommended Model | +|------|-------------------| +| Manager | claude-sonnet-4-5-20250514 | +| Architect | claude-opus-4-5-20250514 | +| Tester | claude-haiku-4-5-20250514 | +| Reviewer | claude-sonnet-4-5-20250514 | +| Default (no role) | claude-sonnet-4-5-20250514 | + +### Commands + +#### pro_router_recommend + +Returns the recommended model for a given project and role. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `projectId` | `String` | Yes | Project identifier | +| `role` | `String` | No | Agent role (manager/architect/tester/reviewer) | + +**Response:** + +```typescript +interface RouterRecommendation { + model: string; + profile: string; // CostSaver | QualityFirst | Balanced + reason: string; // Human-readable explanation +} +``` + +#### pro_router_set_profile + +Sets the routing profile for a project. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `projectId` | `String` | Yes | Project identifier | +| `profile` | `String` | Yes | Profile name: CostSaver, QualityFirst, or Balanced | + +#### pro_router_get_profile + +Returns the current routing profile for a project. Defaults to Balanced. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `projectId` | `String` | Yes | Project identifier | + +#### pro_router_list_profiles + +Returns all available routing profiles with their role-to-model mappings. Takes no arguments. + +### Integration with Agent Launch + +The router recommendation is surfaced in the AgentPane model selector. When a project has a routing profile set, the recommended model appears as a highlighted option in the dropdown. The user retains full control to select any available model.