Drop-in observability for AI agents. Just swap the base_url.
Quick Start Β· How it works Β· Connect an agent Β· Self-hosting Β· Contributing
AgentOrbit sits between your AI agent and the LLM provider as a transparent proxy. It streams the provider response back unchanged, and in parallel records every request as a span β grouping spans into sessions, estimating cost, generating narratives, surfacing failures, and serving a real-time dashboard.
- Zero code changes β point your SDK at AgentOrbit and keep shipping.
- Unchanged responses β SSE chunks are passed through without buffering.
- Fail-open β if the observability layer is down, your agent keeps working.
- Self-host first β three containers, no Redis, no Kafka, no external queue.
| π Transparent proxy | OpenAI- and Anthropic-compatible endpoints, < 50 ms overhead |
| π Real-time dashboard | Live sessions, spans, tokens, cost, latency β over WebSocket |
| π§ LLM-powered narratives | Auto-generated summaries of what each agent session did |
| π¨ Failure clusters & alerts | Group related errors, notify on patterns |
| ποΈ Secure by default | API keys stored as HMAC digests, provider keys AES-256-GCM encrypted |
| π’ Multi-tenant | Organization-scoped, with invitations and roles |
| π€ CSV export | Session- and span-level exports with filters applied |
| π³ One-command deploy | docker compose up -d ships the whole stack |
Requires Docker 24+ and Docker Compose v2.
git clone https://github.com/agentorbit-tech/agentorbit.git
cd agentorbit
cp .env.example .env
# Generate secure secrets
sed -i "s/changeme_jwt_secret_min_32_chars_long/$(openssl rand -hex 32)/" .env
sed -i "s/changeme_hmac_secret_min_32_chars_long/$(openssl rand -hex 32)/" .env
sed -i "s/changeme_generate_64_hex_chars_openssl_rand_hex_32_output_here/$(openssl rand -hex 32)/" .env
sed -i "s/changeme_internal_token_min_32_chars/$(openssl rand -hex 32)/" .env
sed -i "s/changeme_db_password/$(openssl rand -hex 16)/" .env
docker compose up -dThen open:
| Service | URL |
|---|---|
| π Dashboard | http://localhost:8081 |
| π Proxy endpoint | http://localhost:8080 |
Register the first user on the dashboard β in self-host mode they are auto-verified.
| Service | Role |
|---|---|
| Proxy | Stateless. Forwards requests to the upstream LLM, streams SSE without buffering, emits span data to Processing async. Fail-open. |
| Processing | REST API + WebSocket + async workers (narratives, classification, alerts). Runs migrations on startup. Embeds the frontend SPA. |
| Frontend | React 19 SPA, dark theme, compiled into the Processing binary via embed.FS. |
| PostgreSQL | Single source of truth. No Redis, no external queue. |
Internal API between Proxy β Processing is secured by a shared X-Internal-Token header.
Any OpenAI- or Anthropic-compatible client works β just swap base_url and use your AgentOrbit API key (ao-...).
from openai import OpenAI
client = OpenAI(
api_key="ao-...", # Your AgentOrbit API key
base_url="http://localhost:8080/v1",
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello"}],
)import anthropic
client = anthropic.Anthropic(
api_key="ao-...",
base_url="http://localhost:8080",
)
message = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)| Endpoint | Provider |
|---|---|
POST /v1/chat/completions |
OpenAI-compatible |
POST /v1/messages |
Anthropic-compatible |
Add the X-AgentOrbit-Session header with any ID you control, and AgentOrbit will bundle those spans into one session. Without the header, spans are auto-grouped by API key + idle timeout.
Configuration is environment-based. See .env.example for the full list.
| Variable | Purpose |
|---|---|
POSTGRES_PASSWORD |
Database password |
DATABASE_URL |
PostgreSQL connection string |
JWT_SECRET |
HS256 signing key (min 32 chars) |
HMAC_SECRET |
API-key hashing secret (min 32 chars) |
ENCRYPTION_KEY |
AES-256-GCM key for provider keys (64 hex chars) |
INTERNAL_TOKEN |
Proxy β Processing shared secret (min 32 chars) |
| Variable | Default | Purpose |
|---|---|---|
PROCESSING_PORT |
8081 |
Processing service port |
PROXY_PORT |
8080 |
Proxy service port |
JWT_TTL_DAYS |
30 |
JWT token expiration |
PROVIDER_TIMEOUT_SECONDS |
120 |
Upstream LLM timeout |
ALLOWED_ORIGINS |
β | CORS origins (comma-separated) |
DATA_RETENTION_DAYS |
0 |
Auto-delete spans older than N days (0 = keep forever) |
PROCESSING_LLM_BASE_URL |
β | LLM endpoint for narratives/clustering |
PROCESSING_LLM_API_KEY |
β | LLM API key for narratives/clustering |
PROCESSING_LLM_MODEL |
β | LLM model for narratives/clustering |
SMTP_HOST, SMTP_PORT, β¦ |
β | Email delivery (optional) |
Without PROCESSING_LLM_*, narratives fall back to concatenated inputs and clustering is deterministic.
agentorbit/
βββ proxy/ # Stateless proxy service (Go, chi)
βββ processing/ # Stateful API + workers (Go, chi, sqlc, golang-migrate)
βββ web/ # SPA dashboard (Vite, React 19, TS, Tailwind v4)
βββ docs/ # Architecture and deployment guides
βββ scripts/ # Smoke tests, load tests, security audits
βββ docker-compose.yml
- Go 1.26+
- Node.js 22+
- PostgreSQL 17
# 1. Start PostgreSQL (or just: docker compose up -d postgres)
# 2. Processing service
cd processing
DATABASE_URL="postgres://..." go run ./cmd/processing
# 3. Proxy service
cd proxy
PROCESSING_URL="http://localhost:8081" go run ./cmd/proxy
# 4. Frontend dev server
cd web
npm install
npm run dev| Script | What it does |
|---|---|
scripts/smoke-test.sh |
End-to-end: register β login β create org β ingest span β verify |
scripts/test-isolation.sh |
22-check organization isolation audit |
scripts/test-load.sh |
Load test with goroutine-bounds checking |
scripts/audit-logs.sh |
Scan logs for leaked secrets |
scripts/reset.sh |
Destroy all data and rebuild from scratch |
| Layer | Technology |
|---|---|
| Proxy | Go 1.26, go-chi/chi v5 |
| Processing | Go 1.26, chi, sqlc, golang-migrate, pgx/v5, coder/websocket |
| Frontend | Vite 6, React 19, TypeScript 5, Tailwind v4, TanStack Query v5, Zustand, Recharts, shadcn/ui |
| Database | PostgreSQL 17 |
| Auth | JWT (HS256) + API keys (HMAC-SHA256) |
- API keys stored as HMAC-SHA256 digests β never in plaintext.
- Provider API keys encrypted at rest with AES-256-GCM.
- All resources are organization-scoped. No cross-org access.
- Internal API secured by shared secret and may be firewalled by IP.
- API keys, passwords, full LLM I/O, and JWT secrets are never logged.
Report vulnerabilities per docs/SECURITY.md.
Full guide: docs/deployment-guide.md.
Covers:
- System requirements (from 1 CPU / 1 GB RAM for small workloads)
- Reverse proxy (nginx / Caddy) setup with HTTPS
- Backup & restore (
pg_dump/pg_restore) - Data retention policy
- Upgrade procedure
Prebuilt images are published to GHCR on every tagged release:
ghcr.io/agentorbit-tech/agentorbit-proxy:latestghcr.io/agentorbit-tech/agentorbit-processing:latest
Contributions are welcome β see docs/CONTRIBUTING.md and the code of conduct.
MIT Β© 2026 Andrey Dolgikh

