claude-code-logfire-plugin
CLAUDE.md16 starsChanged 9 months agoMITView on GitHub
A Claude Code plugin that captures sessions and exports pydantic-ai compatible OTel traces to Pydantic Logfire, with local JSONL fallback. The plugin is a single Python 3 script (stdlib only, no external dependencies). The entire plugin is a single Python script (scripts/log-event.py) invoked by every hook event defined in hooks/hooks.json. The plugin manifest lives at .claude-plugin/plugin.json. Data flow: Claude Code hook fires -> stdin JSON piped to log-event.py -> appends JSONL locally -> if LOGFIRE_TOKEN set and event is SessionStart/Stop/SubagentStop/SessionEnd,…
The file
We split this CLAUDE.md into the rules it gives an agent
3 rules. About 0 are common, 3 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 44
No automated tests. To test manually:
- Distinctive: line 62
Stop events parse the transcript to extract per-API-call data.
- Distinctive: line 66
All HTTP calls have a 5-second timeout and failures are silently ignored.
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What This Is
A Claude Code plugin that captures sessions and exports pydantic-ai compatible OTel traces to Pydantic Logfire, with local JSONL fallback. The plugin is a single Python 3 script (stdlib only, no external dependencies).
Architecture
The entire plugin is a single Python script (scripts/log-event.py) invoked by every hook event defined in hooks/hooks.json. The plugin manifest lives at .claude-plugin/plugin.json.
Data flow: Claude Code hook fires -> stdin JSON piped to log-event.py -> appends JSONL locally -> if LOGFIRE_TOKEN set and event is SessionStart/Stop/SubagentStop/SessionEnd, builds OTLP/HTTP JSON payload and sends via urllib.
Session state: A temp file ($TMPDIR/claude-logfire-{session_id}.json) persists the root span ID, start time, transcript line offset, accumulated messages, usage totals, and cost details between hook invocations. Created on SessionStart, deleted on SessionEnd.
Trace correlation: trace_id is deterministically derived from session_id via SHA-256.
Span hierarchy (pydantic-ai style):
agent run (root span) <- the session (emitted on SessionEnd)
├── chat claude-opus-4-6 <- LLM API call 1 (emitted on Stop)
├── chat claude-opus-4-6 <- LLM API call 2 (emitted on Stop)
└── chat claude-opus-4-6 <- LLM API call 3 (emitted on Stop)OTLP processing model:
| Hook Event | JSONL | OTLP |
| SessionStart | yes | pending root span (logfire.span_type=pending_span) |
| Stop / SubagentStop | yes | "chat {model}" child spans per LLM API call |
| SessionEnd | yes | finalized root "agent run" span with all_messages, usage, cost |
| All other events | yes | none (early exit) |
Transcript parsing: On Stop events, the script reads new transcript lines (since last offset), deduplicates streaming fragments by message.id, identifies API call boundaries, and converts messages to pydantic-ai format (tool_use -> tool_call, tool_result -> tool_call_response, end_turn -> stop).
Dependencies
python3(3.7+) — the only external dependency; uses stdlib only (json,urllib.request,hashlib,os,time,tempfile)
Testing
No automated tests. To test manually:
# Full lifecycle test
> /tmp/test-transcript.jsonl
echo '{"hook_event_name":"SessionStart","session_id":"test123","cwd":"/tmp","model":"claude-opus-4-6","transcript_path":"/tmp/test-transcript.jsonl"}' | LOGFIRE_TOKEN=your-token python3 scripts/log-event.py
# Write mock transcript lines, then:
echo '{"hook_event_name":"Stop","session_id":"test123","transcript_path":"/tmp/test-transcript.jsonl"}' | LOGFIRE_TOKEN=your-token python3 scripts/log-event.py
echo '{"hook_event_name":"SessionEnd","session_id":"test123"}' | LOGFIRE_TOKEN=your-token python3 scripts/log-event.pyKey Design Decisions
- OTLP spans use pydantic-ai attribute conventions (
gen_ai.input.messages,gen_ai.output.messages,pydantic_ai.all_messages,logfire.metrics) so Logfire renders them identically to pydantic-ai agent traces. - Complex attributes use
to_otlp_anyvaluewhich recursively converts Python values to OTLP AnyValue format (kvlistValue for dicts, arrayValue for lists). Checksboolbeforeintsinceboolis a subclass ofintin Python. logfire.json_schemaattribute tells Logfire which attributes contain structured data vs plain strings.- Stop events parse the transcript to extract per-API-call data; all state accumulates in the temp file across multiple Stop events in a session.
build_child_spans_from_callsis a shared function used by both Stop and SessionEnd handlers, eliminating code duplication.- Atomic state writes use
tempfile.mkstemp()+os.replace()for guaranteed atomic overwrite on all platforms. - Cross-platform locking uses
os.mkdir()(atomic on all POSIX systems). - All HTTP calls have a 5-second timeout and failures are silently ignored.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

