Panoptos LGTM Router
Initial load should stay small. Do not read every topic file up front. Read only the file matching the current user request.
Base Rules Always In Context
Use grafana-engr for Grafana/Loki/Mimir and tempo-server for direct trace analysis.
Datasources
| Use for |
UID |
Name |
Audience |
| App + infra logs |
loki |
Loki (Logs) |
Platform team primary — most used, has all namespaces |
| Product-only logs |
loki-customer |
Loki (Customers) |
Product teams — same data as loki but scoped for product use |
| Observability stack logs |
loki-infra |
Loki (Infra) |
Panoptos infra only — LGTM components, OTel collectors |
| App metrics (Mimir) |
cortex |
Cortex (Metrics) |
All product application metrics |
| Panoptos infra metrics |
prometheus |
Prometheus |
Observability stack infra metrics only — skip for app queries |
| Traces |
tempo |
Tempo (Traces) |
Use tempo-server MCP for direct trace analysis |
Datasource Routing Decision
- User asks about product/service errors, latency, logs →
loki (or loki-customer) + cortex
- User asks about LGTM stack health (cortex-ingester, loki-distributor, tempo, OTel collector) →
loki-infra + prometheus
- User asks about traces →
tempo via tempo-server MCP
- Default to
loki + cortex unless explicitly about observability infra
Default time window for ordinary log triage: last 15 minutes, converted to absolute RFC3339 UTC. Do not pass now-15m to tools.
Always pin labels before querying. Avoid broad scans.
Three-Axis Taxonomy
Every application signal (metrics in cortex, logs in loki/loki-customer) is scoped by three orthogonal labels:
| Axis |
Label |
User says |
Examples |
| Product / domain |
service_namespace |
"product", "team", "domain" |
platform, revenue, ai-platform |
| Service |
service_name |
"service", "API", "worker" |
platform-objectdb-api, revenue-quote-api |
| Environment |
deployment_environment |
"env", "environment" |
prod, rls04, rls03, staging |
Environment aliases are in the understanding-agent-space-deployment-environment-aliases memory (always in context). Resolve friendly names (dev, qa, prod, perf, staging) using that memory before querying.
Product Namespace Index (service_namespace)
Compact routing index. Resolve exact services live via list_prometheus_label_values (see Service Name Resolution) — don't trust hard-coded service lists. Per-namespace service catalogs for platform, revenue, and ai-platform are in their respective memories (always in context).
Cortex metrics + Loki logs: platform, revenue, ai-platform, contracts, conga-sign, congasign, core-apps, xauthor, docgen, maf, esign, srm, conversations, plat-enablement, ccdatasync
Loki-only (no Cortex — use count_over_time for RED): cci, cci-standalone, clm, billing, invoicing, testauthor, approvals, tidb
Infra namespaces (NOT product — don't confuse): cluster-observability, sign, contractssf, argocd, argo-workflows, kube-system, cert-manager, karpenter, external-secrets, rls-operator, rls-app, kong, nginx-ingress, ingress-nginx
loki-infra datasource only: panoptos (LGTM stack: cortex-, loki-, tempo-, grafana), cluster-observability (otelcol-, kube-prometheus-stack-*)
Critical gotchas (keep in mind when routing)
sign namespace = cluster infra for Sign clusters, NOT the Sign product (that's conga-sign / congasign — check both).
congasign overlaps conga-sign — check both for Sign product signals.
docgen has duplicate series with a ;otelcol-contrib suffix — filter service_name!~".*;otelcol-contrib" to avoid double-counting.
kong metrics live in cortex as kong_http_requests_total without service_namespace — filter by route label instead.
approvals logs are in the approvals namespace (Loki-only), but its cortex metrics are under core-apps.
tidb logs live in one shared home env per stack — discover with sum by (deployment_environment) (count_over_time({service_namespace="tidb"}[5m])).
Environment Catalog (deployment_environment)
The friendly-name aliases (dev, qa, prod, perf, staging) are authoritative in the understanding-agent-space-deployment-environment-aliases memory. Always read that memory first when the user names an environment informally.
Extended Cortex Environment Values
Beyond the standard tiers, Cortex data may carry these additional deployment_environment values:
| Tier |
Environments |
| Production |
prod |
| QA |
rls04 |
| Dev |
rls03 |
| Staging / perf |
rls05, rls06, rls07 (perf), rls08 (perf) |
| Other dev |
dev, dev1, dev2, dev3, rlsdev, contractssf-dev, ephemeral, local |
| CCI-specific |
cci-beta-1030, cci-legacy-stage, cci-yama-beta-1030 |
| Yama |
yama-dev-1100 |
| Azure |
rlsaz06 |
| CICD |
cicd |
Loki-Only Environments (not in Cortex)
staging, contracts-dev, qa (in loki-infra), max-pu-xajs-engg-401, max-pu-xajs-kafka-401
Service Name Resolution
Users refer to services by informal shorthand (e.g. "objectdb", "connectcrane", "quote api", "extraction worker"). There are 400+ services across 17+ namespaces — do NOT guess the full service_name or which service_namespace it belongs to.
One-Call Resolution Pattern
When the user gives a partial/informal service name, resolve it with a single MCP call — regex search on service_name without pinning any namespace:
# Find service_name AND its namespace in one call
list_prometheus_label_values(datasourceUid="cortex", labelName="service_namespace",
matches=[{filters: [{name: "service_name", type: "=~", value: ".*<shorthand>.*"}]}])
This returns the service_namespace value(s) that contain matching services. Then if you need the exact service names:
# Get exact matching service names (same call, flip the labelName)
list_prometheus_label_values(datasourceUid="cortex", labelName="service_name",
matches=[{filters: [{name: "service_name", type: "=~", value: ".*<shorthand>.*"}]}])
Examples:
| User says |
Regex |
Returns namespace |
Returns service_name(s) |
| "objectdb" |
.*objectdb.* |
platform |
platform-objectdb-api, platform-objectdb-perftest-api |
| "connectcrane" |
.*connectcrane.* |
core-apps |
connectcrane-web, connectcrane-worker |
| "quote" |
.*quote.* |
revenue |
revenue-quote-api |
| "extraction" |
.*extraction.* |
ai-platform, cci (if metrics exist) |
ai-platform-extraction-worker, cci-extraction-worker, ... |
Resolution Rules
- Always resolve before querying. Never hard-code or guess a
service_name from a shorthand.
- If multiple namespaces match (e.g. "extraction" hits both
ai-platform and cci), ask the user which product they mean.
- If zero matches in cortex, the service may be Loki-only. Retry against Loki:
topk(10, sum by (service_name, service_namespace)
(count_over_time({service_name=~".*<shorthand>.*"}[15m])))
- If the user already specified the product (e.g. "platform objectdb"), skip the namespace lookup and go straight to the service_name regex scoped to that namespace.
Other Dynamic Discovery Patterns
# List all services for a known namespace
list_prometheus_label_values(datasourceUid="cortex", labelName="service_name",
matches=[{filters: [{name: "service_namespace", type: "=", value: "<ns>"}]}])
# List environments where a service is active
list_prometheus_label_values(datasourceUid="cortex", labelName="deployment_environment",
matches=[{filters: [{name: "service_name", type: "=", value: "<svc>"}]}])
# Discover metric families for a product
query_prometheus(datasourceUid="cortex", expr='group by (__name__) ({service_namespace="<ns>", deployment_environment="<env>"})', queryType="instant")
Topic File Map
| User asks about |
Read this file |
| Investigation / RCA / "why did this break?" / root cause / incident — anything beyond a single query |
references/rca-playbook.md (the five-pillar evidence search), then the per-signal files below |
| Generic "what service is failing?" (no service named, no logs/metrics specified) |
logs-first per "Failure triage" below — start with references/loki-logql.md |
| LogQL, log labels, error logs, traceid extraction, raw logs |
references/loki-logql.md |
| PromQL, metrics, RED, latency, Kong/nginx 5xx, Kubernetes metrics |
references/mimir-promql.md (check ingress rollout first — Kong vs nginx) |
| Trace IDs, Tempo, TraceQL, deeplinks, correlation |
references/tempo-traceql.md |
| Long windows, 30 days, all errors over a week, timeout/truncation/max_samples |
references/wide-window-guard.md |
| General triage flow or routing |
stay in this file unless detail is needed |
"Which service is failing?" — generic failure triage
When the user asks the open-ended question "which service is failing / has more errors / is broken" without naming a service or specifying logs vs metrics:
Always logs-first, then metrics. Reason: log-based error counts capture every failure mode (workers, async jobs, app-level exceptions returning HTTP 200, Loki-only namespaces like cci/clm/billing/invoicing/docgen/testauthor/tidb). Ingress metrics only see HTTP-fronted services that transit the ingress.
- Loki first —
topk by service_name on SeverityText=~"ERROR|Error|FATAL" scoped to the env. See references/loki-logql.md query D (and its MCP-wrapper gotcha — pull raw lines + tally with jq).
- Then ingress metrics to confirm severity (ratio, rate) and add HTTP-status context. First detect which ingress is live in this env — see Ingress rollout note below. Then see
references/mimir-promql.md queries E/F.
- Cross-reference the two lists:
- Services topping both → real fires, dig in.
- Logs-only top → may be log-spam or non-HTTP failures (workers, jobs).
- Metrics-only top → HTTP-layer failures (timeouts, upstream 5xx) the app isn't logging as ERROR.
Ingress rollout note (Kong vs nginx)
Kong is being rolled out as the ingress proxy. Some envs are on Kong, others still on nginx, and a few may be mid-cutover with both active. Never assume Kong globally. Before running any ingress-5xx query, detect the live ingress for the target deployment_environment. See references/mimir-promql.md § "Ingress detection (Kong vs nginx)".
Triage Workflow
- Scope to
deployment_environment plus service_name or service_namespace and a 5-15 minute window.
- If the question is generic ("what's failing?"), follow the logs-first failure triage above.
- If logs are needed, read
references/loki-logql.md.
- If metrics are needed, read
references/mimir-promql.md.
- If a trace ID is available or Tempo is needed, read
references/tempo-traceql.md.
- If the requested window is wide, read
references/wide-window-guard.md before querying.
Cost Guardrails
- Default log limit: 100.
- Raw Loki lines over 24h: refuse raw fetch; aggregate first.
- Cortex range queries over 24h need careful step sizing.
- Do not run global metric discovery such as
{__name__=~".+"}.
- If a query returns empty unexpectedly, do one narrow discovery query before concluding no data.
Sharing & Upload Note
This skill is self-contained — the references/ subfolder holds all topic files referenced above. Zip the whole panoptos-lgtm/ folder to share with teammates or upload as a .skill bundle. Topic files load only when relevant, keeping the initial context small.
1---2name: panoptos-lgtm3description: Panoptos observability investigator over Grafana (Loki logs, Mimir/Cortex + Prometheus metrics, Tempo traces). Use whenever the user asks about logs, errors or exceptions, 5xx / 500s, latency or slowness, error rate, request volume, CPU or memory, dashboards, a failing or unhealthy service, a production incident, or root-cause analysis (RCA) — for any product, service, or environment (dev=rls03, qa=rls04, prod). Writes and routes LogQL / PromQL / TraceQL to the correct datasource. Loads topic reference files only when needed.4---56# Panoptos LGTM Router78Initial load should stay small. Do not read every topic file up front. Read only the file matching the current user request.910## Base Rules Always In Context1112Use `grafana-engr` for Grafana/Loki/Mimir and `tempo-server` for direct trace analysis.1314### Datasources1516| Use for | UID | Name | Audience |17|---|---|---|---|18| App + infra logs | `loki` | Loki (Logs) | Platform team primary — most used, has all namespaces |19| Product-only logs | `loki-customer` | Loki (Customers) | Product teams — same data as `loki` but scoped for product use |20| Observability stack logs | `loki-infra` | Loki (Infra) | Panoptos infra only — LGTM components, OTel collectors |21| App metrics (Mimir) | `cortex` | Cortex (Metrics) | All product application metrics |22| Panoptos infra metrics | `prometheus` | Prometheus | Observability stack infra metrics only — skip for app queries |23| Traces | `tempo` | Tempo (Traces) | Use `tempo-server` MCP for direct trace analysis |2425### Datasource Routing Decision2627- User asks about **product/service errors, latency, logs** → `loki` (or `loki-customer`) + `cortex`28- User asks about **LGTM stack health** (cortex-ingester, loki-distributor, tempo, OTel collector) → `loki-infra` + `prometheus`29- User asks about **traces** → `tempo` via `tempo-server` MCP30- Default to `loki` + `cortex` unless explicitly about observability infra3132Default time window for ordinary log triage: last 15 minutes, converted to absolute RFC3339 UTC. Do not pass `now-15m` to tools.3334Always pin labels before querying. Avoid broad scans.3536## Three-Axis Taxonomy3738Every application signal (metrics in `cortex`, logs in `loki`/`loki-customer`) is scoped by three orthogonal labels:3940| Axis | Label | User says | Examples |41|---|---|---|---|42| Product / domain | `service_namespace` | "product", "team", "domain" | `platform`, `revenue`, `ai-platform` |43| Service | `service_name` | "service", "API", "worker" | `platform-objectdb-api`, `revenue-quote-api` |44| Environment | `deployment_environment` | "env", "environment" | `prod`, `rls04`, `rls03`, `staging` |4546> **Environment aliases** are in the `understanding-agent-space-deployment-environment-aliases` memory (always in context). Resolve friendly names (dev, qa, prod, perf, staging) using that memory before querying.4748## Product Namespace Index (service_namespace)4950Compact routing index. **Resolve exact services live** via `list_prometheus_label_values` (see Service Name Resolution) — don't trust hard-coded service lists. Per-namespace service catalogs for `platform`, `revenue`, and `ai-platform` are in their respective memories (always in context).5152**Cortex metrics + Loki logs:** `platform`, `revenue`, `ai-platform`, `contracts`, `conga-sign`, `congasign`, `core-apps`, `xauthor`, `docgen`, `maf`, `esign`, `srm`, `conversations`, `plat-enablement`, `ccdatasync`5354**Loki-only (no Cortex — use `count_over_time` for RED):** `cci`, `cci-standalone`, `clm`, `billing`, `invoicing`, `testauthor`, `approvals`, `tidb`5556**Infra namespaces (NOT product — don't confuse):** `cluster-observability`, `sign`, `contractssf`, `argocd`, `argo-workflows`, `kube-system`, `cert-manager`, `karpenter`, `external-secrets`, `rls-operator`, `rls-app`, `kong`, `nginx-ingress`, `ingress-nginx`5758**loki-infra datasource only:** `panoptos` (LGTM stack: cortex-*, loki-*, tempo-*, grafana), `cluster-observability` (otelcol-*, kube-prometheus-stack-*)5960### Critical gotchas (keep in mind when routing)6162- `sign` namespace = cluster infra for Sign clusters, **NOT** the Sign product (that's `conga-sign` / `congasign` — check both).63- `congasign` overlaps `conga-sign` — check both for Sign product signals.64- `docgen` has duplicate series with a `;otelcol-contrib` suffix — filter `service_name!~".*;otelcol-contrib"` to avoid double-counting.65- `kong` metrics live in `cortex` as `kong_http_requests_total` **without** `service_namespace` — filter by `route` label instead.66- `approvals` logs are in the `approvals` namespace (Loki-only), but its cortex metrics are under `core-apps`.67- `tidb` logs live in one shared home env per stack — discover with `sum by (deployment_environment) (count_over_time({service_namespace="tidb"}[5m]))`.6869## Environment Catalog (deployment_environment)7071> The **friendly-name aliases** (dev, qa, prod, perf, staging) are authoritative in the `understanding-agent-space-deployment-environment-aliases` memory. Always read that memory first when the user names an environment informally.7273### Extended Cortex Environment Values7475Beyond the standard tiers, Cortex data may carry these additional `deployment_environment` values:7677| Tier | Environments |78|---|---|79| Production | `prod` |80| QA | `rls04` |81| Dev | `rls03` |82| Staging / perf | `rls05`, `rls06`, `rls07` (perf), `rls08` (perf) |83| Other dev | `dev`, `dev1`, `dev2`, `dev3`, `rlsdev`, `contractssf-dev`, `ephemeral`, `local` |84| CCI-specific | `cci-beta-1030`, `cci-legacy-stage`, `cci-yama-beta-1030` |85| Yama | `yama-dev-1100` |86| Azure | `rlsaz06` |87| CICD | `cicd` |8889### Loki-Only Environments (not in Cortex)9091`staging`, `contracts-dev`, `qa` (in loki-infra), `max-pu-xajs-engg-401`, `max-pu-xajs-kafka-401`9293## Service Name Resolution9495Users refer to services by informal shorthand (e.g. "objectdb", "connectcrane", "quote api", "extraction worker"). There are 400+ services across 17+ namespaces — do NOT guess the full `service_name` or which `service_namespace` it belongs to.9697### One-Call Resolution Pattern9899When the user gives a partial/informal service name, resolve it with a **single MCP call** — regex search on `service_name` without pinning any namespace:100101```102# Find service_name AND its namespace in one call103list_prometheus_label_values(datasourceUid="cortex", labelName="service_namespace",104 matches=[{filters: [{name: "service_name", type: "=~", value: ".*<shorthand>.*"}]}])105```106107This returns the `service_namespace` value(s) that contain matching services. Then if you need the exact service names:108109```110# Get exact matching service names (same call, flip the labelName)111list_prometheus_label_values(datasourceUid="cortex", labelName="service_name",112 matches=[{filters: [{name: "service_name", type: "=~", value: ".*<shorthand>.*"}]}])113```114115**Examples:**116117| User says | Regex | Returns namespace | Returns service_name(s) |118|---|---|---|---|119| "objectdb" | `.*objectdb.*` | `platform` | `platform-objectdb-api`, `platform-objectdb-perftest-api` |120| "connectcrane" | `.*connectcrane.*` | `core-apps` | `connectcrane-web`, `connectcrane-worker` |121| "quote" | `.*quote.*` | `revenue` | `revenue-quote-api` |122| "extraction" | `.*extraction.*` | `ai-platform`, `cci` (if metrics exist) | `ai-platform-extraction-worker`, `cci-extraction-worker`, ... |123124### Resolution Rules1251261. **Always resolve before querying.** Never hard-code or guess a `service_name` from a shorthand.1272. **If multiple namespaces match** (e.g. "extraction" hits both `ai-platform` and `cci`), ask the user which product they mean.1283. **If zero matches in cortex**, the service may be Loki-only. Retry against Loki:129 ```130 topk(10, sum by (service_name, service_namespace)131 (count_over_time({service_name=~".*<shorthand>.*"}[15m])))132 ```1334. **If the user already specified the product** (e.g. "platform objectdb"), skip the namespace lookup and go straight to the service_name regex scoped to that namespace.134135## Other Dynamic Discovery Patterns136137```138# List all services for a known namespace139list_prometheus_label_values(datasourceUid="cortex", labelName="service_name",140 matches=[{filters: [{name: "service_namespace", type: "=", value: "<ns>"}]}])141142# List environments where a service is active143list_prometheus_label_values(datasourceUid="cortex", labelName="deployment_environment",144 matches=[{filters: [{name: "service_name", type: "=", value: "<svc>"}]}])145146# Discover metric families for a product147query_prometheus(datasourceUid="cortex", expr='group by (__name__) ({service_namespace="<ns>", deployment_environment="<env>"})', queryType="instant")148```149150## Topic File Map151152| User asks about | Read this file |153|---|---|154| Investigation / RCA / "why did this break?" / root cause / incident — anything beyond a single query | `references/rca-playbook.md` (the five-pillar evidence search), then the per-signal files below |155| Generic "what service is failing?" (no service named, no logs/metrics specified) | logs-first per "Failure triage" below — start with `references/loki-logql.md` |156| LogQL, log labels, error logs, traceid extraction, raw logs | `references/loki-logql.md` |157| PromQL, metrics, RED, latency, Kong/nginx 5xx, Kubernetes metrics | `references/mimir-promql.md` (check ingress rollout first — Kong vs nginx) |158| Trace IDs, Tempo, TraceQL, deeplinks, correlation | `references/tempo-traceql.md` |159| Long windows, 30 days, all errors over a week, timeout/truncation/max_samples | `references/wide-window-guard.md` |160| General triage flow or routing | stay in this file unless detail is needed |161162## "Which service is failing?" — generic failure triage163164When the user asks the open-ended question *"which service is failing / has more errors / is broken"* without naming a service or specifying logs vs metrics:165166**Always logs-first, then metrics.** Reason: log-based error counts capture every failure mode (workers, async jobs, app-level exceptions returning HTTP 200, Loki-only namespaces like `cci`/`clm`/`billing`/`invoicing`/`docgen`/`testauthor`/`tidb`). Ingress metrics only see HTTP-fronted services that transit the ingress.1671681. **Loki first** — `topk by service_name` on `SeverityText=~"ERROR|Error|FATAL"` scoped to the env. See `references/loki-logql.md` query D (and its MCP-wrapper gotcha — pull raw lines + tally with jq).1692. **Then ingress metrics** to confirm severity (ratio, rate) and add HTTP-status context. **First detect which ingress is live in this env** — see Ingress rollout note below. Then see `references/mimir-promql.md` queries E/F.1703. **Cross-reference the two lists**:171 - Services topping **both** → real fires, dig in.172 - **Logs-only** top → may be log-spam or non-HTTP failures (workers, jobs).173 - **Metrics-only** top → HTTP-layer failures (timeouts, upstream 5xx) the app isn't logging as ERROR.174175### Ingress rollout note (Kong vs nginx)176177Kong is being rolled out as the ingress proxy. Some envs are on Kong, others still on nginx, and a few may be mid-cutover with both active. **Never assume Kong globally.** Before running any ingress-5xx query, detect the live ingress for the target `deployment_environment`. See `references/mimir-promql.md` § "Ingress detection (Kong vs nginx)".178179## Triage Workflow1801811. Scope to `deployment_environment` plus `service_name` or `service_namespace` and a 5-15 minute window.1822. If the question is generic ("what's failing?"), follow the logs-first failure triage above.1833. If logs are needed, read `references/loki-logql.md`.1844. If metrics are needed, read `references/mimir-promql.md`.1855. If a trace ID is available or Tempo is needed, read `references/tempo-traceql.md`.1866. If the requested window is wide, read `references/wide-window-guard.md` before querying.187188## Cost Guardrails189190- Default log limit: 100.191- Raw Loki lines over 24h: refuse raw fetch; aggregate first.192- Cortex range queries over 24h need careful step sizing.193- Do not run global metric discovery such as `{__name__=~".+"}`.194- If a query returns empty unexpectedly, do one narrow discovery query before concluding no data.195196## Sharing & Upload Note197198This skill is self-contained — the `references/` subfolder holds all topic files referenced above. Zip the whole `panoptos-lgtm/` folder to share with teammates or upload as a `.skill` bundle. Topic files load only when relevant, keeping the initial context small.