A zero-config, private, local-first dashboard that tracks token usage, latency, and cost across every LLM call your AI agents make β OpenAI, Anthropic, and any other provider.
As developers build complex multi-agent workflows, tracing what prompts were sent, how long each LLM call took, and how many tokens (and dollars) it cost becomes impossible to manage across standard logs.
AgentOpsLocal is a standalone telemetry sink for AI agents. Route your LLM calls through a single ingestion endpoint and get a real-time dashboard with cost analytics, latency metrics, anomaly detection, and full prompt/response traces β grouped by task, session, agent, and environment.
It runs entirely on your machine. No accounts, no cloud, no data leaving your laptop.
Why local-first? LLM telemetry contains your prompts, responses, and proprietary logic. AgentOpsLocal keeps all of it on your infrastructure β a self-hosted alternative to SaaS observability platforms, ideal for local development, prototyping, and privacy-sensitive workloads.
- Key Features
- Screenshots
- Tech Stack
- Quickstart (Docker)
- Local Development
- How It Works
- Integrating Your Agent
- API Reference
- Configuration
- Running Tests
- Roadmap
- Contributing
- License
| Feature | Description |
|---|---|
| π Real-time dashboard | Live cost, token, latency, and call-count KPIs that auto-refresh every 5 seconds. |
| π° Cost analytics | Spend broken down by model, task, and agent, plus a cost-over-time trend chart. |
| π¨ Anomaly detection | Automatically flags calls that cost 2Γ (or 5Γ) more than the average for their task. |
| π§΅ Session traces | Reconstruct a full multi-step agent run as an ordered timeline of LLM calls. |
| π― Environment filtering | Slice all analytics by dev, staging, or prod. |
| π Daily budget guardrail | Optionally reject ingestion once a configurable daily spend limit is exceeded. |
| π¦ One-file JSON export | Export all telemetry for backup, auditing, or fine-tuning datasets. |
| π Provider-agnostic | Works with OpenAI, Anthropic, or any LLM β you send a simple JSON payload. |
| π 100% local & private | FastAPI + SQLite. Zero external dependencies at runtime. Your data never leaves your machine. |
- Backend: FastAPI Β· SQLAlchemy 2.0 Β· Pydantic v2 Β· Uvicorn
- Database: SQLite by default β swappable to PostgreSQL via a single environment variable
- Frontend: React 18 Β· Vite Β· Tailwind CSS Β· Recharts
- Tooling: Docker & Docker Compose Β· pytest Β· GitHub Actions CI
The fastest way to run the full stack. Requires Docker Desktop.
git clone https://github.com/manijose1919/agent-ops-local.git
cd agent-ops-local
docker compose up --buildOn Windows you can instead double-click run.bat, which starts Docker Desktop if needed and brings the stack up.
Once running:
| Service | URL |
|---|---|
| π Dashboard | http://localhost:5173 |
| π Backend API | http://localhost:8000 |
| π Interactive API docs (Swagger) | http://localhost:8000/docs |
To stop: docker compose down.
Prefer running the backend and frontend directly (with hot reload)?
- Python 3.11+
- Node.js 18+
# From the repository root
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
uvicorn backend.main:app --reload --port 8000The API is now live at http://localhost:8000 (docs at /docs). A local SQLite file agent_ops.db is created automatically on first run.
In a second terminal:
npm install
npm run devOpen http://localhost:5173. The dashboard talks to the backend at http://localhost:8000 by default (override with VITE_API_BASE_URL).
ββββββββββββββββββββββββββββ
Your AI Agent β AgentOpsLocal β
βββββββββββββββββ β β
β LLM call β POST β FastAPI βββΊ SQLite β
β (OpenAI / βββββββββΊβ /api/v1/ingest β
β Anthropic) β JSON β β
βββββββββββββββββ β β² β
β β REST (analytics) β
β ββββββ΄βββββββββββββββ β
β β React Dashboard β β
β β (cost, latency, β β
β β traces, alerts) β β
β βββββββββββββββββββββ β
ββββββββββββββββββββββββββββ
- Your agent finishes an LLM call and POSTs a small JSON payload to
/api/v1/ingest. - FastAPI validates it, optionally enforces your daily budget, and stores it in SQLite. Calls are linked into sessions automatically when you supply a
session_id. - The React dashboard polls the analytics endpoints and renders live KPIs, charts, anomalies, and session traces.
agent-ops-local/
βββ backend/ # FastAPI application
β βββ main.py # App entrypoint, CORS, router wiring
β βββ database.py # SQLAlchemy engine/session (SQLite β Postgres swappable)
β βββ models.py # ORM models: AgentSession, APICall
β βββ schemas.py # Pydantic request/response schemas
β βββ routers/
β βββ ingest.py # POST /ingest, GET /calls
β βββ analytics.py # summary, anomalies, export, session traces
βββ src/ # React + Vite dashboard
β βββ App.jsx # Dashboard UI (KPIs, charts, table, traces)
β βββ main.jsx
βββ sdk/ # agentops-local Python SDK (auto-instrumentation)
β βββ agentops_local/ # package: config, context, pricing, transport, instrument/
β βββ tests/ # pytest SDK tests
βββ tests/ # pytest backend tests
βββ docker-compose.yml # Full-stack orchestration
βββ Dockerfile.backend
βββ Dockerfile.frontend
βββ requirements.txt
The agentops-local SDK auto-instruments your OpenAI and Anthropic calls β one init() call, no changes to your existing code:
pip install ./sdk[openai] # or [anthropic]import agentops_local as ao
ao.init(
task="summarize_doc",
prices={ # $ per 1M tokens; unknown models record cost=0
"gpt-4o": {"input": 2.50, "output": 10.00},
"claude-opus-4-8": {"input": 15.00, "output": 75.00},
},
)
# Your existing call β captured automatically:
client.chat.completions.create(model="gpt-4o", messages=[...])
# Group calls into tasks and session traces:
with ao.session("run-abc123"):
with ao.task("plan_step"):
client.messages.create(...)Telemetry is sent from a background thread and never blocks or breaks your app β if the backend is down, it warns once and drops the data. See the SDK README for details.
Prefer to log calls yourself? POST to /api/v1/ingest whenever an LLM request completes.
import requests
def log_llm_call(task_name, model, prompt, response, tokens, cost, latency_ms):
requests.post("http://localhost:8000/api/v1/ingest", json={
"task_name": task_name, # e.g. "summarize_doc"
"model": model, # e.g. "gpt-4o"
"provider": "openai",
"prompt": prompt, # string OR list of message dicts
"response": response,
"prompt_tokens": tokens["prompt"],
"completion_tokens": tokens["completion"],
"total_tokens": tokens["total"],
"cost": cost, # USD
"latency_ms": latency_ms,
"session_id": "run-abc123", # optional β groups calls into a trace
"environment": "dev", # optional β dev | staging | prod
})Note: the endpoint is
/api/v1/ingestand the token field istotal_tokens(not/ingest/tokens_used). Onlytask_name,model,prompt, andresponseare required; everything else is optional.
await fetch("http://localhost:8000/api/v1/ingest", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
task_name: "generate_code",
model: "claude-opus-4-8",
provider: "anthropic",
prompt: messages,
response: completion,
total_tokens: usage.total_tokens,
cost: 0.0021,
latency_ms: 842,
session_id: "run-abc123",
}),
});Base URL: http://localhost:8000
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/ingest |
Ingest a single LLM call. Auto-creates the session if session_id is new. Returns 429 if the daily budget is exceeded. |
GET |
/api/v1/calls |
List recent calls. Query: skip, limit, env. |
GET |
/api/v1/analytics/summary |
Aggregated KPIs + breakdowns by model/task/agent + cost-over-time. Query: env. |
GET |
/api/v1/analytics/anomalies |
Calls costing >2Γ their task average. Query: env. |
GET |
/api/v1/analytics/export |
Download all telemetry as a JSON attachment. Query: env. |
GET |
/api/v1/analytics/sessions/{session_id} |
Ordered timeline of all calls in a session. |
Full interactive documentation (request/response schemas, try-it-out) is auto-generated at http://localhost:8000/docs.
| Field | Type | Required | Description |
|---|---|---|---|
task_name |
string | β | Logical task that triggered the call (e.g. summarize_doc). |
model |
string | β | Model identifier (e.g. gpt-4o). |
prompt |
string / list / dict | β | The prompt or message array sent to the model. |
response |
string | β | The model's text response. |
provider |
string | β | e.g. openai, anthropic. |
session_id |
string | β | Groups calls into a session trace. |
agent_id |
string | β | ID of the autonomous agent making the call. |
environment |
string | β | dev (default), staging, or prod. |
prompt_tokens / completion_tokens / total_tokens |
int | β | Token counts (default 0). |
cost |
float | β | Call cost in USD (default 0.0). |
latency_ms |
float | β | Call latency in milliseconds (default 0.0). |
Copy .env.example to .env and adjust as needed. All variables are optional β the defaults give you a working zero-config local setup.
| Variable | Default | Description |
|---|---|---|
HOST |
0.0.0.0 |
Backend bind host. |
PORT |
8000 |
Backend port. |
DATABASE_URL |
sqlite:///./agent_ops.db |
SQLAlchemy connection string. Set to a postgresql://β¦ URL to use PostgreSQL. |
DAILY_BUDGET |
0 (disabled) |
Max USD spend per day. When > 0, ingestion returns 429 once exceeded, and the dashboard shows a budget progress bar. |
API_SECRET_KEY |
empty (open) | When set, /api/v1/* requires X-API-Key or Authorization: Bearer. Pass the same value to the SDK as api_key= / AGENTOPS_API_KEY and to the dashboard as VITE_API_SECRET_KEY. |
CORS_ORIGINS |
http://localhost:5173 |
Comma-separated browser origins allowed to call the API. |
VITE_API_BASE_URL |
http://localhost:8000 |
Backend URL the frontend calls. |
VITE_API_SECRET_KEY |
empty | Dashboard copy of API_SECRET_KEY (baked in at Vite build time). |
pip install -r requirements.txt
pytest tests/The GitHub Actions workflow (.github/workflows/main.yml) runs the backend test suite and builds the frontend on every push and pull request.
- Official Python SDK β auto-instrument OpenAI/Anthropic clients so telemetry is captured with one
init()call and no code changes. βsdk/ - API-key authentication β optional
API_SECRET_KEYon ingest and analytics; unset keeps the zero-config local default. - Server-side pricing engine β compute cost from token counts and a model price table, so the numbers are authoritative.
- Batch ingestion β a
/ingest/batchendpoint for high-throughput agents. - Latency percentiles β p50 / p95 / p99 alongside averages.
- Error & retry tracking β capture failed calls, error types, and retries.
Have an idea? Open an issue.
Contributions are welcome! Please read CONTRIBUTING.md for local setup, branch, and pull-request guidelines.
Distributed under the MIT License. See LICENSE for details.
