langfuse-observability/SKILL.md
LLM observability with Langfuse — query traces, generations, costs, metrics, and debug LLM pipelines via the REST API
npx skillsauth add ddnetters/homelab-agent-skills langfuse-observabilityInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Langfuse is an open-source LLM observability platform. Use this skill to query traces, generations, costs, and metrics from a self-hosted or cloud Langfuse instance.
# Set your Langfuse credentials
export LANGFUSE_HOST="https://langfuse.example.com" # or https://cloud.langfuse.com
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
All API calls use basic auth with public key as username and secret key as password.
# Base pattern for all requests
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/<endpoint>"
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/health" | jq .
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/traces?limit=10&page=1" | \
jq '.data[] | {id, name, timestamp, userId, totalCost, latency, tags}'
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/traces?limit=20&fromTimestamp=2026-02-01T00:00:00Z&toTimestamp=2026-02-28T23:59:59Z" | \
jq '.data[] | {id, name, timestamp, totalCost, latency}'
# By user
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/traces?limit=10&userId=USER_ID" | \
jq '.data[] | {id, name, timestamp, totalCost}'
# By trace name
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/traces?limit=10&name=TRACE_NAME" | \
jq '.data[] | {id, name, timestamp, totalCost}'
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/traces/TRACE_ID" | \
jq '{id, name, timestamp, userId, sessionId, totalCost, latency, tags, metadata,
observations: [.observations[] | {id, type, name, model, startTime, totalCost, usage}]}'
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/traces/TRACE_ID" | jq '{input, output}'
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/observations?type=GENERATION&limit=10&page=1" | \
jq '.data[] | {id, name, model, startTime, totalCost, inputUsage: .usage.input, outputUsage: .usage.output}'
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/observations?type=GENERATION&limit=10" | \
jq '[.data[] | select(.model | test("gpt-4"))] | .[] | {id, model, totalCost}'
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/observations?type=GENERATION&traceId=TRACE_ID" | \
jq '.data[] | {id, name, model, totalCost, usage, input, output}'
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/observations/OBSERVATION_ID" | \
jq '{id, type, name, model, modelParameters, startTime, endTime, totalCost, usage, level, statusMessage}'
# Find errors
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/observations?level=ERROR&limit=10" | \
jq '.data[] | {id, traceId, name, model, level, statusMessage, startTime}'
# Find warnings
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/observations?level=WARNING&limit=10" | \
jq '.data[] | {id, traceId, name, model, level, statusMessage, startTime}'
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/metrics/daily?limit=7" | \
jq '.data[] | {date, traces: .countTraces, cost: .totalCost,
models: [.usage[] | {model, input: .inputUsage, output: .outputUsage, total: .totalUsage}]}'
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/metrics/daily?limit=30" | \
jq '{totalCost: ([.data[].totalCost] | add), totalTraces: ([.data[].countTraces] | add),
days: (.data | length), breakdown: [.data[] | {date, cost: .totalCost, traces: .countTraces}]}'
# List recent sessions
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/sessions?page=1&limit=10" | \
jq '.data[] | {id, createdAt, projectId}'
# Get session details
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/sessions/SESSION_ID" | jq .
# List scores
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/scores?limit=10" | \
jq '.data[] | {id, name, value, dataType, traceId, comment}'
# Scores for a specific trace
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/scores?traceId=TRACE_ID" | \
jq '.data[] | {name, value, dataType, comment}'
services:
langfuse-web:
image: langfuse/langfuse:3
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://user:pass@postgres:5432/langfuse
NEXTAUTH_SECRET: your-secret
SALT: your-salt
ENCRYPTION_KEY: your-encryption-key
NEXTAUTH_URL: https://langfuse.example.com
AUTH_DISABLE_SIGNUP: "true"
depends_on: [postgres]
langfuse-worker:
image: langfuse/langfuse-worker:3
environment:
DATABASE_URL: postgresql://user:pass@postgres:5432/langfuse
SALT: your-salt
ENCRYPTION_KEY: your-encryption-key
postgres:
image: postgres:17
volumes:
- langfuse_pg:/var/lib/postgresql/data
environment:
POSTGRES_DB: langfuse
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
Langfuse v3 also supports ClickHouse for trace storage, Redis for queuing, and MinIO for object storage.
Send traces automatically from OpenRouter to Langfuse:
https://langfuse.example.comAll OpenRouter LLM calls will then appear as traces in Langfuse.
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/traces?limit=50&fromTimestamp=$(date -d '7 days ago' +%FT00:00:00Z)" | \
jq '[.data[] | {id, name, totalCost, timestamp}] | sort_by(-.totalCost) | .[:10]'
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/observations?type=GENERATION&limit=100" | \
jq '[.data[] | .model] | group_by(.) | map({model: .[0], count: length}) | sort_by(-.count)'
ERRORS=$(curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/observations?level=ERROR&limit=1" | jq '.meta.totalItems')
TOTAL=$(curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_HOST/api/public/observations?limit=1" | jq '.meta.totalItems')
echo "Error rate: $ERRORS / $TOTAL"
fromTimestamp/toTimestamp) on large queries to avoid timeoutsmeta.page, meta.limit, meta.totalItems, meta.totalPages2026-02-10T00:00:00Zusage.input, usage.output, usage.totaldevelopment
Use when delegating a single coding task to `codex exec` ("hand off to codex", "run codex on this", "dispatch codex on this ticket", any one-shot invocation). Covers flags, sandbox traps, monitoring, and recovery. Not for multi-issue parallel batches — use codex-issue-waves for those.
development
Use when the user says "have codex fix this" / "have codex implement this" / "let codex handle this" / "give this to codex" / "delegate this to codex" for a single task with context already in scope (a Jira ticket, GitHub issue, file diff, bug, or described change). Plans the work, splits it into reviewable waves, dispatches codex per wave with review and correction between waves before opening a PR. Not for multi-issue parallel batches (use codex-issue-waves) or one-shot codex runs without planning (use invoking-codex-exec).
development
Run a batch of GitHub issues through codex exec in isolated git worktrees as parallel autonomous PRs, then manage the review and correction waves until merge. Use when the user gives a list of issue numbers (≥ 2) and asks to "spawn codex" / "dispatch codex" / "have codex work on" / "manage the PRs" / "process feedback" / "get them merged" for those issues, or when the user asks for multi-issue parallel delegation to codex. Not for single-issue wave-driven delegation (use codex-task-waves), single-issue one-shot dispatch (use invoking-codex-exec), or implementation without delegation (use /pr or direct implementation).
development
Slite knowledge base API — ask questions, search notes, retrieve content, manage users and groups, and audit knowledge health via the REST API