Examples
Runnable agents in examples/,
in Go and Python. Each one sends a trace to a local Conduit and prints a link
to it in the UI. CI runs every example on every push, so they stay working.
Run one in two commands
make quickstart # once: Conduit on localhost, needs only Docker
cd examples/go && go run ./tool-agent # or: python examples/python/tool_agent.py
The examples find the certificates make quickstart generated and send as
agent my-agent. To point them somewhere else, set CONDUIT_GATEWAY_ADDR,
CONDUIT_CERT_DIR (a directory with ca.crt and <agent>.crt/.key), and
CONDUIT_AGENT.
For Python, install the SDK first: pip install conduit-observability, or
pip install "conduit-observability[anthropic,openai]" to include the Claude
and OpenAI SDKs. To try SDK changes from a checkout, use pip install -e sdk/python.
The examples
| Example | Go (examples/go) |
Python (examples/python) |
Needs |
|---|---|---|---|
| Hello trace. The smallest useful trace: a run with one LLM call. Start here. | go run ./hello-trace |
hello_trace.py |
nothing |
| Tool-calling agent. A model/tool loop with a simulated model. | go run ./tool-agent |
tool_agent.py |
nothing |
Async agent. Concurrent tool calls with asyncio.gather; spans still nest correctly. |
async_agent.py |
nothing | |
| Claude agent. The same loop with the official Anthropic SDK and real token usage. | go run ./claude-agent |
claude_agent.py |
ANTHROPIC_API_KEY |
| OpenAI agent. The same loop with the official OpenAI SDK (Chat Completions). | go run ./openai-agent |
openai_agent.py |
OPENAI_API_KEY |
The Claude examples default to claude-sonnet-5 (override with
ANTHROPIC_MODEL). The OpenAI examples default to gpt-5-mini (override with
OPENAI_MODEL). Without a key, they say so and exit.
What a tool-calling trace looks like
Every tool-calling example produces the same span tree. It’s a good shape to copy into your own agent:
agent.run one per task; attributes: question, example
├── llm.call one per model call: model, prompt, completion, tokens, cost
├── tool.get_weather one per tool call: tool.input; error status if the tool failed
├── tool.get_weather
└── llm.call the final answer
- Tools run outside the
llm.callspan. Eachllm.callspan ends before its tools run, so its duration is the model’s latency alone. - Tool spans are children of the run, not of the model call. On the waterfall, concurrent tool calls then show up side by side (see the async example).
- Record the provider’s real usage. Take the token counts and model name
from the API response (
usage.input_tokensfor Anthropic,usage.prompt_tokensfor OpenAI).EstimateCostUSD/estimate_cost_usdturns them into an approximate cost for models it knows.
How CI checks them without API keys
scripts/examples-check.sh runs every example against a running quickstart
and confirms each trace appears in the UI with the expected spans. The
Claude and OpenAI examples run against scripts/fake-llm-server.py, a
stdlib fake of the Messages and Chat Completions APIs. Both official SDKs
honor ANTHROPIC_BASE_URL and OPENAI_BASE_URL, so the examples’ real
request building and response parsing are exercised. The fake rejects a
second turn that lacks correct tool results.