cc-observatory
Local observability for Claude Code: see your sessions, subagents, blocks, logs, tokens and cost, on your own machine.
Status
Pre-alpha. v0.3.0 closes milestone 2 of 8: the app that receives Claude Code's
hooks. The cc-observatory package on PyPI still only prints its version; the stack and
the app run from a clone of this repository.
What v0.3.0 adds:
- the app, built and started by
docker compose up -dand published on127.0.0.1:4300(see "Try the app" below and docs/app.md); - a hook endpoint that always answers with an empty 204 and does its work in the background, so it never slows Claude Code down;
- a state machine for sessions, agents and blocks (sessions waiting on you); a permission prompt denied with Esc fires no hook, so the app closes it from Claude Code's telemetry in Loki;
- SQLite storage of metadata only, with retention, and a read-only JSON API at
/api/v1/sessions; - live state on
/metrics, scraped by Prometheus; - the browser defences: a
Hostallowlist, no CORS, and non-JSON requests to the hook endpoint ignored; - ADRs 0023 to 0030 for the app's decisions.
Until ccobs setup arrives in v0.5.0, you point Claude Code at the app with a settings
file passed to claude --settings. Earlier releases: v0.2.0 (milestone 1) added the
observability stack in Docker Compose with a provisioned Grafana, and v0.1.0 (milestone
0) laid the foundation.
What comes next: milestone 3 (v0.4.0), the web UI with live sessions, agents, blocks and events. The full plan is in the roadmap below.
Unless a section says otherwise, the rest of this README describes the planned design.
What it will show
The release that brings each part is in parentheses. Only the Grafana part comes with v0.2.0 (see "Run the observability stack" below); the rest is planned.
- Live overview of the Claude Code sessions on your machine: which ones are working, waiting on you, idle or ended (v0.4.0).
- Agent tree: each session's main agent and the subagents it started (v0.4.0).
- Blocks: sessions waiting on you, such as a permission prompt or an MCP elicitation, with how long each one has been waiting (tracked from v0.3.0, shown in the web UI from v0.4.0).
- Events and logs for each session (v0.4.0).
- Tokens and cost (v0.4.0) by day, model and agent type (built-in agent names; your
own agents show as
customunless you opt in to tool details) and by project (joined from the working directory that hooks report). Cost is an estimate that comes from Claude Code's telemetry, not the amount you are billed. - Health page: whether each part of the stack is up and receiving data (v0.4.0).
- Grafana for deeper analysis, provisioned with its datasources and a Claude Code overview dashboard (v0.2.0), and later with dashboards that the app links to, already filtered to the session, agent or project you were looking at (v0.7.0).
- Alerts (v0.6.0): browser notifications and, optionally, a Discord webhook when a session has been waiting on you for longer than a threshold, when API errors keep repeating, or when the estimated cost of a session or of a day goes over a limit. You set the thresholds with environment variables or on a settings screen.
How it works
Claude Code ──OTLP (4317/4318)──► OTel Collector ──► Prometheus (metrics)
│ ├──► Loki (events/logs)
│ └──► Tempo (traces, optional profile)
└──hooks──► app (FastAPI) ──► SQLite (sessions, agents, blocks, alerts)
│ └─ /metrics ◄── scraped by Prometheus (live state)
└─ queries Prometheus and Loki over HTTP
Grafana ◄── Prometheus, Loki, Tempo (provisioned datasources and dashboards)
- Telemetry. Claude Code's native OpenTelemetry support exports metrics, events and,
optionally, traces over OTLP to an OpenTelemetry Collector. The collector removes
personal attributes and sends metrics to Prometheus, events to Loki and traces to
Tempo. Tempo runs only in an optional
tracesprofile, because tracing is a beta feature in Claude Code. - Hooks. Claude Code hooks send lifecycle events (a prompt submitted, a permission request, a notification, a subagent starting or stopping, a compaction, the end of a session) to the app, a FastAPI service that keeps sessions, agents, blocks and alerts in SQLite.
- Live state as metrics. The app exposes that live state on
/metrics, which Prometheus scrapes, so it can be charted next to the telemetry. - The app also queries Prometheus and Loki over HTTP for its token, cost and event views.
- Grafana comes provisioned with the Prometheus, Loki and Tempo datasources and with the dashboards.
- Why both sources: telemetry tells you what a session consumed (tokens, cost, API calls, tool results) but not that it is waiting on you right now, which only hooks report, at the moment it happens.
More detail for contributors is in docs/architecture.md. The decisions behind this design, and their reasons, are recorded as architecture decision records in docs/adr/.
Run the observability stack (from v0.2.0)
From v0.2.0 you can run the observability stack from a clone of this repository and see
Claude Code's metrics and events in Grafana. From v0.3.0 the stack also runs the app
(hooks, sessions and blocks; see "Try the app" below). Its web UI comes in v0.4.0 and
ccobs setup in v0.5.0, so until then you point Claude Code at the stack by hand.
-
Start the stack:
git clone https://github.com/Luanderson-Dev/cc-observatory cd cc-observatory docker compose up -d
The first start downloads about 750 MB of images and builds the collector's and the app's images.
docker compose psshows each service and whether it is healthy. To also store Claude Code's traces, a beta feature, start it withdocker compose --profile traces up -d, which adds Tempo, and pass--profile tracesevery time you start or update the stack. -
Open Grafana at http://localhost:4330. Use
localhost: Grafana redirects any other host name,127.0.0.1included, there. There is no login. The home page is the Claude Code overview dashboard: cost, tokens, sessions, active time, code changes, API errors and recent events. -
Point Claude Code at the stack. Add these variables to the
envblock of your user settings,~/.claude/settings.json, keeping the entries you already have, or export them in the shell that starts Claude Code. Project settings (.claude/settings.jsonand.claude/settings.local.json) cannot set them.{ "env": { "CLAUDE_CODE_ENABLE_TELEMETRY": "1", "OTEL_METRICS_EXPORTER": "otlp", "OTEL_LOGS_EXPORTER": "otlp", "OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf", "OTEL_EXPORTER_OTLP_ENDPOINT": "http://127.0.0.1:4318", "OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE": "cumulative" } }
- Use
127.0.0.1, notlocalhost: the ports listen on IPv4 only, andlocalhostcan resolve to::1. - Claude Code has no default protocol, so set one.
grpcalso works, withhttp://127.0.0.1:4317. - Cumulative temporality is recommended: with Claude Code's default, delta, some totals can come out low after a pause (the known limit).
- Leave
OTEL_METRICS_INCLUDE_SESSION_IDat its default (true): without session IDs, the series of concurrent sessions collide. - For traces, also set
CLAUDE_CODE_ENHANCED_TELEMETRY_BETAto1andOTEL_TRACES_EXPORTERtootlp, and run the stack with--profile traces.
- Use
-
Restart Claude Code so that new sessions load the settings. Metrics arrive every 60 seconds and events every 5 seconds, and the dashboard refreshes every minute. If nothing shows up, see No data in the dashboard.
- Settings. Every setting is an environment variable with a default, so a
.envfile is optional: to change one, copy.env.exampleto.env, edit it and rundocker compose up -dagain.CCOBS_HOST_LABEL(defaultlocal) is thehostlabel stored on every metric, event and trace; set it to name the machine. It is stored as you write it, so use the machine's real host name only if you want it stored. The ports and the retention (by default 90 days of metrics, 30 of events and 7 of traces) are set the same way. - After a reboot. The services restart unless you stop them with
docker compose stop, so the stack comes back whenever Docker starts (ADR 0019). Docker Desktop starts when you sign in only if its "Start Docker Desktop when you sign in to your computer" setting is on, and it is off by default; on Linux, enable the Docker service at boot. - More. docs/stack.md covers stopping and updating the stack, its settings, data and retention, memory, and troubleshooting.
Try the app (from v0.3.0)
From v0.3.0, docker compose up -d also builds the app's image from your clone and
starts it at http://127.0.0.1:4300. The app receives Claude Code's hooks and tracks
sessions, agents and blocks in SQLite. Its web UI comes in v0.4.0; until then you can
see what it tracks through its read-only JSON API.
-
Start or update the stack as above.
docker compose psshowsappas healthy once it serves requests. -
Point Claude Code at the app. Until
ccobs setupwrites the hooks for you in v0.5.0, save the hooks block from docs/app.md asccobs-hooks.jsonin your home directory (on Windows, change/dev/nulltoNULin it, as that page explains), and start Claude Code with it:claude --settings "$HOME/ccobs-hooks.json"
Your
~/.claude/settings.jsonstays as it is, and only the sessions you start this way send hooks. The hook URL uses127.0.0.1, notlocalhost. -
See the sessions:
curl -s http://127.0.0.1:4300/api/v1/sessions
Each session has its state (
working,waiting_user,idle,endedorstale), and/api/v1/sessions/<session_id>adds its agents and blocks.
- Stack down. While the stack is down, sessions started with these hooks show a
hook-error notice in the transcript on most hook events; start Claude Code without
--settingsuntil the stack is back. - Esc denials. A permission prompt denied with Esc fires no hook; the app closes it from Claude Code's events in Loki, so keep the telemetry settings from step 3 of the previous section.
- More. docs/app.md covers the API, the app's metrics in Grafana, its settings and retention, privacy and troubleshooting.
Quick start (planned, available from v0.5.0)
Not available yet. Step 1 works from v0.2.0 (see the section above); steps 2 to 4
need the setup command, which arrives in v0.5.0.
-
Start the stack:
git clone https://github.com/Luanderson-Dev/cc-observatory cd cc-observatory docker compose up -d
-
Connect Claude Code to it:
uvx cc-observatory setup
setupbacks up~/.claude/settings.jsonand merges in the telemetryenvblock and the hooks without touching your existing entries, marking what it adds so thatccobs uninstallremoves only that;--dry-runshows the diff without writing anything. -
Open the app at the address that
setupprints. -
Restart Claude Code so that new sessions load the new settings.
ccobs and cc-observatory are the same CLI; uvx cc-observatory <command> runs it
without installing it.
Privacy
- Metadata only by default. Prompt text, tool inputs and outputs, assistant messages and error text are not stored.
- Content capture is an explicit opt-in (planned for v0.5.0).
ccobs setup --capture-contentshows a warning and then turns content capture on in Claude Code's telemetry settings and in the stack (the collector and the app). Without it, the collector drops content from the telemetry even if Claude Code was set to send it. - Personal attributes are removed. The collector deletes your email address, your user, account and organization IDs and your machine's host name from the telemetry before anything is stored.
- Everything stays on your machine. That is a design goal that the bundled configs
enforce: every port binds to
127.0.0.1; Prometheus, Loki and Tempo publish no port and sit on an internal network with no route out; and the usage reporting and update checks of Grafana, Loki and Tempo are turned off. At runtime, nothing leaves your machine except the optional Discord webhook, if you configure one, and DNS lookups of a store's name while that store is stopped (see SECURITY.md). - Grafana has no login. Whoever opens it is an Editor, who can query the data and
save dashboards but cannot change its datasources, plugins, users or settings. It
answers only as
localhost, which keeps other web pages from reading it through DNS rebinding, and it refuses the cross-site requests that could change it or read its answers; a page can still make it run a query blindly, without seeing the result. Anything that runs on your machine can read the data. - Retention is configurable (the observability stack from v0.2.0, by default 90 days of metrics, 30 of events and 7 of traces; the app database from v0.3.0), so old data is deleted after the period you choose.
See SECURITY.md for the security model, including what a web page can still do, and how to report a vulnerability.
No interference with Claude Code
- Hooks never change Claude Code's decisions. The app answers every hook call with an
empty 2xx response, never with a decision, and
setupgives every hook a short timeout. - If the stack is down, Claude Code keeps working. While the stack is down, Claude
Code shows a hook-error notice in the transcript on most hook events (Claude itself does
not see these notices).
ADR 0011
explains this trade-off and how cc-observatory keeps it small:
ccobs doctorchecks that the hook endpoint answers and reports failing hooks, andccobs uninstallremoves the hooks.
Requirements
- Docker Engine 25.0 or later with the Docker Compose plugin 2.20.2 or later (and, if
the Buildx plugin is installed, Buildx 0.17.0 or later): Docker Desktop on Windows and
macOS, or Docker's own packages on Linux, where Docker Engine 28.0 or later also keeps
ports published to
127.0.0.1out of reach of other hosts on the local network. - Memory: leave Docker at least 2304 MiB for the stack (2816 MiB with Tempo), the sum of its memory limits. Measured use was about 260 to 290 MiB idle and 420 to 450 MiB while the dashboard's queries ran through Grafana's API, before the app joined the stack; the app, measured on its own, used about 64 to 70 MiB. Loading Grafana's UI in a browser briefly took Grafana alone to about 630 MiB.
- Disk: about 3 GB for the images, plus about 250 MB for the app's image, plus the data.
- Tested on Linux and on Windows 11 with Docker Desktop, both on amd64; macOS and arm64 have not been tested. Details are in docs/stack.md.
- uv, for the
ccobsCLI (uvx cc-observatory), whose commands arrive in v0.5.0. - Claude Code 2.1.296 or later. That is the version cc-observatory was tested against (ADR 0012); older versions are not supported until they are tested.
Roadmap
| Milestone | Release | Scope | Status |
|---|---|---|---|
| 0 | v0.1.0 | Foundation, tooling, CI, ADRs, telemetry and hooks spike, fixtures, first PyPI release | Released |
| 1 | v0.2.0 | Observability stack in compose, provisioned Grafana | Released |
| 2 | v0.3.0 | Hook ingestion, session state machine, SQLite, blocks, /metrics |
Released |
| 3 | v0.4.0 | Web UI (HTMX + SSE) | Planned |
| 4 | v0.5.0 | ccobs setup, uninstall, doctor, status |
Planned |
| 5 | v0.6.0 | Alerts (browser and Discord) | Planned |
| 6 | v0.7.0 | Grafana dashboards and polish | Planned |
| 7 | v1.0.0 | Distribution: GHCR multi-arch images, release hardening, contributor docs | Planned |
Development
You need uv; it installs the right Python version for you.
uv sync # create the virtualenv with the dev dependencies
uv run pre-commit install # install the pre-commit and commit-msg hooks
uv run pytest # unit tests with the coverage gate
uv run mypy # strict type checks
uv run pre-commit run --all-files # every check that the CI lint job runs
uv run pytest -m integration --no-cov # integration tests (need Docker)
- The integration tests start their own compose project,
ccobs-it, on ports of their own, so they can run next to your stack; see docs/stack.md. - The project uses Gitflow.
developis the default branch: feature pull requests targetdevelopand are squash-merged, and release pull requests go tomainwith merge commits. - The title of a feature pull request becomes its commit on
develop(and, forfeat,fix,refactorandperf, a changelog line), so every PR title must be a Conventional Commit (for example,feat: add the session state machine). CI checks it. - A contributor guide comes with v1.0.0.
Disclaimer
cc-observatory is an independent open-source project. It is not affiliated with, endorsed by or sponsored by Anthropic. "Claude" and "Claude Code" are trademarks of Anthropic, PBC.
License
MIT. Copyright (c) 2026 Luanderson Pimenta Mendes (Luanderson-Dev).
Metadata
Release files for cc-observatory 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| cc_observatory-0.3.0.tar.gz | 82.6 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cc_observatory-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 173.9 kB
Release files / cc_observatory-0.3.0.tar.gz
| Download URL | cc_observatory-0.3.0.tar.gz |
|---|---|
| Size | 82.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
275b15e6258cc94bf46c8c3ea238b64128a57dd5b4d78878433231e2ab5ddde5
|
|
BLAKE2b-256 checksum How to use checksums |
89e0a7ee6af7d3bcdde006098f12b962c829e20a5e15e1c635f4054c5165d9d5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.
Transparency logRelease files / cc_observatory-0.3.0-py3-none-any.whl
| Download URL | cc_observatory-0.3.0-py3-none-any.whl |
|---|---|
| Size | 91.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c1e1f8db2db89664a47e54b14be35942e876e3a21ed36fd449224697a446f5f9
|
|
BLAKE2b-256 checksum How to use checksums |
fbce5ecbab13eef5787691109657030ea8b2172735d46e263b0e91ceb40e8502
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.
Transparency logSecurity for cc-observatory 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for cc_observatory-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.