bitfrost
Drop-in OpenTelemetry observability for Python LLM apps. Standalone or with any OTLP backend — runs on your machine, sends nothing unless you ask it to.
Bitfrost turns the OpenTelemetry spans your LLM libraries already emit into a clean, queryable event stream — in your terminal, in a local web dashboard, in SQLite, or shipped to any backend you choose. One line to start, zero accounts required.
import bitfrost
bitfrost.quickstart(agent="my-app") # auto-detects openai / anthropic / litellm / smolagents
# ...your normal LLM calls now stream to the terminal, color-coded, with tokens + cost.
bitfrost serve capture.db — a local, offline dashboard. No account, no upload.
Why bitfrost
- Standalone first. Capture to your terminal, a JSONL file, or SQLite with zero configuration and zero network calls. Voight is one optional backend, never a requirement.
- Drop-in. Built on the OpenTelemetry GenAI semantic conventions, so it works with the instrumentation libraries you already use — across both the v1.27 and v1.32+ attribute generations.
- Batteries included. Five backends, four auto-instrument helpers, a rich CLI, an interactive TUI, and an offline web dashboard.
- Private by default. Three privacy levels with PII scrubbing (12 patterns + Luhn) applied before any event leaves the process.
- Never crashes your app. Every failure path degrades gracefully — a dead endpoint or a missing optional dependency never takes down your code.
Install
pip install bitfrost # core
pip install 'bitfrost[cli,serve]' # + CLI, TUI and local web dashboard
pip install 'bitfrost[all]' # everything
Python 3.10–3.13.
Capture anywhere
Pick a backend and pass it to any instrument helper (or quickstart). All concrete backends live under bitfrost.backends.*:
| Backend | Import | Use it for |
|---|---|---|
| Console | bitfrost.backends.console.ConsoleBackend |
live, color-coded terminal output |
| SQLite | bitfrost.backends.sqlite.SQLiteBackend |
persistent local log; powers bitfrost serve |
| JSONL | bitfrost.backends.jsonl.JSONLBackend |
one JSON object per line; replay-able |
| OTLP/HTTP | bitfrost.backends.otlp.OTLPBackend |
POST events as JSON to any collector or webhook |
| Voight | bitfrost.backends.voight.VoightBackend |
hosted dashboards (optional, opt-in) |
| Tee | bitfrost.backends.tee.TeeBackend |
fan out to several backends at once |
import bitfrost
from bitfrost.backends.sqlite import SQLiteBackend
bitfrost.instrument_openai(backend=SQLiteBackend("events.db"), agent="my-app")
# then: bitfrost serve events.db
Fan out to several at once:
import bitfrost
from bitfrost.backends.tee import TeeBackend
from bitfrost.backends.console import ConsoleBackend
from bitfrost.backends.sqlite import SQLiteBackend
bitfrost.instrument_auto(
backend=TeeBackend(ConsoleBackend(), SQLiteBackend("events.db")),
agent="my-app",
)
Auto-instrument helpers
import bitfrost
bitfrost.instrument_openai() # opentelemetry-instrumentation-openai
bitfrost.instrument_anthropic() # opentelemetry-instrumentation-anthropic
bitfrost.instrument_litellm() # litellm CustomLogger adapter
bitfrost.instrument_smolagents() # openinference-instrumentation-smolagents
bitfrost.instrument_auto() # instrument every supported lib that's installed
Already wiring OpenTelemetry yourself? Skip the helpers and attach the exporter to your own TracerProvider:
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from bitfrost.exporter import BitfrostExporter
from bitfrost.backends.console import ConsoleBackend
provider = TracerProvider()
provider.add_span_processor(
BatchSpanProcessor(BitfrostExporter(ConsoleBackend(), agent="my-app"))
)
CLI
bitfrost watch capture.db # live tail, one styled line per event
bitfrost replay capture.jsonl # re-render a captured run start to finish
bitfrost query capture.db "SELECT model, COUNT(*) FROM events GROUP BY model"
bitfrost vacuum capture.db --keep-days 7
bitfrost tui capture.db # full-screen interactive dashboard
bitfrost serve capture.db # local web dashboard at http://127.0.0.1:8080
bitfrost tui — the same capture, navigable in your terminal. Prompts masked by default.
Privacy
Three levels, applied in-process before any event is sent:
minimal— metadata only, no prompt/response contentstandard(default) — content kept, PII scrubbed (12 patterns + credit-card Luhn check)full— everything verbatim (use only for local debugging)
bitfrost.instrument_openai(privacy="minimal")
Standalone, or with Voight
Bitfrost is useful entirely on its own — the core has no dependency on any hosted service. If you want managed dashboards, team sharing, and per-user cost attribution, the optional VoightBackend ships your events to voight.xyz. Everything else stays exactly the same.
Documentation
- Cookbook — task-oriented recipes
- Write your own backend — the
ExportBackendprotocol - Full docs: docs.voight.xyz/python/bitfrost
License
MIT. Built by Voight.
Release files for bitfrost 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bitfrost-0.2.0.tar.gz | 182.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bitfrost-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 337.5 kB
Release files / bitfrost-0.2.0.tar.gz
| Download URL | bitfrost-0.2.0.tar.gz |
|---|---|
| Size | 182.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
839ad33013f82ca01cc7edcad4c9c99117d73b7a1c8bba1c0c7ef1c0c7088a55
|
|
BLAKE2b-256 checksum How to use checksums |
19241dff66aec128b320fe3d4b38227baca1fa5502150dc0f71c718fc13c29c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / bitfrost-0.2.0-py3-none-any.whl
| Download URL | bitfrost-0.2.0-py3-none-any.whl |
|---|---|
| Size | 155.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
57dc7a13e67756fd80ed26d3689b4df52b209ff2bc8457f9c6634e970d31bbc6
|
|
BLAKE2b-256 checksum How to use checksums |
6f02f93100e585780d474a8bdaf9e9d99c4e9648ff375de8df8cf91e9ee99481
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|