Skip to content

Import from Braintrust

Do the shared setup first: an ingest key, pip install metergraphrelay, and a .env holding METERGRAPH_APP_TOKEN.

Spans in a project’s logs whose span_attributes.type is llm, read through Braintrust’s POST /btql query endpoint. Task, tool, function and eval spans are not imported, and scores and evals are never read.

CredentialsA Braintrust API key, sent as a bearer token
SelectorA project name or project id. --project is required
Hosthttps://api.braintrust.dev, the US data plane, by default. Set BRAINTRUST_BASE_URL for the EU plane (https://api-eu.braintrust.dev) or your own
.env
METERGRAPH_APP_TOKEN=<your ingest key>
BRAINTRUST_API_KEY=<your key>
# BRAINTRUST_BASE_URL=https://api-eu.braintrust.dev
  1. You need the project, by name or by id, and the earliest timestamp worth importing.

  2. metergraphrelay pull braintrust --project my-project \
    --since 2026-08-01T00:00:00Z --output braintrust.jsonl
    SelectorMeaning
    --projectRequired. A name or an id, and repeatable. Projects are queried together
    --since / --untilBound the span’s created time. --since is inclusive, --until is exclusive and defaults to the moment the command started
    -n, --countCaps spans, never traces. Defaults to 100
    --routeOverrides the route on every row. Not a selector
  3. head -n 2 braintrust.jsonl
    metergraphrelay push braintrust.jsonl
  4. Open Traces in Metergraph. Braintrust’s SDK wrappers name LLM spans after the method, so a route reading OpenAI Chat Completion on every row is expected rather than broken. When one project is one workflow, pass --route and pull again.

metergraphrelay sync braintrust --source-scope my-project \
--initial-since 2026-08-01T00:00:00Z --project my-project

Sync takes no --since, --until or -n: the server picks the window, and it is always bounded, so the thirty second timeout is not a concern here. It requires --project and --source-scope, and accepts --initial-since, --max-window-seconds, --route and --allow-skipped.

The full contract is on How ongoing sync works.

FieldWhere it comes from
RouteThe LLM span’s own name, falling back to braintrust/backfill. --route overrides both
TimestampThe span’s created time, kept as the original
Provider and modelInferred from the span
TokensThe span’s metrics, including cache reads, cache writes and reasoning
CostBraintrust’s estimated_cost
LatencyThe span’s own start and end
Statuserror when the span recorded an error, otherwise success
ContentThe span’s input and output, copied verbatim
Tool calls and tool namesExtracted from the span’s output
Trace, span and parent spanThe span’s root span id, span id and first span parent
TagsBraintrust span tags under braintrust_tags, and the project id under braintrust_project_id
  • Environment. Braintrust rows arrive with no environment set, so they fall outside any environment filter in the dashboard.
  • Function attribution, streaming detail, outcomes and repository identity, as on every import path.
  • Task, tool, function and eval spans, scores and evals, which are never read.
SymptomLikely causeWhat to do
The query times outNo --since on a large projectBound every query
Every route is OpenAI Chat CompletionThe SDK wrapper names spans after the methodPass --route
Nothing comes back from an EU projectThe relay is querying the US data planeSet BRAINTRUST_BASE_URL=https://api-eu.braintrust.dev