Other·terminal · desktop·Apache-2.0
autotel
OpenTelemetry traces of every hook dispatch, and each tool call's duration on its row.

autotel records what the hooks around a Claude Code session did, as OpenTelemetry traces: which plugin sat where in each dispatch, how long each link took, and which one denied a tool call. Claude Code’s own telemetry covers the model and the tools; this covers the hooks around them. It is for plugin authors who want traces of their own hooks, and for anyone who wants each tool call’s duration next to its row in the transcript. It never talks to the model, so it costs no tokens.
What it does
- One trace per turn. A
claude_code.turnroot span opens atprompt.submitand closes atturn.completewith the turn id, reason and duration. - One span per dispatch worth recording. Tool calls and checks, model calls,
process.run,http.fetch,fs.read,fs.write,mcp.call,command.run,agent.spawnand everyclassic.*shell hook. Getters, draws and per-tick events are left out. - The chain beneath, as span events. One
hookevent per link with the plugin name, tier, outcome (returned,passed,skipped,expired), own wall time and skip reason. A denied tool call names the plugin that decided it inclaude_code.decided_by. - A duration badge on tool rows. Once a call settles,
1.2sordenied by hook · 3msappears in dim text beside its row, in the terminal and in the desktop app. $.autotel.spanfor plugins. A noun added in theengine.createfold, so any plugin can put its own spans in the current turn’s trace.
Install
Needs Claude Code 2.1.287 or later, npm, and an OTLP/HTTP collector to receive the spans. The author does not declare a minimum Claude Code version; the package README still prefixes its commands with CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1, which 2.1.287 no longer needs. Version 0.1.0 at the time of writing.
npm install autotel-claude-code
claude --plugin-dir node_modules/autotel-claude-code
Point OTEL_EXPORTER_OTLP_ENDPOINT at your collector before starting, or let autotel-devtools, the local trace viewer from the same monorepo, set it for you:
npx autotel-devtools claude --plugin-dir node_modules/autotel-claude-code
There is no marketplace. The package README suggests pointing one at the package directory if you prefer claude plugin install.
How it works
At session.start the mod reads OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS and OTEL_SERVICE_NAME (default claude-code, so the spans sit beside Claude Code’s own). A * hook then wraps every dispatch, records the ones on its list and skips its own. A ui.render hook on the ToolUse component appends the badge.
What a span carries is narrow. Each dispatch gets the event name, the plugin that raised it and its tier. A tool.call adds the tool name, the tool_use_id and, in a subagent, the agent id. The turn root gets the turn id, reason, aborted flag and duration. A dispatch that throws gets the error message; a dropped prompt gets the reason a hook returned, not the prompt. Chain links carry plugin name, tier, outcome, milliseconds and skip reason. Nothing else: no tool arguments, file paths, commands, URLs, prompt text or model output. What you put in your own $.autotel.span attributes is your call.
Spans queue up and go out as one POST to <endpoint>/v1/traces a second after the first one lands, through $.http.fetch and $.clock.after; the queue also flushes when a turn ends and at session end. The resource carries service.name and the session id. Up to 1,000 spans wait for an unreachable collector, oldest dropped first. Nothing is written to disk. With no endpoint set the mod is inert: no spans, no badge, and $.autotel.span only runs its body.
For a plugin, the call takes a name, a body that receives the span, and optional attributes. The span joins the current turn’s trace, ends when the body settles, and a throw marks it failed and rethrows.
const result = await $.autotel.span('summarise', async (span) => {
span.setAttribute('plugin.feature', 'summary');
return $.model.complete(request);
});
For types, add node_modules/autotel-claude-code/types to the include of your tsconfig, or import Autotel from the package. Where the mod is not installed, $.autotel is absent and the call throws.
Limitations
- A hook’s own
$calls during a dispatch (a file read insidetool.call, say) land as siblings under the turn, not as children of that dispatch: the sandbox has no async context to carry a parent. - One attempt per batch, no retry. A collector that is down loses that batch.
Similar Claude Mods
context-bar
Your context window as one stacked bar above the prompt, a color per category.
pin-memo
Notes and clickable todos pinned above the prompt, back when you resume the session.
token-weather-usage
Context, 5-hour and 7-day limits, cache countdown and cost on one line above the prompt.
Agent Standup band
A line above the prompt when another Claude Code session waits for you, plus toasts.
Popular Claude Mods
The whole directory →plan-progress
Claude's plan as live progress bars above the prompt, with subagents under each task.
cache-keeper
Prompt-cache timer, keep-warm pings, cold-send guard, a board of chats and a handoff.
show-your-work
Claude shows screenshots and recorded Playwright runs in the chat, with before/after QA.
Claude-sama
An unofficial kami mascot who reads above the prompt and reacts to what Claude is doing.





