Skip to content
Back to skills

Toad Telemetry

ASecurity

OpenTelemetry instrumentation for Batrachian Toad AI agent terminal.

  • 61 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 6, 2026
developmentpythongobashdockerapibackenddocumentation

Works with

  • claude code
  • terminal
  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 5 files and shows the line behind each finding

Scanned September 6, 2026

npx -y skills add plurigrid/asi --skill toad-telemetry --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Toad Telemetry?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Toad Telemetry
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/plurigrid-toad-telemetry/badge)](https://www.skillsdirectory.com/skills/plurigrid-toad-telemetry)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: toad-telemetry
description: OpenTelemetry instrumentation for Batrachian Toad AI agent terminal.
---
# 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

```bash
# 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)

```bash
# 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

```python
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 |
|----------|---------|-------------|
| `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://localhost:4317` | OTLP collector endpoint |
| `TOAD_TELEMETRY_ENABLED` | `1` | Enable/disable telemetry |
| `TOAD_TELEMETRY_CONSOLE` | `0` | Print spans to console |
| `TOAD_SERVICE_NAME` | `toad` | Service name in traces |

## Quick Start with Jaeger

```bash
# 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>`)

- `toad.tool.id` - Unique tool call ID
- `toad.tool.name` - Tool name (Bash, Read, Write, etc.)
- `toad.tool.kind` - Tool category
- `toad.tool.status` - Completion status
- `toad.tool.duration_ms` - Execution time
- `toad.tool.error` - Error message (if any)
- `toad.session.id` - Session identifier
- `toad.agent` - Agent name

### Turn Spans (`agent.turn`)

- `toad.prompt.length` - Input prompt character count
- `toad.turn.stop_reason` - Why the turn ended
- `toad.turn.duration_ms` - Total turn time
- `toad.agent` - Agent name

## 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:

1. `instrument_toad()` installs an import hook that waits for `toad.app` to load
2. Once Toad is fully initialized, it patches `Agent.rpc_session_update` and `Agent.send_prompt`
3. `rpc_session_update` receives all ACP protocol events (tool_call, tool_call_update, etc.)
4. Each tool call gets a span that tracks its lifecycle from start to completion
5. `send_prompt` wraps each agent turn with timing and stop reason

## Files

- `SKILL.md` - This documentation
- `__init__.py` - Package entry point
- `instrumentation.py` - Core monkey-patching and OTEL integration
- `toadia` - Wrapper script with Jaeger quickstart help

## Backends

### Jaeger (Local Development)

```bash
docker run -d --name jaeger \
  -p 16686:16686 \
  -p 4317:4317 \
  jaegertracing/all-in-one:latest
```

### Grafana Tempo

```bash
# With Grafana stack
docker-compose up -d  # includes tempo, grafana
# View in Grafana Explore with Tempo datasource
```

### Honeycomb (Cloud)

```bash
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:
```bash
uv pip install opentelemetry-sdk opentelemetry-exporter-otlp \
  --python ~/.local/share/uv/tools/batrachian-toad/bin/python3
```

### No spans appearing

1. Check collector is running: `docker ps | grep jaeger`
2. Enable console export: `TOAD_TELEMETRY_CONSOLE=1 toadia ...`
3. Verify telemetry enabled: `TOAD_TELEMETRY_ENABLED=1`

### gRPC connection errors

Try HTTP exporter (port 4318 instead of 4317):
```bash
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 toadia -a claude .
```

## Related Skills

- `otel-cli` - Command-line OTEL span emission
- `claude_telemetry` - Similar instrumentation for Claude Code CLI


## ACP atlas

Part of: `acp-commons`.

Files in this skill

  • CONCOMITANT_SKILLS.md763 B
  • SKILL.md7 KB
  • __init__.py650 B
  • instrumentation.py12.2 KB
  • toadia4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…