Release
Announcing Toise 0.9.0 — strict spec alignment and read-surface security
Toise still starts the same way: one binary, no config — point your OTLP producers at it and the graph appears. 0.9.0 does not touch that. It sharpens two things instead: the fidelity of what Toise records from the OpenTelemetry entity-events wire, and the control you have over who authenticates on which surface. Everything is additive.
This is a small, precise release. Its point is that the graph an LLM reads should be a faithful mirror of what your producers actually reported — no quietly dropped structure, no lost intent — and that exposing the read surfaces should not force a posture onto ingest. It is not a wire-contract break and needs no data migration; a 0.8 deployment upgrades in place.
Faithful to the entity-events spec
The OpenTelemetry spec types entity.description as an
AnyValue — scalars, arrays, or nested maps. Earlier Toise
kept only the four scalar kinds and dropped the rest. 0.9.0 ingests the
full AnyValue end to end (ingest, store, projection,
GraphQL and MCP): an array or a nested map survives intact and renders on
read as compact JSON tagged array / kvlist.
Identity stays scalar by contract — exact-match identity
is over scalar strings, so entity.id is still a flat map and
a nested value there is surfaced, never hashed.
Two more alignments round it out. A delete can now carry
entity.delete.reason — an open enum
(terminated, expired, evicted, …,
never checked against a closed set) — captured, persisted, and surfaced on
recent_changes, graph_diff, and the GraphQL
ChangeEvent.deleteReason, so a consumer can tell a graceful
shutdown from an eviction. And entity.report.interval == 0
(or absent) now means "no cadence": such an entity is removed only
by an explicit entity.delete, never expired by the liveness
sweep — a distinction now locked by a conformance test.
Decoupled ingest and read authentication
Until now, configuring any token armed both surfaces: protecting
GraphQL and MCP with tokens also made OTLP ingest demand a bearer. But
when producers already authenticate by mutual TLS, that
bearer is redundant. The new opt-in ingest_mtls_only
(TOISE_INGEST_MTLS_ONLY, requires a client-CA) separates the
two: ingest is authenticated by the verified client certificate alone,
while the read surfaces keep requiring their per-client scoped tokens
(role read / full, individually revocable) or OIDC. Off by default; the
bearer-on-ingest posture is unchanged.
Also — a reconciliation fix and a security bump
Out-of-order edges are parked until their endpoint arrives. If the endpoint reappeared on a slower cadence than the buffer window — a host re-announced every few minutes while the buffer expired in seconds — the edge could be dropped just before its next heartbeat, leaving a service momentarily detached from its host. 0.9.0 holds a parked edge for at least one of the source's re-emit cycles, so the endpoint's next heartbeat attaches it; the hold auto-scales from the reported interval. Separately, the Go toolchain is pinned to 1.26.4, clearing three reachable standard-library advisories.
Get it
go install github.com/toise-dev/toise/cmd/toise-server@v0.9.0
Binaries for linux and darwin (amd64 / arm64) are on the
release,
each with a checksum. See the
0.9.0 docs, the
0.8 → 0.9 migration guide,
and the
changelog.
Producers using the SDK can pick up the new fidelity with
pkg/emit/v0.3.0.