Quickstart: Observe Your Agents
Add observability to any Python AI agent in under 5 minutes. There are three levels of instrumentation -- most agents only need the first one:
- Auto-instrument -- 2 lines of code, zero changes to your agent.
- Decorators -- when you want more structure, or something auto-instrumentation can't see.
WaxellContext-- explicit lifecycle control when decorators don't fit your code shape.
Before You Start: Two Shortcuts
Claude Skills -- don't instrument by hand at all. Install the Waxell skills and your coding agent instruments and governs your agents for you. If you use a coding agent, start here.
Working examples -- complete, runnable agents for every provider, framework, and pattern: instrumentation, decorators, policies, multi-agent, RAG, streaming, per-end-user attribution. Clone one that matches your stack instead of starting from scratch.
Two fast paths to your first run
Pick the one closest to what you have today. All three end with a fully-instrumented agent emitting runs to your tenant — they just start from different places.
| If you... | Use | Time |
|---|---|---|
| Want a working agent to copy and adapt | Agent Examples Repo — 10 conversational REPLs, each demonstrates one Waxell capability (decorator, tools, RAG, end-user attribution, policies, multi-agent, streaming, …) | ~3 min |
| Already have a Python agent and want to add Waxell to it | The instrument-with-waxell-observe Claude Code skill — open your agent in Claude Code, invoke the skill, it installs wax + the SDK, wires the decorator, and verifies one run lands | ~5 min |
| Want to understand the pattern by hand first | Skip to Prerequisites below — the manual walkthrough covers the same flow Path A and Path B automate | ~10 min |
Path A — Clone a working example
The waxell-ai/waxell-agent-examples repo ships 10 self-contained conversational agents covering every Waxell capability. Each example is one folder with agent.py, setup.sh, README.md, and a requirements.txt — no cross-dependencies.
git clone https://github.com/waxell-ai/waxell-agent-examples.git
cd waxell-agent-examples
# Seed .env from your local wax profile (or copy .env.example and fill in by hand)
./scripts/seed-env-from-wax.sh
# Pick an example, install its deps, run it
./scripts/setup-example.sh 01-hello-waxell
source examples/01-hello-waxell/.venv/bin/activate
python examples/01-hello-waxell/agent.py
After a few REPL turns, wax runs list --limit 5 shows the runs in your tenant. The numbered index in the examples README tells you which example demonstrates which capability — copy whichever is closest to what you're building, rename the agent, and start changing the system prompt.
Path B — Instrument your existing agent
If you have a Python agent you already use, the instrument-with-waxell-observe Claude Code skill retrofits it without you copy-pasting from anywhere. Open your agent in Claude Code and invoke:
/instrument-with-waxell-observe
The skill walks the file, then:
- Checks
waxCLI is installed; installs and configures it if not. - Adds the two-line decorator pattern (
waxell.init()at module top +@waxell.observe(...)on your entry function) at the right place in your file. - Installs
waxell-observeand pins a known-working version. - Runs your agent once to verify a run lands in your tenant.
- Walks you through one starter governance policy (PII block, cost cap, etc.) if you want it.
Your existing agent runs unchanged afterward — it just also emits full telemetry. The skill source + README is in waxell-ai/claude-skills.
Path C — Manual walkthrough
If you'd rather understand the pattern by hand, the rest of this page walks through the exact same flow Path A and Path B automate. Continue with Prerequisites below.
Prerequisites
- Python 3.10+
- A Waxell API key (get one from your Waxell control plane dashboard)
Install the Observe SDK, plus the waxell
package for the wax CLI — used below to confirm your runs landed:
pip install waxell-observe # the instrumentation SDK
pip install waxell # the wax CLI (verify runs, manage your tenant)
Verify your install
wax --version # CLI is installed and on your PATH
python -c "import waxell_observe" # SDK imports cleanly (no output = success)
Once your API key is set (via the env vars shown below, or wax login),
wax whoami confirms the credentials resolve and wax doctor runs a full
health check. If wax isn't found or the import errors, see the
CLI install troubleshooting
(command not found, PATH, PEP 668).
Level 1: Auto-Instrument (2 lines)
Call init() before importing any LLM SDK. This auto-instruments 200+ libraries (OpenAI, Anthropic, Groq, LiteLLM, Cohere, Mistral, Gemini, LangChain, LlamaIndex, vector DBs, and more) with zero changes to your agent code.
import waxell_observe as waxell
waxell.init(api_key="wax_sk_...", api_url="https://acme.waxell.dev")
# Import LLM SDKs AFTER init()
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello!"}]
)
# Automatically traced: model, tokens, cost, latency
That's it. Every LLM call in your process is now tracked -- model, tokens, cost, latency, prompt/response previews -- and visible in the Waxell dashboard.
You can also configure via environment variables:
export WAXELL_API_URL="https://acme.waxell.dev"
export WAXELL_API_KEY="wax_sk_..."
Then just call waxell.init() without arguments.
See Auto-Instrumentation for the full library list and configuration options.
Level 2: Decorators (more detail, or things auto-instrumentation missed)
Auto-instrumentation sees your LLM and framework calls. It doesn't know which function is your agent, what your tools do, or why your agent made a decision. When you need that structure, add decorators.
Start with @observe on your agent's entrypoint -- it creates a named, tracked run for each call with input/output capture and policy enforcement:
import waxell_observe as waxell
waxell.init()
from openai import OpenAI
client = OpenAI()
@waxell.observe(agent_name="support-bot")
async def handle_ticket(query: str) -> str:
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": query}],
)
return response.choices[0].message.content
Then decorate the internal functions you care about. Each decorated call becomes a structured span in the trace:
@waxell.tool(tool_type="vector_db") # tool calls: name, inputs, output, duration
def search_knowledge_base(query: str) -> list[dict]: ...
@waxell.retrieval(source="pinecone") # RAG: query, documents, scores
async def retrieve_docs(query: str) -> list[dict]: ...
@waxell.decision(name="route_query", options=["faq", "technical", "billing"])
async def classify_query(query: str) -> dict: ... # routing: chosen option, reasoning
There are also decorators for reasoning steps (@reasoning_dec), pipeline steps (@step_dec), and retry logic (@retry_dec), plus inline one-liners -- waxell.score(), waxell.tag(), waxell.metadata(), waxell.step() -- for enrichment without wrapping anything. Session and user attribution go straight on the decorator:
@waxell.observe(agent_name="chat-agent", session_id="session-abc123", user_id="user-456")
async def handle_message(message: str) -> str: ...
Behavior decorators are no-ops outside an @observe or WaxellContext scope -- your functions work normally with zero overhead.
See Decorator Pattern for the full @observe reference and Behavior Tracking for every decorator and inline function.
Level 3: WaxellContext (full control)
If decorators don't fit -- you can't wrap the entrypoint, you're instrumenting someone else's framework loop, or you need explicit control over when a run starts and ends -- use the context manager:
from waxell_observe import WaxellContext
async with WaxellContext(
agent_name="chat-agent",
session_id="session-abc123", # groups related runs
user_id="user-456", # per-user cost attribution
) as ctx:
response = await call_llm(prompt)
ctx.set_result({"output": response})
Everything that works inside @observe -- auto-instrumented LLM calls, behavior decorators, inline enrichment -- works identically inside a WaxellContext block.
See Context Manager for the full reference.
What You Get in the Dashboard
Every run appears in the Waxell dashboard with:
- Agent name, workflow, and execution status
- Captured inputs and outputs
- LLM calls with model, tokens, cost, latency, prompt/response previews
- Behavior spans -- tool calls, retrievals, decisions, reasoning steps
- Scores, tags, and metadata
- Session timeline grouping related runs, with per-user cost attribution
Next Steps
- Auto-Instrumentation -- full list of 200+ auto-instrumented libraries
- Decorator Pattern -- full
@observereference with all parameters - Behavior Tracking -- every behavior decorator and inline enrichment function
- Context Manager -- full
WaxellContextreference - Cost Management -- track and control LLM spending
- Policy & Governance -- pre-execution and mid-execution policy checks
- FAQ and Common Mistakes