Claude Modsunofficial directory

Other·terminal · desktop·Apache-2.0

autotel

OpenTelemetry traces of every hook dispatch, and each tool call's duration on its row.

Generic Claude Mods cover for autotel, an OpenTelemetry mod for Claude Code plugins

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.turn root span opens at prompt.submit and closes at turn.complete with 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.spawn and every classic.* shell hook. Getters, draws and per-tick events are left out.
  • The chain beneath, as span events. One hook event 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 in claude_code.decided_by.
  • A duration badge on tool rows. Once a call settles, 1.2s or denied by hook · 3ms appears in dim text beside its row, in the terminal and in the desktop app.
  • $.autotel.span for plugins. A noun added in the engine.create fold, so any plugin can put its own spans in the current turn’s trace.

Install

Needs Claude Code with function hooks enabled, npm, and an OTLP/HTTP collector to receive the spans. The author does not declare a minimum Claude Code version.

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 inside tool.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.