Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
c870798
feat(hook): drop numbering from LLM call observation names
milanagm Aug 5, 2026
8612682
Merge pull request #44 from milanagm/feature/remove-llm-call-numbering
hassiebp Aug 5, 2026
ffc553d
feat(hook): make the state directory configurable via CC_LANGFUSE_STA…
milanagm Aug 6, 2026
61bd27e
feat(plugin): offer the state directory option in the config wizard
milanagm Aug 6, 2026
aa670fa
docs(plugin): document CC_LANGFUSE_STATE_DIR
milanagm Aug 6, 2026
214891f
fix(hook): let per-repo env vars win over machine-wide wizard config
milanagm Aug 7, 2026
6e365ba
Merge pull request #46 from milanagm/feature/issue-41-configurable-st…
hassiebp Aug 10, 2026
852ca2d
Apply suggestion from @hassiebp
hassiebp Aug 10, 2026
ce37f9a
Merge pull request #47 from milanagm/lfe-14299-machine-wide-wizard-co…
hassiebp Aug 10, 2026
ad0f967
test(hook): update the default-host pin to the EU endpoint
milanagm Aug 10, 2026
35128e5
fix(plugin): align wizard default and README with the EU code default
milanagm Aug 10, 2026
39d5fb4
test: add workflow-subagent transcript fixture
milanagm Aug 5, 2026
9b84186
fix(hook): trace Workflow-spawned subagent transcripts
milanagm Aug 5, 2026
6cc89a7
test: cover workflow subagent discovery, deferral, and emission
milanagm Aug 5, 2026
1f09bcb
refactor(hook): name workflow agent generations plainly as LLM Call
milanagm Aug 5, 2026
05b7742
Merge pull request #53 from milanagm/fix/default-host-alignment
hassiebp Aug 10, 2026
8eae032
refactor(hook): share agent meta-to-jsonl resolution between discover…
milanagm Aug 11, 2026
f493772
Merge pull request #45 from milanagm/feature/workflow-subagent-visibi…
hassiebp Aug 11, 2026
b5bd11d
feat(hook): use a constant trace name for name-based grouping
milanagm Aug 12, 2026
5b3d432
Merge pull request #55 from milanagm/feature/issue-50-trace-name-style
hassiebp Aug 12, 2026
c427cdf
feat(hook): capture image blocks as markers and opt-in Langfuse media…
milanagm Aug 17, 2026
d068298
perf(hook): read workflow run directories only when a turn references…
milanagm Aug 21, 2026
d3d461b
fix(hook): raise the Langfuse SDK pin to 4.7 for the v4 data model (#65)
milanagm Aug 27, 2026
52ffcad
fix: teammate agents traced in subagent dir (#66)
milanagm Aug 27, 2026
707e022
fix(plugin): bump the version so updates reach installed users (#71)
milanagm Aug 28, 2026
10cc02d
updated the readme (#72)
milanagm Aug 31, 2026
84cf1ec
fix(hook): end a generation at its assistant row, not its tool result…
milanagm Sep 3, 2026
49ace2b
feat(hook): capture assistant thinking blocks as ChatML thinking part…
milanagm Sep 3, 2026
19d082e
fix(hook): restore logging when keys are missing instead of silent fa…
milanagm Sep 3, 2026
e510f3d
fix: tracing of cache cost details and updated readme accordingly (#73)
milanagm Sep 3, 2026
169ddfa
feat(hook): record the conversation history as each LLM call's input …
milanagm Sep 3, 2026
074f293
fix(hook): emit tool calls in the nested shape Langfuse renders (#77)
milanagm Sep 7, 2026
ece30fe
fix: removed dublicates in forked session (#81)
milanagm Sep 7, 2026
e7fb71c
fix(hook): preserve tool and turn failure levels (#84)
milanagm Sep 9, 2026
0c3c040
update stale tool_calls expectations after #77 (#85)
milanagm Sep 9, 2026
f6e1a19
feat(hook): accept caller trace tags via CC_LANGFUSE_TRACE_TAGS (#87)
milanagm Sep 9, 2026
b96b688
added workflows to claude integration (#86)
milanagm Sep 9, 2026
3279daf
chore(plugin): bump the version to 1.2.0 for release (#88)
milanagm Sep 9, 2026
fbabf3e
fix(hook): narrow the state lock so concurrent sessions keep their tu…
milanagm Sep 14, 2026
9082224
feat: attach project name to trace metadata (#60)
johnbuccola Sep 14, 2026
75db78d
fix: Remove install-required flags from API-key userConfig fields (#40)
SalesforceRocks Sep 14, 2026
4f84277
docs: verify Claude traces via Observations API v2
cursoragent Sep 15, 2026
53c7b08
docs: drop the v3 traces-list verification fallback
cursoragent Sep 15, 2026
b521100
Merge pull request #91 from langfuse/cursor/verify-observations-api-v…
jannikmaierhoefer Sep 15, 2026
8870487
docs(readme): slim the README and add a contributing guide (#94)
milanagm Sep 24, 2026
d7e0882
fix(hook): trace subagents launched by subagents (#102)
pushkar Oct 6, 2026
b5b7cc3
chore: release v1.2.1
hassiebp Oct 6, 2026
155c825
Merge remote-tracking branch 'upstream/main' into sync/upstream-v1.2.1
Oct 12, 2026
5e7d21f
Re-apply agent:<type> tags and the OTel queue ceiling on top of upstr…
Oct 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "langfuse-observability",
"description": "The Langfuse x Claude Code Observability Plugin",
"version": "1.0.0",
"version": "1.2.1",
"author": {
"name": "Langfuse"
},
Expand All @@ -13,20 +13,18 @@
"type": "string",
"title": "Langfuse Secret Key",
"description": "Your Langfuse project secret key (sk-lf-...)",
"sensitive": true,
"required": true
"sensitive": true
},
"LANGFUSE_PUBLIC_KEY": {
"type": "string",
"title": "Langfuse Public Key",
"description": "Your Langfuse project public key (pk-lf-...)",
"required": true
"description": "Your Langfuse project public key (pk-lf-...)"
},
"LANGFUSE_BASE_URL": {
"type": "string",
"title": "Langfuse Base URL",
"description": "Langfuse host. Use https://us.cloud.langfuse.com for US, https://cloud.langfuse.com for EU, or your self-hosted URL.",
"default": "https://us.cloud.langfuse.com"
"default": "https://cloud.langfuse.com"
},
"LANGFUSE_USER_ID": {
"type": "string",
Expand Down Expand Up @@ -57,6 +55,17 @@
"description": "Include the injected skill instruction text in the Skill tool span output",
"default": false
},
"CC_LANGFUSE_CAPTURE_IMAGES": {
"type": "boolean",
"title": "Capture images",
"description": "Upload images to Langfuse and show them in the trace. This includes pasted images and screenshots from tool results. Your Langfuse deployment must support media upload. Set to false to show short text markers instead.",
"default": true
},
"CC_LANGFUSE_STATE_DIR": {
"type": "string",
"title": "State directory",
"description": "Optional. Absolute directory for the hook's state, lock and log files (default ~/.claude/state). Set a distinct value per CLAUDE_CONFIG_DIR installation to keep their state separate. Leave empty for the default."
},
"CC_LANGFUSE_TRACE_SEED": {
"type": "string",
"title": "Trace ID seed",
Expand Down
71 changes: 71 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
name: CI

on:
pull_request:
push:
branches:
- main

permissions: {}

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: Test on Python ${{ matrix.python-version }}
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.13"]
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup uv
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
enable-cache: true
- name: Test
run: uv run --python ${{ matrix.python-version }} --group dev pytest

lint:
name: Lint
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup uv
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
enable-cache: true
- name: Ruff
run: uvx ruff check --select F,E9 .

hook-smoke:
name: Hook starts from its own script header
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup uv
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
enable-cache: true
- name: Run the hook with an empty payload
run: echo '{}' | uv run --script hooks/langfuse_hook.py
44 changes: 44 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
name: Release

on:
push:
tags:
- "v*"

permissions: {}

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

jobs:
release:
name: Verify the tag and draft a GitHub release
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Validate release version
run: |
manifest_version="$(python3 -c 'import json; print(json.load(open(".claude-plugin/plugin.json"))["version"])')"
if [[ "$GITHUB_REF_NAME" != "v$manifest_version" ]]; then
echo "Tag $GITHUB_REF_NAME does not match plugin.json version $manifest_version" >&2
exit 1
fi
- name: Setup uv
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
- name: Test
run: uv run --group dev pytest
- name: Run the hook with an empty payload
run: echo '{}' | uv run --script hooks/langfuse_hook.py
# Draft, so the notes get a human pass before anyone sees them.
- name: Create draft GitHub release
run: gh release create "$GITHUB_REF_NAME" --draft --generate-notes --verify-tag
env:
GH_TOKEN: ${{ github.token }}
36 changes: 36 additions & 0 deletions .github/workflows/zizmor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
name: Check GitHub Actions

on:
workflow_dispatch:
push:
branches:
- "main"
merge_group:
pull_request:
branches:
- "main"

permissions: {}

jobs:
zizmor:
name: Check GitHub Actions security
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
actions: read
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Run zizmor
uses: zizmorcore/zizmor-action@70fb788f84895a7701f5643d103d587e460b5c99 # v0.6.3
with:
# Findings upload to code scanning only on push; a pull request from a
# fork has no write token for it.
advanced-security: ${{ github.event_name == 'push' && 'true' || 'false' }}
min-severity: low
64 changes: 64 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Development and Maintenance

See the [main CONTRIBUTING.md](https://github.com/langfuse/langfuse/blob/main/CONTRIBUTING.md) to learn how to contribute to Langfuse and its integrations.

## Local Development

The hook is a single uv script with inline dependency metadata, and Claude Code
runs `hooks/langfuse_hook.py` directly. There is no build step and no package to
install.

Run the tests:

```bash
uv run --group dev pytest
```

Lint with the same rules as CI:

```bash
uvx ruff check --select F,E9 .
```

CI also starts the hook once with an empty payload, which catches a broken
script header before it reaches a user:

```bash
echo '{}' | uv run --script hooks/langfuse_hook.py
```

Tests run against Python 3.10 and 3.13 in CI. Add `--python 3.10` to `uv run` to
reproduce the older matrix entry.

To try your checkout as a real plugin, register the repository itself as a
marketplace instead of the GitHub one:

```bash
claude plugin marketplace add /path/to/Claude-Observability-Plugin
claude plugin install langfuse-observability@langfuse-observability
```

Restart Claude Code afterwards, so that it loads the hook. Run
`claude plugin marketplace remove langfuse-observability` when you are done, and
add the GitHub marketplace again to go back to the released plugin.

## Releasing

1. From a clean, up-to-date `main` branch, raise `version` in
`.claude-plugin/plugin.json` and commit that change.

2. Tag the release commit and push both:

```bash
git tag v1.2.3
git push origin main --follow-tags
```

The release workflow refuses a tag that does not match the manifest version.
It then runs the tests and the hook smoke check, and creates a draft GitHub
release with generated notes.

3. Review the draft release, give the notes a human pass, and publish it.

Installed plugins do not update themselves, so users reach the new version only
after `claude plugin marketplace update` and `claude plugin update`.
Loading
Loading