Self-hosting
How-to

Monitor the platform

Monitor Agent Barn services, runtime health, communication delivery, and cost synchronization freshness in a self-hosted deployment.

For
Platform engineers, self-hosted operators, and incident responders
On this page
  1. Cost synchronization
  2. Overview
  3. Monitoring architecture
  4. What the stack covers
  5. Before you begin
  6. 1. Configure monitoring
  7. 2. Deploy monitoring
  8. 3. Access Grafana
  9. 4. Verify scrape targets
  10. Monitor Communications
  11. 5. Use the dashboards
  12. Understand the alerts
  13. 6. Respond to alerts
  14. 7. Monitor Agent coverage
  15. Cover the monitoring gaps
  16. 8. Validate monitoring changes
  17. Troubleshooting
  18. Next steps

Monitoring outcome

Actionable namespace signals with explicit coverage gaps

Complete this guide to operate the built-in stack and connect every alert to a verified response path.

  • Prometheus discovers the expected Services and Agent endpoints.
  • Grafana’s four provisioned dashboards display current environment data.
  • Alertmanager sends firing and resolved notifications to Slack.
  • External monitoring covers infrastructure and recovery signals the chart cannot collect.

Overview

Agent Barn deploys a namespace-scoped monitoring stack through the regular Helmfile release.

Services and AgentsPrometheusAlert rulesAlertmanagerSlack
GrafanaProvisioned dashboards read from Prometheus

The design fits environments where Agent Barn controls a Kubernetes namespace but cannot install cluster-wide operators, CRDs, ClusterRoles, or admission webhooks.

EnvironmentNamespaceEnvironment label
Productionagent-farmproduction
Stagingagent-farm-stagingstaging

Monitoring architecture

The chart under helm/monitoring/ deploys plain Prometheus, Grafana, Alertmanager, and kube-state-metrics. It does not use Prometheus Operator or monitoring CRDs.

Namespace workloadsAPI :8000 and ingest :8001LiteLLM :4000Agent health :8081
PrometheusScrape, retain, evaluate
GrafanaTLS ingress
AlertmanagerInternal → Slack
All discovery and storage stay inside the release namespace; only Grafana receives ingress.
ComponentResponsibilityExposure
PrometheusScrapes metrics, stores time series, and evaluates alert rulesCluster-internal
AlertmanagerGroups alerts and sends firing and resolved notifications to SlackCluster-internal
GrafanaDisplays provisioned dashboards backed by PrometheusTraefik ingress with TLS
kube-state-metricsExposes selected pod state and restart metricsCluster-internal

Namespace-scoped access

The chart creates no RBAC resources. Prometheus and kube-state-metrics reuse the existing <namespace>-user ServiceAccount: agent-farm-user in production and agent-farm-staging-user in staging. Prometheus mounts that token for discovery in its own namespace.

Grafana does not mount a Kubernetes ServiceAccount token. Its dashboards come from a ConfigMap rather than a Kubernetes-discovery sidecar.

GrafanaTraefik and TLS ingressOperator-facing
PrometheusCluster-internalTemporary port-forward only
AlertmanagerCluster-internalTemporary port-forward only

What the stack covers

AreaIncluded signalsImportant boundary
Product APIAvailability, request rate, response status, latency, restartsNo end-user synthetic monitoring
Ingest APIAvailability and Tool Call outcome countersA healthy main API does not prove ingest works
CommunicationsProcess availability, Connection status, Delivery queues and outcomes, latency, reconnects, and policy dispositionsAdd the internal Service as a scrape target; no Communications-specific dashboards or alert rules are currently provisioned
Application PostgreSQLAPI database-connectivity probeNo replication, capacity, backup, or restore monitoring
AgentsScrape availability, runtime connectivity, token validation, ERROR state, restartsExisting resources may need rebuilding before discovery works
LiteLLMAvailability, requests, failures, tokens, and spendDoes not monitor the LiteLLM database directly
OpenRouterRemaining key limit and credit-poll healthLow-credit alert requires a limit on the key
Kubernetes podsRestarts and selected pod labelsNo node, kubelet, cAdvisor, CPU, or memory metrics
Alert deliverySlack firing and resolved notificationsSlack is the only built-in receiver
DashboardsFour provisioned operational dashboardsPrometheus retains metrics for 15 days
Business audit dataActivity, Tool Calls, costs, and Event Deliveries in Agent BarnUse the product UI; Prometheus is not durable audit storage

Before you begin

You need:

  • A deployed Agent Barn environment and access to its target namespace.
  • Helm and Helmfile for manual deployments.
  • DNS for Grafana and a working letsencrypt-http01 ClusterIssuer.
  • A strong Grafana administrator password and a Slack incoming webhook for #alerts.
  • A durable StorageClass for Prometheus.
  • An OpenRouter inference key when you want credit monitoring.

Prometheus, Grafana, and Alertmanager each run one replica. Prometheus scrapes every 30 seconds, evaluates rules every minute, retains metrics for 15 days, and uses a 10 GiB persistent volume.

Prometheus defaults
Scrape interval:   30 seconds
Rule evaluation:   1 minute
Retention:         15 days
Persistent volume: 10 GiB

Plan an independent check for the monitoring stack itself. A total Prometheus or Alertmanager failure can prevent the built-in system from reporting its own outage.

Configure monitoring

GitHub Actions deployment

NameTypeEnvironment behavior
SLACK_ALERTS_WEBHOOK_URLSecretShared by production and staging
GRAFANA_ADMIN_PASSWORDSecretProduction Grafana password
MONITORING_WEB_PASSWORDSecretBasic auth for Prometheus and Alertmanager (12+ alphanumeric)
STAGING_MONITORING_WEB_PASSWORDSecretStaging basic auth for Prometheus and Alertmanager
STAGING_GRAFANA_ADMIN_PASSWORDSecretStaging Grafana password
GRAFANA_HOSTVariableProduction Grafana hostname
STAGING_GRAFANA_HOSTVariableStaging Grafana hostname
OPENROUTER_API_KEYSecretUsed by the API and credit probe
STORAGE_CLASSVariableUsed by the Prometheus persistent volume

The workflow derives the environment label from the target branch. Use distinct Grafana passwords and hostnames; the current workflow shares the Slack webhook and OpenRouter key.

Manual deployment

Protected production environment
ENVIRONMENT=production
NAMESPACE=agent-farm

GRAFANA_HOST=grafana.agentbarn.example.com
GRAFANA_ADMIN_PASSWORD=REPLACE_WITH_STRONG_PASSWORD
SLACK_ALERTS_WEBHOOK_URL=https://hooks.slack.com/services/REPLACE_WITH_WEBHOOK

STORAGE_CLASS=REPLACE_WITH_DURABLE_STORAGE_CLASS
OPENROUTER_API_KEY=sk-or-REPLACE_WITH_OPENROUTER_KEY

Do not commit a populated deployment environment file.

Configure DNS and TLS

Point GRAFANA_HOST at cluster ingress. Grafana uses Traefik, the grafana-tls Secret, and the fixed letsencrypt-http01 ClusterIssuer. INGRESS_CLUSTER_ISSUER does not change the Grafana issuer.

Configure OpenRouter credit monitoring

The main API polls OpenRouter GET /key with the inference key and records limit_remaining. An unlimited key reports positive infinity, so OpenRouterCreditsLow cannot fire until the key has a limit.

Deploy the stack

The monitoring release is part of the regular Helmfile deployment and depends on the Agent Barn API release.

Production deployment
ENV_FILE=.env.deploy bash deploy.sh

Monitoring is part of the Helmfile stack and uses the target namespace's configured ServiceAccount. For staging, provision and align that identity before deploying the stack. The generic launcher applies the agent-farm bootstrap regardless of which environment file is selected, so the previous staging launcher command is not sufficient.

For an independently managed namespace whose prerequisites and exported Helmfile inputs are already prepared, the application step is:

Prepared namespace application step
helmfile -f helmfile.yaml.gotmpl sync --wait

This command assumes the intended cluster context, namespace, registry credentials, image references, pod kubeconfig, and other required environment values are already configured. It does not create or repair the missing namespace/RBAC prerequisites. Use the Configuration reference for the input contract and the Kubernetes deployment guide for the normal setup sequence.

Staging monitoring values
ENVIRONMENT=staging
NAMESPACE=agent-farm-staging
GRAFANA_HOST=grafana-staging.agentbarn.example.com
Releases and resources
helm list --namespace agent-farm

kubectl get pods,services,persistentvolumeclaims,ingress \
  --namespace agent-farm

kubectl get certificate,challenge \
  --namespace agent-farm
Wait for readiness
kubectl get pods \
  --namespace agent-farm \
  --watch

Expected components include Prometheus, Alertmanager, Grafana, and kube-state-metrics. Confirm the Prometheus claim and Grafana certificate are ready.

Access Grafana

Grafana address
https://GRAFANA_HOST
Grafana administrator
Username: admin
Password: the value of GRAFANA_ADMIN_PASSWORD
  1. Confirm the provisioned Prometheus data source is healthy.
  2. Open every built-in dashboard and confirm current environment data appears.
  3. Restrict the Grafana hostname through organizational network or identity controls.

Dashboards are provisioned from the grafana-dashboards ConfigMap. Treat JSON under helm/monitoring/dashboards/ as the source of truth rather than UI-only edits.

Verify scrape targets

Prometheus is cluster-internal. Open a temporary authorized port-forward:

Shell
kubectl port-forward \
  --namespace agent-farm \
  service/monitoring-prometheus-server \
  9090:80

Open http://localhost:9090/targets and verify:

JobExpected targets
agentbarn-apiMain http endpoint and ingest endpoint
litellmLiteLLM metrics endpoint with authenticated read-only proxy_admin_viewer key
agentOne target for every discoverable running Agent
kube-state-metricsNamespace pod-state metrics
prometheusPrometheus self-scrape
communicationsAdd the internal Communications Service on port 8002; not currently a provisioned target
PromQL
up{job="agentbarn-api"}
agentbarn_database_up
up{job="litellm"}
up{job="agent"}
agentbarn_agents_in_error
agentbarn_openrouter_credits_scrape_ok

up == 1 means successful scraping. up == 0 means a discovered target cannot be scraped. An absent target indicates discovery, label, Service, or endpoint failure.

Understand the two API endpoints

EndpointPortImportant metrics
Main API8000HTTP requests, database probe, Agents in ERROR, OpenRouter credits
Ingest API8001Ingest HTTP requests and Tool Call outcome counter
Communications8002Process /health and internal /metrics for Connection and Delivery operations

The database, Agent ERROR, and OpenRouter gauges exist only on the main API process. Tool Call outcome metrics are emitted by ingest.

Monitor Communications

Communications is a separately deployed Service on port 8002. Its internal /health endpoint confirms process-level availability only; it does not prove that every provider Connection is authenticated, connected, or successfully delivering messages. Keep /metrics internal and add the Communications Service as an internal Prometheus scrape target.

MetricTypeLabelsPurpose
agentbarn_communication_connection_statusGaugestatusNumber of Connections currently in each status
agentbarn_communication_delivery_outcomesCounterdirection, outcomeDelivery processing outcomes
agentbarn_communication_queue_depthGaugedirectionCurrent queued Delivery count
agentbarn_communication_oldest_queued_age_secondsGaugedirectionAge of the oldest queued Delivery
agentbarn_communication_delivery_latency_secondsHistogramdirection, outcomeDelivery processing latency
agentbarn_communication_reconnectsCounterNoneProvider reconnect attempts
agentbarn_communication_policy_dispositionsCounterdispositionInbound policy evaluation results

Useful values include Connection statuses PENDING, CONNECTING, CONNECTED, DEGRADED, and ERROR; Delivery directions inbound and outbound; outcomes succeeded, dead_lettered, cancelled, unavailable, and retrying; and dispositions accepted, bot_ignored, event_ignored, mention_required, user_denied, channel_denied, and malformed_payload. Metrics refresh failures retain previous scrape values and do not interrupt Communications processing.

Query durable state correctly

Database-backed gauges can expose the same snapshot from multiple Communications replicas, so use max across replicas rather than summing them. Counters and histogram observations are process-local, so aggregate replicas with sum(rate(...)).

Connection degradation
max by (status) (
  agentbarn_communication_connection_status{status=~"DEGRADED|ERROR"}
)
Queue depth
max by (direction) (
  agentbarn_communication_queue_depth
)
Oldest queued age
max by (direction) (
  agentbarn_communication_oldest_queued_age_seconds
)
Delivery outcomes
sum by (direction, outcome) (
  rate(agentbarn_communication_delivery_outcomes[15m])
)
Reconnect rate
sum(
  rate(agentbarn_communication_reconnects[15m])
)
Policy dispositions
sum by (disposition) (
  rate(agentbarn_communication_policy_dispositions[15m])
)
p95 Delivery latency
histogram_quantile(
  0.95,
  sum by (le, direction) (
    rate(agentbarn_communication_delivery_latency_seconds_bucket[15m])
  )
)

Use complementary signals

  1. Communications process availability
  2. Provider Connection status
  3. Delivery queue health and outcomes
  4. Delivery latency
  5. Reconnect activity
  6. Policy dispositions
  7. Agent Runtime health

A healthy Communications process does not guarantee healthy provider Connections; a connected provider does not guarantee successful Delivery processing; and a healthy Agent Runtime does not guarantee its Communications Connection works.

Use the dashboards

Agent Barn provisions four dashboards from a ConfigMap; no Grafana sidecar discovers them.

DashboardSignalsUse
API HealthAPI and ingest availability, database reachability, request rate and latency, API pod restartsStart with UI or API availability and latency incidents
Agent HealthDiscovered and down Agents, ERROR state, token validation, runtime connectivity, pod generations and restartsFilter and investigate by Organization and Agent
Error RatesAPI 5xx ratios, Tool Call error ratio and outcomes, failures grouped by toolSeparate API failures from tool, credential, and provider failures
LLM Costs & ErrorsLiteLLM health, OpenRouter credits, spend, requests, failures, tokens, and model attributionUse product and provider records for durable cost investigation

Agent series receive stable app, agent_name, org_id, and org_name labels from Service labels, preserving identity across pod replacements.

A high Tool Call error ratio does not necessarily mean the API is failing. Check the affected tool, Agent credentials, provider access, and recent configuration changes.

Metrics remain for 15 days. Use Agent Barn cost surfaces and provider billing records for durable cost investigation.

Understand the alerts

API and database alerts

AlertSeverityFires when
APIDowncriticalThe main API target fails scrapes for 2 minutes
APIAbsentcriticalThe main API target is absent for 5 minutes
IngestAPIDownwarningThe ingest process fails scrapes for 5 minutes
DatabaseDowncriticalThe API database probe reports failure for 2 minutes

Error-rate alerts

AlertSeverityFires when
HighAPI5xxRatewarningAPI 5xx ratio exceeds 5% for 5 minutes with non-trivial traffic
HighAPI5xxRatecriticalAPI 5xx ratio exceeds 20% for 5 minutes with non-trivial traffic
HighToolCallErrorRatewarningTool Call error ratio exceeds 25% over 15 minutes and remains elevated for 10 minutes

Agent alerts

AlertSeverityFires when
AgentTargetDowncriticalAn Agent health endpoint cannot be scraped for 2 minutes
AgentUnhealthywarningA previously connected runtime remains unhealthy for 10 minutes
AgentsInErrorStatewarningAt least one Agent remains in control-plane ERROR for 5 minutes

LiteLLM and OpenRouter alerts

AlertSeverityFires when
LiteLLMDowncriticalLiteLLM is down or absent for 3 minutes
OpenRouterCreditsLowcriticalRemaining key limit is below USD 5 for 15 minutes
OpenRouterCreditsUnknownwarningThe credit poll fails for 30 minutes

DatabaseDown bridges short metric gaps during API rollouts. API ratio alerts include request-rate gates. AgentUnhealthy applies only after agent_healthz_ever_connected reports a prior connection.

The OpenRouter poll is cached for five minutes and separates stale credit value from scrape health. Provider authentication and connectivity failures belong to Connection status, safe Connection diagnostics, reconnect activity, Delivery outcomes, and Communications journal entries, not Agent-level Slack tokens or raw credential logs.

Recommended Communications alerts

These are recommended custom alerts, not alert rules or dashboards currently shipped by the monitoring chart:

  • Communications target absent or down
  • Sustained ERROR or DEGRADED Connection counts
  • Growing queue depth or excessive oldest queued Delivery age
  • Increased dead-lettered or unavailable outcomes, or elevated Delivery latency
  • Reconnect spikes or unexpected changes in rejected policy dispositions

Select thresholds from the deployment’s traffic profile and normal baseline; queue, latency, and reconnect limits are not universal.

Alert delivery behavior

  • Alerts route to Slack #alerts and group by alert name and Organization name.
  • New groups wait 30 seconds, group updates send every five minutes, and unresolved alerts repeat every four hours.
  • Resolved notifications are sent and Slack titles include the environment label.
  • The webhook is stored in a Kubernetes Secret mounted into Alertmanager, not the rendered ConfigMap.

Respond to alerts

  1. Confirm whether the alert is from production or staging.
  2. Identify the affected service, Organization, or Agent.
  3. Confirm the signal in Grafana or Prometheus.
  4. Check the current Kubernetes workload state.
  5. Review recent deployments, migrations, and configuration changes.
  6. Inspect service or Agent logs.
  7. Mitigate user impact.
  8. Verify recovery from the original signal.
  9. Record the incident and any missing monitoring.
Kubernetes state and events
kubectl get pods,deployments,statefulsets,jobs,cronjobs \
  --namespace agent-farm

kubectl get events \
  --namespace agent-farm \
  --sort-by=.lastTimestamp
Workload details and logs
kubectl describe pod POD_NAME \
  --namespace agent-farm

kubectl logs POD_NAME \
  --namespace agent-farm \
  --all-containers \
  --tail=200

Respond to a Communications alert

  1. Confirm the Communications process is available.
  2. Inspect Connection status counts.
  3. Check queue depth and oldest queued Delivery age.
  4. Compare Delivery outcomes and latency.
  5. Review reconnect and policy-disposition changes.
  6. Open the affected Connection’s safe diagnostics and Communications journal history.
  7. Check the Agent Runtime separately if Delivery reached the Agent boundary.

Do not put raw credentials, message content, provider request bodies, headers, webhook payloads, or unfiltered exception text in metrics, alerts, or response notes.

Inspect Alertmanager

Shell
kubectl port-forward \
  --namespace agent-farm \
  service/monitoring-alertmanager \
  9093:9093

Open http://localhost:9093 to inspect grouping, delivery, and active silences. A silence suppresses notifications; it does not repair the failure.

Correlate product evidence

SignalFollow-up surface
Agent down or unhealthyAgent health and logs
Agent in ERRORAgent lifecycle status and last_error
Tool Call errorsActivity and Tool Calls
Unexpected spendCost review
Delivery processing concernPlatform Event Deliveries
Communication credential or Delivery concernConnection status, safe diagnostics, Communications journal, and Delivery outcomes

Platform Administrators can inspect Event Deliveries at /dashboard/platform/event-deliveries. The built-in rules do not alert on Redis, workers, reconciliation, or Event Delivery lifecycle state.

Monitor Agent coverage

Prometheus discovers Agent metrics on port 8081 through Services with agentbarn.io/component=agent and an endpoint named healthz.

Agents created before monitoring

Existing Agents may lack the health script, endpoint, or labels. Stop and start each affected Agent once so the API rebuilds its Kubernetes resources.

Services with the old component label

When metrics already exist and only the old pre-rebrand label is missing, patch the Service without restarting:

Shell
kubectl label services \
  --namespace agent-farm \
  --selector agentfarm.io/component=agent \
  agentbarn.io/component=agent \
  --overwrite
Verify Agent Services
kubectl get services \
  --namespace agent-farm \
  --selector agentbarn.io/component=agent \
  --show-labels

Prometheus derives app, agent-name, org-id, and org-name from the Service. Restart an Agent when its target lacks current identity labels.

Cover the monitoring gaps

The namespace stack intentionally leaves these production responsibilities to operators.

Missing coverageRecommended external control
Node CPU, memory, disk, and healthCluster or infrastructure monitoring
Container CPU and memorykubelet/cAdvisor or managed Kubernetes observability
PVC capacity and storage latencyStorage and volume monitoring
PostgreSQL replication and internal healthPostgreSQL exporter or managed database monitoring
Backup success and restore readinessBackup-system alerts and scheduled restore tests
Certificate expiry and renewalcert-manager or external certificate monitoring
Public UI and API reachabilityExternal synthetic probes
DNS availabilityExternal DNS monitoring
Redis and worker readinessAdditional application and Redis metrics
Event Delivery backlog or dead lettersPlatform Event Deliveries plus additional alert rules
Firecrawl health and capacityFirecrawl-specific monitoring
Email delivery and provider quotaCloudflare provider monitoring
Long-term metricsRemote write or an externally managed metrics platform
Monitoring-stack availabilityIndependent external checks
High availabilityA separately designed and tested HA architecture

Validate monitoring changes

Shell
helm dependency build helm/monitoring
make check-monitoring

make check-monitoring renders the chart, extracts alert rules, parses dashboard PromQL, runs promtool checks, and executes alert threshold and annotation unit tests. It needs Helm, Docker, and built chart dependencies.

Chart.lock pins dependencies; downloaded archives under helm/monitoring/charts/ are not committed. Monitoring CI runs for helm/monitoring/**, the workflow, and relevant Make target changes.

Verify alert delivery in staging

  • Produce a safe, known staging alert and observe it pending, then firing.
  • Confirm Alertmanager receives it and Slack shows the environment-tagged notification.
  • Remove the condition and confirm both the rule and Slack notification resolve.
  • Verify the response procedure identifies the correct first checks.

Operational checklist

  • Initial setup

  • After deployment

  • Ongoing operations

Troubleshooting

SymptomLikely causeResolution
Helmfile reports a missing Grafana or Slack valueRequired monitoring environment variables are absentAdd GRAFANA_HOST, GRAFANA_ADMIN_PASSWORD, and SLACK_ALERTS_WEBHOOK_URL
Grafana ingress has no certificateDNS or the fixed letsencrypt-http01 ClusterIssuer is unavailableVerify DNS, Ingress, Certificate, Challenge, and ClusterIssuer resources
Grafana opens but dashboards are missingThe dashboards ConfigMap was not mounted or Grafana has not received the updateInspect grafana-dashboards and redeploy the chart
Grafana dashboards show no dataThe Prometheus data source or scrape targets are unavailableVerify the data source, Prometheus pod, and /targets
Prometheus cannot discover any targetsIts ServiceAccount lacks namespace read accessVerify the <namespace>-user ServiceAccount and tenant RoleBinding
API target is absentAPI Service labels or endpoints do not match discovery rulesInspect the agentbarn-api Service and its http and ingest endpoints
Database alert fires while PostgreSQL is runningThe API cannot authenticate, resolve, or query the databaseInspect API logs, the database Service, credentials, and migration state
Tool Call dashboard is emptyIngest is not receiving Tool Call resultsVerify the ingest target, Agent ingest configuration, and recent Tool Calls
Agents do not appear in PrometheusTheir Services lack current labels or health endpointsStop and start old Agents, or patch only the legacy component label
Agent appears down after pod replacementThe Service has no ready healthz endpointInspect Agent readiness, health server, Service, and endpoint
Communications process is healthy but messages failProvider Connection or Delivery processing is impairedInspect Connection status, safe diagnostics, reconnects, Delivery outcomes, and the Communications journal
OpenRouter credits show infinityThe key has no credit limitConfigure a key limit if low-credit alerting is required
OpenRouterCreditsUnknown firesThe key is invalid or OpenRouter is unreachableVerify API configuration, egress, and the OpenRouter key
Low-credit alert never firesThe key has no limit or the poll is unhealthyCheck both remaining-credit and scrape-health gauges
Slack receives no alertsWebhook, Secret mount, Alertmanager route, or Slack access is invalidInspect the Secret, Alertmanager pod, configuration, and logs
Staging alerts look like productionENVIRONMENT is wrongCorrect the environment label and redeploy monitoring
CPU and memory panels are unavailableNode and cAdvisor scraping is intentionally disabledAdd separate cluster-level infrastructure monitoring
Prometheus data ends after 15 daysThe retention period elapsedAdd remote storage for longer retention
A monitoring pod failure produced no Slack alertThe stack cannot reliably monitor its own total failureAdd an independent external availability check

Next steps

Use Self-hosting Communications for service operation, self-hosting configuration for internal URLs and credentials, Communication Connections for Connection ownership, and troubleshooting for broader incidents.

Continue the self-hosting sequence Upgrade Agent Barn → Review, stage, deploy, verify, and recover future releases.

Cost freshness and synchronization

See Cost synchronization for the entrypoint, credentials, schedule, backfill, and healing behavior.

Calls can occur while Costs remains empty or stale. Check cost-sync scheduling and logs, database access, LiteLLM master-key lookup, and upstream availability. An absent record or unresolved OpenRouter lookup does not prove a call was free. Review attribution and recovery backlog separately from Runtime health.

Docker Compose and run.sh do not schedule cost synchronization automatically. Local reporting needs an explicit invocation in a configured application environment; refreshing Costs does not perform synchronization.

Documentation