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.
The design fits environments where Agent Barn controls a Kubernetes namespace but cannot install cluster-wide operators, CRDs, ClusterRoles, or admission webhooks.
| Environment | Namespace | Environment label |
|---|---|---|
| Production | agent-farm | production |
| Staging | agent-farm-staging | staging |
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.
| Component | Responsibility | Exposure |
|---|---|---|
| Prometheus | Scrapes metrics, stores time series, and evaluates alert rules | Cluster-internal |
| Alertmanager | Groups alerts and sends firing and resolved notifications to Slack | Cluster-internal |
| Grafana | Displays provisioned dashboards backed by Prometheus | Traefik ingress with TLS |
| kube-state-metrics | Exposes selected pod state and restart metrics | Cluster-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.
What the stack covers
| Area | Included signals | Important boundary |
|---|---|---|
| Product API | Availability, request rate, response status, latency, restarts | No end-user synthetic monitoring |
| Ingest API | Availability and Tool Call outcome counters | A healthy main API does not prove ingest works |
| Application PostgreSQL | API database-connectivity probe | No replication, capacity, backup, or restore monitoring |
| Agents | Scrape availability, runtime connectivity, token validation, ERROR state, restarts | Existing resources may need rebuilding before discovery works |
| LiteLLM | Availability, requests, failures, tokens, and spend | Does not monitor the LiteLLM database directly |
| OpenRouter | Remaining key limit and credit-poll health | Low-credit alert requires a limit on the key |
| Kubernetes pods | Restarts and selected pod labels | No node, kubelet, cAdvisor, CPU, or memory metrics |
| Alert delivery | Slack firing and resolved notifications | Slack is the only built-in receiver |
| Dashboards | Four provisioned operational dashboards | Prometheus retains metrics for 15 days |
| Business audit data | Activity, Tool Calls, costs, and Event Deliveries in Agent Barn | Use 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-http01ClusterIssuer. - 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.
Scrape interval: 30 seconds
Rule evaluation: 1 minute
Retention: 15 days
Persistent volume: 10 GiBPlan 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
| Name | Type | Environment behavior |
|---|---|---|
SLACK_ALERTS_WEBHOOK_URL | Secret | Shared by production and staging |
GRAFANA_ADMIN_PASSWORD | Secret | Production Grafana password |
STAGING_GRAFANA_ADMIN_PASSWORD | Secret | Staging Grafana password |
GRAFANA_HOST | Variable | Production Grafana hostname |
STAGING_GRAFANA_HOST | Variable | Staging Grafana hostname |
OPENROUTER_API_KEY | Secret | Used by the API and credit probe |
STORAGE_CLASS | Variable | Used 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
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_KEYDo 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.
ENV_FILE=.env.deploy bash deploy.shENV_FILE=.env.deploy.staging bash deploy.shENVIRONMENT=staging
NAMESPACE=agent-farm-staging
GRAFANA_HOST=grafana-staging.agentbarn.example.comhelm list --namespace agent-farm
kubectl get pods,services,persistentvolumeclaims,ingress \
--namespace agent-farm
kubectl get certificate,challenge \
--namespace agent-farmkubectl get pods \
--namespace agent-farm \
--watchExpected components include Prometheus, Alertmanager, Grafana, and kube-state-metrics. Confirm the Prometheus claim and Grafana certificate are ready.
Access Grafana
https://GRAFANA_HOSTUsername: admin
Password: the value of GRAFANA_ADMIN_PASSWORD- Confirm the provisioned Prometheus data source is healthy.
- Open every built-in dashboard and confirm current environment data appears.
- 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:
kubectl port-forward \
--namespace agent-farm \
service/monitoring-prometheus-server \
9090:80Open http://localhost:9090/targets and verify:
| Job | Expected targets |
|---|---|
agentbarn-api | Main http endpoint and ingest endpoint |
litellm | LiteLLM http endpoint |
agent | One target for every discoverable running Agent |
kube-state-metrics | Namespace pod-state metrics |
prometheus | Prometheus self-scrape |
up{job="agentbarn-api"}
agentbarn_database_up
up{job="litellm"}
up{job="agent"}
agentbarn_agents_in_error
agentbarn_openrouter_credits_scrape_okup == 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
| Endpoint | Port | Important metrics |
|---|---|---|
| Main API | 8000 | HTTP requests, database probe, Agents in ERROR, OpenRouter credits |
| Ingest API | 8001 | Ingest HTTP requests and Tool Call outcome counter |
The database, Agent ERROR, and OpenRouter gauges exist only on the main API process. Tool Call outcome metrics are emitted by ingest.
Use the dashboards
Agent Barn provisions four dashboards from a ConfigMap; no Grafana sidecar discovers them.
| Dashboard | Signals | Use |
|---|---|---|
| API Health | API and ingest availability, database reachability, request rate and latency, API pod restarts | Start with UI or API availability and latency incidents |
| Agent Health | Discovered and down Agents, ERROR state, token validation, runtime connectivity, pod generations and restarts | Filter and investigate by Organization and Agent |
| Error Rates | API 5xx ratios, Tool Call error ratio and outcomes, failures grouped by tool | Separate API failures from tool, credential, and provider failures |
| LLM Costs & Errors | LiteLLM health, OpenRouter credits, spend, requests, failures, tokens, and model attribution | Use 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
| Alert | Severity | Fires when |
|---|---|---|
APIDown | critical | The main API target fails scrapes for 2 minutes |
APIAbsent | critical | The main API target is absent for 5 minutes |
IngestAPIDown | warning | The ingest process fails scrapes for 5 minutes |
DatabaseDown | critical | The API database probe reports failure for 2 minutes |
Error-rate alerts
| Alert | Severity | Fires when |
|---|---|---|
HighAPI5xxRate | warning | API 5xx ratio exceeds 5% for 5 minutes with non-trivial traffic |
HighAPI5xxRate | critical | API 5xx ratio exceeds 20% for 5 minutes with non-trivial traffic |
HighToolCallErrorRate | warning | Tool Call error ratio exceeds 25% over 15 minutes and remains elevated for 10 minutes |
Agent alerts
| Alert | Severity | Fires when |
|---|---|---|
AgentTargetDown | critical | An Agent health endpoint cannot be scraped for 2 minutes |
AgentUnhealthy | warning | A previously connected runtime remains unhealthy for 10 minutes |
AgentSlackTokensInvalid | warning | The Agent token-validation gauge reports failure for 10 minutes |
AgentsInErrorState | warning | At least one Agent remains in control-plane ERROR for 5 minutes |
LiteLLM and OpenRouter alerts
| Alert | Severity | Fires when |
|---|---|---|
LiteLLMDown | critical | LiteLLM is down or absent for 3 minutes |
OpenRouterCreditsLow | critical | Remaining key limit is below USD 5 for 15 minutes |
OpenRouterCreditsUnknown | warning | The 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 Agent token metric and alert retain Slack-specific names; verify the actual platform for non-Slack Agents. The OpenRouter poll is cached for five minutes and separates stale credit value from scrape health.
Alert delivery behavior
- Alerts route to Slack
#alertsand 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
- Confirm whether the alert is from production or staging.
- Identify the affected service, Organization, or Agent.
- Confirm the signal in Grafana or Prometheus.
- Check the current Kubernetes workload state.
- Review recent deployments, migrations, and configuration changes.
- Inspect service or Agent logs.
- Mitigate user impact.
- Verify recovery from the original signal.
- Record the incident and any missing monitoring.
kubectl get pods,deployments,statefulsets,jobs,cronjobs \
--namespace agent-farm
kubectl get events \
--namespace agent-farm \
--sort-by=.lastTimestampkubectl describe pod POD_NAME \
--namespace agent-farm
kubectl logs POD_NAME \
--namespace agent-farm \
--all-containers \
--tail=200Inspect Alertmanager
kubectl port-forward \
--namespace agent-farm \
service/monitoring-alertmanager \
9093:9093Open http://localhost:9093 to inspect grouping, delivery, and active silences. A silence suppresses notifications; it does not repair the failure.
Correlate product evidence
| Signal | Follow-up surface |
|---|---|
| Agent down or unhealthy | Agent health and logs |
| Agent in ERROR | Agent lifecycle status and last_error |
| Tool Call errors | Activity and Tool Calls |
| Unexpected spend | Cost review |
| Delivery processing concern | Platform Event Deliveries |
| Credential validation failure | Agent credentials and integration validation |
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:
kubectl label services \
--namespace agent-farm \
--selector agentfarm.io/component=agent \
agentbarn.io/component=agent \
--overwritekubectl get services \
--namespace agent-farm \
--selector agentbarn.io/component=agent \
--show-labelsPrometheus 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 coverage | Recommended external control |
|---|---|
| Node CPU, memory, disk, and health | Cluster or infrastructure monitoring |
| Container CPU and memory | kubelet/cAdvisor or managed Kubernetes observability |
| PVC capacity and storage latency | Storage and volume monitoring |
| PostgreSQL replication and internal health | PostgreSQL exporter or managed database monitoring |
| Backup success and restore readiness | Backup-system alerts and scheduled restore tests |
| Certificate expiry and renewal | cert-manager or external certificate monitoring |
| Public UI and API reachability | External synthetic probes |
| DNS availability | External DNS monitoring |
| Redis and worker readiness | Additional application and Redis metrics |
| Event Delivery backlog or dead letters | Platform Event Deliveries plus additional alert rules |
| Firecrawl health and capacity | Firecrawl-specific monitoring |
| Email delivery and provider quota | Cloudflare provider monitoring |
| Long-term metrics | Remote write or an externally managed metrics platform |
| Monitoring-stack availability | Independent external checks |
| High availability | A separately designed and tested HA architecture |
Validate monitoring changes
helm dependency build helm/monitoring
make check-monitoringmake 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
| Symptom | Likely cause | Resolution |
|---|---|---|
| Helmfile reports a missing Grafana or Slack value | Required monitoring environment variables are absent | Add GRAFANA_HOST, GRAFANA_ADMIN_PASSWORD, and SLACK_ALERTS_WEBHOOK_URL |
| Grafana ingress has no certificate | DNS or the fixed letsencrypt-http01 ClusterIssuer is unavailable | Verify DNS, Ingress, Certificate, Challenge, and ClusterIssuer resources |
| Grafana opens but dashboards are missing | The dashboards ConfigMap was not mounted or Grafana has not received the update | Inspect grafana-dashboards and redeploy the chart |
| Grafana dashboards show no data | The Prometheus data source or scrape targets are unavailable | Verify the data source, Prometheus pod, and /targets |
| Prometheus cannot discover any targets | Its ServiceAccount lacks namespace read access | Verify the <namespace>-user ServiceAccount and tenant RoleBinding |
| API target is absent | API Service labels or endpoints do not match discovery rules | Inspect the agentbarn-api Service and its http and ingest endpoints |
| Database alert fires while PostgreSQL is running | The API cannot authenticate, resolve, or query the database | Inspect API logs, the database Service, credentials, and migration state |
| Tool Call dashboard is empty | Ingest is not receiving Tool Call results | Verify the ingest target, Agent ingest configuration, and recent Tool Calls |
| Agents do not appear in Prometheus | Their Services lack current labels or health endpoints | Stop and start old Agents, or patch only the legacy component label |
| Agent appears down after pod replacement | The Service has no ready healthz endpoint | Inspect Agent readiness, health server, Service, and endpoint |
| Slack token alert appears for another platform | The current metric and alert names remain Slack-specific | Verify actual platform credentials through health and logs |
| OpenRouter credits show infinity | The key has no credit limit | Configure a key limit if low-credit alerting is required |
| OpenRouterCreditsUnknown fires | The key is invalid or OpenRouter is unreachable | Verify API configuration, egress, and the OpenRouter key |
| Low-credit alert never fires | The key has no limit or the poll is unhealthy | Check both remaining-credit and scrape-health gauges |
| Slack receives no alerts | Webhook, Secret mount, Alertmanager route, or Slack access is invalid | Inspect the Secret, Alertmanager pod, configuration, and logs |
| Staging alerts look like production | ENVIRONMENT is wrong | Correct the environment label and redeploy monitoring |
| CPU and memory panels are unavailable | Node and cAdvisor scraping is intentionally disabled | Add separate cluster-level infrastructure monitoring |
| Prometheus data ends after 15 days | The retention period elapsed | Add remote storage for longer retention |
| A monitoring pod failure produced no Slack alert | The stack cannot reliably monitor its own total failure | Add an independent external availability check |