feat: Claude Code Monitor — lanes, pipelines and a merged workspace
Internal SmartGift build of a Claude Code monitoring dashboard. Lanes: a durable unit of parallel agent work, one per working directory, tracked across session restarts. Managed lanes are git worktrees the dashboard provisions and can reset or remove behind a three-check destroy guard and a counted preflight; adopted lanes are directories you already own and are never destroyable. Pipelines: a lane moves through pipeline stages. A stage the agent declares with evidence renders green; a stage inferred from the tool-event stream renders dashed amber and never counts as done. Detection is forward-only within a 30-minute window, and never writes the declared stage. Workspace: one page at /run with a lane grid, the selected lane's pipeline, and a full Claude console behind a disclosure.
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Alertmanager configuration for Claude Code Agent Monitor
|
||||
#
|
||||
# Replace placeholder values (marked with <PLACEHOLDER>) before deploying.
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
global:
|
||||
# SMTP defaults for email notifications
|
||||
smtp_smarthost: "<SMTP_HOST>:587"
|
||||
smtp_from: "alertmanager@example.com"
|
||||
smtp_auth_username: "<SMTP_USERNAME>"
|
||||
smtp_auth_password: "<SMTP_PASSWORD>"
|
||||
smtp_require_tls: true
|
||||
|
||||
# Slack API URL (override per-receiver if needed)
|
||||
slack_api_url: "<SLACK_WEBHOOK_URL>"
|
||||
|
||||
# PagerDuty URL
|
||||
pagerduty_url: "https://events.pagerduty.com/v2/enqueue"
|
||||
|
||||
# Global resolve timeout
|
||||
resolve_timeout: 5m
|
||||
|
||||
# ── Templates ───────────────────────────────────────────────────────────────
|
||||
templates:
|
||||
- "/etc/alertmanager/templates/*.tmpl"
|
||||
|
||||
# ── Inhibition rules ───────────────────────────────────────────────────────
|
||||
# Prevent lower-severity alerts from firing when a higher-severity alert
|
||||
# for the same service/alertname is already active.
|
||||
inhibit_rules:
|
||||
# If a critical alert is firing, suppress warning alerts for the same service
|
||||
- source_matchers:
|
||||
- severity = critical
|
||||
target_matchers:
|
||||
- severity = warning
|
||||
equal:
|
||||
- alertname
|
||||
- service
|
||||
- namespace
|
||||
|
||||
# If a critical alert is firing, suppress info alerts for the same service
|
||||
- source_matchers:
|
||||
- severity = critical
|
||||
target_matchers:
|
||||
- severity = info
|
||||
equal:
|
||||
- service
|
||||
- namespace
|
||||
|
||||
# If a warning alert is firing, suppress info alerts for the same service
|
||||
- source_matchers:
|
||||
- severity = warning
|
||||
target_matchers:
|
||||
- severity = info
|
||||
equal:
|
||||
- service
|
||||
- namespace
|
||||
|
||||
# If AgentMonitorDown is firing, suppress all other agent-monitor alerts
|
||||
- source_matchers:
|
||||
- alertname = AgentMonitorDown
|
||||
target_matchers:
|
||||
- service = agent-monitor
|
||||
equal:
|
||||
- namespace
|
||||
|
||||
# ── Route tree ──────────────────────────────────────────────────────────────
|
||||
route:
|
||||
# Default receiver for unmatched alerts
|
||||
receiver: slack-default
|
||||
|
||||
# Group alerts by these labels
|
||||
group_by:
|
||||
- alertname
|
||||
- environment
|
||||
- namespace
|
||||
|
||||
# Wait before sending initial notification (allows grouping)
|
||||
group_wait: 30s
|
||||
|
||||
# Wait before sending updates to an existing group
|
||||
group_interval: 5m
|
||||
|
||||
# Wait before re-sending a resolved notification
|
||||
repeat_interval: 4h
|
||||
|
||||
# Child routes (evaluated top-to-bottom, first match wins)
|
||||
routes:
|
||||
# ── Critical → PagerDuty + Slack ──────────────────────────────────────
|
||||
- matchers:
|
||||
- severity = critical
|
||||
receiver: pagerduty-critical
|
||||
group_wait: 10s
|
||||
repeat_interval: 1h
|
||||
continue: true # Also notify Slack
|
||||
|
||||
- matchers:
|
||||
- severity = critical
|
||||
receiver: slack-critical
|
||||
group_wait: 10s
|
||||
repeat_interval: 1h
|
||||
|
||||
# ── Warning → Slack ───────────────────────────────────────────────────
|
||||
- matchers:
|
||||
- severity = warning
|
||||
receiver: slack-warning
|
||||
group_wait: 30s
|
||||
repeat_interval: 4h
|
||||
|
||||
# ── Info → Email ──────────────────────────────────────────────────────
|
||||
- matchers:
|
||||
- severity = info
|
||||
receiver: email-info
|
||||
group_wait: 1m
|
||||
repeat_interval: 12h
|
||||
|
||||
# ── Watchdog (deadman's switch) ───────────────────────────────────────
|
||||
- matchers:
|
||||
- alertname = Watchdog
|
||||
receiver: "null"
|
||||
repeat_interval: 5m
|
||||
|
||||
# ── Receivers ───────────────────────────────────────────────────────────────
|
||||
receivers:
|
||||
# ── Null receiver (discard alerts) ────────────────────────────────────────
|
||||
- name: "null"
|
||||
|
||||
# ── Slack: Default channel ────────────────────────────────────────────────
|
||||
- name: slack-default
|
||||
slack_configs:
|
||||
- channel: "#agent-monitor-alerts"
|
||||
send_resolved: true
|
||||
username: "AlertManager"
|
||||
icon_emoji: ":bell:"
|
||||
title: >-
|
||||
[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}]
|
||||
{{ .CommonLabels.alertname }}
|
||||
text: >-
|
||||
{{ range .Alerts }}
|
||||
*Alert:* {{ .Labels.alertname }} - `{{ .Labels.severity }}`
|
||||
*Environment:* {{ .Labels.namespace }}
|
||||
*Description:* {{ .Annotations.description }}
|
||||
*Details:*
|
||||
{{ range .Labels.SortedPairs }} • *{{ .Name }}:* `{{ .Value }}`
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
actions:
|
||||
- type: button
|
||||
text: "Dashboard :grafana:"
|
||||
url: "{{ (index .Alerts 0).Annotations.dashboard_url }}"
|
||||
- type: button
|
||||
text: "Runbook :book:"
|
||||
url: "{{ (index .Alerts 0).Annotations.runbook_url }}"
|
||||
|
||||
# ── Slack: Critical alerts ────────────────────────────────────────────────
|
||||
- name: slack-critical
|
||||
slack_configs:
|
||||
- channel: "#agent-monitor-critical"
|
||||
send_resolved: true
|
||||
username: "AlertManager"
|
||||
icon_emoji: ":rotating_light:"
|
||||
color: >-
|
||||
{{ if eq .Status "firing" }}danger{{ else }}good{{ end }}
|
||||
title: >-
|
||||
:rotating_light: [{{ .Status | toUpper }}]
|
||||
{{ .CommonLabels.alertname }}
|
||||
text: >-
|
||||
{{ range .Alerts }}
|
||||
*CRITICAL Alert:* {{ .Labels.alertname }}
|
||||
*Environment:* {{ .Labels.namespace }}
|
||||
*Description:* {{ .Annotations.description }}
|
||||
*Summary:* {{ .Annotations.summary }}
|
||||
*Started:* {{ .StartsAt.Format "2006-01-02 15:04:05 UTC" }}
|
||||
{{ end }}
|
||||
actions:
|
||||
- type: button
|
||||
text: "Dashboard"
|
||||
url: "{{ (index .Alerts 0).Annotations.dashboard_url }}"
|
||||
- type: button
|
||||
text: "Runbook"
|
||||
url: "{{ (index .Alerts 0).Annotations.runbook_url }}"
|
||||
|
||||
# ── Slack: Warning alerts ─────────────────────────────────────────────────
|
||||
- name: slack-warning
|
||||
slack_configs:
|
||||
- channel: "#agent-monitor-alerts"
|
||||
send_resolved: true
|
||||
username: "AlertManager"
|
||||
icon_emoji: ":warning:"
|
||||
color: >-
|
||||
{{ if eq .Status "firing" }}warning{{ else }}good{{ end }}
|
||||
title: >-
|
||||
:warning: [{{ .Status | toUpper }}]
|
||||
{{ .CommonLabels.alertname }}
|
||||
text: >-
|
||||
{{ range .Alerts }}
|
||||
*Warning:* {{ .Labels.alertname }}
|
||||
*Environment:* {{ .Labels.namespace }}
|
||||
*Description:* {{ .Annotations.description }}
|
||||
{{ end }}
|
||||
|
||||
# ── PagerDuty: Critical alerts ───────────────────────────────────────────
|
||||
- name: pagerduty-critical
|
||||
pagerduty_configs:
|
||||
- routing_key: "<PAGERDUTY_ROUTING_KEY>"
|
||||
severity: >-
|
||||
{{ if eq .CommonLabels.severity "critical" }}critical{{ else }}warning{{ end }}
|
||||
description: >-
|
||||
{{ .CommonAnnotations.summary }}
|
||||
details:
|
||||
environment: "{{ .CommonLabels.namespace }}"
|
||||
alertname: "{{ .CommonLabels.alertname }}"
|
||||
service: "{{ .CommonLabels.service }}"
|
||||
description: "{{ .CommonAnnotations.description }}"
|
||||
num_firing: "{{ .Alerts.Firing | len }}"
|
||||
|
||||
# ── Email: Info-level alerts ──────────────────────────────────────────────
|
||||
- name: email-info
|
||||
email_configs:
|
||||
- to: "<ALERT_EMAIL_RECIPIENTS>"
|
||||
send_resolved: true
|
||||
headers:
|
||||
Subject: >-
|
||||
[Agent Monitor {{ .Status | toUpper }}]
|
||||
{{ .CommonLabels.alertname }}
|
||||
({{ .CommonLabels.namespace }})
|
||||
html: |
|
||||
<h2>{{ .CommonLabels.alertname }}</h2>
|
||||
<p><b>Status:</b> {{ .Status }}</p>
|
||||
<p><b>Environment:</b> {{ .CommonLabels.namespace }}</p>
|
||||
<table border="1" cellpadding="5">
|
||||
<tr><th>Alert</th><th>Severity</th><th>Description</th><th>Started</th></tr>
|
||||
{{ range .Alerts }}
|
||||
<tr>
|
||||
<td>{{ .Labels.alertname }}</td>
|
||||
<td>{{ .Labels.severity }}</td>
|
||||
<td>{{ .Annotations.description }}</td>
|
||||
<td>{{ .StartsAt.Format "2006-01-02 15:04:05 UTC" }}</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</table>
|
||||
Reference in New Issue
Block a user