install
source · Clone the upstream repo
git clone https://github.com/plurigrid/asi
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/plurigrid/asi "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/toad-telemetry" ~/.claude/skills/plurigrid-asi-toad-telemetry && rm -rf "$T"
manifest:
skills/toad-telemetry/SKILL.mdsource content
Toad Telemetry Skill
OpenTelemetry instrumentation for Batrachian Toad AI agent terminal.
Overview
Provides deep observability into Toad agent sessions:
- Per-tool spans: Every tool call (Bash, Read, Write, etc.) gets its own span
- Turn tracking: Prompt → response cycles with timing
- Session lifecycle: Start/stop with agent metadata
- Error tracking: Exceptions and error states captured
Installation
# Install Toad uv tool install batrachian-toad --python 3.14 # Install OTEL SDK in Toad's environment uv pip install opentelemetry-sdk opentelemetry-exporter-otlp \ --python ~/.local/share/uv/tools/batrachian-toad/bin/python3 # Install toad_telemetry library mkdir -p ~/.local/lib/toad_telemetry cp instrumentation.py ~/.local/lib/toad_telemetry/ cp __init__.py ~/.local/lib/toad_telemetry/ # Install wrapper script cp toadia ~/.local/bin/ chmod +x ~/.local/bin/toadia
Usage
Via Wrapper Script (Recommended)
# Run toad with telemetry enabled toadia -a claude . # Run ACP agent with telemetry toadia acp "my-command" . # Disable telemetry TOAD_TELEMETRY_ENABLED=0 toadia -a claude .
Programmatic
from toad_telemetry import instrument_toad, ToadTelemetryConfig config = ToadTelemetryConfig( service_name="my-toad-session", endpoint="http://localhost:4317", agent_name="claude", project_dir="/path/to/project", ) instrument_toad(config) # Now run toad normally from toad.cli import main main()
Environment Variables
| Variable | Default | Description |
|---|---|---|
| | OTLP collector endpoint |
| | Enable/disable telemetry |
| | Print spans to console |
| | Service name in traces |
Quick Start with Jaeger
# Start Jaeger docker run -d --name jaeger \ -p 16686:16686 \ -p 4317:4317 \ jaegertracing/all-in-one:latest # Run toadia toadia -a claude . # View traces at http://localhost:16686
Span Attributes
Tool Spans (tool.<name>
)
tool.<name>
- Unique tool call IDtoad.tool.id
- Tool name (Bash, Read, Write, etc.)toad.tool.name
- Tool categorytoad.tool.kind
- Completion statustoad.tool.status
- Execution timetoad.tool.duration_ms
- Error message (if any)toad.tool.error
- Session identifiertoad.session.id
- Agent nametoad.agent
Turn Spans (agent.turn
)
agent.turn
- Input prompt character counttoad.prompt.length
- Why the turn endedtoad.turn.stop_reason
- Total turn timetoad.turn.duration_ms
- Agent nametoad.agent
Architecture
┌─────────────────────────────────────────────────────────────┐ │ Toad TUI │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ Prompt │ │ Conversation│ │ Agent ACP │ │ │ └─────────────┘ └─────────────┘ └──────────┬──────────┘ │ │ │ │ │ ┌────────────────────────────────────────────┴───────────┐ │ │ │ toad_telemetry (monkey-patch) │ │ │ │ ┌───────────────────┐ ┌──────────────────────────┐ │ │ │ │ │ rpc_session_update│ │ send_prompt │ │ │ │ │ │ (tool spans) │ │ (turn spans) │ │ │ │ │ └─────────┬─────────┘ └────────────┬─────────────┘ │ │ │ └────────────┼─────────────────────────┼─────────────────┘ │ └───────────────┼─────────────────────────┼───────────────────┘ │ │ ▼ ▼ ┌──────────────────────────────────┐ │ OTEL Collector │ │ (Jaeger / Tempo / Honeycomb) │ └──────────────────────────────────┘
How It Works
The instrumentation uses deferred monkey-patching via Python import hooks to avoid circular imports:
installs an import hook that waits forinstrument_toad()
to loadtoad.app- Once Toad is fully initialized, it patches
andAgent.rpc_session_updateAgent.send_prompt
receives all ACP protocol events (tool_call, tool_call_update, etc.)rpc_session_update- Each tool call gets a span that tracks its lifecycle from start to completion
wraps each agent turn with timing and stop reasonsend_prompt
Files
- This documentationSKILL.md
- Package entry point__init__.py
- Core monkey-patching and OTEL integrationinstrumentation.py
- Wrapper script with Jaeger quickstart helptoadia
Backends
Jaeger (Local Development)
docker run -d --name jaeger \ -p 16686:16686 \ -p 4317:4317 \ jaegertracing/all-in-one:latest
Grafana Tempo
# With Grafana stack docker-compose up -d # includes tempo, grafana # View in Grafana Explore with Tempo datasource
Honeycomb (Cloud)
OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io:443 \ OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=YOUR_API_KEY" \ toadia -a claude .
Troubleshooting
"OpenTelemetry not available"
Install the SDK in Toad's Python environment:
uv pip install opentelemetry-sdk opentelemetry-exporter-otlp \ --python ~/.local/share/uv/tools/batrachian-toad/bin/python3
No spans appearing
- Check collector is running:
docker ps | grep jaeger - Enable console export:
TOAD_TELEMETRY_CONSOLE=1 toadia ... - Verify telemetry enabled:
TOAD_TELEMETRY_ENABLED=1
gRPC connection errors
Try HTTP exporter (port 4318 instead of 4317):
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 toadia -a claude .
Related Skills
- Command-line OTEL span emissionotel-cli
- Similar instrumentation for Claude Code CLIclaude_telemetry