docs: refresh repository readme [skip ci] (#2190)
This commit is contained in:
parent
8bbc4c94fe
commit
3efcd497de
356
README.md
356
README.md
|
|
@ -1,221 +1,223 @@
|
||||||
# ReverbCode
|
<div align="center">
|
||||||
|
|
||||||
The orchestration layer for parallel AI coding agents. ReverbCode is a
|
<p align="center">
|
||||||
Go-backed daemon that supervises many coding-agent sessions at once, each in
|
<img src="ao-logo.svg" alt="Agent Orchestrator" width="200" height="200" />
|
||||||
its own `git worktree`, and routes the feedback they need (CI failures, review
|
</p>
|
||||||
comments, merge conflicts) back to the right agent automatically. It ships with
|
|
||||||
an `ao` CLI and an Electron supervisor that both drive the same daemon over
|
|
||||||
loopback.
|
|
||||||
|
|
||||||
The Go module and packages remain `agent-orchestrator`; "ReverbCode" is the
|
<h1 align="center">Agent Orchestrator</h1>
|
||||||
public name.
|
|
||||||
|
|
||||||
See [`docs/architecture.md`](docs/architecture.md) for the backend mental model
|
<p align="center"><strong>The orchestration layer for parallel AI coding agents</strong></p>
|
||||||
and [`AGENTS.md`](AGENTS.md) for the contributor / worker contract. For current
|
|
||||||
progress (what's shipped vs. in flight) see [`docs/STATUS.md`](docs/STATUS.md).
|
|
||||||
|
|
||||||
## What it does
|
<p align="center">
|
||||||
|
<a href="https://github.com/AgentWrapper/agent-orchestrator/stargazers"><img src="https://img.shields.io/github/stars/AgentWrapper/agent-orchestrator" alt="Stars" /></a>
|
||||||
|
<a href="https://github.com/AgentWrapper/agent-orchestrator/graphs/contributors"><img src="https://img.shields.io/github/contributors/AgentWrapper/agent-orchestrator" alt="Contributors" /></a>
|
||||||
|
<a href="https://x.com/aoagents"><img src="https://img.shields.io/badge/Twitter-1DA1F2?logo=twitter&logoColor=white" alt="Twitter" /></a>
|
||||||
|
<a href="https://discord.com/invite/UZv7JjxbwG"><img src="https://img.shields.io/badge/Discord-join%20the%20community-5865F2?logo=discord&logoColor=white" alt="Discord" /></a>
|
||||||
|
<a href="https://www.apache.org/licenses/LICENSE-2.0"><img src="https://img.shields.io/badge/License-Apache--2.0-blue.svg" alt="License: Apache-2.0" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
- **Agent-agnostic.** A 23-adapter platform under
|
<p align="center">An Agentic IDE that supervises parallel AI coding agents in isolated workspaces, with complete control and automatic feedback loops from CI failures, review comments, and merge conflicts.</p>
|
||||||
`backend/internal/adapters/agent/` (`claude-code`, `codex`, `cursor`,
|
|
||||||
`opencode`, `aider`, `amp`, `goose`, `copilot`, `grok`, `qwen`, `kimi`,
|
|
||||||
`crush`, `cline`, `droid`, `devin`, `auggie`, `continue`, `kiro`, `kilocode`,
|
|
||||||
and more), registered through a shared registry with common
|
|
||||||
activity-dispatch / hook utilities. Worker and orchestrator defaults are set
|
|
||||||
per project.
|
|
||||||
- **Isolated workspaces.** Worker and orchestrator sessions spawn into their own
|
|
||||||
`git worktree` (`backend/internal/adapters/workspace/gitworktree/`), launched
|
|
||||||
inside a `zellij` runtime adapter (`backend/internal/adapters/runtime/`) so
|
|
||||||
every session has its own attachable terminal.
|
|
||||||
- **Live PR observation.** The provider-neutral SCM observer
|
|
||||||
(`backend/internal/observe/scm/`) polls each session's PR with ETag guards and
|
|
||||||
semantic diffing, tracking CI/check runs and review threads, and feeds those
|
|
||||||
facts into the lifecycle manager, which sends the owning agent nudges for CI
|
|
||||||
failures, review feedback, and merge conflicts. GitHub is the implemented
|
|
||||||
provider today.
|
|
||||||
- **Durable facts, derived status.** The SQLite store
|
|
||||||
(`backend/internal/storage/sqlite/`) persists a small set of session facts
|
|
||||||
plus PR/check/comment rows; display status is computed at read time, never
|
|
||||||
stored. DB triggers append every user-visible change to `change_log`, and a
|
|
||||||
CDC poller/broadcaster (`backend/internal/cdc/`) feeds in-process subscribers
|
|
||||||
and an SSE replay endpoint.
|
|
||||||
- **Loopback-only daemon.** The HTTP daemon (`backend/internal/httpd`) controls
|
|
||||||
projects, sessions, orchestrators, and hook callbacks over `127.0.0.1` with no
|
|
||||||
auth, CORS, or TLS by design.
|
|
||||||
- **Lifecycle manager + reaper** (`backend/internal/lifecycle/`,
|
|
||||||
`backend/internal/observe/reaper/`) reduce runtime/activity/PR observations
|
|
||||||
into the durable session state and reclaim dead sessions.
|
|
||||||
|
|
||||||
## How it works
|
<p align="center">
|
||||||
|
<img src="ao-dashboard-preview.png" alt="Agent Orchestrator Dashboard" />
|
||||||
|
</p>
|
||||||
|
|
||||||
1. Register a local git repo as a project (`ao project add`).
|
### See AO in Action (before the re-write)
|
||||||
2. Spawn a worker session (`ao spawn`), or an orchestrator that fans work out
|
|
||||||
across sessions. Each session gets its own `git worktree` and a `zellij`
|
|
||||||
pane.
|
|
||||||
3. The agent develops, tests, and opens a PR from inside its worktree.
|
|
||||||
4. The SCM observer watches that PR and routes feedback back to the agent: a CI
|
|
||||||
failure, a requested change, or a merge conflict becomes a nudge to the agent
|
|
||||||
that owns the PR.
|
|
||||||
5. You inspect, attach a terminal, and merge from the CLI or the Electron app;
|
|
||||||
human attention is needed only where the loop can't resolve on its own.
|
|
||||||
|
|
||||||
## Extensibility
|
<table border="1" style="border-collapse: collapse; width: 100%;">
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 10px; text-align: center; border: 1px solid #ddd;">
|
||||||
|
<a href="https://x.com/agent_wrapper/status/2026329204405723180"><img src="screenshots/first.png" alt="First" width="400"></a><br><br>
|
||||||
|
<a href="https://x.com/agent_wrapper/status/2026329204405723180">Visit</a>
|
||||||
|
</td>
|
||||||
|
<td style="padding: 10px; text-align: center; border: 1px solid #ddd;">
|
||||||
|
<a href="https://x.com/agent_wrapper/status/2025986105485733945"><img src="screenshots/second.png" alt="Second" width="400"></a><br><br>
|
||||||
|
<a href="https://x.com/agent_wrapper/status/2025986105485733945">Visit</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 10px; text-align: center; border: 1px solid #ddd;">
|
||||||
|
<a href="https://x.com/agent_wrapper/status/2064157228400341312"><img src="screenshots/third.png" alt="Third" width="400"></a><br><br>
|
||||||
|
<a href="https://x.com/agent_wrapper/status/2064157228400341312">Visit</a>
|
||||||
|
</td>
|
||||||
|
<td style="padding: 10px; text-align: center; border: 1px solid #ddd;">
|
||||||
|
<a href="https://x.com/agent_wrapper/status/2024885035774738700?s=20"><img src="screenshots/image.png" alt="Fourth" width="400"></a><br><br>
|
||||||
|
<a href="https://x.com/agent_wrapper/status/2024885035774738700?s=20">Visit</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
The backend is organized around inbound/outbound port contracts
|
[Features](#features) • [Quick Start](#quick-start) • [Architecture](#architecture) • [Documentation](#documentation) • [Contributing](#contributing)
|
||||||
(`backend/internal/ports/`) with swappable adapters under
|
|
||||||
`backend/internal/adapters/`:
|
|
||||||
|
|
||||||
| Port | Implemented adapters |
|
</div>
|
||||||
| --------- | --------------------------------------------- |
|
|
||||||
| Agent | 23 harnesses (see above) |
|
|
||||||
| Runtime | `zellij` |
|
|
||||||
| Workspace | `git worktree` |
|
|
||||||
| SCM | GitHub |
|
|
||||||
| Tracker | GitHub (adapter present; no runtime loop yet) |
|
|
||||||
| Reviewer | `claude-code` |
|
|
||||||
| Notifier | port defined; no shipped adapter yet |
|
|
||||||
|
|
||||||
See [`docs/STATUS.md`](docs/STATUS.md) for which lanes are live at runtime.
|
---
|
||||||
|
|
||||||
## Quick start
|
## Features
|
||||||
|
|
||||||
Requirements: Go 1.25+, [`zellij`](https://zellij.dev/) on `PATH` for the
|
| Feature | Description |
|
||||||
runtime adapter, and `gh` (or `GITHUB_TOKEN`) if you want the SCM observer to
|
| :--- | :--- |
|
||||||
authenticate against GitHub. The SQLite driver is the pure-Go
|
| **Agent-Agnostic Platform** | 23+ agent adapters including [Claude Code](https://code.claude.com/docs/en/overview), [OpenAI Codex](https://openai.com/), [Cursor](https://cursor.com/), [OpenCode](https://opencode.ai/), [Aider](https://aider.chat/), [Amp](https://ampcode.com/manual), [Goose](https://goose-docs.ai/), [GitHub Copilot](https://github.com/features/copilot), [Grok](https://x.ai/grok), [Qwen Code](https://github.com/QwenLM/qwen-code), [Kimi Code](https://www.kimi.com/code), [Cline](https://cline.bot/), [Continue](https://www.continue.dev/), [Kiro](https://kiro.dev/), and more |
|
||||||
`modernc.org/sqlite` — no system SQLite library is required.
|
| **Isolated Workspaces** | Each session spawns into its own git worktree with dedicated runtime |
|
||||||
|
| **Platform-Native Runtimes** | tmux on Darwin/Linux, conpty on Windows for optimal performance |
|
||||||
|
| **Live PR Observation** | Provider-neutral SCM observer with automatic feedback routing |
|
||||||
|
| **Automatic Feedback Routing** | CI failures, review comments, and merge conflicts routed to the owning agent |
|
||||||
|
| **Durable Facts Storage** | SQLite persists immutable facts with display status derived at read time |
|
||||||
|
| **CDC Broadcasting** | DB triggers append changes to change_log, broadcasted via SSE |
|
||||||
|
| **Desktop Experience** | Native Electron app with React UI and live terminal streaming |
|
||||||
|
| **Loopback-Only Daemon** | HTTP control over 127.0.0.1 with no auth, CORS, or TLS by design |
|
||||||
|
|
||||||
```bash
|
### Supported Agents
|
||||||
cd backend
|
|
||||||
go build -o /tmp/ao ./cmd/ao
|
|
||||||
|
|
||||||
# Start the daemon and wait for /readyz.
|
Works with 23+ CLI-based coding agents including Claude Code, OpenAI Codex, Cursor, OpenCode, Aider, Amp, Goose, GitHub Copilot, Grok, Qwen Code, Kimi Code, Crush, Cline, Droid, Devin, Auggie, Continue, Kiro, and Kilo Code.
|
||||||
/tmp/ao start
|
|
||||||
|
|
||||||
# Register a local git repo as a project. The id defaults to the lowercased
|
**If it runs in a terminal, it runs on Agent Orchestrator.**
|
||||||
# base of --path; pass --id explicitly when the directory name doesn't match.
|
|
||||||
/tmp/ao project add --path /path/to/your/repo --id your-repo --name your-repo \
|
|
||||||
--worker-agent codex --orchestrator-agent codex
|
|
||||||
|
|
||||||
# Spawn a worker session running the project's worker agent.
|
---
|
||||||
/tmp/ao spawn --project your-repo --prompt "Refactor the auth module"
|
|
||||||
|
|
||||||
# Inspect what's running.
|
## Quick Start
|
||||||
/tmp/ao status
|
|
||||||
/tmp/ao session ls
|
|
||||||
```
|
|
||||||
|
|
||||||
### Electron app (dev)
|
### Prerequisites
|
||||||
|
|
||||||
The desktop supervisor lives under `frontend/` and is started separately:
|
| Requirement | Minimum | Recommended |
|
||||||
|
|-------------|---------|-------------|
|
||||||
|
| Go | 1.25+ | Latest |
|
||||||
|
| Node.js | 20+ | Latest LTS |
|
||||||
|
| Git | Any | Latest |
|
||||||
|
| pnpm | Any | Latest |
|
||||||
|
|
||||||
```bash
|
**Optional:**
|
||||||
cd frontend
|
- `tmux` (Darwin/Linux) - For Unix runtime
|
||||||
npm install
|
- `gh` (GitHub CLI) - For authenticated GitHub API calls
|
||||||
npm run dev # electron-forge start
|
|
||||||
```
|
|
||||||
|
|
||||||
Heads-up: `npm run dev` does **not** start the daemon for you. Start it first
|
### Installation
|
||||||
(`ao start`, see above) — the renderer attaches to the running daemon over
|
|
||||||
loopback (`127.0.0.1:3001` by default, the `AO_PORT` from the table below).
|
|
||||||
Without a daemon the app opens but shows its daemon-not-ready state.
|
|
||||||
|
|
||||||
For renderer-only UI work without the Electron shell, use
|
Download the latest release for your platform:
|
||||||
`npm run dev:web` (Vite in a regular browser).
|
|
||||||
|
|
||||||
## CLI surface
|
| Platform | Download |
|
||||||
|
|----------|----------|
|
||||||
|
| **Windows** | [Setup.exe](https://github.com/AgentWrapper/agent-orchestrator/releases/latest) |
|
||||||
|
| **macOS** | [Agent Orchestrator.dmg](https://github.com/AgentWrapper/agent-orchestrator/releases/latest) |
|
||||||
|
| **Linux** | [Agent Orchestrator.AppImage](https://github.com/AgentWrapper/agent-orchestrator/releases/latest) |
|
||||||
|
|
||||||
The CLI is intentionally thin: every product command resolves to a daemon HTTP
|
**Direct Download:** [Latest Release](https://github.com/AgentWrapper/agent-orchestrator/releases/latest)
|
||||||
route. Run `ao <command> --help` for the authoritative flag shape; the table
|
|
||||||
below groups what's on `main` today.
|
|
||||||
|
|
||||||
| Lane | Command | Purpose |
|
---
|
||||||
| ------------ | ------------------------------------ | ---------------------------------------------------------------------------------- |
|
|
||||||
| Daemon | `ao start` | Start the daemon in the background and wait for `/readyz`. |
|
|
||||||
| Daemon | `ao stop` | Graceful shutdown via loopback `POST /shutdown`. |
|
|
||||||
| Daemon | `ao status` | Report PID/port/health/readiness from `running.json`. |
|
|
||||||
| Daemon | `ao daemon` | Hidden internal entrypoint used by `ao start`. |
|
|
||||||
| Project | `ao project add` | Register a local git repo as a project. |
|
|
||||||
| Project | `ao project ls` | List registered projects. |
|
|
||||||
| Project | `ao project get <id>` | Fetch one project. |
|
|
||||||
| Project | `ao project set-config <id>` | Update per-project config. |
|
|
||||||
| Project | `ao project rm <id>` | Remove a project. |
|
|
||||||
| Session | `ao spawn` | Spawn a worker session in a registered project. |
|
|
||||||
| Session | `ao session ls` | List sessions (filter by project, include terminated). |
|
|
||||||
| Session | `ao session get <id>` | Fetch one session. |
|
|
||||||
| Session | `ao session kill <id>` | Terminate a session. |
|
|
||||||
| Session | `ao session rename <id> <name>` | Rename a session. |
|
|
||||||
| Session | `ao session restore <id>` | Relaunch a terminated session. |
|
|
||||||
| Session | `ao session cleanup` | Reclaim eligible workspaces for terminated sessions. |
|
|
||||||
| Session | `ao session claim-pr <session> <pr>` | Attach an existing PR to a session. |
|
|
||||||
| Orchestrator | `ao orchestrator ls` | List orchestrator sessions. |
|
|
||||||
| Messaging | `ao send` | Send a message to a running agent session. |
|
|
||||||
| Preview | `ao preview [url]` | Open a URL (or the workspace `index.html`) in the session's desktop browser panel. |
|
|
||||||
| Utility | `ao doctor` | Local health checks (config, data dir, DB, `git`, `zellij`). |
|
|
||||||
| Utility | `ao completion <shell>` | Generate bash/zsh/fish/powershell completions. |
|
|
||||||
| Utility | `ao version` | Print build metadata. |
|
|
||||||
| Internal | `ao hooks <agent> <event>` | Hidden adapter hook callback. |
|
|
||||||
|
|
||||||
See [`docs/cli/`](docs/cli/) for the daemon-control intent and command shape.
|
## Telemetry
|
||||||
|
|
||||||
## Configuration
|
Agent Orchestrator collects minimal telemetry for reliability and product understanding. Data is stored locally by default; remote transmission is opt-in via environment variables. [Read the full telemetry policy](docs/telemetry.md).
|
||||||
|
|
||||||
All configuration is env-driven; the daemon takes no config file. The bind
|
---
|
||||||
host is hard-coded to `127.0.0.1` — the daemon has no auth, CORS, or TLS, and
|
|
||||||
exposing it beyond loopback would be a security regression.
|
|
||||||
|
|
||||||
| Var | Default | Purpose |
|
|
||||||
| --------------------- | ------------------------------------------------- | --------------------------------------------------------------------------- |
|
|
||||||
| `AO_PORT` | `3001` | Bind port; daemon fails fast if taken. |
|
|
||||||
| `AO_REQUEST_TIMEOUT` | `60s` | Per-request timeout (Go duration). |
|
|
||||||
| `AO_SHUTDOWN_TIMEOUT` | `10s` | Graceful-shutdown hard cap. |
|
|
||||||
| `AO_RUN_FILE` | `<UserConfigDir>/agent-orchestrator/running.json` | PID + port handshake path. |
|
|
||||||
| `AO_DATA_DIR` | `<UserConfigDir>/agent-orchestrator/data` | SQLite DB, WAL files, managed state. |
|
|
||||||
| `AO_AGENT` | `claude-code` | Compatibility agent adapter id validated at daemon startup. |
|
|
||||||
| `AO_SESSION_ID` | _(unset)_ | Set inside spawned sessions; read by `ao send` and `ao hooks`. |
|
|
||||||
| `GITHUB_TOKEN` | _(unset)_ | Used by the GitHub SCM and tracker adapters. Falls back to `gh auth token`. |
|
|
||||||
|
|
||||||
Health check:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl localhost:3001/healthz
|
|
||||||
curl localhost:3001/readyz
|
|
||||||
```
|
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
The daemon is a long-running supervisor. Adapters observe external facts (PR
|
Agent Orchestrator is a long-running Go daemon built around **inbound/outbound port contracts** with swappable adapters.
|
||||||
state, agent activity, runtime liveness); the lifecycle manager reduces those
|
|
||||||
into a small set of durable session facts (`activity_state`, `is_terminated`,
|
|
||||||
PR rows). Display status is _derived_ from those facts at read time — it is
|
|
||||||
never stored. SQLite triggers append every user-visible change to `change_log`,
|
|
||||||
and the CDC poller broadcasts those events to in-process subscribers and an
|
|
||||||
SSE stream.
|
|
||||||
|
|
||||||
Full mental model and load-bearing rules: [`docs/architecture.md`](docs/architecture.md).
|
**Core mental model:** OBSERVE external facts → UPDATE durable facts → DERIVE display status / ACT
|
||||||
Package-by-package ownership: [`docs/backend-code-structure.md`](docs/backend-code-structure.md).
|
|
||||||
|
**Key components:**
|
||||||
|
- **Frontend** - Electron + React UI with TanStack Router/Query and shadcn/ui
|
||||||
|
- **Backend Daemon** - Go-based HTTP server with controllers, services, and adapters
|
||||||
|
- **Runtime** - Platform-specific: `tmux` on Darwin/Linux, `conpty` on Windows
|
||||||
|
- **Storage** - SQLite with change-data-capture (CDC) for real-time updates
|
||||||
|
- **Adapters** - 23+ agent adapters, git worktree workspace, GitHub SCM integration
|
||||||
|
|
||||||
|
For detailed architecture diagrams, data flows, and load-bearing rules, see [architecture.md](docs/architecture.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
| Document | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| [Architecture](docs/architecture.md) | System architecture, data flows, and load-bearing rules |
|
||||||
|
| [Backend Code Structure](docs/backend-code-structure.md) | Package-by-package ownership and dependency rules |
|
||||||
|
| [AGENTS.md](AGENTS.md) | Contributor and worker-agent contract |
|
||||||
|
| [Agent Adapter Contract](docs/agent/README.md) | Agent adapter interface and hook behavior |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
The local gate is the backend Go build and race-enabled test suite:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd backend && go build ./... && go test -race ./...
|
# Backend tests
|
||||||
|
cd backend
|
||||||
|
go test -race ./...
|
||||||
|
|
||||||
|
# Frontend tests
|
||||||
|
cd frontend
|
||||||
|
pnpm test
|
||||||
|
|
||||||
|
# Full CI validation locally
|
||||||
|
npx @redwoodjs/agent-ci run --all
|
||||||
```
|
```
|
||||||
|
|
||||||
GitHub Actions is the authoritative pre-merge gate; mirror its commands here
|
---
|
||||||
when in doubt. See [`AGENTS.md`](AGENTS.md) for the regen workflow when
|
|
||||||
touching the daemon API surface (`npm run sqlc`, `npm run api`).
|
|
||||||
|
|
||||||
## Status and roadmap
|
## Configuration
|
||||||
|
|
||||||
Progress tracking lives in [`docs/STATUS.md`](docs/STATUS.md): what is shipped
|
All configuration is environment-driven. The daemon takes no config file.
|
||||||
on `main` today, what is still in flight, and the linked
|
|
||||||
[`rewrite`](https://github.com/aoagents/agent-orchestrator/milestone/1)
|
| Variable | Default | Purpose |
|
||||||
milestone on GitHub.
|
|----------|---------|---------|
|
||||||
|
| `AO_PORT` | `3001` | HTTP bind port |
|
||||||
|
| `AO_REQUEST_TIMEOUT` | `60s` | Per-request timeout |
|
||||||
|
| `AO_SHUTDOWN_TIMEOUT` | `10s` | Graceful shutdown cap |
|
||||||
|
| `AO_RUN_FILE` | `~/.ao/running.json` | PID/port handshake |
|
||||||
|
| `AO_DATA_DIR` | `~/.ao/data` | SQLite data directory |
|
||||||
|
| `AO_AGENT` | `claude-code` | Compatibility agent adapter |
|
||||||
|
| `GITHUB_TOKEN` | - | GitHub auth token |
|
||||||
|
|
||||||
|
### Health Checks
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl localhost:3001/healthz # Liveness probe
|
||||||
|
curl localhost:3001/readyz # Readiness probe
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Repo layout and the worker contract live in [`AGENTS.md`](AGENTS.md). Keep
|
We love contributions! Join our community on Discord to get started.
|
||||||
changes surgical, follow the package boundaries documented in
|
|
||||||
[`docs/backend-code-structure.md`](docs/backend-code-structure.md), and prefer
|
### Join us on Discord
|
||||||
adding daemon HTTP routes over leaking storage / runtime into the CLI.
|
|
||||||
|
[](https://discord.com/invite/UZv7JjxbwG)
|
||||||
|
|
||||||
|
**Daily contributor sync:** Every day at **10:00 PM IST**
|
||||||
|
|
||||||
|
Get your issues verified by core contributors, ask questions, share progress, and learn from the community. New contributors are always welcome!
|
||||||
|
|
||||||
|
**Why join Discord?**
|
||||||
|
|
||||||
|
- Get your issues and PRs verified by core contributors before investing time
|
||||||
|
- Learn from experienced contributors in daily sync calls
|
||||||
|
- Share your progress and get feedback
|
||||||
|
- Get help troubleshooting in real-time
|
||||||
|
- Stay updated on the latest developments and roadmap
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
1. **Join the Discord** - Connect with the community and get guidance
|
||||||
|
2. **Read the contributor contract** - See [AGENTS.md](AGENTS.md) for repo layout, daemon/API boundaries, and coding conventions
|
||||||
|
3. **Pick a focused problem** - Browse [open issues](https://github.com/AgentWrapper/agent-orchestrator/issues) and choose one small enough for a focused PR
|
||||||
|
4. **Open a clear PR** - Keep changes narrow, explain user-visible impact, link issues, include tests
|
||||||
|
5. **Iterate with contributors** - Use review feedback to tighten the PR until verified
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Apache License 2.0 - see [LICENSE](LICENSE) for details.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
**[Star us on GitHub](https://github.com/AgentWrapper/agent-orchestrator)** • **[Report Issues](https://github.com/AgentWrapper/agent-orchestrator/issues)** • **[Discussions](https://github.com/AgentWrapper/agent-orchestrator/discussions)**
|
||||||
|
|
||||||
|
Made with love by the Agent Orchestrator community
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 209 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 56 KiB |
1019
docs/agent/README.md
1019
docs/agent/README.md
File diff suppressed because it is too large
Load Diff
|
|
@ -1,103 +1,856 @@
|
||||||
# Agent Orchestrator backend architecture
|
# Agent Orchestrator Architecture
|
||||||
|
|
||||||
The backend is a long-running Go daemon that supervises coding-agent sessions.
|
Agent Orchestrator is a long-running Go daemon that supervises multiple parallel AI coding agent sessions. Each session runs in an isolated git worktree with its own runtime, while the daemon coordinates lifecycle, observes external state, and routes feedback.
|
||||||
The current model is intentionally small: session rows persist only durable facts,
|
|
||||||
and display status is derived at read time.
|
|
||||||
|
|
||||||
## Mental model
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Mental Model](#mental-model)
|
||||||
|
- [System Overview](#system-overview)
|
||||||
|
- [Core Architectural Principles](#core-architectural-principles)
|
||||||
|
- [Component Architecture](#component-architecture)
|
||||||
|
- [Data Flows](#data-flows)
|
||||||
|
- [Persistence and CDC](#persistence-and-cdc)
|
||||||
|
- [Status Derivation](#status-derivation)
|
||||||
|
- [Lifecycle Management](#lifecycle-management)
|
||||||
|
- [Observation Loops](#observation-loops)
|
||||||
|
- [HTTP Layer](#http-layer)
|
||||||
|
- [Terminal Multiplexing](#terminal-multiplexing)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mental Model
|
||||||
|
|
||||||
|
The fundamental architecture follows a simple three-stage pipeline:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
A[OBSERVE<br/>External Facts] --> B[UPDATE<br/>Durable Facts]
|
||||||
|
B --> C[DERIVE<br/>Display Status / ACT]
|
||||||
|
|
||||||
```
|
|
||||||
OBSERVE external facts → UPDATE durable facts → DERIVE display status / ACT
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The durable session facts are:
|
**Key insight:** Display status is never stored. It is computed at read time from durable facts.
|
||||||
|
|
||||||
- `activity_state` — what the agent last reported or what the runtime observer
|
### Durable Session Facts
|
||||||
can safely conclude (`active`, `idle`, `waiting_input`, `exited`).
|
|
||||||
- `is_terminated` — whether the session should be treated as over.
|
|
||||||
- PR facts in the `pr`, `pr_checks`, and `pr_comment` tables.
|
|
||||||
|
|
||||||
The UI status is not stored. `service.Session` computes it from the session
|
The only persistent session state is:
|
||||||
record plus PR facts while assembling controller-facing read models.
|
|
||||||
|
|
||||||
## Package layout
|
- `activity_state` — What the agent last reported (`active`, `idle`, `waiting_input`, `exited`)
|
||||||
|
- `is_terminated` — Whether the session should be treated as over
|
||||||
|
- PR facts — `pr`, `pr_checks`, `pr_comment` tables
|
||||||
|
|
||||||
|
### What is NOT Durable
|
||||||
|
|
||||||
|
Display status like `working`, `needs_input`, `ci_failed`, `mergeable` are **computed at read time** by the service layer from the durable facts above.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## System Overview
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph Frontend
|
||||||
|
FE[Electron + React UI]
|
||||||
|
CLI[ao CLI]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph HTTP["HTTP Daemon (127.0.0.1)"]
|
||||||
|
Controllers[REST Controllers]
|
||||||
|
SSE[SSE Events]
|
||||||
|
Terminal[Terminal WebSocket]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Core["Core Services"]
|
||||||
|
SessionSvc[Session Service]
|
||||||
|
ProjectSvc[Project Service]
|
||||||
|
PRSvc[PR Service]
|
||||||
|
ReviewSvc[Review Service]
|
||||||
|
SessionMgr[Session Manager]
|
||||||
|
LCM[Lifecycle Manager]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Observe["Observation Layer"]
|
||||||
|
SCMObserver[SCM Observer]
|
||||||
|
Reaper[Runtime Reaper]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Storage["Persistence Layer"]
|
||||||
|
SQLite[(SQLite DB)]
|
||||||
|
CDC[CDC Poller]
|
||||||
|
Broadcaster[Event Broadcaster]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Adapters["Adapters"]
|
||||||
|
AgentAdapter[Agent Adapters]
|
||||||
|
RuntimeAdapter[Runtime tmux/conpty]
|
||||||
|
WorkspaceAdapter[Workspace git worktree]
|
||||||
|
SCMAdapter[SCM GitHub]
|
||||||
|
end
|
||||||
|
|
||||||
|
FE -->|REST/SSE| Controllers
|
||||||
|
CLI -->|REST| Controllers
|
||||||
|
Controllers --> SessionSvc
|
||||||
|
Controllers --> ProjectSvc
|
||||||
|
Controllers --> PRSvc
|
||||||
|
|
||||||
|
SessionSvc --> SessionMgr
|
||||||
|
SessionMgr --> LCM
|
||||||
|
SessionMgr --> AgentAdapter
|
||||||
|
SessionMgr --> RuntimeAdapter
|
||||||
|
SessionMgr --> WorkspaceAdapter
|
||||||
|
|
||||||
|
LCM --> SQLite
|
||||||
|
LCM --> AgentAdapter
|
||||||
|
|
||||||
|
SCMObserver --> SCMAdapter
|
||||||
|
SCMObserver --> SQLite
|
||||||
|
SCMObserver --> LCM
|
||||||
|
|
||||||
|
Reaper --> RuntimeAdapter
|
||||||
|
Reaper --> SQLite
|
||||||
|
Reaper --> LCM
|
||||||
|
|
||||||
|
CDC -->|poll| SQLite
|
||||||
|
CDC --> Broadcaster
|
||||||
|
Broadcaster --> SSE
|
||||||
|
|
||||||
|
Terminal --> RuntimeAdapter
|
||||||
|
|
||||||
```
|
```
|
||||||
backend/internal/domain shared vocabulary and API status value types
|
|
||||||
backend/internal/ports inbound/outbound interfaces
|
---
|
||||||
backend/internal/service/{project,session,pr,review}
|
|
||||||
controller-facing services and read-model assembly
|
## Core Architectural Principles
|
||||||
backend/internal/session_manager internal session command manager
|
|
||||||
backend/internal/lifecycle runtime/activity/spawn/termination session fact reducer
|
### 1. Port-Based Design
|
||||||
backend/internal/observe/scm SCM (GitHub) observer loop feeding PR facts
|
|
||||||
backend/internal/observe/reaper runtime liveness observation loop
|
Core code never depends on concrete implementations. All external systems are accessed through port interfaces defined in `backend/internal/ports/`:
|
||||||
backend/internal/storage SQLite persistence and DB-triggered CDC
|
|
||||||
backend/internal/cdc change-log poller and broadcaster
|
```mermaid
|
||||||
backend/internal/httpd daemon HTTP surface (REST + SSE + terminal mux)
|
graph LR
|
||||||
backend/internal/terminal WebSocket terminal multiplexer
|
Core[Core Services] -->|consumes| Ports[Port Interfaces]
|
||||||
backend/internal/adapters agent/tmux+conpty runtime/git-worktree/GitHub SCM + tracker adapters
|
Adapters[Adapters] -->|implement| Ports
|
||||||
backend/internal/daemon production wiring and shutdown
|
External[External Systems] -->|wrapped by| Adapters
|
||||||
backend/internal/config daemon env/default config
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Status derivation
|
### 2. Durable Facts, Derived Status
|
||||||
|
|
||||||
`service.Session` selects the display PR from all PR snapshots for a session, then
|
Storage layer persists minimal facts. Service layer computes display status on-demand:
|
||||||
applies this rough precedence:
|
|
||||||
|
|
||||||
1. `is_terminated` → `terminated`, except merged PRs display `merged`.
|
```mermaid
|
||||||
2. `activity_state=waiting_input` → `needs_input`.
|
flowchart LR
|
||||||
3. Open PR facts drive PR pipeline statuses: `ci_failed`, `draft`,
|
SQLite[(SQLite)] -->|raw facts| Service[Session Service]
|
||||||
`changes_requested`, `mergeable`, `approved`, `review_pending`, `pr_open`.
|
Service -->|compute| Status[Display Status]
|
||||||
4. `activity_state=active` → `working`.
|
Service -->|enrich| UI[Dashboard/UI]
|
||||||
5. A signal-capable harness that has never sent a hook callback past the
|
|
||||||
~90s spawn grace → `no_signal` (a broken hook pipeline is visible rather
|
|
||||||
than reported as a confident `idle`). Hook-less harnesses stay `idle`.
|
|
||||||
6. Everything else → `idle`.
|
|
||||||
|
|
||||||
## Lifecycle manager
|
SQLite -->|activity_state| Service
|
||||||
|
SQLite -->|is_terminated| Service
|
||||||
|
SQLite -->|PR facts| Service
|
||||||
|
SQLite -->|runtime_handle| Service
|
||||||
|
|
||||||
`lifecycle.Manager` is the write path for session lifecycle facts and lifecycle-owned agent nudges:
|
```
|
||||||
|
|
||||||
- runtime observations can mark a session terminated only when runtime and
|
### 3. Observer Pattern
|
||||||
process are both clearly dead and recent activity does not contradict that;
|
|
||||||
failed/unknown probes do not persist a special state.
|
|
||||||
- activity signals update `activity_state`; `exited` also marks the session
|
|
||||||
terminated.
|
|
||||||
- PR observations do not write PR rows here, but after the PR service persists
|
|
||||||
them lifecycle sends actionable agent nudges for CI failures, review feedback,
|
|
||||||
and merge conflicts.
|
|
||||||
|
|
||||||
## PR manager
|
Observation is separated from action:
|
||||||
|
|
||||||
`pr.Manager` records SCM observations into the PR/check/comment tables, then
|
- **Observe layer** — SCM Observer, Runtime Reaper poll external state
|
||||||
forwards the observation to lifecycle for agent nudges. A merged PR marks the
|
- **Lifecycle layer** — Reduces observations into durable facts
|
||||||
owning session terminated through the lifecycle manager; other PR facts are
|
- **Service layer** — Computes display status from facts
|
||||||
consumed at read time for display status.
|
|
||||||
|
|
||||||
## Session manager
|
### 4. Change Data Capture
|
||||||
|
|
||||||
`session_manager.Manager` performs internal session mutations:
|
All durable changes flow through a CDC pipeline:
|
||||||
|
|
||||||
- `Spawn` creates a row, creates workspace/runtime resources, and reports the
|
```mermaid
|
||||||
handles to the lifecycle manager.
|
flowchart LR
|
||||||
- `Kill` marks the row terminated, then tears down runtime/workspace resources.
|
DB[(SQLite)] -->|triggers| ChangeLog[change_log table]
|
||||||
- `Restore` relaunches a terminated session and clears `is_terminated` via the
|
ChangeLog -->|tail| Poller[CDC Poller]
|
||||||
spawn-completed path.
|
Poller -->|Event| Broadcaster[Event Broadcaster]
|
||||||
|
Broadcaster -->|fan-out| Subscribers[Subscribers]
|
||||||
|
Subscribers -->|SSE| Clients[Dashboard Clients]
|
||||||
|
|
||||||
`service.Session` is the controller-facing boundary. It delegates commands to
|
```
|
||||||
`session_manager.Manager` and attaches derived display status on read paths.
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Component Architecture
|
||||||
|
|
||||||
|
### Package Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
backend/internal/
|
||||||
|
├── domain/ # Shared vocabulary and durable fact records
|
||||||
|
├── ports/ # Inbound/outbound interfaces
|
||||||
|
├── service/ # Controller-facing services
|
||||||
|
│ ├── project/ # Project CRUD
|
||||||
|
│ ├── session/ # Session read-model assembly
|
||||||
|
│ ├── pr/ # PR observation service
|
||||||
|
│ └── review/ # Code review service
|
||||||
|
├── session_manager/ # Internal session command engine
|
||||||
|
├── lifecycle/ # Durable session fact reducer
|
||||||
|
├── observe/ # Observation loops
|
||||||
|
│ ├── scm/ # SCM (GitHub) observer
|
||||||
|
│ └── reaper/ # Runtime liveness observer
|
||||||
|
├── storage/ # SQLite persistence
|
||||||
|
│ └── sqlite/ # DB, migrations, queries, stores
|
||||||
|
├── cdc/ # Change-log poller and broadcaster
|
||||||
|
├── httpd/ # HTTP API, controllers, terminal mux
|
||||||
|
├── terminal/ # Terminal session protocol
|
||||||
|
├── adapters/ # Concrete adapter implementations
|
||||||
|
│ ├── agent/ # 23+ agent harnesses
|
||||||
|
│ ├── runtime/ # tmux/conpty runtimes
|
||||||
|
│ ├── workspace/ # git worktree
|
||||||
|
│ ├── scm/ # GitHub
|
||||||
|
│ └── tracker/ # GitHub tracker
|
||||||
|
├── daemon/ # Production wiring
|
||||||
|
└── config/ # Environment-based configuration
|
||||||
|
```
|
||||||
|
|
||||||
|
### Core Data Flow
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant UI as Dashboard
|
||||||
|
participant HTTP as HTTP Controller
|
||||||
|
participant Svc as Session Service
|
||||||
|
participant Mgr as Session Manager
|
||||||
|
participant LCM as Lifecycle Manager
|
||||||
|
participant Agent as Agent Adapter
|
||||||
|
participant Runtime as Runtime Adapter
|
||||||
|
participant WS as Workspace Adapter
|
||||||
|
participant DB as SQLite
|
||||||
|
participant CDC as CDC Broadcaster
|
||||||
|
|
||||||
|
UI->>HTTP: POST /sessions
|
||||||
|
HTTP->>Svc: Spawn(config)
|
||||||
|
Svc->>Mgr: Spawn(config)
|
||||||
|
|
||||||
|
Note over Mgr: 1. Create session row
|
||||||
|
Mgr->>DB: Insert session
|
||||||
|
DB->>CDC: trigger change_log
|
||||||
|
CDC->>UI: SSE session.created
|
||||||
|
|
||||||
|
Note over Mgr: 2. Create workspace
|
||||||
|
Mgr->>WS: Create(project, branch)
|
||||||
|
WS->>WS: git worktree add
|
||||||
|
|
||||||
|
Note over Mgr: 3. Launch runtime
|
||||||
|
Mgr->>Runtime: Create(session)
|
||||||
|
Runtime->>Runtime: Start tmux/conpty
|
||||||
|
|
||||||
|
Note over Mgr: 4. Start agent
|
||||||
|
Mgr->>Agent: GetLaunchCommand()
|
||||||
|
Agent-->>Mgr: launch command
|
||||||
|
Mgr->>Runtime: Execute(agent command)
|
||||||
|
|
||||||
|
Note over Mgr: 5. Mark spawned
|
||||||
|
Mgr->>LCM: MarkSpawned(handle)
|
||||||
|
LCM->>DB: Update activity_state
|
||||||
|
DB->>CDC: trigger change_log
|
||||||
|
CDC->>UI: SSE session.updated
|
||||||
|
|
||||||
|
Mgr-->>Svc: Session(created)
|
||||||
|
Svc-->>HTTP: Session response
|
||||||
|
HTTP-->>UI: 201 Created
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Data Flows
|
||||||
|
|
||||||
|
### Session Spawn Flow
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
Start([User spawns session]) --> Validate[Validate project config]
|
||||||
|
Validate --> CreateRow[Create session row in SQLite]
|
||||||
|
CreateRow --> CreateWS[Create git worktree]
|
||||||
|
CreateWS --> CreateRT[Launch runtime tmux/conpty]
|
||||||
|
CreateRT --> GetCmd[Get agent launch command]
|
||||||
|
GetCmd --> ExecAgent[Execute agent in runtime]
|
||||||
|
ExecAgent --> MarkSpawned[MarkSpawned in LCM]
|
||||||
|
MarkSpawned --> Trigger1[CDC: session.created]
|
||||||
|
Trigger1 --> Trigger2[CDC: session.updated]
|
||||||
|
Trigger2 --> Done([Session running])
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Observation Flow
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
subgraph SCM["SCM Observer Loop"]
|
||||||
|
Poll1[Poll PRs every 30s]
|
||||||
|
Poll1 --> Fetch[Fetch from GitHub API]
|
||||||
|
Fetch --> Diff[Semantic diff vs local]
|
||||||
|
Diff --> Changed{Changed?}
|
||||||
|
Changed -->|Yes| WritePR[Write PR/check/comment]
|
||||||
|
Changed -->|No| Wait1[Wait for tick]
|
||||||
|
WritePR --> NotifyLCM[Notify Lifecycle Manager]
|
||||||
|
NotifyLCM --> Trigger1[CDC event]
|
||||||
|
Trigger1 --> Wait1
|
||||||
|
Wait1 --> Poll1
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Reaper["Runtime Reaper Loop"]
|
||||||
|
Poll2[Poll every 5s]
|
||||||
|
Poll2 --> Probe[Probe each runtime]
|
||||||
|
Probe --> Report[Report fact to LCM]
|
||||||
|
Report --> Trigger2[CDC event]
|
||||||
|
Trigger2 --> Wait2[Wait for tick]
|
||||||
|
Wait2 --> Poll2
|
||||||
|
end
|
||||||
|
|
||||||
|
LCM[Lifecycle Manager] -->|consumes| NotifyLCM
|
||||||
|
LCM -->|consumes| Report
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Feedback Routing Flow
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant SCM as SCM Observer
|
||||||
|
participant LCM as Lifecycle Manager
|
||||||
|
participant Agent as Agent Adapter
|
||||||
|
participant Runtime as Runtime Adapter
|
||||||
|
|
||||||
|
SCM->>SCM: Observe PR comment
|
||||||
|
SCM->>LCM: ApplySCMObservation()
|
||||||
|
LCM->>LCM: Detect actionable feedback
|
||||||
|
LCM->>Agent: SendNudge(feedback)
|
||||||
|
|
||||||
|
SCM->>SCM: Observe CI failure
|
||||||
|
SCM->>LCM: ApplySCMObservation()
|
||||||
|
LCM->>LCM: Detect actionable feedback
|
||||||
|
LCM->>Agent: SendNudge(CI failure)
|
||||||
|
|
||||||
|
SCM->>SCM: Observe merge conflict
|
||||||
|
SCM->>LCM: ApplySCMObservation()
|
||||||
|
LCM->>LCM: Detect actionable feedback
|
||||||
|
LCM->>Agent: SendNudge(merge conflict)
|
||||||
|
|
||||||
|
Note over Agent,Runtime: Agent receives nudges via<br/>runtime messages or hooks
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Persistence and CDC
|
## Persistence and CDC
|
||||||
|
|
||||||
SQLite is the durable store. User-visible table changes are captured by database
|
### SQLite Schema
|
||||||
triggers into `change_log`; the Go store does not manually emit CDC events. A
|
|
||||||
poller tails `change_log` and publishes live events to in-process subscribers.
|
|
||||||
|
|
||||||
## Load-bearing rules
|
```mermaid
|
||||||
|
erDiagram
|
||||||
|
projects ||--o{ sessions : owns
|
||||||
|
sessions ||--o{ pull_requests : owns
|
||||||
|
pull_requests ||--o{ pr_checks : has
|
||||||
|
pull_requests ||--o{ pr_review_threads : has
|
||||||
|
pull_requests ||--o{ pr_comments : has
|
||||||
|
sessions ||--o{ notifications : has
|
||||||
|
change_log }|--|| projects : tracks
|
||||||
|
change_log }|--|| sessions : tracks
|
||||||
|
change_log }|--|| pull_requests : tracks
|
||||||
|
|
||||||
- Do not store display status.
|
projects {
|
||||||
- Keep session status facts small: `activity_state`, `is_terminated`, and PR
|
string id PK
|
||||||
facts are the durable inputs.
|
string name
|
||||||
- Do not treat failed probes as death.
|
string repo
|
||||||
- Do not force-delete registered dirty worktrees.
|
jsonb config
|
||||||
|
}
|
||||||
|
|
||||||
|
sessions {
|
||||||
|
string id PK
|
||||||
|
string project_id FK
|
||||||
|
string harness
|
||||||
|
string activity_state
|
||||||
|
boolean is_terminated
|
||||||
|
jsonb metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
pull_requests {
|
||||||
|
string id PK
|
||||||
|
string session_id FK
|
||||||
|
integer number
|
||||||
|
string state
|
||||||
|
string title
|
||||||
|
boolean draft
|
||||||
|
boolean mergeable
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_checks {
|
||||||
|
string id PK
|
||||||
|
string pr_id FK
|
||||||
|
string name
|
||||||
|
string status
|
||||||
|
string conclusion
|
||||||
|
}
|
||||||
|
|
||||||
|
change_log {
|
||||||
|
bigint seq PK
|
||||||
|
string table_name
|
||||||
|
string row_id
|
||||||
|
string operation
|
||||||
|
jsonb old_data
|
||||||
|
jsonb new_data
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### CDC Pipeline
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
DB[(SQLite)] -->|INSERT/UPDATE/DELETE| Trigger[DB Trigger]
|
||||||
|
Trigger -->|append| ChangeLog[change_log]
|
||||||
|
ChangeLog -->|poll| Poller[CDC Poller]
|
||||||
|
Poller -->|decode| Decoder[Event Decoder]
|
||||||
|
Decoder -->|Event| Broadcaster[Broadcaster]
|
||||||
|
Broadcaster -->|callback| Sub1[Terminal Fanout]
|
||||||
|
Broadcaster -->|callback| Sub2[SSE Writer]
|
||||||
|
Broadcaster -->|callback| Sub3[Cache Invalidation]
|
||||||
|
|
||||||
|
Poller -->|watermark| Watermark[seq tracking]
|
||||||
|
Watermark -->|resume position| Poller
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Status Derivation
|
||||||
|
|
||||||
|
### Display Status Precedence
|
||||||
|
|
||||||
|
The `service.Session` computes display status from durable facts using this precedence (highest to lowest):
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
CheckTerm{is_terminated?}
|
||||||
|
CheckTerm -->|Yes| PRMerged{PR merged?}
|
||||||
|
CheckTerm -->|No| CheckWait{activity_state<br/>== waiting_input?}
|
||||||
|
|
||||||
|
PRMerged -->|Yes| Merged[merged]
|
||||||
|
PRMerged -->|No| Terminated[terminated]
|
||||||
|
|
||||||
|
CheckWait -->|Yes| NeedsInput[needs_input]
|
||||||
|
CheckWait -->|No| CheckPR{Has PR facts?}
|
||||||
|
|
||||||
|
CheckPR -->|Yes| PRPipeline[PR Pipeline Check]
|
||||||
|
CheckPR -->|No| CheckActive{activity_state<br/>== active?}
|
||||||
|
|
||||||
|
PRPipeline --> PRState{PR State}
|
||||||
|
PRState -->|ci failed| CIFailed[ci_failed]
|
||||||
|
PRState -->|draft| Draft[draft]
|
||||||
|
PRState -->|changes requested| Changes[changes_requested]
|
||||||
|
PRState -->|not mergeable| Conflict[merge_conflict]
|
||||||
|
PRState -->|mergeable| Mergeable[mergeable]
|
||||||
|
PRState -->|approved| Approved[approved]
|
||||||
|
PRState -->|review pending| ReviewPending[review_pending]
|
||||||
|
PRState -->|open| PROpen[pr_open]
|
||||||
|
|
||||||
|
CheckActive -->|Yes| Working[working]
|
||||||
|
CheckActive -->|No| CheckSignal{Signal capable<br/>&& no signal?}
|
||||||
|
|
||||||
|
CheckSignal -->|Yes| NoSignal[no_signal]
|
||||||
|
CheckSignal -->|No| Idle[idle]
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### PR Pipeline States
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
PR[Open PR] --> CI{CI Status}
|
||||||
|
CI -->|failing| CIFailed[ci_failed]
|
||||||
|
CI -->|pending| CIPending[ci_pending]
|
||||||
|
CI -->|passing| Review{Reviews}
|
||||||
|
|
||||||
|
Review -->|changes requested| Changes[changes_requested]
|
||||||
|
Review -->|approved| Mergeable{Mergeable?}
|
||||||
|
|
||||||
|
Mergeable -->|conflict| Conflict[merge_conflict]
|
||||||
|
Mergeable -->|yes| Merged[Mergeable]
|
||||||
|
|
||||||
|
PR -.->|draft| Draft[Draft State]
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lifecycle Management
|
||||||
|
|
||||||
|
### Lifecycle Manager Responsibilities
|
||||||
|
|
||||||
|
The `lifecycle.Manager` is the **canonical write path** for all session lifecycle facts:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
subgraph Inputs["Observation Inputs"]
|
||||||
|
RuntimeObs[Runtime Observations]
|
||||||
|
ActivitySignals[Agent Activity Signals]
|
||||||
|
SCMObs[SCM Observations]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph LCM["Lifecycle Manager"]
|
||||||
|
Reducer[Fact Reducer]
|
||||||
|
StateMachine[Activity State Machine]
|
||||||
|
Termination[Termination Logic]
|
||||||
|
Nudge[Agent Nudge Engine]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Outputs["Durable Facts"]
|
||||||
|
ActivityState[activity_state]
|
||||||
|
IsTerminated[is_terminated]
|
||||||
|
PRFacts[PR Facts Table]
|
||||||
|
end
|
||||||
|
|
||||||
|
RuntimeObs --> Reducer
|
||||||
|
ActivitySignals --> Reducer
|
||||||
|
SCMObs --> Reducer
|
||||||
|
|
||||||
|
Reducer --> StateMachine
|
||||||
|
StateMachine --> Termination
|
||||||
|
Termination --> ActivityState
|
||||||
|
Termination --> IsTerminated
|
||||||
|
|
||||||
|
SCMObs --> Nudge
|
||||||
|
Nudge -->|route| Agent[Agent Adapter]
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Session State Machine
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> Spawning: Spawn()
|
||||||
|
Spawning --> Active: MarkSpawned
|
||||||
|
Active --> Idle: activity_state = idle
|
||||||
|
Active --> Working: activity_state = active
|
||||||
|
Active --> Waiting: activity_state = waiting_input
|
||||||
|
Active --> Exited: activity_state = exited
|
||||||
|
Working --> Active: work completes
|
||||||
|
Waiting --> Active: user responds
|
||||||
|
Idle --> Active: agent starts work
|
||||||
|
Exited --> Terminated: process exit
|
||||||
|
Active --> Terminated: Kill()
|
||||||
|
Waiting --> Terminated: Kill()
|
||||||
|
Idle --> Terminated: Kill()
|
||||||
|
Terminated --> [*]
|
||||||
|
|
||||||
|
note right of Active
|
||||||
|
Agent is working
|
||||||
|
Runtime alive
|
||||||
|
end note
|
||||||
|
|
||||||
|
note right of Waiting
|
||||||
|
Agent needs input
|
||||||
|
Waiting for user
|
||||||
|
end note
|
||||||
|
|
||||||
|
note right of Terminated
|
||||||
|
Session over
|
||||||
|
Runtime cleaned up
|
||||||
|
end note
|
||||||
|
```
|
||||||
|
|
||||||
|
### Termination Guardrails
|
||||||
|
|
||||||
|
The lifecycle manager only terminates when **all** conditions are met:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
Check{Can terminate?}
|
||||||
|
Check -->|No| Keep[Keep running]
|
||||||
|
|
||||||
|
Check -->|Yes| AllDead{Runtime AND<br/>process dead?}
|
||||||
|
AllDead -->|No| Keep
|
||||||
|
AllDead -->|Yes| NoRecent{No recent<br/>activity?}
|
||||||
|
NoRecent -->|No| Keep
|
||||||
|
NoRecent -->|Yes| NoPR{No merged PR<br/>ownership?}
|
||||||
|
NoPR -->|No| Keep
|
||||||
|
NoPR -->|Yes| Terminate[Mark terminated]
|
||||||
|
|
||||||
|
Terminate --> Cleanup[Trigger cleanup]
|
||||||
|
Cleanup --> CDC[CDC event]
|
||||||
|
CDC --> UI[Dashboard update]
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key principle:** Failed probes are NOT proof of death. A session is only terminated when the runtime and process are **both** clearly dead and recent activity doesn't contradict that.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Observation Loops
|
||||||
|
|
||||||
|
### SCM Observer
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
Start([Observer Start]) --> Immediate[Immediate Poll]
|
||||||
|
Immediate --> Loop{Tick every 30s}
|
||||||
|
|
||||||
|
Loop --> ListRepos[List active repos]
|
||||||
|
ListRepos --> CheckCreds{Credentials<br/>available?}
|
||||||
|
CheckCreds -->|No| Disabled[Disabled mode]
|
||||||
|
CheckCreds -->|Yes| Fetch[Fetch PRs via ETags]
|
||||||
|
|
||||||
|
Fetch --> ListPRs[List open PRs]
|
||||||
|
ListPRs --> Discover[Discover new PRs]
|
||||||
|
Discover --> FetchDetailed[Fetch detailed PR data]
|
||||||
|
FetchDetailed --> FetchChecks[Fetch CI checks]
|
||||||
|
FetchChecks --> FetchReviews[Fetch review threads]
|
||||||
|
|
||||||
|
FetchReviews --> Write[Write to SQLite]
|
||||||
|
Write --> Notify[Notify Lifecycle]
|
||||||
|
Notify --> Trigger[CDC event]
|
||||||
|
|
||||||
|
Disabled --> Loop
|
||||||
|
Trigger --> Loop
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Runtime Reaper
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
Start([Reaper Start]) --> Loop{Tick every 5s}
|
||||||
|
|
||||||
|
Loop --> List[List non-terminated<br/>sessions]
|
||||||
|
List --> ForEach[For each session]
|
||||||
|
|
||||||
|
ForEach --> GetHandle{Has runtime<br/>handle?}
|
||||||
|
GetHandle -->|No| Skip[Skip session]
|
||||||
|
GetHandle -->|Yes| Probe[Probe runtime]
|
||||||
|
|
||||||
|
Probe --> Result{Probe result}
|
||||||
|
Result -->|Error| ReportFailed[Report ProbeFailed]
|
||||||
|
Result -->|Alive| ReportAlive[Report ProbeAlive]
|
||||||
|
Result -->|Dead| ReportDead[Report ProbeDead]
|
||||||
|
|
||||||
|
ReportFailed --> Apply[ApplyRuntimeObservation]
|
||||||
|
ReportAlive --> Apply
|
||||||
|
ReportDead --> Apply
|
||||||
|
|
||||||
|
Apply --> LCM[Lifecycle Manager]
|
||||||
|
LCM --> Update[Update facts]
|
||||||
|
Update --> CDC[CDC event]
|
||||||
|
|
||||||
|
Skip --> NextSession{More sessions?}
|
||||||
|
CDC --> NextSession
|
||||||
|
NextSession -->|Yes| ForEach
|
||||||
|
NextSession -->|No| Loop
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Observation Integration
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph External["External State"]
|
||||||
|
GitHub[GitHub API]
|
||||||
|
Runtimes[tmux/conpty]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Observers["Observation Layer"]
|
||||||
|
SCM[SCM Observer]
|
||||||
|
Reaper[Runtime Reaper]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Core["Core Processing"]
|
||||||
|
LCM[Lifecycle Manager]
|
||||||
|
PRMgr[PR Manager]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Storage["Persistence"]
|
||||||
|
SQLite[(SQLite)]
|
||||||
|
end
|
||||||
|
|
||||||
|
GitHub --> SCM
|
||||||
|
Runtimes --> Reaper
|
||||||
|
|
||||||
|
SCM --> PRMgr
|
||||||
|
PRMgr --> SQLite
|
||||||
|
PRMgr --> LCM
|
||||||
|
|
||||||
|
Reaper --> LCM
|
||||||
|
LCM --> SQLite
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## HTTP Layer
|
||||||
|
|
||||||
|
### API Structure
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
subgraph HTTPD["HTTP Daemon"]
|
||||||
|
Router[Router + Middleware]
|
||||||
|
|
||||||
|
Router --> API[REST API]
|
||||||
|
Router --> Events[SSE Events]
|
||||||
|
Router --> Terminal[Terminal WebSocket]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Controllers["Controllers"]
|
||||||
|
Sessions[Sessions Controller]
|
||||||
|
Projects[Projects Controller]
|
||||||
|
PRs[PRs Controller]
|
||||||
|
Reviews[Reviews Controller]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Services["Services"]
|
||||||
|
SessionSvc[Session Service]
|
||||||
|
ProjectSvc[Project Service]
|
||||||
|
PRSvc[PR Service]
|
||||||
|
ReviewSvc[Review Service]
|
||||||
|
end
|
||||||
|
|
||||||
|
API --> Sessions
|
||||||
|
API --> Projects
|
||||||
|
API --> PRs
|
||||||
|
API --> Reviews
|
||||||
|
|
||||||
|
Sessions --> SessionSvc
|
||||||
|
Projects --> ProjectSvc
|
||||||
|
PRs --> PRSvc
|
||||||
|
Reviews --> ReviewSvc
|
||||||
|
|
||||||
|
Events -->|subscribe| CDC[CDC Broadcaster]
|
||||||
|
Terminal --> TerminalMux[Terminal Manager]
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Request Flow
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant Client
|
||||||
|
participant Router
|
||||||
|
participant Controller
|
||||||
|
participant Service
|
||||||
|
participant Manager
|
||||||
|
participant Store
|
||||||
|
participant DB
|
||||||
|
|
||||||
|
Client->>Router: POST /api/v1/sessions
|
||||||
|
Router->>Router: Middleware (auth, logging)
|
||||||
|
Router->>Controller: handler(w, r)
|
||||||
|
Controller->>Controller: decode JSON
|
||||||
|
Controller->>Service: Spawn(config)
|
||||||
|
Service->>Manager: Spawn(config)
|
||||||
|
Manager->>Store: Create session
|
||||||
|
Store->>DB: INSERT INTO sessions
|
||||||
|
DB->>Store: session record
|
||||||
|
Store->>Manager: session record
|
||||||
|
Manager->>Manager: Create workspace
|
||||||
|
Manager->>Manager: Launch runtime
|
||||||
|
Manager->>Service: Session response
|
||||||
|
Service->>Controller: enriched session
|
||||||
|
Controller->>Controller: encode JSON
|
||||||
|
Controller->>Client: 201 Created + Session
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Terminal Multiplexing
|
||||||
|
|
||||||
|
### Terminal Architecture
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
subgraph Frontend
|
||||||
|
Browser[Browser Terminal]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph HTTPD
|
||||||
|
WS[WebSocket Handler]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Terminal
|
||||||
|
Mux[Terminal Mux]
|
||||||
|
Sessions[Session States]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Runtime
|
||||||
|
TMux[tmux Runtime]
|
||||||
|
ConPTY[conpty Runtime]
|
||||||
|
end
|
||||||
|
|
||||||
|
Browser -->|WebSocket| WS
|
||||||
|
WS -->|attach| Mux
|
||||||
|
Mux --> Sessions
|
||||||
|
Sessions -->|create| TMux
|
||||||
|
Sessions -->|create| ConPTY
|
||||||
|
|
||||||
|
TMux -->|PTY attach| Mux
|
||||||
|
ConPTY -->|loopback dial| Mux
|
||||||
|
|
||||||
|
Mux -->|frame| WS
|
||||||
|
WS -->|binary| Browser
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Attach Flow
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant Client as Browser
|
||||||
|
participant WS as WebSocket Handler
|
||||||
|
participant Mux as Terminal Mux
|
||||||
|
participant Runtime as tmux/conpty
|
||||||
|
|
||||||
|
Client->>WS: WebSocket upgrade
|
||||||
|
WS->>Mux: Attach(session, rows, cols)
|
||||||
|
Mux->>Runtime: Attach(handle, rows, cols)
|
||||||
|
|
||||||
|
Runtime->>Runtime: Create PTY
|
||||||
|
Runtime->>Runtime: Spawn tmux attach
|
||||||
|
|
||||||
|
loop Data Loop
|
||||||
|
Runtime->>Mux: PTY output
|
||||||
|
Mux->>WS: Binary frame
|
||||||
|
WS->>Client: WebSocket message
|
||||||
|
|
||||||
|
Client->>WS: User input
|
||||||
|
WS->>Mux: Input frame
|
||||||
|
Mux->>Runtime: Write to PTY
|
||||||
|
end
|
||||||
|
|
||||||
|
Client->>WS: Close
|
||||||
|
WS->>Mux: Detach
|
||||||
|
Mux->>Runtime: Close PTY
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Load-Bearing Rules
|
||||||
|
|
||||||
|
These rules are **load-bearing** — changing them breaks fundamental architectural assumptions:
|
||||||
|
|
||||||
|
1. **Never store display status** — Status is derived from durable facts at read time
|
||||||
|
2. **Never treat failed probes as death** — A failed probe is a fact, not a termination signal
|
||||||
|
3. **Never force-delete dirty worktrees** — User data safety over cleanup convenience
|
||||||
|
4. **All app state under ~/.ao** — No OS-default app-data locations
|
||||||
|
5. **Daemon binds to 127.0.0.1 only** — No network exposure, ever
|
||||||
|
6. **CLI is thin** — All logic lives in the daemon, CLI is just an HTTP client
|
||||||
|
7. **CDC is source-truth for events** — DB triggers write to change_log, poller fans out
|
||||||
|
8. **Adapters are leaves** — Adapters never import core packages, only ports and domain
|
||||||
|
9. **Hooks are gitignored** — Every file an adapter writes must be in .gitignore
|
||||||
|
10. **Migrations never change** — Add new migrations, never modify existing ones
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Agent Orchestrator's architecture is designed around:
|
||||||
|
|
||||||
|
- **Separation of concerns** — Observation, persistence, and display are distinct layers
|
||||||
|
- **Port-based design** — Core code depends on interfaces, not implementations
|
||||||
|
- **Durable minimalism** — Store only facts, compute everything else
|
||||||
|
- **Event-driven updates** — CDC broadcasts changes to all subscribers
|
||||||
|
- **Isolation** — Each session in its own worktree with its own runtime
|
||||||
|
- **Safety** — Conservative termination, path validation, gitignored hooks
|
||||||
|
|
||||||
|
This architecture enables parallel AI agents to work safely while maintaining complete visibility and control.
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,90 @@
|
||||||
|
# Telemetry
|
||||||
|
|
||||||
|
Agent Orchestrator includes telemetry for understanding product usage, reliability, and failure modes. Telemetry is implemented as **best-effort structured events** and is controlled by environment variables.
|
||||||
|
|
||||||
|
## What We Collect
|
||||||
|
|
||||||
|
Telemetry events are structured records that capture:
|
||||||
|
|
||||||
|
- **Event Name** — The type of event (e.g., session lifecycle events, daemon operations, errors)
|
||||||
|
- **Source** — The component that emitted the event
|
||||||
|
- **Timestamp** — When the event occurred
|
||||||
|
- **Level** — Severity level (Debug, Info, Warn, Error)
|
||||||
|
- **Context** — Project ID, Session ID, and Request ID when applicable
|
||||||
|
- **Payload** — Event-specific metadata
|
||||||
|
|
||||||
|
**We do not collect:**
|
||||||
|
|
||||||
|
- Code from your repositories
|
||||||
|
- File contents or workspace data
|
||||||
|
- Authentication credentials or API keys
|
||||||
|
- Personal information beyond what is necessary for operational analytics
|
||||||
|
|
||||||
|
## Storage and Transmission
|
||||||
|
|
||||||
|
### Local Storage (Default)
|
||||||
|
|
||||||
|
By default, all telemetry events are stored locally in a SQLite database at:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.ao/data/telemetry.db
|
||||||
|
```
|
||||||
|
|
||||||
|
No data leaves your machine unless you explicitly configure remote telemetry.
|
||||||
|
|
||||||
|
### Remote Telemetry (Opt-In)
|
||||||
|
|
||||||
|
You may optionally configure remote telemetry via PostHog by setting the `POSTHOG_API_KEY` environment variable. When configured:
|
||||||
|
|
||||||
|
- Events are transmitted to PostHog for aggregate analytics
|
||||||
|
- Transmission is best-effort — failures do not affect daemon operation
|
||||||
|
- Events are batched to minimize network overhead
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Telemetry behavior is controlled by these environment variables:
|
||||||
|
|
||||||
|
| Variable | Default | Purpose |
|
||||||
|
| -------------------- | ------------------------- | ------------------------------------------------------ |
|
||||||
|
| `AO_TELEMETRY_LEVEL` | `info` | Minimum event level to emit (debug, info, warn, error) |
|
||||||
|
| `POSTHOG_API_KEY` | unset | PostHog API key for remote telemetry |
|
||||||
|
| `POSTHOG_HOST` | `https://app.posthog.com` | PostHog host endpoint |
|
||||||
|
| `AO_DATA_DIR` | `~/.ao/data` | Directory for local telemetry database |
|
||||||
|
|
||||||
|
## Disabling Telemetry
|
||||||
|
|
||||||
|
To completely disable telemetry:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export AO_TELEMETRY_LEVEL=none
|
||||||
|
```
|
||||||
|
|
||||||
|
This prevents both local storage and any remote transmission of telemetry events.
|
||||||
|
|
||||||
|
## Event Examples
|
||||||
|
|
||||||
|
Typical telemetry events include:
|
||||||
|
|
||||||
|
- Session spawned, terminated, or restored
|
||||||
|
- Daemon started or stopped
|
||||||
|
- Agent harness lifecycle events
|
||||||
|
- HTTP request errors
|
||||||
|
- Runtime failures
|
||||||
|
- SCM observation errors
|
||||||
|
|
||||||
|
These events help us understand:
|
||||||
|
|
||||||
|
- How agents are being used
|
||||||
|
- Where failures occur
|
||||||
|
- How to improve reliability
|
||||||
|
- Which features need attention
|
||||||
|
|
||||||
|
## Privacy Commitment
|
||||||
|
|
||||||
|
- Local telemetry is stored on your machine only
|
||||||
|
- Remote telemetry is opt-in via explicit environment variable configuration
|
||||||
|
- We do not collect code, file contents, or credentials
|
||||||
|
- Events are designed for aggregate product analytics, not individual surveillance
|
||||||
|
- PostHog configuration respects your privacy settings and data retention policies
|
||||||
|
|
||||||
|
For questions or concerns about telemetry, please open an issue on GitHub or join our Discord community.
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 786 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 144 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 491 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 183 KiB |
Loading…
Reference in New Issue