Self-hosted · optional dev tooling

Watch your governed agents.

Cendor Monitor — the optional, self-hosted journey view — renders the standard OpenTelemetry your Cendor libraries and SDK already emit as the whole story of every governed run: agents → sessions → runs, the full journey (prompts, responses, thinking, tokens, cost — content opt-in) with governance verdicts inline. It has two doors, one per way of using Cendor — Libraries and SDK, each its own store, never mixed. It runs where your agents run; nothing leaves your infrastructure. This is dev tooling, like cendor-mcp — never "the product".

self-hostedone docker runstandard OTLP inCendor never operates a telemetry endpoint

One wire, two ways to watch it. Cendor emits standard OpenTelemetry — one wire, no Cendor-specific exporter, never a Cendor endpoint. Where it goes is your choice: your own backend (Azure Monitor, CloudWatch, Datadog, Langfuse, any OTLP) for production fleets — or Cendor Monitor, the free, open-source, self-hosted journey view, when you want to see your governed agents in one screen: every prompt, token, dollar, and the exact step where a budget or guardrail acted. Same wire either way; switch or run both without touching code.

The monitor, screen by screen

Real screenshots of the shipped console — captured on v0.14.2 — rendering one real governed run: a keyless, reproducible refunds-triage workload (a stubbed model, one cassette-replayed call), with content capture opted in for it. The monitor ships no sample app and seeds nothing: every screen here is fed by an actual run, so the numbers are that run's. The tag you run below is 0.15.0, which changed the ingest service and the docs — not these screens.

Two doors

Pick a door — Libraries or SDK

The console has two doors, and each is its own store: Libraries for apps that use the libraries directly under their own framework, SDK for apps built on the Cendor agent loop. They never mix — a run lands in exactly one, every setting belongs to exactly one, and the switcher only appears once both have data. Container-level config (auth, gateway forward, backups) lives on its own door-less page, because it is not a door's setting.

Cendor Monitor — Pick a door — Libraries or SDK (dark)Cendor Monitor — Pick a door — Libraries or SDK (light)
Overview

Land on the Overview

The Cendor value strip — blocked projected spend (a budget refused pre-flight, never spent), tokens saved by compression, $0 cassette replays, guardrail blocks — above the fleet tiles (runs, spend, blocks, errors, p50/p95, TTFT), dependency-free trend charts, and cost attribution: top models, top agents, top users by spend, spend by feature. A time-range row + a Go-live toggle sit up top. Recorded numbers only — no ROI math, and each spend surface carries the caveat that says what it does and does not count.

Cendor Monitor — Land on the Overview (dark)Cendor Monitor — Land on the Overview (light)
Drill-down

Agents → Sessions → Runs

A session groups the runs of one multi-turn conversation (auto gen_ai.conversation.id from run(session=…)) — drill from an agent to its sessions to the individual runs, no trace id to paste anywhere. An agent page lists that agent's own runs; where a framework or an Agent(id=…) supplied a real identity, it is shown as identity, never invented.

Cendor Monitor — Agents → Sessions → Runs (dark)Cendor Monitor — Agents → Sessions → Runs (light)
Journey

The run journey — governance inline

The whole conversation for one run — system / user / assistant / thinking / tool args + results — with tokens, cost, latency, and TTFT per step, and the exact step where a budget block, guardrail verdict, or compression fired, shown inline. Content shows only because this run opted in; the rule-6 banner is verbatim. A run's header can no longer disagree with its own body: the governance count it reports is exactly what the journey below lists.

Cendor Monitor — The run journey — governance inline (dark)Cendor Monitor — The run journey — governance inline (light)
Proof

A proof page per library

Seven per-library pages turn the monitor into proof of the libraries — each with a trend, a value tile, and the raw events. Here tokenguard: spend attributed by feature and by user, a blocked-projected-spend tile, and the budget-events table (which budget blocked what — projected vs cap). squeeze's page shows compression events (before/after tokens, metadata only, never text).

Cendor Monitor — A proof page per library (dark)Cendor Monitor — A proof page per library (light)
Governance

The governance stream

Every decision, budget event, and guardrail action as a typed stream with counters, split so the verdicts (what governance decided — blocked, flagged, redacted) come before the trajectory (what the agent did). Runs, Sessions, and Governance share a filter bar (facet dropdowns + free-text + time-range + sort + paging, all deep-linked); the free-text box toggles between metadata and a real indexed content search — over what you opted to store. A live toggle (off by default) refreshes as runs land.

Cendor Monitor — The governance stream (dark)Cendor Monitor — The governance stream (light)
Libraries door

The other door — libraries, no SDK

An app that never touches the SDK still gets its own overview, its calls grouped the way core.trace() grouped them (one scope is one trace, with numbered steps), its governance, its models, and the same seven proof pages. Agent vocabulary appears here only when a framework adapter actually attached an agent — a plain libraries app sees none, rather than a placeholder.

Cendor Monitor — The other door — libraries, no SDK (dark)Cendor Monitor — The other door — libraries, no SDK (light)
Settings

Config, per door

A read-only reference of how this door is configured — theme, retention, storage backend, content-capture status, CSV caps — where every value names the exact environment variable behind it. A door's Settings never shows a value that also governs the other door.

Cendor Monitor — Config, per door (dark)Cendor Monitor — Config, per door (light)
Container

The container, on its own page

The settings that belong to the container rather than to either door — basic auth, the gateway forward, the host port, the chrome theme, backup and upgrade — plus a docker-run / compose builder and per-door status. Secrets (the Postgres DSN, auth password, forward URL) are never shown.

Cendor Monitor — The container, on its own page (dark)Cendor Monitor — The container, on its own page (light)

Watch the walkthrough

The whole loop in about two minutes — one docker run, a keyless governed run exports standard OpenTelemetry, and the journey view renders it. On your own machine.

Watch your governed agents — Cendor Monitor
Watch your governed agents — Cendor Monitor

60 seconds to a local monitor

Run the container, point your app's OpenTelemetry pipeline at it, open localhost:3000.

No login, no key: the image is public and multi-arch (linux/amd64 + linux/arm64). The libraries and the SDK need none of it — they emit standard OTLP to whatever backend you already have.

docker run --rm -p 3000:3000 -p 4317:4317 -p 4318:4318 -v cendor-monitor-data:/data ghcr.io/cendorhq/cendor-monitor:0.15.0
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
export OTEL_SERVICE_NAME=support-bot

Then attach the emitters you already know: use_sink(OTelSink()) (spend), live_spans() (trajectory), AuditLog(mirror=OTelMirror()) (governance). To see prompts/responses/thinking in the journey, opt in with otel.capture_content() (OFF by default). See the Cendor Monitor docs and the Observability guide. Use an embedded SQLite store by default, or point CENDOR_MONITOR_DB at Postgres for a team deploy. Set CENDOR_MONITOR_FORWARD_ENDPOINT and the same image doubles as a prod gateway (content stripped from the forward unless you opt in).

What it is — and what it isn't

It isIt is not
A self-hosted monitor you runA hosted Cendor service — Cendor never operates a telemetry endpoint
Standard OTLP in (one env var)A Cendor-specific exporter, API, or key in your app
An operational copy of the audit streamThe evidence — verify() runs on the audit file, never on the monitor
Content only when you opt in (off by default)A capture that the monitor turns on for you
Optional dev tooling — your own OTel backend stays the production defaultA dependency of any library, or a replacement for your production backend

An operational copy — not evidence

The governance views show an operational copy of your audit stream, for monitoring and alerting. The tamper-evident, hash-chained audit file on your app host is the only verifiable artifact — run verify() against that file. Nothing here is a "verified ✓" badge or a compliance attestation. And content lands only where your OTLP goes — Cendor never receives it. The screenshots above are from a real run: the monitor ships no sample app and fabricates nothing, so an empty console means nothing has been sent yet — not that it is broken.

Licensing — a permissive aggregate

The v0.15.0 image — the tag above — is Apache-2.0 (code) with OFL-1.1 fonts — every part is permissive, and there's no AGPL/GPL, so running it triggers no copyleft or source-disclosure obligation.

ComponentLicense
Cendor's monitor UI · ingest service · configsApache-2.0
OpenTelemetry Collector (bundled)Apache-2.0
Node.js runtimeMIT
nginxBSD-2-Clause
Manrope + JetBrains Mono (vendored fonts)SIL OFL-1.1

Obligations are light — keep the bundled notices (shipped at /licenses, font texts at /licenses/fonts). The OFL fonts may not be sold on their own and must be renamed if you modify + redistribute them. Trademarks belong to their owners.