Observability and Metrics System Design

Observability and Metrics System Design

Document Version: 1.0 Date: 2026-01-31 Author: Reliability Engineer Status: Design Proposal


Table of Contents

1. Executive Summary 2. Current State Analysis 3. Architecture Overview 4. Metrics Collection Design 5. Log Aggregation Design 6. SLI/SLO Definitions 7. Alert Rules 8. Dashboard Specifications 9. Implementation Roadmap 10. Appendices


Executive Summary

This document defines a comprehensive observability strategy for the agentic-sandbox VM orchestration platform. The design provides:

  • Host-based metrics aggregation using Prometheus
  • Per-agent custom metrics via node_exporter textfile collector
  • Centralized log shipping to host-based storage
  • Actionable SLIs/SLOs for agent availability and task success
  • Three-tier alerting (warning, critical, emergency)

The architecture maintains the existing lightweight footprint while enabling production-grade observability.


Current State Analysis

Existing Capabilities

ComponentCurrent StateGap Analysis
Management ServerPrometheus metrics exposed at `/metrics` (port 8122)✓ Good foundation, needs enrichment
Agent MetricsBasic metrics sent via gRPC heartbeat (CPU, memory)⚠ Not persisted or aggregated over time
Agent LoggingLocal file logging to `/mnt/inbox/runs/` when agentshare mounted⚠ No centralized collection or search
Distributed TracingNone✗ Missing
AlertingNone✗ Missing

Current Metrics (Management Server)

From `/home/roctinam/dev/agentic-sandbox/management/src/telemetry/metrics.rs`:

agentic_uptime_seconds                      # Server uptime
agentic_agents_connected                    # Connected agent count
agentic_agents_by_status{status}           # ready, busy
agentic_commands_total                      # Total commands dispatched
agentic_commands_by_result{result}         # success, failed
agentic_commands_duration_seconds_sum      # Sum of durations
agentic_grpc_requests_total{method}        # gRPC request count
agentic_ws_connections_current/total       # WebSocket metrics
agentic_tasks_total                         # Total tasks
agentic_tasks_by_state{state}              # pending, running, completed, failed

Current Metrics (Agent Client)

From `/home/roctinam/dev/agentic-sandbox/agent-rs/src/main.rs` (lines 214-238):

Agents collect metrics locally but only write to `/mnt/inbox/runs/*/metrics.json`:

  • CPU percent
  • Memory (used/total bytes)
  • Disk (used/total bytes)

Gap: These are point-in-time snapshots, not time-series data.


Architecture Overview

┌─────────────────────────────────────────────────────────────────────────────┐
│                              Host System                                     │
│                                                                               │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                     Management Server (Port 8122)                     │   │
│  │  • /metrics (Prometheus format)                                      │   │
│  │  • Aggregates agent metrics from gRPC heartbeats                     │   │
│  │  • Custom metrics for tasks, commands, sessions                      │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                    ▲                                          │
│                                    │ gRPC Heartbeat                           │
│                                    │ (metrics embedded)                       │
│  ┌─────────────────────────────────┼──────────────────────────────────────┐ │
│  │           Prometheus Server     │                                      │ │
│  │           (Host or External)    │                                      │ │
│  │                                 │                                      │ │
│  │  1. Scrape management /metrics  │                                      │ │
│  │  2. Scrape node_exporter (VMs) <─────┐                                │ │
│  │  3. PromQL queries → Grafana         │                                │ │
│  │  4. Alertmanager integration          │                                │ │
│  └───────────────────────────────────────┘                                │ │
│                                         │                                    │
│  ┌──────────────────────────────────────┼────────────────────────────────┐ │
│  │            Log Aggregation           │                                │ │
│  │            (Promtail/Vector)         │                                │ │
│  │                                      │                                │ │
│  │  • Tail agent logs from agentshare  │                                │ │
│  │  • Ship to Loki/ElasticSearch       │                                │ │
│  │  • Structured JSON parsing          │                                │ │
│  └──────────────────────────────────────┘                                │ │
│                                         │                                    │
│  ┌──────────────────────────────────────▼────────────────────────────────┐ │
│  │                      QEMU/KVM Agent VMs                               │ │
│  │  ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐   │ │
│  │  │  agent-01        │  │  agent-02        │  │  agent-03        │   │ │
│  │  │                  │  │                  │  │                  │   │ │
│  │  │  ┌────────────┐  │  │  ┌────────────┐  │  │  ┌────────────┐  │   │ │
│  │  │  │node_export │  │  │  │node_export │  │  │  │node_export │  │   │ │
│  │  │  │:9100       │  │  │  │:9100       │  │  │  │:9100       │  │   │ │
│  │  │  └────────────┘  │  │  └────────────┘  │  │  └────────────┘  │   │ │
│  │  │                  │  │                  │  │                  │   │ │
│  │  │  ┌────────────┐  │  │  ┌────────────┐  │  │  ┌────────────┐  │   │ │
│  │  │  │Custom      │  │  │  │Custom      │  │  │  │Custom      │  │   │ │
│  │  │  │Metrics     │  │  │  │Metrics     │  │  │  │Metrics     │  │   │ │
│  │  │  │Exporter    │  │  │  │Exporter    │  │  │  │Exporter    │  │   │ │
│  │  │  │(systemd)   │  │  │  │(systemd)   │  │  │  │(systemd)   │  │   │ │
│  │  │  └────────────┘  │  │  └────────────┘  │  │  └────────────┘  │   │ │
│  │  │                  │  │                  │  │                  │   │ │
│  │  │  Log files:      │  │  Log files:      │  │  Log files:      │   │ │
│  │  │  • agent.log     │  │  • agent.log     │  │  • agent.log     │   │ │
│  │  │  • commands.log  │  │  • commands.log  │  │  • commands.log  │   │ │
│  │  │  • /mnt/inbox/   │  │  • /mnt/inbox/   │  │  • /mnt/inbox/   │   │ │
│  │  └──────────────────┘  │  └──────────────┘  │  └──────────────┘   │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘

Design Principles

1. Minimal Agent Footprint: Use standard exporters (node_exporter) + textfile collector 2. Host-Side Aggregation: Prometheus scrapes both management server and agent VMs 3. Shared Storage as Bridge: Leverage existing virtiofs mounts for log collection 4. Two-Layer Metrics: System metrics (node_exporter) + application metrics (custom) 5. Structured Logging: JSON format for machine-readable parsing


Metrics Collection Design

3.1 Management Server Metrics (Existing + Extensions)

File: `/home/roctinam/dev/agentic-sandbox/management/src/telemetry/metrics.rs`

Proposed Additions

// Add to existing Metrics struct:

// Agent session tracking
agent_session_count: AtomicU64,
agent_session_duration_sum_ms: AtomicU64,
agent_restarts_total: AtomicU64,

// Storage metrics (aggregated from agent heartbeats)
agentshare_inbox_bytes: HashMap<String, AtomicU64>,  // Per-agent storage

// Command execution detail
command_latency_buckets: [AtomicU64; 10],  // Histogram: 0-10ms, 10-50ms, 50-100ms, ...

// Task success rate
task_success_total: AtomicU64,
task_failure_total: AtomicU64,
task_timeout_total: AtomicU64,

New Prometheus Metrics

# Agent session metrics
agentic_agent_sessions_active{agent_id}                 # Current active sessions
agentic_agent_session_duration_seconds_sum{agent_id}    # Total session time
agentic_agent_restarts_total{agent_id}                  # Restart count

# Storage metrics (from heartbeat reports)
agentic_agentshare_inbox_bytes{agent_id}                # Per-agent inbox usage

# Command execution latency histogram
agentic_command_latency_seconds_bucket{le}              # Buckets: 0.01, 0.05, 0.1, 0.5, 1, 5, 10, 30, 60, +Inf
agentic_command_latency_seconds_sum
agentic_command_latency_seconds_count

# Task outcomes
agentic_task_outcomes_total{outcome}                    # success, failure, timeout

3.2 Agent VM System Metrics (node_exporter)

Installation via provisioning profile:

# Add to images/qemu/profiles/agentic-dev/packages.txt
prometheus-node-exporter

Systemd service: Enabled by default on Ubuntu package install.

Exposed metrics: `http://192.168.122.20X:9100/metrics`

Key Metrics

# CPU
node_cpu_seconds_total{cpu,mode}                        # Per-CPU time by mode
node_load1, node_load5, node_load15                     # Load averages

# Memory
node_memory_MemTotal_bytes
node_memory_MemAvailable_bytes
node_memory_Cached_bytes
node_memory_SwapTotal_bytes
node_memory_SwapFree_bytes

# Disk
node_filesystem_avail_bytes{mountpoint}
node_filesystem_size_bytes{mountpoint}
node_disk_io_time_seconds_total{device}
node_disk_read_bytes_total{device}
node_disk_written_bytes_total{device}

# Network
node_network_receive_bytes_total{device}
node_network_transmit_bytes_total{device}
node_network_receive_errs_total{device}

# System
node_boot_time_seconds
node_time_seconds

3.3 Custom Agent Metrics (Textfile Collector)

Design: Agent client writes metrics to `/var/lib/prometheus/node-exporter/agent.prom` every 60 seconds.

File Format: Prometheus text exposition format

File: `/home/roctinam/dev/agentic-sandbox/agent-rs/src/main.rs` (new module)

Implementation Sketch

// New module: agent-rs/src/metrics_exporter.rs

use std::fs;
use std::io::Write;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use tokio::time::interval;

pub struct AgentMetricsExporter {
    agent_id: String,
    output_path: String,
    counters: Arc<Mutex<Counters>>,
}

struct Counters {
    commands_executed: u64,
    commands_success: u64,
    commands_failed: u64,
    claude_tasks_total: u64,
    pty_sessions_total: u64,
    current_command_count: u64,
    last_command_latency_ms: u64,
}

impl AgentMetricsExporter {
    pub fn new(agent_id: String) -> Self {
        Self {
            agent_id,
            output_path: "/var/lib/prometheus/node-exporter/agent.prom".to_string(),
            counters: Arc::new(Mutex::new(Counters::default())),
        }
    }

    pub fn spawn(&self) {
        let counters = self.counters.clone();
        let agent_id = self.agent_id.clone();
        let output_path = self.output_path.clone();

        tokio::spawn(async move {
            let mut interval = interval(Duration::from_secs(60));
            loop {
                interval.tick().await;
                Self::write_metrics(&counters, &agent_id, &output_path);
            }
        });
    }

    fn write_metrics(counters: &Arc<Mutex<Counters>>, agent_id: &str, path: &str) {
        let c = counters.lock().unwrap();
        let mut output = String::new();

        output.push_str(&format!(
            "# HELP agentic_agent_commands_total Total commands executed\
\
             # TYPE agentic_agent_commands_total counter\
\
             agentic_agent_commands_total{{agent_id=\"{}\"}} {}\
\
",
            agent_id, c.commands_executed
        ));

        output.push_str(&format!(
            "# HELP agentic_agent_commands_success Successful command count\
\
             # TYPE agentic_agent_commands_success counter\
\
             agentic_agent_commands_success{{agent_id=\"{}\"}} {}\
\
",
            agent_id, c.commands_success
        ));

        output.push_str(&format!(
            "# HELP agentic_agent_commands_failed Failed command count\
\
             # TYPE agentic_agent_commands_failed counter\
\
             agentic_agent_commands_failed{{agent_id=\"{}\"}} {}\
\
",
            agent_id, c.commands_failed
        ));

        output.push_str(&format!(
            "# HELP agentic_agent_claude_tasks_total Claude task count\
\
             # TYPE agentic_agent_claude_tasks_total counter\
\
             agentic_agent_claude_tasks_total{{agent_id=\"{}\"}} {}\
\
",
            agent_id, c.claude_tasks_total
        ));

        output.push_str(&format!(
            "# HELP agentic_agent_pty_sessions_total PTY session count\
\
             # TYPE agentic_agent_pty_sessions_total counter\
\
             agentic_agent_pty_sessions_total{{agent_id=\"{}\"}} {}\
\
",
            agent_id, c.pty_sessions_total
        ));

        output.push_str(&format!(
            "# HELP agentic_agent_current_commands Active command count\
\
             # TYPE agentic_agent_current_commands gauge\
\
             agentic_agent_current_commands{{agent_id=\"{}\"}} {}\
\
",
            agent_id, c.current_command_count
        ));

        output.push_str(&format!(
            "# HELP agentic_agent_last_command_latency_ms Last command latency\
\
             # TYPE agentic_agent_last_command_latency_ms gauge\
\
             agentic_agent_last_command_latency_ms{{agent_id=\"{}\"}} {}\
\
",
            agent_id, c.last_command_latency_ms
        ));

        // Atomic write
        let tmp_path = format!("{}.tmp", path);
        if let Ok(mut f) = fs::File::create(&tmp_path) {
            let _ = f.write_all(output.as_bytes());
            let _ = f.sync_all();
            drop(f);
            let _ = fs::rename(tmp_path, path);
        }
    }

    pub fn increment_commands(&self) {
        self.counters.lock().unwrap().commands_executed += 1;
    }

    pub fn record_success(&self, latency_ms: u64) {
        let mut c = self.counters.lock().unwrap();
        c.commands_success += 1;
        c.last_command_latency_ms = latency_ms;
    }

    pub fn record_failure(&self, latency_ms: u64) {
        let mut c = self.counters.lock().unwrap();
        c.commands_failed += 1;
        c.last_command_latency_ms = latency_ms;
    }

    pub fn increment_claude_tasks(&self) {
        self.counters.lock().unwrap().claude_tasks_total += 1;
    }

    pub fn increment_pty_sessions(&self) {
        self.counters.lock().unwrap().pty_sessions_total += 1;
    }

    pub fn set_current_commands(&self, count: u64) {
        self.counters.lock().unwrap().current_command_count = count;
    }
}

Custom Metrics Exposed

# Agent-specific counters (textfile collector)
agentic_agent_commands_total{agent_id}                  # Commands executed
agentic_agent_commands_success{agent_id}                # Successful commands
agentic_agent_commands_failed{agent_id}                 # Failed commands
agentic_agent_claude_tasks_total{agent_id}              # Claude task count
agentic_agent_pty_sessions_total{agent_id}              # PTY sessions created
agentic_agent_current_commands{agent_id}                # Active command count (gauge)
agentic_agent_last_command_latency_ms{agent_id}         # Last command duration

3.4 Prometheus Configuration

File: `/etc/prometheus/prometheus.yml` (host system)

global:
  scrape_interval: 15s
  evaluation_interval: 15s
  external_labels:
    cluster: 'agentic-sandbox'
    environment: 'production'

scrape_configs:
  # Management server
  - job_name: 'management-server'
    static_configs:
      - targets: ['localhost:8122']
        labels:
          component: 'management'

  # Agent VMs (node_exporter)
  - job_name: 'agent-vms'
    static_configs:
      # Auto-discover via file_sd_config for dynamic agents
      - targets:
          - '192.168.122.201:9100'
          - '192.168.122.202:9100'
          - '192.168.122.203:9100'
        labels:
          component: 'agent-vm'
    relabel_configs:
      # Extract agent ID from IP address (192.168.122.20X → agent-0X)
      - source_labels: [__address__]
        regex: '192\.168\.122\.20([0-9]):9100'
        target_label: agent_id
        replacement: 'agent-0$1'

  # Alternative: File-based service discovery
  # - job_name: 'agent-vms-dynamic'
  #   file_sd_configs:
  #     - files:
  #         - '/etc/prometheus/targets/agents.json'
  #       refresh_interval: 30s

Dynamic targets file: `/etc/prometheus/targets/agents.json`

[
  {
    "targets": ["192.168.122.201:9100", "192.168.122.202:9100"],
    "labels": {
      "component": "agent-vm"
    }
  }
]

Log Aggregation Design

4.1 Logging Architecture

┌───────────────────────────────────────────────────────────────────┐
│                       Host System                                  │
│                                                                     │
│  ┌──────────────────────────────────────────────────────────────┐ │
│  │  Log Shipper (Promtail or Vector)                            │ │
│  │  • Watches /srv/agentshare/inbox/*/runs/*/                   │ │
│  │  • Parses JSON structured logs                               │ │
│  │  • Ships to Loki/Elasticsearch                               │ │
│  └──────────────────────────────────────────────────────────────┘ │
│                            │                                        │
│                            ▼                                        │
│  ┌──────────────────────────────────────────────────────────────┐ │
│  │  Log Storage (Loki or Elasticsearch)                         │ │
│  │  • Retention: 30 days                                        │ │
│  │  • Indexed by: agent_id, run_id, timestamp                   │ │
│  │  • Full-text search capability                               │ │
│  └──────────────────────────────────────────────────────────────┘ │
│                            │                                        │
│                            ▼                                        │
│  ┌──────────────────────────────────────────────────────────────┐ │
│  │  Grafana (Query UI)                                          │ │
│  │  • LogQL queries (Loki) or Lucene (ES)                       │ │
│  │  • Log panels on dashboards                                  │ │
│  │  • Correlation with metrics                                  │ │
│  └──────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────┘

4.2 Agent Logging Strategy

Current Implementation: Agents write to `/mnt/inbox/runs/run-YYYYMMDD-HHMMSS/`:

  • `stdout.log` - Command stdout
  • `stderr.log` - Command stderr
  • `commands.log` - Command execution log
  • `metadata.json` - Run metadata

Enhancement: Add structured JSON logging

File: `/home/roctinam/dev/agentic-sandbox/agent-rs/src/main.rs` (lines 1545-1584)

Proposed Changes

1. Enable JSON logging via LOG_FORMAT env var

# In agent.env
LOG_FORMAT=json

2. Add structured fields to logs

// Use tracing's JSON formatter with custom fields
use tracing_subscriber::fmt::format::JsonFields;

tracing::info!(
    agent_id = %config.agent_id,
    command_id = %command_id,
    exit_code = exit_code,
    duration_ms = duration_ms,
    "Command completed"
);

3. Write agent logs to both stdout and file

// Dual output: systemd journal + file
let file_appender = tracing_appender::rolling::daily("/var/log/agentic-sandbox", "agent.log");
let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);

tracing_subscriber::registry()
    .with(env_filter)
    .with(fmt::layer().json().with_writer(std::io::stdout))
    .with(fmt::layer().json().with_writer(non_blocking))
    .init();

4.3 Log Shipping (Promtail Configuration)

File: `/etc/promtail/config.yml` (host system)

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /var/lib/promtail/positions.yaml

clients:
  - url: http://localhost:3100/loki/api/v1/push

scrape_configs:
  # Management server logs
  - job_name: management-server
    static_configs:
      - targets:
          - localhost
        labels:
          job: management-server
          component: management
          __path__: /var/log/agentic-sandbox/management.log

  # Agent run logs (agentshare)
  - job_name: agent-runs
    static_configs:
      - targets:
          - localhost
        labels:
          job: agent-runs
          component: agent
          __path__: /srv/agentshare/inbox/*/runs/*/stdout.log
    pipeline_stages:
      # Extract agent_id from path
      - regex:
          expression: '/srv/agentshare/inbox/(?P<agent_id>[^/]+)/runs/(?P<run_id>[^/]+)/stdout.log'
      - labels:
          agent_id:
          run_id:

  # Agent system logs (VM journald → rsyslog → host)
  - job_name: agent-systemd
    journal:
      json: true
      max_age: 12h
      path: /var/log/journal
      labels:
        job: agent-systemd
        component: agent
    relabel_configs:
      # Filter for agent VMs only
      - source_labels: ['__journal__hostname']
        regex: 'agent-.*'
        action: keep
      - source_labels: ['__journal__hostname']
        target_label: agent_id

4.4 Log Retention and Rotation

Agent VM (local logs):

# /etc/logrotate.d/agentic-agent
/var/log/agentic-sandbox/agent.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0640 agent agent
}

Agentshare (inbox logs):

Managed by task lifecycle cleanup (see orchestrator/cleanup.rs).

Loki (centralized):

# loki-config.yaml
limits_config:
  retention_period: 720h  # 30 days

chunk_store_config:
  max_look_back_period: 720h

table_manager:
  retention_deletes_enabled: true
  retention_period: 720h

SLI/SLO Definitions

5.1 Service Level Indicators (SLIs)

SLIDefinitionMeasurement
Agent AvailabilityPercentage of time agents are in READY state`avg_over_time(agentic_agents_by_status{status="ready"}[5m]) / scalar(agentic_agents_connected)`
Command Success RatePercentage of commands completing successfully`rate(agentic_commands_by_result{result="success"}[5m]) / rate(agentic_commands_total[5m])`
Task Success RatePercentage of tasks completing without failure`rate(agentic_tasks_by_state{state="completed"}[1h]) / (rate(agentic_tasks_total[1h]) - rate(agentic_tasks_by_state{state="cancelled"}[1h]))`
Command Latency P9595th percentile command execution time`histogram_quantile(0.95, rate(agentic_command_latency_seconds_bucket[5m]))`
Agent Session StabilityMean time between agent restarts`time() - rate(agentic_agent_restarts_total[1h])`
Storage Quota CompliancePercentage of agents under 80% inbox quota`count(agentic_agentshare_inbox_bytes < (50 1024^3 0.8)) / count(agentic_agentshare_inbox_bytes)`

5.2 Service Level Objectives (SLOs)

Critical SLOs (99.0% target)

ObjectiveTargetMeasurement WindowError Budget
Agent Availability99.0% of agents READY when not executing tasksRolling 7 days100.8 minutes/week downtime
Command Success Rate99.0% of commands succeed (excluding user errors)Rolling 24 hours14.4 minutes/day errors
Management Server Uptime99.9% uptimeRolling 30 days43 minutes/month downtime

Important SLOs (95.0% target)

ObjectiveTargetMeasurement WindowError Budget
Task Success Rate95.0% of tasks complete successfullyRolling 7 days8.4 hours/week failures
Command Latency P95< 5 seconds for non-interactive commandsRolling 1 hour5% of requests > 5s
PTY Session Latency P95< 200ms for interactive PTY commandsRolling 5 minutes5% of requests > 200ms

Operational SLOs (90.0% target)

ObjectiveTargetMeasurement WindowError Budget
Agent Session Stability< 1 restart per agent per weekRolling 7 days10% restart rate
Storage Quota Compliance90% of agents under 80% quotaRolling 24 hours10% quota violations
Log Shipping Lag< 60 seconds between log write and Loki ingestionRolling 5 minutes10% of logs delayed

5.3 Error Budget Policy

Error Budget Depletion Actions:

Budget RemainingAction
> 50%Normal development velocity, no restrictions
25-50%Freeze on risky deployments, prioritize reliability fixes
10-25%CRITICAL: All non-essential changes blocked, on-call escalation
< 10%EMERGENCY: Rollback last deployment, incident commander assigned

Calculation:

# Error budget remaining (%)
100 * (1 - (
  (agentic_commands_failed + agentic_tasks_by_state{state="failed"}) /
  (agentic_commands_total + agentic_tasks_total)
) / (1 - SLO_TARGET))

Alert Rules

6.1 Alerting Tiers

SeverityResponse TimeEscalationExample
WARNINGBest-effort, business hoursSlack notificationAgent CPU > 80% for 10 minutes
CRITICALPage on-call engineerPagerDutyManagement server down for 2 minutes
EMERGENCYPage incident commanderPagerDuty + Slack + SMSError budget < 10%

6.2 Prometheus Alert Rules

File: `/etc/prometheus/rules/agentic-sandbox.yml`

groups:
  - name: agent-health
    interval: 30s
    rules:
      # WARNING: High CPU usage
      - alert: AgentHighCPU
        expr: |
          100 - (avg by (agent_id) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
        for: 10m
        labels:
          severity: warning
          component: agent
        annotations:
          summary: "Agent {{ $labels.agent_id }} high CPU usage"
          description: "CPU usage is {{ $value | humanize }}% for 10 minutes"

      # WARNING: High memory usage
      - alert: AgentHighMemory
        expr: |
          (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 85
        for: 10m
        labels:
          severity: warning
          component: agent
        annotations:
          summary: "Agent {{ $labels.agent_id }} high memory usage"
          description: "Memory usage is {{ $value | humanize }}% for 10 minutes"

      # CRITICAL: Agent disk full
      - alert: AgentDiskFull
        expr: |
          (1 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})) * 100 > 90
        for: 5m
        labels:
          severity: critical
          component: agent
        annotations:
          summary: "Agent {{ $labels.agent_id }} disk nearly full"
          description: "Disk usage is {{ $value | humanize }}% (> 90% threshold)"

      # CRITICAL: Agent disconnected
      - alert: AgentDisconnected
        expr: |
          up{job="agent-vms"} == 0
        for: 2m
        labels:
          severity: critical
          component: agent
        annotations:
          summary: "Agent {{ $labels.agent_id }} disconnected"
          description: "Agent has been unreachable for 2 minutes"

  - name: command-execution
    interval: 30s
    rules:
      # WARNING: High command failure rate
      - alert: HighCommandFailureRate
        expr: |
          (rate(agentic_commands_by_result{result="failed"}[5m]) / rate(agentic_commands_total[5m])) > 0.05
        for: 10m
        labels:
          severity: warning
          component: management
        annotations:
          summary: "High command failure rate"
          description: "{{ $value | humanizePercentage }} of commands are failing (> 5%)"

      # CRITICAL: Command execution stalled
      - alert: CommandExecutionStalled
        expr: |
          rate(agentic_commands_total[5m]) == 0 AND agentic_tasks_by_state{state="running"} > 0
        for: 5m
        labels:
          severity: critical
          component: management
        annotations:
          summary: "Command execution appears stalled"
          description: "No commands executed in 5 minutes despite {{ $value }} running tasks"

      # WARNING: Slow command execution
      - alert: SlowCommandExecution
        expr: |
          histogram_quantile(0.95, rate(agentic_command_latency_seconds_bucket[5m])) > 5
        for: 10m
        labels:
          severity: warning
          component: agent
        annotations:
          summary: "Slow command execution (P95 latency)"
          description: "95th percentile latency is {{ $value | humanizeDuration }} (> 5s threshold)"

  - name: task-orchestration
    interval: 60s
    rules:
      # WARNING: High task failure rate
      - alert: HighTaskFailureRate
        expr: |
          (rate(agentic_tasks_by_state{state="failed"}[1h]) / rate(agentic_tasks_total[1h])) > 0.10
        for: 30m
        labels:
          severity: warning
          component: orchestrator
        annotations:
          summary: "High task failure rate"
          description: "{{ $value | humanizePercentage }} of tasks are failing (> 10%)"

      # CRITICAL: Task queue backlog
      - alert: TaskQueueBacklog
        expr: |
          agentic_tasks_by_state{state="pending"} > 10
        for: 15m
        labels:
          severity: critical
          component: orchestrator
        annotations:
          summary: "Task queue backlog building"
          description: "{{ $value }} tasks pending for 15+ minutes"

  - name: management-server
    interval: 30s
    rules:
      # CRITICAL: Management server down
      - alert: ManagementServerDown
        expr: |
          up{job="management-server"} == 0
        for: 2m
        labels:
          severity: critical
          component: management
        annotations:
          summary: "Management server is down"
          description: "Management server has been unreachable for 2 minutes"

      # WARNING: High gRPC error rate
      - alert: HighGrpcErrorRate
        expr: |
          (rate(grpc_server_handled_total{grpc_code!="OK"}[5m]) / rate(grpc_server_handled_total[5m])) > 0.05
        for: 10m
        labels:
          severity: warning
          component: management
        annotations:
          summary: "High gRPC error rate"
          description: "{{ $value | humanizePercentage }} of gRPC requests are failing"

  - name: slo-violations
    interval: 60s
    rules:
      # CRITICAL: Agent availability SLO violation
      - alert: AgentAvailabilitySLOViolation
        expr: |
          (avg_over_time(agentic_agents_by_status{status="ready"}[5m]) / scalar(agentic_agents_connected)) < 0.99
        for: 30m
        labels:
          severity: critical
          component: slo
        annotations:
          summary: "Agent availability SLO violated"
          description: "Agent availability is {{ $value | humanizePercentage }} (< 99% target)"

      # EMERGENCY: Error budget depleted
      - alert: ErrorBudgetDepleted
        expr: |
          (1 - ((agentic_commands_by_result{result="failed"} + agentic_tasks_by_state{state="failed"}) /
                (agentic_commands_total + agentic_tasks_total)) / 0.01) < 0.10
        for: 10m
        labels:
          severity: emergency
          component: slo
        annotations:
          summary: "Error budget critically depleted"
          description: "Only {{ $value | humanizePercentage }} of error budget remains (< 10%)"

  - name: storage-quotas
    interval: 300s  # Check every 5 minutes
    rules:
      # WARNING: Agent inbox quota warning
      - alert: AgentInboxQuotaWarning
        expr: |
          (agentic_agentshare_inbox_bytes / (50 * 1024^3)) > 0.80
        for: 30m
        labels:
          severity: warning
          component: storage
        annotations:
          summary: "Agent {{ $labels.agent_id }} inbox nearing quota"
          description: "Inbox usage is {{ $value | humanizePercentage }} of 50GB quota"

      # CRITICAL: Agent inbox quota exceeded
      - alert: AgentInboxQuotaExceeded
        expr: |
          (agentic_agentshare_inbox_bytes / (50 * 1024^3)) > 0.95
        for: 10m
        labels:
          severity: critical
          component: storage
        annotations:
          summary: "Agent {{ $labels.agent_id }} inbox quota exceeded"
          description: "Inbox usage is {{ $value | humanizePercentage }} of 50GB quota (> 95%)"

6.3 Alertmanager Configuration

File: `/etc/alertmanager/alertmanager.yml`

global:
  resolve_timeout: 5m
  slack_api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'

route:
  receiver: 'default'
  group_by: ['alertname', 'component']
  group_wait: 10s
  group_interval: 5m
  repeat_interval: 4h

  routes:
    # EMERGENCY alerts → immediate PagerDuty + Slack
    - match:
        severity: emergency
      receiver: 'pagerduty-emergency'
      group_wait: 0s
      repeat_interval: 1h

    # CRITICAL alerts → PagerDuty
    - match:
        severity: critical
      receiver: 'pagerduty-critical'
      group_wait: 30s
      repeat_interval: 2h

    # WARNING alerts → Slack only
    - match:
        severity: warning
      receiver: 'slack-warnings'
      group_wait: 5m
      repeat_interval: 12h

receivers:
  - name: 'default'
    slack_configs:
      - channel: '#agentic-sandbox-alerts'
        title: '{{ .GroupLabels.alertname }}'
        text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'

  - name: 'pagerduty-emergency'
    pagerduty_configs:
      - service_key: 'YOUR_PAGERDUTY_SERVICE_KEY'
        severity: 'critical'
        description: 'EMERGENCY: {{ .GroupLabels.alertname }}'
    slack_configs:
      - channel: '#agentic-sandbox-incidents'
        title: ':rotating_light: EMERGENCY: {{ .GroupLabels.alertname }}'
        text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
        color: 'danger'

  - name: 'pagerduty-critical'
    pagerduty_configs:
      - service_key: 'YOUR_PAGERDUTY_SERVICE_KEY'
        severity: 'error'
        description: '{{ .GroupLabels.alertname }}'

  - name: 'slack-warnings'
    slack_configs:
      - channel: '#agentic-sandbox-alerts'
        title: ':warning: {{ .GroupLabels.alertname }}'
        text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
        color: 'warning'

inhibit_rules:
  # Inhibit warning alerts if critical alert is firing for same component
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'warning'
    equal: ['component', 'agent_id']

  # Inhibit all alerts if management server is down
  - source_match:
      alertname: 'ManagementServerDown'
    target_match_re:
      alertname: '.*'

Dashboard Specifications

7.1 Grafana Dashboard: Agent Fleet Overview

Panel Layout (3 columns, 5 rows):

┌──────────────────────────────────────────────────────────────────┐
│                    Agentic Sandbox Fleet                         │
├──────────────────────────────────────────────────────────────────┤
│ Row 1: Key Metrics (Stat Panels)                                 │
│ ┌────────────┬────────────┬────────────┬────────────────────────┐│
│ │ Total      │ Ready      │ Busy       │ SLO Compliance         ││
│ │ Agents: 24 │ Agents: 22 │ Agents: 2  │ 99.2% (Green)          ││
│ └────────────┴────────────┴────────────┴────────────────────────┘│
├──────────────────────────────────────────────────────────────────┤
│ Row 2: Availability Timeline (Time Series)                       │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Agent Availability (Last 24h)                                │ │
│ │ Query: agentic_agents_by_status{status="ready"}              │ │
│ │ [Graph showing ready agents over time, stacked area]         │ │
│ └──────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ Row 3: Resource Utilization (Gauges + Time Series)               │
│ ┌────────────────────────┬────────────────────────────────────┐  │
│ │ Fleet CPU Usage (Avg)  │ Fleet Memory Usage (Avg)           │  │
│ │ Gauge: 45%             │ Gauge: 62%                         │  │
│ └────────────────────────┴────────────────────────────────────┘  │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Per-Agent Resource Heatmap (Last 6h)                         │ │
│ │ X: Time, Y: Agent ID, Color: CPU %                           │ │
│ └──────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ Row 4: Command Execution (Time Series + Table)                   │
│ ┌────────────────────────┬────────────────────────────────────┐  │
│ │ Command Rate           │ Command Success Rate               │  │
│ │ (commands/sec)         │ (% success)                        │  │
│ └────────────────────────┴────────────────────────────────────┘  │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Command Latency Histogram (P50/P95/P99)                      │ │
│ │ Query: histogram_quantile(...)                               │ │
│ └──────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ Row 5: Agent List (Table)                                        │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Agent ID │ Status │ CPU % │ Mem % │ Disk % │ Last Heartbeat│ │
│ │──────────┼────────┼───────┼───────┼────────┼───────────────│ │
│ │ agent-01 │ Ready  │  23%  │  45%  │  62%   │ 5s ago        │ │
│ │ agent-02 │ Busy   │  87%  │  78%  │  55%   │ 3s ago        │ │
│ │ agent-03 │ Ready  │  12%  │  32%  │  48%   │ 7s ago        │ │
│ └──────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘

Panel Queries

Total Agents (Stat):

count(agentic_agents_connected)

Ready Agents (Stat):

agentic_agents_by_status{status="ready"}

SLO Compliance (Stat with thresholds):

(agentic_commands_by_result{result="success"} / agentic_commands_total) * 100
Thresholds: < 99% = Red, 99-99.5% = Yellow, > 99.5% = Green

Agent Availability Timeline (Time Series):

agentic_agents_by_status

Fleet CPU Usage (Gauge):

avg(100 - (avg by (agent_id) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100))

Fleet Memory Usage (Gauge):

avg((1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100)

Per-Agent Resource Heatmap:

100 - (avg by (agent_id) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
Visualization: Heatmap

Command Rate (Time Series):

rate(agentic_commands_total[5m])

Command Success Rate (Time Series):

rate(agentic_commands_by_result{result="success"}[5m]) / rate(agentic_commands_total[5m]) * 100

Command Latency Histogram:

histogram_quantile(0.50, rate(agentic_command_latency_seconds_bucket[5m])) * 1000  # P50 in ms
histogram_quantile(0.95, rate(agentic_command_latency_seconds_bucket[5m])) * 1000  # P95 in ms
histogram_quantile(0.99, rate(agentic_command_latency_seconds_bucket[5m])) * 1000  # P99 in ms

Agent List Table:

# Multi-query table panel combining:
up{job="agent-vms"}                                                                    # Status
100 - (avg by (agent_id) (rate(node_cpu_seconds_total{mode="idle"}[1m])) * 100)      # CPU
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100            # Memory
(1 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})) * 100  # Disk
(time() - agentic_heartbeat_timestamp_ms / 1000)                                      # Last heartbeat

7.2 Grafana Dashboard: Task Orchestration

Panel Layout:

┌──────────────────────────────────────────────────────────────────┐
│                    Task Orchestration Dashboard                   │
├──────────────────────────────────────────────────────────────────┤
│ Row 1: Task States (Stat Panels)                                 │
│ ┌────────────┬────────────┬────────────┬────────────────────────┐│
│ │ Pending    │ Running    │ Completed  │ Failed (Last 24h)      ││
│ │ Tasks: 3   │ Tasks: 8   │ Tasks: 142 │ Tasks: 5 (3.4%)        ││
│ └────────────┴────────────┴────────────┴────────────────────────┘│
├──────────────────────────────────────────────────────────────────┤
│ Row 2: Task Lifecycle Timeline                                   │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Task States Over Time (Stacked Area)                         │ │
│ │ pending, running, completing, completed, failed              │ │
│ └──────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ Row 3: Task Success Rate (Time Series + Gauge)                   │
│ ┌────────────────────────┬────────────────────────────────────┐  │
│ │ Task Success Rate      │ Task Failure Rate                  │  │
│ │ (rolling 1h)           │ (rolling 1h)                       │  │
│ └────────────────────────┴────────────────────────────────────┘  │
├──────────────────────────────────────────────────────────────────┤
│ Row 4: Task Duration Analysis                                    │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Task Duration Histogram (P50/P90/P99)                        │ │
│ │ Bucket: 0-1h, 1-6h, 6-12h, 12-24h                            │ │
│ └──────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ Row 5: Active Tasks (Table)                                      │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Task ID │ State │ Agent │ Duration │ Last Activity          │ │
│ │─────────┼───────┼───────┼──────────┼────────────────────────│ │
│ │ abc123  │ RUN   │ a-01  │ 12m      │ 10s ago                │ │
│ └──────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘

7.3 Grafana Dashboard: Storage & Quotas

Panel Layout:

┌──────────────────────────────────────────────────────────────────┐
│                    Storage & Quota Dashboard                      │
├──────────────────────────────────────────────────────────────────┤
│ Row 1: Global Storage Summary                                    │
│ ┌────────────┬────────────┬────────────┬────────────────────────┐│
│ │ Total      │ Used       │ Available  │ Quota Violations       ││
│ │ 2.4TB      │ 1.2TB      │ 1.2TB      │ 2 agents (> 80%)       ││
│ └────────────┴────────────┴────────────┴────────────────────────┘│
├──────────────────────────────────────────────────────────────────┤
│ Row 2: Per-Agent Inbox Usage (Bar Gauge)                         │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Agent ID │ ████████████░░░░░░░░ 65% (32.5GB / 50GB)         │ │
│ │ agent-01 │ ██████████████████░░ 92% (46GB / 50GB) ⚠         │ │
│ │ agent-02 │ ████████░░░░░░░░░░░░ 42% (21GB / 50GB)           │ │
│ └──────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ Row 3: Storage Growth Trends                                     │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Inbox Storage Growth (Last 7 days)                           │ │
│ │ Query: increase(agentic_agentshare_inbox_bytes[7d])          │ │
│ └──────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ Row 4: Disk I/O Performance                                      │
│ ┌────────────────────────┬────────────────────────────────────┐  │
│ │ Read Throughput        │ Write Throughput                   │  │
│ │ (MB/s per agent)       │ (MB/s per agent)                   │  │
│ └────────────────────────┴────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────────┘

7.4 Grafana Dashboard: SLO Compliance

Panel Layout:

┌──────────────────────────────────────────────────────────────────┐
│                    SLO Compliance Dashboard                       │
├──────────────────────────────────────────────────────────────────┤
│ Row 1: SLO Health Summary (Stat Panels with Traffic Light)       │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Agent Availability │ Command Success │ Task Success          │ │
│ │ 99.4% ✅ (Target: 99%) │ 99.8% ✅      │ 96.5% ✅             │ │
│ │ Error Budget: 60%      │ EB: 80%       │ EB: 70%              │ │
│ └──────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ Row 2: Error Budget Burn Rate (Time Series)                      │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Error Budget Consumption (30-day window)                     │ │
│ │ Query: 1 - ((failures / total) / (1 - SLO_TARGET))           │ │
│ │ Alert Threshold: < 10% triggers emergency escalation         │ │
│ └──────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ Row 3: SLI Trends (Multi-Series Time Series)                     │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ All SLIs on Single Graph (Last 7 days)                       │ │
│ │ • Agent Availability (99% line)                              │ │
│ │ • Command Success Rate (99% line)                            │ │
│ │ • Task Success Rate (95% line)                               │ │
│ └──────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ Row 4: SLO Violation Log (Table)                                 │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Timestamp │ SLO │ Actual │ Target │ Duration │ Cause        │ │
│ │───────────┼─────┼────────┼────────┼──────────┼──────────────│ │
│ │ 12:34 PM  │ Cmd │ 98.7%  │ 99%    │ 15m      │ Network lag  │ │
│ └──────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘

Implementation Roadmap

Phase 1: Foundation (Week 1-2)

Deliverables:

  • [ ] Prometheus server deployed on host
  • [ ] node_exporter installed on all agent VMs (via provisioning script)
  • [ ] Management server metrics endpoint verified (`/metrics`)
  • [ ] Basic Grafana instance with initial dashboards

Tasks: 1. Install Prometheus on host (`apt install prometheus`) 2. Configure `/etc/prometheus/prometheus.yml` with static agent targets 3. Add `prometheus-node-exporter` to `agentic-dev` profile packages 4. Verify scrape targets: `curl http://localhost:9090/api/v1/targets` 5. Install Grafana (`apt install grafana`) 6. Import pre-built node_exporter dashboard (ID: 1860)

Success Criteria:

  • All agent VMs showing `UP` in Prometheus targets
  • Node exporter metrics queryable in Grafana
  • Management server metrics visible in Prometheus

Phase 2: Custom Metrics (Week 3)

Deliverables:

  • [ ] Custom agent metrics exporter implemented
  • [ ] Textfile collector metrics exposed via node_exporter
  • [ ] Enriched management server metrics (session tracking, storage)

Tasks: 1. Implement `AgentMetricsExporter` in `agent-rs/src/metrics_exporter.rs` 2. Wire exporter into agent client startup 3. Configure node_exporter textfile collector path 4. Add custom metrics to Prometheus scrape 5. Extend management server metrics with session and storage tracking 6. Update Grafana dashboards with custom metrics panels

Success Criteria:

  • Custom metrics visible in Prometheus: `agentic_agent_commands_total{agent_id="agent-01"}`
  • Command success/failure counters incrementing
  • Storage metrics updating every 60 seconds

Phase 3: Log Aggregation (Week 4)

Deliverables:

  • [ ] Loki server deployed
  • [ ] Promtail configured for agentshare log tailing
  • [ ] JSON log parsing in place
  • [ ] Log search functional in Grafana

Tasks: 1. Install Loki (`docker run -d -p 3100:3100 grafana/loki`) 2. Install Promtail (`apt install promtail`) 3. Configure Promtail scrape configs for agentshare paths 4. Enable JSON logging in agent client (`LOG_FORMAT=json`) 5. Add Loki data source to Grafana 6. Create log panel in Agent Fleet dashboard

Success Criteria:

  • Agent logs searchable in Grafana Explore
  • Log volume visible in Loki metrics
  • Logs correlated with metrics (shared `agent_id` label)

Phase 4: SLI/SLO Implementation (Week 5)

Deliverables:

  • [ ] SLI recording rules configured
  • [ ] SLO dashboards created
  • [ ] Error budget tracking active
  • [ ] SLO violation alerts defined

Tasks: 1. Define Prometheus recording rules for SLIs 2. Create SLO Compliance dashboard 3. Implement error budget calculation queries 4. Document SLO targets in runbooks 5. Set up SLO alert thresholds

Success Criteria:

  • SLO dashboard shows real-time compliance
  • Error budget percentage visible
  • Historical SLO trends queryable

Phase 5: Alerting (Week 6)

Deliverables:

  • [ ] Alertmanager deployed and configured
  • [ ] Alert rules installed in Prometheus
  • [ ] Slack integration tested
  • [ ] PagerDuty integration tested
  • [ ] Runbooks created for each alert

Tasks: 1. Install Alertmanager (`apt install prometheus-alertmanager`) 2. Configure `/etc/alertmanager/alertmanager.yml` 3. Add alert rules to `/etc/prometheus/rules/agentic-sandbox.yml` 4. Test firing alerts: `amtool alert add --alertmanager.url=http://localhost:9093` 5. Create runbook wiki with remediation steps 6. Conduct tabletop exercise for critical alerts

Success Criteria:

  • Test alert successfully delivered to Slack
  • PagerDuty incident created for critical alert
  • Alert inhibition rules working (no duplicate pages)
  • On-call engineers trained on alert response

Phase 6: Production Hardening (Week 7-8)

Deliverables:

  • [ ] Prometheus retention tuned
  • [ ] Alertmanager silencing procedure documented
  • [ ] Backup/restore tested
  • [ ] Capacity planning baseline established
  • [ ] ORR checklist completed

Tasks: 1. Configure Prometheus retention (`--storage.tsdb.retention.time=90d`) 2. Set up Prometheus remote write to long-term storage (optional) 3. Create backup script for Prometheus data 4. Test metric recovery from backup 5. Run load test to establish capacity baselines 6. Document on-call procedures and escalation paths 7. Conduct Operational Readiness Review (ORR)

Success Criteria:

  • Prometheus metrics retained for 90 days
  • Recovery time objective (RTO) < 1 hour from backup
  • Capacity plan approved for next 12 months
  • ORR signed off by engineering and operations

Appendices

A. Metrics Reference

Complete Metrics Catalog:

Metric NameTypeLabelsDescription
`agentic_uptime_seconds`gauge-Management server uptime
`agentic_agents_connected`gauge-Connected agent count
`agentic_agents_by_status`gauge`status`Agents by status (ready, busy)
`agentic_commands_total`counter-Total commands dispatched
`agentic_commands_by_result`counter`result`Commands by result (success, failed)
`agentic_commands_duration_seconds_sum`counter-Sum of command durations
`agentic_command_latency_seconds_bucket`histogram`le`Command latency histogram
`agentic_grpc_requests_total`counter`method`gRPC requests by method
`agentic_ws_connections_current`gauge-Active WebSocket connections
`agentic_ws_connections_total`counter-Total WebSocket connections
`agentic_tasks_total`counter-Total tasks created
`agentic_tasks_by_state`gauge`state`Tasks by state
`agentic_agent_sessions_active`gauge`agent_id`Active agent sessions
`agentic_agent_restarts_total`counter`agent_id`Agent restart count
`agentic_agentshare_inbox_bytes`gauge`agent_id`Agent inbox storage usage
`agentic_agent_commands_total`counter`agent_id`Commands executed per agent
`agentic_agent_commands_success`counter`agent_id`Successful commands per agent
`agentic_agent_claude_tasks_total`counter`agent_id`Claude tasks per agent

B. PromQL Query Library

Agent Health:

# Agent availability percentage (last 5 minutes)
(avg_over_time(agentic_agents_by_status{status="ready"}[5m]) / scalar(agentic_agents_connected)) * 100

# Agents with high CPU (> 80%)
100 - (avg by (agent_id) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80

# Agents with high memory (> 85%)
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 85

# Agent uptime (in hours)
(time() - node_boot_time_seconds) / 3600

Command Execution:

# Command success rate (rolling 5 minutes)
rate(agentic_commands_by_result{result="success"}[5m]) / rate(agentic_commands_total[5m])

# Command latency P95
histogram_quantile(0.95, rate(agentic_command_latency_seconds_bucket[5m]))

# Commands per second
rate(agentic_commands_total[1m])

# Failed commands in last hour
increase(agentic_commands_by_result{result="failed"}[1h])

Task Orchestration:

# Task success rate (rolling 1 hour)
rate(agentic_tasks_by_state{state="completed"}[1h]) / rate(agentic_tasks_total[1h])

# Task queue depth
agentic_tasks_by_state{state="pending"}

# Average task duration (requires custom metric)
agentic_task_duration_seconds_sum / agentic_task_duration_seconds_count

Storage:

# Agents over 80% inbox quota
(agentic_agentshare_inbox_bytes / (50 * 1024^3)) > 0.80

# Total inbox storage used (GB)
sum(agentic_agentshare_inbox_bytes) / 1024^3

# Disk write rate (MB/s)
rate(node_disk_written_bytes_total[5m]) / 1024^2

C. Runbook Template

Alert: `AgentHighCPU`

Severity: Warning

Trigger: Agent CPU usage > 80% for 10 minutes

Symptoms:

  • Slow command execution
  • Increased latency in task processing
  • Possible OOM kills

Investigation Steps:

1. Check CPU usage:

   ssh [email protected] 'top -bn1 | head -20'

2. Identify hot processes:

   ssh [email protected] 'ps aux --sort=-%cpu | head -10'

3. Check for runaway Claude tasks:

   ssh [email protected] 'pgrep -a claude'

4. Review recent commands:

   ssh [email protected] 'tail -50 /mnt/inbox/current/commands.log'

Remediation:

  • If single command is the cause: Wait for command to complete, or kill if hung
  • If systemic: Reduce concurrent task limit in orchestrator config
  • If persistent: Increase VM CPU allocation in provision-vm.sh

Escalation:

  • If CPU remains > 90% for 30 minutes, escalate to on-call engineer
  • If multiple agents affected, page incident commander

D. Capacity Planning Baselines

Resource Utilization Targets:

ResourceNormalWarningCritical
CPU (per agent)< 60%60-80%> 80%
Memory (per agent)< 70%70-85%> 85%
Disk (per agent)< 60%60-80%> 80%
Network (host)< 1 Gbps1-5 Gbps> 5 Gbps
Inbox Storage< 60%60-80%> 80%

Scaling Thresholds:

ConditionAction
Avg agent CPU > 70% for 24hProvision additional agents
Task queue > 10 for 1hIncrease agent pool size
Disk IOPS > 80% capacityMigrate to faster storage
Network saturation > 50%Enable traffic shaping

E. Tool Versions

Recommended Versions:

  • Prometheus: 2.50.0+
  • Grafana: 10.3.0+
  • Loki: 2.9.0+
  • Promtail: 2.9.0+
  • Alertmanager: 0.27.0+
  • node_exporter: 1.7.0+

Approval

Document Status: Draft for Review

Reviewed By:

  • [ ] Engineering Lead
  • [ ] DevOps Lead
  • [ ] Security Team
  • [ ] Operations Lead

Approved By:

  • [ ] VP Engineering

Next Review Date: 2026-03-31


End of Document