📦 Part of the
langfuse-coding-agentsmonorepo. Other tools:claude-code·codex·oh-my-codex·opencode·gemini-cli
Automatic Langfuse tracing for Gemini CLI. Every agent turn, LLM call, tool execution, and session event is captured as structured traces in your Langfuse dashboard -- zero code changes required.
- ✅ Hook pipeline verified on real Gemini CLI sessions
- ✅ Session lifecycle, turn traces, tool spans, and buffer flow validated
- ✅ Repository cleanup completed (no unnecessary tracked files found)
- ✅
v0.0.1release/tag refreshed with final docs sync - ✅ LGC (
langfuse-gemini-cli) aligned with companion repos:langfuse-oh-my-codexlangfuse-claude-codelangfuse-opencode
- Progress docs: English | 한국어
- Full event coverage -- all 11 Gemini CLI hook events are captured
- Per-turn tracing -- each user prompt + assistant response becomes a Langfuse trace
- LLM call tracking -- before/after model calls with request, response, and token usage
- Tool call tracking -- before/after tool execution with inputs, outputs, and duration
- Tool selection capture -- tool filtering and selection decisions are recorded
- Session lifecycle -- session start (startup/resume/clear) and end (exit/logout) events
- Notification capture -- system notifications logged as independent events
- Context compression -- pre-compression events tracked for observability
- Session grouping -- traces are grouped by Gemini CLI session ID
- Buffer-based assembly -- events are buffered per-turn and assembled into complete traces
- Fail-open design -- if anything goes wrong the hook exits silently; Gemini CLI is never blocked
- Cross-platform -- works on macOS, Linux, and Windows
- Dual SDK support -- works with both langfuse
>= 3.12(nested spans) and older versions (flat traces)
- Gemini CLI -- installed and working (
gemini --versionto verify) - Python 3.8+ -- with
pipavailable (python3 -m pip --versionorpython -m pip --versionto verify) - Langfuse account -- cloud.langfuse.com (free tier available) or a self-hosted instance
# Clone and run the installer
git clone https://github.com/BAEM1N/langfuse-coding-agents.git
cd langfuse-coding-agents/tools/gemini-cli
bash install.shOn Windows (PowerShell):
git clone https://github.com/BAEM1N/langfuse-coding-agents.git
cd langfuse-coding-agents/tools/gemini-cli
.\install.ps1The installer will:
- Check Python 3.8+ is available
- Install the
langfusePython package - Copy the hook script to
~/.gemini/hooks/ - Prompt you for your Langfuse credentials
- Register all 11 hook events in
~/.gemini/settings.json - Verify the installation
pip install langfusemkdir -p ~/.gemini/hooks ~/.gemini/state
cp langfuse_hook.py ~/.gemini/hooks/
chmod +x ~/.gemini/hooks/langfuse_hook.pyAdd (or merge) the following into your settings file:
{
"hooks": {
"SessionStart": [{"hooks": [{"type": "command", "command": "python3 ~/.gemini/hooks/langfuse_hook.py"}]}],
"BeforeAgent": [{"hooks": [{"type": "command", "command": "python3 ~/.gemini/hooks/langfuse_hook.py"}]}],
"BeforeModel": [{"hooks": [{"type": "command", "command": "python3 ~/.gemini/hooks/langfuse_hook.py"}]}],
"BeforeToolSelection": [{"hooks": [{"type": "command", "command": "python3 ~/.gemini/hooks/langfuse_hook.py"}]}],
"AfterModel": [{"hooks": [{"type": "command", "command": "python3 ~/.gemini/hooks/langfuse_hook.py"}]}],
"BeforeTool": [{"hooks": [{"type": "command", "command": "python3 ~/.gemini/hooks/langfuse_hook.py"}]}],
"AfterTool": [{"hooks": [{"type": "command", "command": "python3 ~/.gemini/hooks/langfuse_hook.py"}]}],
"AfterAgent": [{"hooks": [{"type": "command", "command": "python3 ~/.gemini/hooks/langfuse_hook.py"}]}],
"Notification": [{"hooks": [{"type": "command", "command": "python3 ~/.gemini/hooks/langfuse_hook.py"}]}],
"PreCompress": [{"hooks": [{"type": "command", "command": "python3 ~/.gemini/hooks/langfuse_hook.py"}]}],
"SessionEnd": [{"hooks": [{"type": "command", "command": "python3 ~/.gemini/hooks/langfuse_hook.py"}]}]
},
"env": {
"TRACE_TO_LANGFUSE": "true",
"LANGFUSE_PUBLIC_KEY": "pk-lf-...",
"LANGFUSE_SECRET_KEY": "sk-lf-...",
"LANGFUSE_BASE_URL": "https://cloud.langfuse.com",
"LANGFUSE_USER_ID": "your-username"
}
}| Variable | Required | Default | Description |
|---|---|---|---|
TRACE_TO_LANGFUSE |
Yes | - | Set to "true" to enable tracing |
LANGFUSE_PUBLIC_KEY |
Yes | - | Langfuse public key (or GC_LANGFUSE_PUBLIC_KEY) |
LANGFUSE_SECRET_KEY |
Yes | - | Langfuse secret key (or GC_LANGFUSE_SECRET_KEY) |
LANGFUSE_BASE_URL |
No | https://cloud.langfuse.com |
Langfuse host URL (or GC_LANGFUSE_BASE_URL) |
LANGFUSE_USER_ID |
No | gemini-user |
User ID for trace attribution (or GC_LANGFUSE_USER_ID) |
GC_LANGFUSE_DEBUG |
No | false |
Set to "true" for verbose logging |
GC_LANGFUSE_MAX_CHARS |
No | 20000 |
Max characters per text field before truncation |
All LANGFUSE_* variables also accept a GC_LANGFUSE_* prefix (which takes priority).
┌──────────────────────────────────────────────────────────────┐
│ Gemini CLI │
│ │
│ User prompt ──► Model call ──► Tool calls ──► Response │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ BeforeAgent BeforeModel BeforeTool AfterAgent │
│ │ AfterModel AfterTool │ │
│ │ │ │ │ │
│ └──────────────┴──────┬───────┘ │ │
│ │ │ │
│ ┌───────▼───────┐ ┌────────▼────────┐ │
│ │ Buffer (JSONL) │ │ Assemble Trace │ │
│ └───────────────┘ └────────┬─────────┘ │
│ │ │
│ SessionStart ──┐ │ │
│ Notification ──┤ (independent events) │ │
│ PreCompress ───┤ │ │
│ SessionEnd ────┘ │ │
└───────────────────────────────────────────────────┼───────────┘
│
▼
┌─────────────────────┐
│ Langfuse │
│ │
│ Trace (Turn 1) │
│ ├─ Agent Request │
│ ├─ LLM Call [1] │
│ │ ├─ model │
│ │ ├─ usage tokens │
│ │ └─ response │
│ ├─ Tool Selection │
│ ├─ Tool: read_file │
│ ├─ LLM Call [2] │
│ ├─ Tool: write_file │
│ └─ Agent Response │
│ │
│ Event: SessionStart │
│ Event: Notification │
│ Event: SessionEnd │
│ │
│ Session: abc123 │
└─────────────────────┘
Flow:
- Gemini CLI fires hook events at each stage of the agent loop
- Buffer events (
BeforeAgent,BeforeModel,AfterModel,BeforeToolSelection,BeforeTool,AfterTool) are appended to a JSONL buffer file - When AfterAgent fires (turn complete), the buffer is read, assembled into a complete trace, and sent to Langfuse
- Independent events (
SessionStart,SessionEnd,Notification,PreCompress) are emitted immediately - Each turn trace includes:
- Agent Request span (user prompt from BeforeAgent)
- LLM Call generation observations (with model, token usage from AfterModel)
- Tool Selection spans (from BeforeToolSelection)
- Tool spans (paired BeforeTool/AfterTool with inputs and outputs)
- Agent Response span (final response from AfterAgent)
- All traces share the same
session_idfor grouping
| Event | Type | Data Captured |
|---|---|---|
SessionStart |
Independent | Session source (startup/resume/clear) |
BeforeAgent |
Buffered | User prompt |
BeforeModel |
Buffered | LLM request |
BeforeToolSelection |
Buffered | Available tools configuration |
AfterModel |
Buffered | LLM request + response + token usage |
BeforeTool |
Buffered | Tool name + input |
AfterTool |
Buffered | Tool name + input + response |
AfterAgent |
Trace emit | Prompt + response (assembles buffered events) |
Notification |
Independent | Notification type + message |
PreCompress |
Independent | Compression trigger |
SessionEnd |
Flush + cleanup | Exit reason + remaining buffer flush |
| Component | Version |
|---|---|
| Python | 3.8+ |
| langfuse SDK | 2.0+ (flat traces), 3.12+ (nested spans) |
| Gemini CLI | 0.26.0+ (hooks support) |
| OS | macOS, Linux, Windows |
- Verify
TRACE_TO_LANGFUSEis set to"true"in your settings - Check that your API keys are correct
- Enable debug logging: set
GC_LANGFUSE_DEBUGto"true" - Check the log file:
~/.gemini/state/langfuse_hook.log
- Confirm hooks are in
~/.gemini/settings.jsonunder all 11 event keys - Verify the Python path in the command is correct (
python3vspython) - Test manually:
echo '{"hook_event_name":"SessionStart","session_id":"test"}' | python3 ~/.gemini/hooks/langfuse_hook.py(usepythoninstead ofpython3on Windows)
The hook tracks turn counts in ~/.gemini/state/langfuse_state.json. Delete this file for a fresh start.
By default, text fields are truncated at 20,000 characters. Adjust with GC_LANGFUSE_MAX_CHARS:
"GC_LANGFUSE_MAX_CHARS": "50000"- Remove all hook entries from
~/.gemini/settings.json - Delete the hook script:
rm ~/.gemini/hooks/langfuse_hook.py - Optionally remove state:
rm -rf ~/.gemini/state/langfuse_*