Observability-first CLI for the Langfuse LLM platform, following gh-ux patterns.
Features: traces, observations, prompts, scores, datasets, experiments, sessions | JSON/table/TSV output | config profiles | system keyring secrets | agent-friendly --json mode
# With uv (recommended)
uv tool install langfuse-cli
# With pip
pip install langfuse-cli
# With Homebrew
brew install aviadshiber/tap/langfuse-cli
# From source
git clone https://github.com/aviadshiber/langfuse-cli.git && cd langfuse-cli
uv sync && uv run lf --version# Set credentials (or use config file below)
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
export LANGFUSE_HOST="https://cloud.langfuse.com" # optional, this is the default
# List recent traces
lf traces list --limit 5 --from 2026-02-01
# List prompts
lf prompts list
# Get JSON output (agent-friendly)
lf --json traces list --limit 5 --from 2026-02-01Configuration is resolved in this order (first match wins):
- CLI flags (
--host,--profile) - Environment variables (
LANGFUSE_HOST,LANGFUSE_PUBLIC_KEY,LANGFUSE_SECRET_KEY) - Config file (
~/.config/langfuse/config.toml) - System keyring (macOS Keychain / Linux Secret Service)
- Defaults (host:
https://cloud.langfuse.com)
# ~/.config/langfuse/config.toml
[default]
host = "https://cloud.langfuse.com"
public_key = "pk-lf-..."
# secret_key stored in keyring, NOT in plaintext
[profiles.staging]
host = "https://staging.langfuse.example.com"
public_key = "pk-lf-staging-..."
[defaults]
limit = 50
output = "table"Secret keys are stored in the system keyring (service: langfuse-cli):
- macOS: Keychain (
security add-generic-password -s langfuse-cli -a default/secret_key -w <secret>) - Linux: Secret Service API (GNOME Keyring / KDE Wallet)
- Fallback: Environment variables or config file
| Variable | Description |
|---|---|
LANGFUSE_HOST |
Langfuse host URL |
LANGFUSE_BASEURL |
Alias for LANGFUSE_HOST (SDK compatibility) |
LANGFUSE_PUBLIC_KEY |
Public API key |
LANGFUSE_SECRET_KEY |
Secret API key |
LANGFUSE_PROFILE |
Config profile name |
LANGFUSE_FORCE_TTY |
Force TTY mode (set to 1) |
NO_COLOR |
Disable color output |
Global options go before the subcommand:
lf --json traces list --limit 5 # correct
lf --quiet scores summary # correct| Flag | Description |
|---|---|
--version, -v |
Show version and exit |
--host URL |
Override Langfuse host URL |
--profile NAME |
Use named config profile |
--json |
Output as JSON |
--fields FIELDS |
Filter JSON to specific fields (comma-separated, implies --json) |
--jq EXPR |
Filter JSON with jq expression (implies --json) |
--quiet, -q |
Suppress status messages |
# List traces (use --from to avoid timeouts on large projects)
lf traces list --limit 10 --from 2026-02-01
lf traces list --user-id user-123 --session-id sess-456
lf traces list --tags production,v2 --name chat-completion
# Get a single trace
lf traces get <trace-id>
# Visualize trace hierarchy as a tree
lf traces tree <trace-id>| Flag | Type | Description |
|---|---|---|
--limit, -l |
INT | Max results (default: 50) |
--user-id, -u |
TEXT | Filter by user ID |
--session-id, -s |
TEXT | Filter by session ID |
--tags |
TEXT | Filter by tags (comma-separated) |
--name, -n |
TEXT | Filter by trace name |
--from |
DATETIME | Start time filter (ISO 8601) |
--to |
DATETIME | End time filter (ISO 8601) |
# List all prompts
lf prompts list
# Get a specific prompt
lf prompts get my-prompt
lf prompts get my-prompt --label production
lf prompts get my-prompt --version 3
# Compile a prompt with variables
lf prompts compile my-prompt --var name=Alice --var role=engineer
# Compare two versions
lf prompts diff my-prompt --v1 3 --v2 5# List scores
lf scores list --trace-id abc-123
lf scores list --name quality --from 2026-01-01
# Aggregated statistics
lf scores summary
lf scores summary --name quality --from 2026-01-01# List datasets
lf datasets list
# Get dataset with items
lf datasets get my-dataset --limit 10# List runs for a dataset
lf experiments list my-dataset
# Compare two runs
lf experiments compare my-dataset run-baseline run-improved# List sessions
lf sessions list --limit 20 --from 2026-01-01
# Get session details
lf sessions get session-abc-123# List observations for a trace
lf observations list --trace-id abc-123
# Filter by type and name
lf observations list --type GENERATION --name llm-call --limit 20
# With time range
lf observations list --trace-id abc-123 --from 2026-01-01 --to 2026-01-31| Flag | Type | Description |
|---|---|---|
--limit, -l |
INT | Max results (default: 50) |
--trace-id, -t |
TEXT | Filter by trace ID |
--type |
TEXT | Filter by type (GENERATION, SPAN, EVENT) |
--name, -n |
TEXT | Filter by observation name |
--from |
DATETIME | Start time filter (ISO 8601) |
--to |
DATETIME | End time filter (ISO 8601) |
| Context | Format | Status Messages |
|---|---|---|
| Terminal (TTY) | Rich aligned columns with colors | Shown |
| Piped (non-TTY) | Tab-separated values | Suppressed |
--json flag |
JSON array | Suppressed unless error |
--quiet flag |
Normal tables | All suppressed |
# Rich table (terminal)
lf prompts list
# Tab-separated (piped)
lf traces list --limit 5 --from 2026-02-01 | head
# JSON (agent-friendly)
lf --json traces list --limit 5 --from 2026-02-01
# Filtered JSON fields
lf --fields id,name,userId traces list --limit 5 --from 2026-02-01
# jq expression
lf --jq '.[].name' traces list --limit 5 --from 2026-02-01| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Error (API failure, auth, general) |
| 2 | Resource not found |
| 3 | Cancelled (Ctrl+C) |
Hybrid SDK + REST approach:
- REST (httpx): Traces, observations, scores, sessions — full filter control, 60s timeout
- SDK (langfuse): Prompts (built-in 300s caching), datasets, experiments — complex operations
Timeouts on large projects — Use --from to limit the time range:
lf traces list --from 2026-02-01 # fast: scoped query
lf traces list # slow: may timeout on large projectsDatetime format — --from/--to accept ISO 8601 without milliseconds or Z suffix:
lf traces list --from 2026-02-16 # date only
lf traces list --from 2026-02-16T10:30:00 # datetime
lf traces list --from "2026-02-16 10:30:00" # space separator (quote it)
# NOT supported: 2026-02-16T10:30:00.213Z (ms + Z suffix)Authentication errors — Verify credentials are set:
echo $LANGFUSE_PUBLIC_KEY # should show pk-lf-...
echo $LANGFUSE_SECRET_KEY # should show sk-lf-...
lf --json traces list --limit 1 --from 2026-02-01 # test connectivityBatch processing — Use --to with the last timestamp to page through results:
# Batch 1
RAW=$(lf --jq '.[-1].timestamp' traces list --limit 50 --from 2026-02-01 2>/dev/null)
CURSOR=$(echo "$RAW" | tr -d '"' | sed 's/\.[0-9]*Z$//')
# Batch 2 (older results)
lf --json traces list --limit 50 --from 2026-02-01 --to "$CURSOR"lf supports tab completions for bash, zsh, and fish via Typer's built-in mechanism.
Bash — add to ~/.bashrc:
eval "$(_LF_COMPLETE=bash_source lf)"Zsh — add to ~/.zshrc:
eval "$(_LF_COMPLETE=zsh_source lf)"Fish — add to ~/.config/fish/config.fish:
_LF_COMPLETE=fish_source lf | sourceAfter adding, restart your shell or source the config file.
# Setup
git clone https://github.com/aviadshiber/langfuse-cli.git && cd langfuse-cli
uv sync
# Run tests
uv run pytest
# Lint, format & type check
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/
uv run mypy src/
# Run locally
uv run lf --versionSee CONTRIBUTING.md for detailed development guidelines.