Documentation

Starter template — langgraph-agent

Skip the copy-paste dance. Download a ready-to-run LangGraph agent pre-wired for tracing — 5 files, ≈17 KB. Apache 2.0.

Download ZIP
What's inside
  • template.pyMinimal copy-paste agent with AuditTrailIngestor
  • agent.pyFull 7-tool agent showing rich DAG patterns
  • requirements.txtpip dependencies
  • README.mdAgent-specific quickstart
  • LICENSEApache 2.0

AuditTrail Quickstart Guide

Tip — Five-minute path

If you have Docker already, step 1 alone will get you the dashboard at http://localhost:3000. Everything below step 1 is instrumentation for your own agents.

Prerequisites

  • Docker and Docker Compose (recommended)
  • Python 3.12+ -- for running agents
  • An OpenAI API key -- for the example LangGraph agent (uses gpt-4o-mini)

1. Start AuditTrail

bash
cd AuditTrailCodebase
docker compose up --build
ServiceURLDescription
Dashboardhttp://localhost:3000Next.js 16 frontend
APIhttp://localhost:8000FastAPI backend
Proxy (prod)https://your-domainCaddy reverse proxy (TLS + /api/* routing)

Verify the API is running:

bash
curl http://localhost:8000/api/v1/health
# {"status":"ok","version":"<current release>","db_connected":true,...}

Want to skip this? Click View Demo on auditrail.imaginaerium.in — no install required. The demo user is seeded with a live fleet burst (12 traces across 6 agents in the last 15 min), a gateway-routed Operations Assistant chat, and an open Tier 2 deployment action proposal.


2. Create Your Account

  1. Open http://localhost:3000
  2. Click Register -- create an account with email and password
  3. Log in with your credentials
  4. You'll see an empty dashboard -- that's correct, you have no traces yet

3. Create an API Key

Your agents need an API key to send traces to your account.

  1. Go to Profile (click your avatar in the sidebar)
  2. In the API Keys section, enter a key name (e.g., "My Agent")
  3. Select scope ingest and click the + button
  4. A yellow box appears with your secret key -- copy it immediately!

The secret key starts with sk-at-... and is shown only once. If you lose it, delete the key and create a new one.

  1. Save the key in your agent's environment:
bash
export AUDITTRAIL_API_KEY=sk-at-your-secret-key-here

4. Run Your First Agent

bash
cd examples/langgraph-agent
 
# Install dependencies
pip install -r requirements.txt
 
# Set your keys
export OPENAI_API_KEY=sk-proj-...
export AUDITTRAIL_API_KEY=sk-at-...
 
# Run the template agent
python template.py "Search for the latest AI developments and summarize them"

You'll see:

  [OK] API key configured (sk-at-384327...)
  [OK] Trace registered: abc123...
  [LIVE] Open http://localhost:3000/traces/abc123... to watch live
  ...
  [LIVE] All spans sent incrementally. Trace complete.

5. View Your Trace

Open the trace URL printed by the agent. You'll see:

  • Spans -- Every step the agent took (LLM calls, tool executions)
  • DAG -- Interactive decision-chain graph with hierarchical grouping
  • Timeline -- Waterfall view of sequential and parallel execution
  • Sankey -- Causal attribution diagram (click "Run Ablation" to generate)

The trace shows as Running while the agent executes and transitions to Complete when done.

Try the Full Agent (7 tools, rich DAG)

bash
python agent.py "Research climate change impacts, check current time, look up reports from the database, read the agent_config.json file, calculate crop yield at 8 percent per degree, compare output of 92 tons against target of 100, and summarize findings"

Tried & Tested: Deep Search Agent

examples/deep-search-agent/ is a fully working LangGraph agent that was used during AuditTrail's own development and integration testing. It is not a template — it is a complete, battle-tested agent you can run against a local or hosted AuditTrail instance.

bash
cd examples/deep-search-agent
 
# Install dependencies
pip install -r requirements.txt
 
# Configure (copy and fill in your keys)
cp .env.example .env
# Edit .env: set OPENAI_API_KEY, AUDITTRAIL_API and AUDITTRAIL_API_KEY
 
# Run
python agent.py

What it does: a LangGraph multi-tool agent (web search, calculator, file reader, database lookup, weather, time, summariser) that streams full live traces to AuditTrail as it runs — every LLM call, every tool invocation, every state transition. In the dashboard you get the multi-level DAG, live streaming, per-span cost attribution, causal attribution (run Ablation on the trace detail page), and constitutional evaluation against the default rules.

To point it at a hosted instance, set AUDITTRAIL_API in .env to the instance URL and use an API key minted from that dashboard.


Agent Integration Guide

Authentication

All agents authenticate via API key in the Authorization header:

python
headers = {"Authorization": "Bearer sk-at-your-key-here"}
httpx.post(f"{API}/api/v1/ingest/spans", json={"batch": spans}, headers=headers)

Cost Calculation

AuditTrail calculates costs automatically using a four-layer system (most specific wins):

PrioritySourceHowBadge Color
1Agent-reportedAgent sends cost field in spanGreen "Agent"
2Operator overridesrules/pricing.yaml — substring match, longest key winsBlue "Estimated"
3Community catalog~3k known models priced automatically (bundled snapshot of LiteLLM's price index, auto-refreshed daily)Blue "Estimated"
4Default rateModel in neither table, uses fallbackYellow "Default Rate"

You don't need to calculate cost in your agent code. Just send model and tokens_in/tokens_out — known models (GPT, Claude, Gemini, DeepSeek, …) price automatically from the catalog, including dated variants like gpt-4o-mini-2024-07-18. Each span shows a badge indicating where the cost came from.

To override: send cost=0.05 in your span and it will be used as-is (source: "agent").

To set your own rates (negotiated pricing, zero-cost self-hosted models): edit rules/pricing.yaml — rates are per 1M tokens in USD and beat the catalog.

The catalog refreshes from upstream every 24h while AUDITTRAIL_PRICING_AUTO_REFRESH is enabled (default). Air-gapped installs simply run on the bundled snapshot — a failed refresh never degrades pricing.

To view the current configuration: GET /api/v1/settings/pricing (operator overrides, default rate, and catalog size/freshness).

Traces are automatically assigned to the user who owns the API key. Each user only sees their own traces.

Option 1: Copy the Template (Fastest)

bash
cp examples/langgraph-agent/template.py my_agent.py
# Edit: replace tools, update AGENT_NAME, set AUDITTRAIL_API_KEY
python my_agent.py "Your prompt"

The template includes the AuditTrailIngestor class with authentication, live tracing, and correct formats built in.

If you already have the Python SDK installed (pip install audittrail), the same templates are available from the CLI — no browser needed:

bash
audittrail list                 # print the template catalog (id · title · description)
audittrail scaffold quickstart  # materialise a runnable copy into ./<name>/
# then: cd into it, pip install -r requirements.txt, cp .env.example .env, python agent.py "your prompt"

scaffold takes --name, --dir and --force; it prints the exact next-steps recipe when it finishes. These are siblings of the documented audittrail daemon (Local runner) and audittrail secrets (Agent secrets) subcommands.

Option 2: HTTP Ingest API (Any Framework)

Send spans directly via HTTP. Works with any language or framework.

Register a Trace

python
import httpx
from uuid import uuid4
 
API = "http://localhost:8000"
headers = {"Authorization": f"Bearer {os.environ['AUDITTRAIL_API_KEY']}"}
trace_id = str(uuid4())
 
httpx.post(f"{API}/api/v1/ingest/traces", json={
    "trace": {
        "trace_id": trace_id,
        "agent_name": "my-agent",
        "environment": "development",
        "metadata": {"user_prompt": "..."},
    }
}, headers=headers)

Send Spans

python
spans = [{
    "span_id": str(uuid4()),
    "trace_id": trace_id,
    "parent_span_id": None,
    "name": "my_llm_call",
    "span_type": "llm",          # llm | tool | agent | chain | retriever | custom
    "start_time": datetime.now(UTC).isoformat(),
    "end_time": (datetime.now(UTC) + timedelta(milliseconds=500)).isoformat(),
    "status": "ok",              # ok | error | running
    "input": {"prompt": "..."},
    "output": {"response": "..."},
    "model": "gpt-4o-mini",
    "tokens_in": 100,
    "tokens_out": 50,
    "cost": 0.0001,
    "tool_calls": None,
    "attributes": {},
}]
 
resp = httpx.post(f"{API}/api/v1/ingest/spans", json={"batch": spans}, headers=headers)

Live Tracing Pattern

For real-time dashboard updates, send spans incrementally:

python
# When a step STARTS — send with status="running", no end_time:
httpx.post(f"{API}/api/v1/ingest/spans", json={"batch": [{
    "span_id": span_id,
    "trace_id": trace_id,
    "name": "my_tool",
    "span_type": "tool",
    "start_time": datetime.now(UTC).isoformat(),
    "end_time": None,
    "status": "running",
    ...
}]}, headers=headers)
 
# When the step COMPLETES — send same span_id with status="ok":
httpx.post(f"{API}/api/v1/ingest/spans", json={"batch": [{
    "span_id": span_id,      # same span_id = upsert
    "trace_id": trace_id,
    "name": "my_tool",
    "span_type": "tool",
    "start_time": start.isoformat(),
    "end_time": datetime.now(UTC).isoformat(),
    "status": "ok",
    "output": {"result": "..."},
    ...
}]}, headers=headers)

The API upserts on span_id. WebSocket broadcasts notify the dashboard to re-render live.

Tool Calls Format

python
"tool_calls": [
    {
        "tool_name": "web_search",
        "arguments": {"query": "AI safety 2026"},
        "result": {"output": "Found 3 papers..."},  # MUST be dict or null
        "selected_from": ["web_search", "calculator"],
    }
]

The result field must be a dict (e.g., {"output": "..."}) or null. Passing a plain string causes a 422 error.

Reading API Responses

All GET endpoints wrap responses in {"data": ...}:

python
resp = httpx.get(f"{API}/api/v1/traces/{trace_id}", headers=headers)
trace = resp.json()["data"]   # NOT resp.json()

Option 3: LangChain Callback Handler

For LangGraph/LangChain agents, use the built-in callback handler:

bash
cd apps/api && pip install -e ".[agent]"
python
from audittrail.callback_handler import AuditTrailCallbackHandler
from audittrail.traceable import init_tracer, start_trace, shutdown_tracer
 
await init_tracer()
 
async with start_trace("my-agent", "development") as trace_id:
    handler = AuditTrailCallbackHandler(trace_id=trace_id)
    result = await graph.ainvoke(
        {"messages": [HumanMessage(content="...")]},
        config={"callbacks": [handler]},
    )
 
await shutdown_tracer()

Common Pitfalls

IssueCauseFix
422 on span ingestiontool_calls[].result is a stringUse {"output": "..."} not "..."
Empty trace dataReading resp.json()Use resp.json()["data"]
Traces not showingNo API key or wrong keyCheck AUDITTRAIL_API_KEY env var
Flat DAGAll spans same parentCreate intermediate chain/agent spans
Trace stuck on "Running"Root span not completedSend final send_complete() for root
401 on all requestsSession expiredRe-login or use API key
Cost shows $0.00No model field in spanSend model="gpt-4o-mini" with tokens
Cost shows "Default Rate"Model in neither the catalog nor pricing.yamlAdd your model to rules/pricing.yaml (or check the id for typos — catalog matching is exact)

Demo Mode

Click View Demo on the landing page to explore AuditTrail with sample data (no account needed).


Manual Development Setup

For development without Docker:

Backend

bash
cd apps/api
cp ../../.env.example ../../.env    # Edit: set AUDITTRAIL_SECRET_KEY
pip install -e ".[dev]"
uvicorn audittrail.main:app --reload --port 8000

Frontend

bash
cd apps/web
npm install
npm run dev

Environment Variables

VariableDefaultDescription
AUDITTRAIL_SECRET_KEYdev-secret-...JWT signing secret. Change in production.
AUDITTRAIL_DEBUGfalseVerbose logging
AUDITTRAIL_RULES_DIR./rulesConstitutional rule YAML directory
AUDITTRAIL_CORS_ORIGINS["http://localhost:3000"]Allowed CORS origins
AUDITTRAIL_DATABASE_URLsqlite+aiosqlite:///./data/audittrail.dbDatabase connection for the running app (all app settings use the AUDITTRAIL_ prefix)
OPENAI_API_KEY(empty)For agents and ablation
API_INTERNAL_URLhttp://localhost:8000/apiBuild-time Docker ARG — the Next.js /api/* rewrite destination is baked at next build (compose passes http://api:8000/api via build.args); changing it requires a rebuild, not a restart

Two DB variables, two consumers: the running app reads only the prefixed AUDITTRAIL_DATABASE_URL; the unprefixed DATABASE_URL is read only by the Alembic migration runner (alembic/env.py). Setting the unprefixed one has no effect on the live API process.

The frontend uses a relative /api URL in the browser and derives the WebSocket URL from window.location at runtime, so it works on any host without baking NEXT_PUBLIC_API_URL / NEXT_PUBLIC_WS_URL into the bundle.


New in V2.x — Live Ops Surfaces

Once traces are flowing, explore the three operations surfaces shipped between V2.2 and V2.5:

  • /fleet (V2.2) — per-agent summary with error rate, p95 latency, violation rate, and one-click jump to the most recent trace. Auto-refreshes every 15s.
  • /assistant (V2.3) — BYOK chatbot grounded on your fleet. Add your OpenAI / Anthropic API key at Settings → AI Assistant. Keys are encrypted with Fernet (HKDF-derived from your AUDITTRAIL_SECRET_KEY), scoped to your account, and never returned in API responses.
  • Per-node actions (V2.2) — right-click any DAG node to propose a 3-tier deployment action (Tier 1 autonomous-safe alerts, Tier 2 supervised throttle/swap-model, Tier 3 typed-confirm kill-run). Every proposal lands at /deployments with a full audit row.

For deeper docs on compliance + gateway + SDKs, see the respective sidebar entries.


Project Structure

AuditTrailCodebase/
  apps/
    api/                  # FastAPI backend (Python 3.12)
    web/                  # Next.js frontend (TypeScript)
  rules/                  # Constitutional rule YAML files
  examples/
    langgraph-agent/      # Real LangGraph agent + template
      agent.py            # Full 7-tool agent with live tracing
      template.py         # Minimal copy-paste template
      requirements.txt
    deep-search-agent/    # Tried & tested multi-tool LangGraph agent
      agent.py            # Complete integration-test agent (~280 LOC)
      requirements.txt
      .env.example
    demo_happy_path.py    # Mock demo scenarios (no API key needed)
    demo_constitutional.py
    demo_debugging.py
  docs/                   # Documentation
  docker-compose.yml      # Production compose