Private preview · for Python, Celery & Kubernetes teams
Know what your system actually does.
Your app's behaviour is split across repos, deploy config and running infrastructure, and they often disagree. Layerwatch joins them and shows what's really live, with the evidence. For engineers and their coding agents.
- Where does this data actually go?
- Which setting is live, and who set it?
- What really reached production?
Question
What concurrency is report-worker actually running in prod?
reported by the worker itself · 14:22:07Z
How we know
- Code settings.py:12 · default overridden 8 declared
- Deploy values-prod.yaml:22 30 configured
- Runtime celery inspect · report-worker-7f9c 14:22:07Z 30 observed
- Conflict ConfigMap/report-worker now says possible cause: pods predate the edit (not proven) 50 observed
- Git repositories
- Python
- Celery
- Redis
- Kubernetes
- Helm
- Kustomize
- PostgreSQL
- OpenTelemetry
The problem
The answer is never in one place.
A producer in one repo. A consumer in another. A queue picked by config. A value overridden at deploy time. A new database nobody mentioned until a customer reported a bug.
Docs generated from one repository can be perfectly coherent and still answer the wrong question. Every investigation starts from scratch, usually by pinging whoever built it.
Two repos, a Kubernetes secret and a Slack thread. Nobody had the whole picture. →
producer
reports.build.delay(asset_id)
consumer writes to
os.environ["REPORT_DB_URL"]
REPORT_DB_URL comes from
secret: reporting-db
a customer reports a bug
"wait, which database does the report page read?"
Your system is layers.We watch every one.
Where the answers come from, and exactly what access each layer needs.
Layer by layer
Layer by layer
Your system is layers.We watch every one.
Where the answers come from, and exactly what access each layer needs.
- 01
Code
Reads each selected repository at a pinned revision: task definitions, producer call sites and configuration reads. Your code is parsed, never imported or run.
- Connects
- GitHub / GitLab · Python today
- Access
- read-only checkout
- 02
Deploy
Renders your actual Helm or Kustomize inputs with pinned versions, then compares them with the live Kubernetes objects.
- Connects
- Helm · Kustomize · Kubernetes
- Access
- namespace-scoped read · Secrets referenced, never read
- 03
Runtime
Asks Celery workers what they are consuming, identifies the Redis broker, and uses the OpenTelemetry traces you already have.
- Connects
- Celery · Redis · OpenTelemetry
- Access
- allowlisted, rate-limited inspection
- 04
Data
Reads schemas, tables and indexes from each datastore the workflow touches.
- Connects
- PostgreSQL
- Access
- fixed catalog queries · no row sampling, no arbitrary SQL
- ∞
Joined into one model
Every fact keeps its source, version and timestamp, so answers stay checkable and refresh when something changes.
- Connects
- local UI · MCP for coding agents
- Access
- runs on your machine or in your cluster
Workflow map
Follow one workflow, not the whole company.
Remember the Slack question, "which database does the report page read?" This is the whole path from API to database, with evidence on every link. Click any step.
evidenceingest-api
2 claims- declared
POST /assets calls reports.build.delay(asset_id)
ingest-service@4e1a9c2 · api/assets.py:88
- observed
Deployment ingest-api runs image sha256:9b1f…
k8s prod/ingest-api · rv 118204 · 14:21:58Z
evidencereports
3 claims- configured
task_routes maps reports.* → queue "reports"
worker-service@b73d010 · celeryconfig.py:14
- configured
Broker URL resolves to redis-broker:6379/0 (not the cache on /2)
values-prod.yaml:9 → Deployment env BROKER_URL
- unresolved
Queue name "reports" also exists on staging broker — not joined
identity rule: broker + db + name
evidencereport-worker
3 claims- observed
All 3 workers are consuming queue "reports"
celery inspect active_queues · 14:22:07Z
- configured
REPORT_DB_URL comes from secret "reporting-db" (reference only, value never read)
k8s prod/report-worker · env[4].valueFrom
- observed
Pod report-worker-2c1d still runs the previous image
k8s prod/report-worker-2c1d · status.imageID · 14:22:03Z
evidencereporting
4 claims- declared
Written by report-worker: INSERT INTO asset_reports
worker-service@b73d010 · tasks.py:57
- inferred
Read by report-api for GET /reports/:id
reporting-service@2d9f7aa · queries.py:31 (model candidate, no trace yet)
- observed
Its own Postgres instance, reporting-db, not the main app database
pg_catalog · reporting-db/reporting · 14:20:41Z
- unresolved
Why a separate database was introduced: not recorded
no decision record or PR rationale found
evidencereport-api
2 claims- inferred
Reads asset_reports by asset_id for GET /reports/:id
reporting-service@2d9f7aa · queries.py:31 (model candidate)
- unresolved
Timeout for the report call: loader not supported yet
config read via custom loader · settings/dynamic.py
Every claim carries one of five labels. No blended confidence score.
A source file or manifest says so. It shows intent, not proof that it runs.
A supported path from code through deploy inputs resolves to this effective value.
A named source reported this state at a specific time, for a specific instance.
AI or partial analysis proposes it. Useful, clearly marked, never promoted on its own.
Evidence is missing, conflicting or unsupported, so we say that instead of guessing.
For coding agents
Your agent gets the same facts, and the same limits.
A local MCP server exposes typed, bounded tools. Claude Code, Cursor or any MCP client can pull the workflow, a setting's derivation or the coverage gaps without re-reading five repos every session.
-
get_workflownodes, edges, evidence and unknowns -
get_settingconfigured vs observed, with derivation -
get_changeswhat moved between two snapshots -
get_coveragemissing access, stale sources, failures
No shell tool. No arbitrary SQL. No cluster mutation.
→ tool call
get_setting(workload="report-worker", setting="concurrency", env="prod")
← result
{
"snapshot": "snap_0928_1422",
"configured": { "value": 30, "basis": "configured" },
"observed": [
{ "instance": "report-worker-7f9c", "value": 30,
"observed_at": "2026-09-28T14:22:07Z" }
],
"shadowed": ["settings.py:12 default=8"],
"conflicts": ["ConfigMap now 50; pods predate edit"],
"limitations": ["report-worker-2c1d runs the previous image"]
} Trust
Built to be trusted with access.
The access each layer needs is listed above. On top of that, four commitments about your data. We won't promise "no approval needed", but we'll make approval easy.
Redacted before it leaves
Sensitive values are removed before anything is stored, exported or sent to a model.
Your choice of model
Use a hosted model or an approved local one. The processing mode is always explicit, so you know what leaves your environment.
Deletion that sticks
Remove a source or revoke access, and the evidence, cached answers and exports built from it are removed too.
Open-source core
The collectors, evidence model, local UI and MCP server are planned as open source.
FAQ
Fair questions.
Can't Claude or ChatGPT already do this?
With the same access, a strong agent can reconstruct many of these answers. It has to do it again every session and for every person. Layerwatch does the collection, identity binding, revision tracking and refresh once, keeps it current, and serves the same facts to people and agents. If your team rarely needs this, a general agent may be enough, and we would rather you knew that.
Does it need production access?
It uses access you already have, scoped to one application. Missing access shows up as a coverage gap rather than a workaround, and you can start with a staging environment.
Is it read-only?
Collection is non-mutating for your business data, but "read-only" is not the whole story. Celery inspection publishes control messages over the broker, and catalog queries still use database resources. Each call is allowlisted, with rate and time limits.
Will it tell me why something was built this way?
Only if someone recorded it. We can explain what an index or cache does and what the evidence suggests it helps with. If the original decision was never written down, the answer is "not recorded", not an invented backstory.
Early access
Lost an afternoon tracing a workflow across repos?
We're opening early access to a small number of backend teams running Python, Celery and Kubernetes. We'll set it up with you and check together whether it actually saves your team time.
A good fit if you have
- Several services spread across more than one repo
- Cross-repo investigations or handovers that keep coming back
- Someone who can connect the relevant repos and cluster
We'll only use your email, and any note, to follow up about early access. Privacy