# Getting started (/docs/getting-started)



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 obs-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 [#choose-how-to-run]

| Runtime path                 | Use when                                                                           | Starts                                                                                                                                                          |
| ---------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Option 1 — Docker image**  | You 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 install** | You 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 [#choose-what-to-observe]

| Data path               | Use when                                                       | Start here                                                      |
| ----------------------- | -------------------------------------------------------------- | --------------------------------------------------------------- |
| **Seeded sample data**  | You want populated dashboards immediately.                     | Built into Option 1, or run `pnpm run seed` with Option 2.      |
| **Astronomy Shop demo** | You want realistic microservice traffic and service-map edges. | Run the OpenTelemetry demo against your local collector.        |
| **Your own app**        | You want to validate obs-unified against a real application.   | Add SDKs or OpenTelemetry exporters pointing at your collector. |

## Prerequisites [#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 [#option-1--docker-image]

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

### Prebuilt image from GHCR [#prebuilt-image-from-ghcr]

No clone needed. The release image is published as
[`ghcr.io/dev-sawan-ruparel/obs-unified`](https://github.com/users/dev-sawan-ruparel/packages/container/package/obs-unified)
and fails closed without your own credentials:

```bash
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:latest
```

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-the-local-image-with-sample-data]

Build and run from the personal monorepo:

```bash
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:

```bash
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:

| Interface        | URL                     |
| ---------------- | ----------------------- |
| Dashboard        | `http://localhost:5173` |
| Collector ingest | `http://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.

```bash
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](/docs/installation)):

| Credential         | Environment Variable               | Local image value     |
| ------------------ | ---------------------------------- | --------------------- |
| Ingest write key   | `INGEST_KEY` / `OBS_INGEST_KEY`    | `dev-ingest-key`      |
| Dashboard password | `DASHBOARD_PASSWORD`               | `e2e-test-pass`       |
| Read bearer token  | `DASHBOARD_TOKEN` on the collector | `e2e-dashboard-token` |

#### Tokens and env vars [#tokens-and-env-vars]

| Where              | Variable                           | Purpose                                                                                                                                                  |
| ------------------ | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Collector          | `INGEST_KEY`                       | Write-only key that SDKs and exporters present to ingest telemetry.                                                                                      |
| Collector          | `DASHBOARD_PASSWORD`               | Browser login for the dashboard (`POST /auth/login`).                                                                                                    |
| Collector          | `DASHBOARD_TOKEN`                  | Read bearer token for `/internal/*`, the CLI, and MCP.                                                                                                   |
| Client (CLI, MCP)  | `OBS_DASHBOARD_TOKEN`              | Canonical 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_TOKEN` | Aliases for `OBS_DASHBOARD_TOKEN` (verified against CLI 1.1.3 with `doctor`, `keys list`, and `changes list`).                                           |
| Client (SDKs, CLI) | `OBS_INGEST_KEY`                   | The 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:

```bash
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:

```bash
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 [#option-2--local-install]

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

```bash
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:

| Service   | URL                     |
| --------- | ----------------------- |
| Dashboard | `http://localhost:5173` |
| Demo API  | `http://localhost:8787` |
| Collector | `http://localhost:8790` |

## Seeded sample data [#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.

```bash
pnpm run seed
```

Expected result: Traces, Logs, AI Calls, Usage, and Issues show sample data. Replays require browser interaction, so open the dashboard's Playground tab and trigger a replay-producing interaction once.

## Astronomy Shop demo [#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 obs-unified collector.

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

```bash
pnpm dev:collector
```

Prepare the upstream demo services:

```bash
pnpm demo:setup
pnpm demo:preflight
```

Launch the microservices:

```bash
pnpm demo:up
```

Access URLs:

| Interface          | URL                     |
| ------------------ | ----------------------- |
| Dashboard          | `http://localhost:5173` |
| Shop web interface | `http://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:

```bash
pnpm demo:down
```

## Your own app [#your-own-app]

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

| Target                         | Setup guide                                                    |
| ------------------------------ | -------------------------------------------------------------- |
| React/Vite frontend + Hono API | [React + Hono walkthrough](/docs/instrumenting)                |
| Python Flask API               | [Python Flask walkthrough](/docs/instrument-python-flask)      |
| Browser-only application       | [Analytics SDK reference](/docs/sdks#obs-unifiedanalytics-sdk) |
| TypeScript backend             | [Telemetry SDK reference](/docs/sdks#obs-unifiedtelemetry-sdk) |
| Polyglot recipes               | [Examples](/docs/examples#language-recipes)                    |

### Application compatibility & signal matrix [#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:

| Tier                                         | Application shape                                                                                                                                                               | Supported signals                                                                                                                                                                                                                       | Notes & constraints                                                                                                                                                                                                                                                                                                                                                                                                         |
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Tier 1 — Full First-Party Unified Stack**  | Browser 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 services | Traces, 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 Flags                                   | Full out-of-the-box correlation via `@obsunified/analytics-sdk`, `@obsunified/telemetry-sdk`, `@obsunified/sdk`, `sdks/go`, and `sdks/rust`.                                                                                                                                                                                                                                                                                |
| **Tier 2 — Standard OpenTelemetry Backends** | Python (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 Shapes**   | **Native Mobile** (iOS, Android, React Native, Flutter)<br />**Headless / CLI / Cron**<br />**Async Message Queues** (Kafka, SQS, RabbitMQ, BullMQ)<br />**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).<br />&#x2A;*Queues:** Producer must propagate `traceparent` / `x-obs-interaction` / `x-obs-action-id` in message headers or consumer spans appear as disconnected roots.<br />&#x2A;*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 [#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:

```bash
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`.

3. Configure `OBS_COLLECTOR_URL` and a write-only ingest key (`INGEST_KEY`).
4. 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).
5. Verify connectivity and CORS headers:

```bash
pnpm dlx @obsunified/cli doctor http://localhost:8790 --origin http://localhost:3000
```

## Autonomous AI agent setup & verification playbook [#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://obsunified.com/llms.txt), [`https://docs.obsunified.com/llms.txt`](https://docs.obsunified.com/llms.txt), or [`https://docs.obsunified.com/llms-full.txt`](https://docs.obsunified.com/llms-full.txt), or install the prebuilt `.skill` bundles from the [`skills-v0.1.4` release](https://github.com/dev-sawan-ruparel/obs-unified/releases/tag/skills-v0.1.4).
* **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`); it only reads, so do not give it the ingest key — see [MCP Server](/docs/mcp-server).

### What is autonomous vs. what requires human intervention [#what-is-autonomous-vs-what-requires-human-intervention]

| Phase                             | What the AI agent does autonomously                                                                                                                                         | When human intervention is needed                                                                                                                                                                                                                    |
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **1. Discovery & stack fit**      | Inspects 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 startup**          | Checks `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.<br />• For **production cloud deploys** requiring interactive OAuth (`wrangler login`), DNS setup, or cloud billing/account selection.                                           |
| **3. Code instrumentation & env** | Scaffolds 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).<br />• Confirming privacy consent before enabling continuous DOM recording (`startReplay()`) in production. |
| **4. End-to-end verification**    | Starts 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 operations**   | Registers `@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 [#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:

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