Observability Unified

Getting started

Start the collector with sample data, investigate a seeded slow checkout through MCP and the dashboard, then connect your own app.

This guide gets you from a fresh checkout to unified observability in the dashboard. The goal is not just to send a trace or a log; it is to see multiple signal types connected through the same collector and identity chain. There are two decisions:

  1. How do you want to run Observability Unified? Use the all-in-one Docker image, or install and run the repo locally.
  2. What data do you want to look at? Use seeded sample data, the Astronomy Shop demo, or telemetry from your own app.

Choose how to run

Runtime pathUse whenStarts
Option 1 — Docker imageYou want the quickest first run with the fewest host dependencies.Postgres, collector, dashboard, and filesystem blob store in one container: pull the prebuilt image from GHCR, or build the local image to include sample data.
Option 2 — local installYou want to edit code, run dev servers, or inspect internals while using the repo.Local collector, demo API, and Vite dashboard from the workspace.

Choose what to observe

Data pathUse whenStart here
Seeded sample dataYou want populated dashboards immediately.Built into Option 1, or run pnpm run seed with Option 2.
Astronomy Shop demoYou want realistic microservice traffic and service-map edges.Run the OpenTelemetry demo against your local collector.
Your own appYou want to validate Observability Unified against a real application.Add SDKs or OpenTelemetry exporters pointing at your collector.

Prerequisites

  • Docker: required for the Docker image and Astronomy Shop demo.
  • Node.js 22+ and pnpm 10+: required for local install and repo scripts.

Option 1 — Docker image

This packages the full local stack into one container. It is the lowest-friction first run.

Prebuilt image from GHCR

No clone needed. The release image is published as ghcr.io/dev-sawan-ruparel/obs-unified and fails closed without your own credentials:

export INGEST_KEY="pick-a-long-random-ingest-key"
export DASHBOARD_PASSWORD="pick-a-dashboard-password"
export DASHBOARD_TOKEN="pick-a-read-token-for-mcp-and-cli"

docker run --rm \
  -p 5173:5173 \
  -p 8790:8790 \
  -e INGEST_KEY \
  -e DASHBOARD_PASSWORD \
  -e DASHBOARD_TOKEN \
  -e OBS_LOCAL_SEED=true \
  -v obs-unified-db:/var/lib/postgresql \
  -v obs-unified-blobs:/data \
  ghcr.io/dev-sawan-ruparel/obs-unified:2.4.3

Dashboard at http://localhost:5173, collector at http://localhost:8790. Passing -e OBS_LOCAL_SEED=true populates all demo scenarios (traces, logs, AI calls, Agent Action Graph, and AutoSRE Scenario D) immediately on first boot; omit it when you want an empty collector for Astronomy Shop or your own app.

Build the local image with sample data

Build and run from the personal monorepo:

git clone https://github.com/dev-sawan-ruparel/obs-unified.git
cd obs-unified
pnpm install --frozen-lockfile
pnpm local:image
pnpm local:run

Or use Docker directly:

docker build -f Dockerfile.local -t obs-unified/local:dev .
docker run --rm -p 5173:5173 -p 8790:8790 obs-unified/local:dev

Access the interfaces:

InterfaceURL
Dashboardhttp://localhost:5173
Collector ingesthttp://localhost:8790

To log in from a script, POST the dashboard password and keep the obs_session cookie. Logout only clears the browser cookie; the signed session stays valid until it expires (7 days) or DASHBOARD_PASSWORD is rotated.

curl -i -X POST http://localhost:5173/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"password":"<DASHBOARD_PASSWORD>"}'
# set-cookie: obs_session=...; HttpOnly; SameSite=Strict; Max-Age=604800

Credentials for the locally built image (pnpm local:run only; the prebuilt GHCR image rejects these values and requires your own, see Installation):

CredentialEnvironment VariableLocal image value
Ingest write keyINGEST_KEY / OBS_INGEST_KEYdev-ingest-key
Dashboard passwordDASHBOARD_PASSWORDe2e-test-pass
Read bearer tokenDASHBOARD_TOKEN on the collectore2e-dashboard-token

Tokens and env vars

WhereVariablePurpose
CollectorINGEST_KEYWrite-only key that SDKs and exporters present to ingest telemetry.
CollectorDASHBOARD_PASSWORDBrowser login for the dashboard (POST /auth/login).
CollectorDASHBOARD_TOKENRead bearer token for /internal/*, the CLI, and MCP.
Client (CLI, MCP)OBS_DASHBOARD_TOKENCanonical name for the value of the collector's DASHBOARD_TOKEN. Accepted by the CLI (doctor, keys, changes list), and @obsunified/mcp-server.
Client (CLI)OBS_ADMIN_TOKEN, OBS_API_TOKENAliases for OBS_DASHBOARD_TOKEN (verified against CLI 1.1.3 with doctor, keys list, and changes list).
Client (SDKs, CLI)OBS_INGEST_KEYThe collector's INGEST_KEY, used by the SDKs and obs-unified changes record (OBS_API_KEY is also accepted by the CLI).

To persist local database and blob storage state across container restarts:

docker volume create obs-unified-local-db
docker volume create obs-unified-local-blobs
docker run --rm \
  -p 5173:5173 \
  -p 8790:8790 \
  -v obs-unified-local-db:/var/lib/postgresql \
  -v obs-unified-local-blobs:/data \
  obs-unified/local:dev

Verify the full first-run path:

pnpm smoke:local-image

The smoke test builds the image, boots a fresh container, seeds data, and verifies collector health, dashboard HTML, and login from outside Docker.

Option 2 — local install

Use this when you are modifying dashboard code, collector code, or SDK packages.

git clone https://github.com/dev-sawan-ruparel/obs-unified.git
cd obs-unified
pnpm install
pnpm run setup
pnpm run dev

pnpm run setup creates apps/collector/.dev.vars from apps/collector/.dev.vars.example if needed, then runs local migrations. If you change the local dashboard password or ingest key later, pnpm run seed reads the same file automatically.

The local dev stack exposes:

ServiceURL
Dashboardhttp://localhost:5173
Demo APIhttp://localhost:8787
Collectorhttp://localhost:8790

Seeded sample data

Use this when you want populated dashboards immediately.

  • Docker image: sample data is seeded automatically on startup.
  • Local install: run the seeder in a second terminal.
pnpm run seed

Investigate a slow checkout

The seed includes one slow checkout among many ordinary ones. Use the 2.4.3 image from the Docker command above, or a newer release, with OBS_LOCAL_SEED=true. The seed places the request about two minutes before the first start that used your storage volumes. Restarting with the same volumes keeps that original request and does not add a second copy of its evidence. If you come back later, widen the dashboard time range and tell the agent when you first started the container. Agents' trace searches default to the last 24 hours, and the collector keeps data for 72 hours by default. If you ran an earlier image with the same volumes, remove them first with docker volume rm obs-unified-db obs-unified-blobs.

  1. Connect an AI agent using the MCP setup. Optionally install the investigate-obs-unified skill from the skills release. Configure the collector's read/admin bearer token and leave OBS_MCP_ENABLE_WRITES unset to use the default read-only tool set. The setting controls tool registration and the token retains its collector permissions.
  2. Ask the agent, in your own words: “A checkout request in checkout-api (POST /api/checkout) was slow around the time I started the container. Where did it spend its time, and what does the evidence say about why? Cite the IDs and give me the dashboard link.”
  3. The agent should find the 980 ms request and report that the payment.charge span covers 710 ms, about 72% of the request. Its evidence bundle cites two payment logs and a CPU profile indexed to the trace. A warning log records a 2.4 MB provider response, logged from packages/payments/src/charge.ts:47. In the profile frames, JSON.parse accounts for 410 ms of the 480 ms of sampled CPU under payment.charge. Frame values are inclusive, so checkout.handle is listed first.
  4. Open the agent's link, or open Onboarding → Find the seeded checkout. Expand the 980 ms request and compare the trace and span IDs. Select the payment.charge span to see both payment logs under Logs in this trace in the Connected Rail. Use the Profile checkout-api/cpu button in the trace detail to open the profile.

The seeded finding is complete when both paths cite the same trace, payment span, warning log, and profile. Together they support parsing a large provider response as the leading explanation for the slow payment step. This is a synthetic fixture. In your own incidents, treat the same combination as a cited hypothesis to confirm in code.

If the agent needs more direction

Ask it to call recent_traces for checkout-api with the operation as the text query, a limit of 500, and hours covering your first start, then pick the slowest request in your window. The seed adds about 100 ordinary checkout requests, so the default limit of 30 can miss it. Then call get_evidence_bundle with intent explain_latency and expand the evidence.bundle.profile_frames retrieval ref with retrieve_evidence_ref.

For your own telemetry, start in Traces and substitute a service, operation, and time window from your incident.

Astronomy Shop demo

Use this when you want realistic microservice traffic and service-map edges. It runs the official OpenTelemetry Astronomy Shop demo and points its exporters at your local Observability Unified collector.

This path assumes the collector is already running. For local development, start it with:

pnpm dev:collector

Prepare the upstream demo services:

pnpm demo:setup
pnpm demo:preflight

Launch the microservices:

pnpm demo:up

Access URLs:

InterfaceURL
Dashboardhttp://localhost:5173
Shop web interfacehttp://localhost:8080

The load generator takes roughly 30 seconds to begin driving traffic. Once running, Traces, Service Maps, Issues, Logs, and Metrics populate dynamically from active microservice calls.

Stop and remove the compose stack:

pnpm demo:down

Your own app

This is a data path that sends telemetry to whichever collector you started above.

TargetSetup guide
React/Vite frontend + Hono APIReact + Hono walkthrough
Python Flask APIPython Flask walkthrough
Browser-only applicationAnalytics SDK reference
TypeScript backendTelemetry SDK reference
Polyglot recipesExamples

Application compatibility & signal matrix

Before instrumenting an application (or when an AI agent scouts your repository), use this matrix to verify which signals are supported for your architecture:

TierApplication shapeSupported signalsNotes & constraints
Tier 1 — Full First-Party Unified StackBrowser SPAs & SSR web apps (React, Next.js, Vite, Vue, Svelte, Vanilla TS/JS) + TypeScript/Node/Edge backends (Cloudflare Workers, Hono, Express, Fastify) or Go/Rust servicesTraces, Structured Logs, Metrics, Usage Events, rrweb DOM Session Replay, Click-to-Trace (x-obs-interaction), AI Calls, Agent Action Graph, CPU Profiles, AutoSRE Release Lineage & Feature FlagsFull out-of-the-box correlation via @obsunified/analytics-sdk, @obsunified/telemetry-sdk, @obsunified/sdk, sdks/go, and sdks/rust.
Tier 2 — Standard OpenTelemetry BackendsPython (Flask, FastAPI, Django), Java/Kotlin (Spring Boot), .NET, Ruby, PHP, C++OTLP HTTP Traces (/v1/traces), Logs (/v1/logs), Metrics (/v1/metrics), plus HTTP JSON ingest for AI Calls (/v1/ai), Agent Action Graph (/v1/actions, /v1/agent-runs, /v1/tool-calls), and Release Changes (/v1/changes)Supports both OTEL_EXPORTER_OTLP_PROTOCOL=http/json and http/protobuf (with optional gzip). For browser click-to-trace correlation, read the incoming x-obs-interaction HTTP header and set span attribute obs.interaction.id.
Tier 3 — Partial or Constrained ShapesNative Mobile (iOS, Android, React Native, Flutter)
Headless / CLI / Cron
Async Message Queues (Kafka, SQS, RabbitMQ, BullMQ)
gRPC-only OTLP
Backend traces, logs, metrics, AI calls, and Action Graph (startAgentRun({ agentId, agentName, ... }, fn))Native mobile: No rrweb session replay (requires browser DOM).
Queues: Producer must propagate traceparent / x-obs-interaction / x-obs-action-id in message headers or consumer spans appear as disconnected roots.
gRPC OTLP: Collector endpoints speak HTTP (application/json and application/x-protobuf); place an OTel Collector gateway in front if agents only emit gRPC.

Common wiring & non-interactive scaffolding

  1. Deploy or run an accessible collector endpoint.
  2. Scaffold a pre-wired template (supports non-interactive flags for CI and AI agents) or install the SDKs into an existing app:
pnpm dlx @obsunified/cli create my-app \
  --template react-vite \
  --collector-url http://localhost:8790 \
  --yes

Available --template (-t) values: react-vite, vanilla-ts, hono-workers.

  1. Configure OBS_COLLECTOR_URL and a write-only ingest key (INGEST_KEY).
  2. Ensure API CORS policies allow x-obs-interaction and your app's local dev origin (the Docker images allow localhost / 127.0.0.1 on ports 5173, 5174, and 3000 by default; add more with -e ALLOWED_ORIGINS="http://localhost:5173,http://localhost:4173", a comma-separated list that replaces the default).
  3. Verify connectivity and CORS headers:
pnpm dlx @obsunified/cli doctor http://localhost:8790 --origin http://localhost:3000

Autonomous AI agent setup & verification playbook

If you are an AI coding agent (Claude Code, Cursor, Codex, Antigravity, Windsurf) tasked with setting up Observability Unified for a user:

  • Machine-readable documentation: Fetch https://obsunified.com/llms.txt, https://docs.obsunified.com/llms.txt, or https://docs.obsunified.com/llms-full.txt, or install the prebuilt .skill bundles from the skills-v0.1.5 release.
  • Step 1 (Assess fit): Inspect the user's package.json, pyproject.toml, go.mod, or Cargo.toml against the Application compatibility & signal matrix above. Report clearly to the user which signals are supported and call out any Tier 3 constraints before editing code.
  • Step 2 (Boot collector & verify): Start the GHCR container with INGEST_KEY, DASHBOARD_PASSWORD, and DASHBOARD_TOKEN set, then run pnpm dlx @obsunified/cli doctor http://localhost:8790 --origin <user-app-origin>.
  • Step 3 (Instrument without blocking on TTY prompts): Always pass --yes (-y) and --template when running pnpm dlx @obsunified/cli create. When instrumenting Cloudflare Workers or Hono, register app.use("*", async (c, next) => { await next(); c.executionCtx.waitUntil(flushSpans()); }).
  • Step 4 (Verify ingestion end-to-end): Trigger a test request or record a release change (pnpm dlx @obsunified/cli changes record --url http://localhost:8790 --api-key $INGEST_KEY --service my-api --version 0.1.0 --environment <env> --summary "Agent onboarding verification"; --environment defaults to default, so pass the environment your instrumented service reports), then confirm non-zero telemetry with pnpm dlx @obsunified/cli changes list --url http://localhost:8790 --token $DASHBOARD_TOKEN and curl -fsSL -H "Authorization: Bearer $DASHBOARD_TOKEN" http://localhost:8790/internal/telemetry/overview.
  • Step 5 (Connect MCP server): Configure @obsunified/mcp-server with OBS_COLLECTOR_URL and OBS_DASHBOARD_TOKEN ($DASHBOARD_TOKEN). The collector treats this as a read/admin bearer token. Leave OBS_MCP_ENABLE_WRITES unset for read-only MCP tools. See MCP server configuration.

What is autonomous vs. what requires human intervention

PhaseWhat the AI agent does autonomouslyWhen human intervention is needed
1. Discovery & stack fitInspects repo manifests (package.json, pyproject.toml, go.mod, Cargo.toml) against the 3-Tier Compatibility Matrix.Only if the app has Tier 3 constraints (e.g., native mobile without browser DOM for rrweb replay, or unpropagated message queues) and needs scope confirmation.
2. Collector startupChecks docker info, boots ghcr.io/dev-sawan-ruparel/obs-unified:latest on 5173/8790 with credentials it generates, and runs pnpm dlx @obsunified/cli doctor.• If Docker Desktop is stopped or not installed on the machine.
• For production cloud deploys requiring interactive OAuth (wrangler login), DNS setup, or cloud billing/account selection.
3. Code instrumentation & envScaffolds with pnpm dlx @obsunified/cli create --yes or installs SDKs, wires middleware (flushSpans()), and populates .env.local / .dev.vars + .env.example.• Adding encrypted production secrets in remote CI/CD or hosting providers (Vercel, Netlify, GitHub Actions, Cloudflare Worker secrets).
• Confirming privacy consent before enabling continuous DOM recording (startReplay()) in production.
4. End-to-end verificationStarts the app server, fires synthetic HTTP requests, captures x-obs-trace-id, and queries GET /internal/telemetry/overview (Authorization: Bearer $DASHBOARD_TOKEN).Only if verifying visual rrweb DOM replay when the agent has no headless browser tool (human clicks once in a real browser tab).
5. MCP & AutoSRE operationsRegisters @obsunified/mcp-server, investigates traces/logs/blast radius, and proposes governed remediations.Approving pending_human_approval remediation proposals in the dashboard when causal proof is below cohort isolation or counterfactual verification.

Standalone Node collector variant

The all-in-one Docker image is the recommended first-run Docker path. If you only want the collector service backed by Postgres and RustFS/S3, use the standalone Node collector:

cd apps/collector-node
docker compose up -d
docker compose logs -f collector

On this page