Blog

Loops are the primitive

July 3, 2026 · 5 min read · markdown

Every telemetry product is built on the same primitives: spans, traces, metrics, logs. Two decades of tooling made those primitives very good at answering one question — what happened? Dashboards, alerts, and trace explorers are all projections of the same idea: collect signals, show them to a human.

But the question a product team actually cares about is different: did we get better? And there is no primitive for that.

The loop everyone runs, and nobody stores

Every serious team already runs an improvement loop. Something fails in production, someone notices, someone diagnoses, a fix ships, and — sometimes — someone checks whether it worked. The loop is real. It's just not represented anywhere.

It lives in heads, Slack threads, and ticket queues. It has no identity, no state, no API. And implicit loops fail in predictable ways:

Observability tools can't fix this, because their data model ends at the human. A span can tell you a tool call timed out nine times. Nothing in the model can tell you that this cluster was diagnosed last Tuesday, that PR #142 claims to fix it, and that the next window will decide whether it did.

What "first-class" actually means

Programming languages have a precise meaning for first-class: a thing is first-class when you can name it, pass it around, store it, and inspect it — when it's a value, not a convention.

Apply that to improvement loops and you get a concrete checklist. In LoopOps:

What falls out when the loop is data

Once the loop is a value instead of a convention, useful properties stop being discipline and start being structure.

Nothing resurfaces silently. The batch cycle claims every unprocessed trace since the last close — the claim is the window. There is no gap between windows for a recurring failure to hide in, and pain that was already fixed and verified doesn't come back as a fresh discovery.

Agents can operate the loop. Because a loop is an addressable object with an API, a coding agent can open one, read the evidence, draft the eval and the patch plan, record each stage, and stop at the approval boundary. This is the part dashboards structurally can't do: a human-first surface makes the human the parsing layer for every trace; a loop-first surface makes the human the approver of every write.

Humans keep the write side. The approval gate isn't a setting bolted onto the loop — it's part of the primitive. Nothing posts an issue, opens a PR, or touches production until a human says so. First-class does not mean autonomous.

The dashboard becomes a projection. The console's Loop tab is honest about what it is: a view over loop.* events, the same rows any agent reads over the API. When the loop is the primitive, every surface — console, report, MCP tool — is just a lens on it.

"But everyone is building self-improving agents"

They are, and that's worth being honest about. Detect-diagnose-fix features are appearing inside the big agent platforms, and they validate the thesis: telemetry should end in improvement, not in a chart.

The difference is representation and ownership. In a platform, the loop is a feature — a background job and a UI workflow that works best when you build on that platform's framework and trace to its store. The loop's state belongs to the platform. In LoopOps, the loop is a data primitive on top of open telemetry: loop.* events any stack can emit over OTLP, runs any agent can read over MCP or plain HTTP. Your improvement history is portable evidence, not a vendor's UI state.

That's the claim behind "loops as first-class primitives." Not that we invented improvement — every good team runs the loop already. It's that the loop deserves the same treatment spans got twenty years ago: a name, a schema, a lifecycle, and an API of its own.

Where this goes

Primitives compound. Once loops are data:

LoopOps is in alpha, and the loop primitive is live today: POST /v1/loops/events records stages, GET /v1/loops reads runs, POST /v1/runs/verify closes them honestly. Point it at your traces and open your first loop — the quickstart takes about five minutes.