tsirysndr/otelview-skills/otelview-operate
Claude Code and agent skill by tsirysndr/otelview-skills
- community
Checking that the SKILL.md file is still in the repository.
Run and configure an otelview instance — choosing a storage backend (memory, duckdb, jaeger, remote), setting retention, securing OTLP ingest and the query API with tokens, enabling and locking down the MCP endpoint, deploying with Docker, systemd or Nix, and composing instances so one otelview stores for another. Use when asked to deploy, configure, secure, size or troubleshoot an otelview server rather than to query or instrument one.
Install
npx vskill@latest install tsirysndr/otelview-skills/otelview-operateSKILL.md
Running an otelview
One binary, four processes' worth of job: OTLP receivers on :4317 (gRPC) and :4318 (HTTP), storage, the web UI and query API on :4319, and an MCP endpoint at /mcp on that same port. No cluster, no JVM, no sidecar.
--print-config is the honest source of truth for what a version accepts. Reach for it before writing config from memory.
Configuration
YAML or TOML, decided by the file extension. Every field is optional, so a config only needs what differs from the defaults:
ui.listen defaults to 127.0.0.1, so nothing is reachable from another machine until you say 0.0.0.0 — and the moment you do, read Securing it before anything else.
Choosing a backend
| Backend | Use it when | |
|---|---|---|
memory | Local work, CI, a demo. Bounded ring buffers; gone on restart. | |
duckdb | Anything you want to keep. One file, analytical, fast, embedded. | |
jaeger | Traces already live in a Jaeger v2 remote-storage backend. | |
remote | Another otelview holds all three signals; this one is just a face. |
duckdb is the default answer. It is linked statically from the official release binaries, so there is nothing to install, and one file holds everything — back it up by copying it. It is also single-writer: one process may hold the database. A second otelview on the same path, or otelview mcp --storage duckdb while a server runs, will fail to open it.
jaeger keeps traces in an external jaeger.storage.v2.TraceReader backend and puts logs and metrics in a local fallback (memory or duckdb), because that API does not carry them.
remote makes this instance a thin reader of another otelview over gRPC — which is how you give a team a local UI onto a central store, and how otelviews compose:
Every otelview also serves jaeger.storage.v2.TraceReader plus otelview.storage.v1.{LogReader, MetricReader, Diagnostics} on its gRPC port, so it can back Jaeger v2 as well.
Retention
storage.retention ("36h", "7d", "2w", "1mo") deletes anything older on a sweep every retention_sweep_interval. Unset means keep forever, which on a busy instance means a file that grows until the disk says no.
It is honoured by backends that own their data — duckdb. With memory the ring buffers already bound themselves; with jaeger or remote the storage server behind it manages its own retention, and otelview says so once, loudly, at startup rather than pretending to delete. A bad duration is refused at startup, because a typo that silently keeps everything defeats the point.
Securing it
Three independent doors, which is worth being deliberate about:
| Door | Opened by | Guarded by | |
|---|---|---|---|
| OTLP ingest | auth.token | auth.header (default x-otelview-token) | |
| Web UI + REST API | ui.token, or auth.protect_api + auth.token | that header, or Authorization: Bearer | |
| MCP endpoint | mcp.token → ui.token → auth.token | the same, plus an Origin check |
The MCP token falls back through that chain, so locking the UI locks MCP with the same key — there is no second setting to forget. OTELVIEW_MCP_TOKEN overrides it, which is how to keep the secret out of the config file:
Two refusals are built in rather than left to the operator: serving MCP on a non-loopback address with no token fails at startup, and an MCP request carrying a browser Origin from anywhere but loopback is rejected (the DNS-rebinding mitigation — without it a web page could read a local instance). Set mcp.enabled: false to remove the endpoint entirely.
Telemetry is not innocuous: spans and logs carry URLs, user ids, SQL and whatever an exception message happened to include. Treat an open 0.0.0.0:4319 as publishing it. Put TLS in front (a reverse proxy) for anything crossing a network you do not own — otelview speaks plain HTTP itself.
Deploying
Docker — the image is ghcr.io/tsirysndr/otelview, multi-arch:
Inside a container, ui.listen must be 0.0.0.0:4319 to be reachable from outside it — which is exactly when to set a token. Keep the DuckDB file on a volume, or a restart is a fresh start.
systemd — one binary, no working directory to speak of. Give it a user, a WorkingDirectory where the DuckDB file lives, Restart=always, and the token via Environment= or EnvironmentFile=.
Nix — nix run github:tsirysndr/otelview, or install the flake; binaries come from the otelview cachix cache, so nothing compiles.
Package managers — Homebrew, APT (apt.fury.io/tsiry), DNF (yum.fury.io/tsiry), bun/npm, or the install script. The desktop app (Tauri) ships alongside and points at any remote otelview API.
Sizing
From the benchmarks on the DuckDB backend, on a laptop: ~400k spans/s and ~600k logs/s ingested, trace search in single-digit milliseconds, an attribute search across a million spans in tens of milliseconds, and a retention sweep at ~2M rows/s. Reads do not queue behind ingest: writes serialize on one connection while queries run on a pool of their own.
In practice the constraints are disk (JSON attributes on every row; set retention) and the sampled analytics (service_stats, service_graph and field discovery read up to 250 recent traces per request, which is what keeps them fast and what makes them a sample rather than a count).
When something is off
- "binding OTLP HTTP receiver to 0.0.0.0:4318" — the port is taken, very
often by another otelview. Change the listen, or disable that receiver with enabled: false. The first server task to fail takes the process down by design, so one bad port stops everything.
- DuckDB will not open — another process holds it. One writer per file.
- The UI loads but is empty — nothing is arriving. Check
/api/stats, then
the sender: that is the otelview-instrument skill.
- `401` on ingest — the sender is not sending
auth.header. On the API,
ui.token or protect_api is set and the browser or client has no token.
- "storage.retention is set but this backend does not own its data" — a
jaeger or remote backend cannot delete on your behalf. Configure retention where the data actually lives.
- The desktop app cannot reach the API —
ui.corsmust be true for a
non-browser origin, and the address must not be loopback-only if the app is on another machine.
- Config rejected at startup — unknown fields are refused rather than
ignored, so a typo names itself. --print-config shows the accepted shape.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/otelview-operate/SKILL.md
Popularity
- Repository stars
- 1
- 7-day trend score
- 3
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/tsirysndr/otelview-skills/otelview-operate)