otel
Export Treeship artifacts as OpenTelemetry spans.
Hidden from --help. otel is implemented and shipped -- otel is a default Cargo feature (on unless built with --no-default-features), and the command is additionally hidden from the top-level list as a UX choice.
Treeship can export every artifact as an OpenTelemetry (OTLP) span, letting you visualize agent workflows in any observability tool that speaks OTLP.
In the default build
OpenTelemetry export is part of the standard treeship binary since 0.31.6: the one npm install -g treeship and curl -fsSL https://www.treeship.dev/install | sh fetch, and a plain cargo build -p treeship-cli. Nothing is exported until TREESHIP_OTEL_ENDPOINT is set, so a machine without that variable behaves exactly as before.
A binary built with cargo build -p treeship-cli --no-default-features leaves it out, and every treeship otel command then says so:
otel export is not compiled into this binary (built with --no-default-features)Do NOT use cargo install treeship-cli from crates.io. It does not install an old
version -- it fails: all seven published versions are yanked, so crates.io reports
max_version: 0.0.0 and cargo answers could not find treeship-cli in registry.
The CLI ships exclusively via the npm wrapper (npm install -g treeship) and the treeship.dev/install script, which fetch a prebuilt platform binary. To get a Rust toolchain build, clone the repo and cargo build -p treeship-cli.
Commands
treeship otel test
Verify OTLP connectivity by sending a test span to the configured endpoint.
treeship otel test sending test span...
✓ connected
endpoint: http://localhost:4318
service: treeship
sent 1 test spantreeship otel status
Show the current OpenTelemetry configuration.
treeship otel statusotel
endpoint: http://localhost:4318
service: treeship
enabled: true
auth: noneWith TREESHIP_OTEL_ENDPOINT unset it prints otel not configured and the export line to set.
treeship otel export <id>
Export a single artifact as an OTLP span.
treeship otel export art_f8e2a1b3c4d5e6f7✓ exported
artifact: art_f8e2a1b3c4d5e6f7
endpoint: http://localhost:4318The span's traceId is derived from the artifact id, so the same artifact always lands in the same trace.
treeship otel enable / disable
Export is controlled by environment variables, not by stored state. These two commands print the variables to set; they change nothing on disk.
treeship otel enable
treeship otel disableAuto-export behavior
When TREESHIP_OTEL_ENDPOINT is set and TREESHIP_OTEL_ENABLED is not 0 or false:
treeship wrap -- <cmd>exports one span for the action receipt after the command finishes.treeship session closeexports one span for thesession.closeartifact. The per-action receipts inside the session are not re-exported at close;wrapalready exported its own, and any artifact can be sent withtreeship otel export <id>.
Export is best-effort with a five-second timeout per request. A collector that is down or slow never fails wrap or session close; the receipt is sealed first, the export is attempted afterwards, and a failure is printed as a dim note.
Environment variables
| Variable | Description | Default |
|---|---|---|
TREESHIP_OTEL_ENDPOINT | OTLP/HTTP endpoint; spans go to <endpoint>/v1/traces | unset, which means no export |
TREESHIP_OTEL_AUTH | Full Authorization header value, for example Bearer … | (none) |
TREESHIP_OTEL_SERVICE | service.name resource attribute | treeship |
TREESHIP_OTEL_ENABLED | 0 or false disables export without unsetting the endpoint | enabled |
Span attributes
The span name is the receipt's action (or its predicate type when there is no action). traceId is derived from the artifact id; spanId is random per export. The start time is the receipt's signed_at, and the end time adds meta.elapsedMs when the receipt carries it.
| Attribute | When | Example |
|---|---|---|
treeship.artifact_id | always | art_f8e2a1b3c4d5e6f7 |
treeship.type | always | treeship/action/v1 |
treeship.signed | always | true |
treeship.key_id | always | key_945abaa2ecb76f56 |
treeship.actor | the statement names an actor | agent://ci-runner |
treeship.parent_id | the receipt has a parent | art_c4d5e6f7a1b2c3d4 |
treeship.verify_url | the artifact was pushed to a hub | https://hub.treeship.dev/a/art_… |
treeship.exit_code | wrap receipts | 0 |
treeship.output_digest | wrap receipts | sha256:a1b2c3d4… |
treeship.files_modified | wrap receipts with a git diff | 3 |
treeship.git_before / treeship.git_after | wrap receipts inside a git repo | 4bf92f35… |
treeship.session_id | the receipt was minted inside a session | ssn_42e740bd9eb238f6 |
treeship.approval_nonce | the action consumed a signed approval | nonce_… |
The resource carries service.name from TREESHIP_OTEL_SERVICE.
Compatible backends
Works with any backend that accepts OTLP over HTTP:
- Jaeger (local development)
- Honeycomb
- Datadog
- Langfuse (LLM observability)
- Arize Phoenix (LLM tracing)
- Grafana Tempo
Quick start with local Jaeger
# Start Jaeger with OTLP support
docker run -d -p 4318:4318 -p 16686:16686 jaegertracing/all-in-one
# Point Treeship at it
export TREESHIP_OTEL_ENDPOINT=http://localhost:4318
# Verify connectivity
treeship otel test
# Run a command -- span is exported automatically
treeship otel enable
treeship wrap -- npm test
# Open Jaeger UI to see the span
# http://localhost:16686For Honeycomb or Datadog, set TREESHIP_OTEL_AUTH to your API key and TREESHIP_OTEL_ENDPOINT to the vendor's OTLP ingest URL.