[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CBRMFAF3Q03FQFPJPHRFVW":3,"skill-same:01M6CBRMFAF3Q03FQFPJPHRFVW":64},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":28,"linkOnly":29,"markdownContent":30,"markdownBody":31,"frontMatter":32,"refName":33,"commitSha":34,"skillDirectory":35,"forksCount":36,"repositoryHtmlUrl":37,"repositoryHomepageUrl":6,"ownerHtmlUrl":38,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":39,"install":40,"resources":53},"01M6CBRMFAF3Q03FQFPJPHRFVW","alert-management",null,"Implement comprehensive alert management with PagerDuty, escalation policies, and incident coordination. Use when setting up alerting systems, managing on-call schedules, or coordinating incident response.","ray-manaloto\u002Fmacos-development-environment","ray-manaloto","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F227192835?v=4","01M6CBR7J13ZA01X5YB1A1QRJP","01M6CBR7P0S3NS8ZV81JYNST14",1,"MIT","https:\u002F\u002Fgithub.com\u002Fray-manaloto\u002Fmacos-development-environment\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Falert-management\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27],"management","alert","alert management","incident response","implement","alerting","escalation","coordination","use","up","2026-11-10 10:12:30",false,"---\nname: alert-management\ndescription: Implement comprehensive alert management with PagerDuty, escalation policies, and incident coordination. Use when setting up alerting systems, managing on-call schedules, or coordinating incident response.\n---\n\n# Alert Management\n\n## Overview\n\nDesign and implement sophisticated alert management systems with PagerDuty integration, escalation policies, alert routing, and incident coordination.\n\n## When to Use\n\n- Setting up alert routing\n- Managing on-call schedules\n- Coordinating incident response\n- Creating escalation policies\n- Integrating alerting systems\n\n## Instructions\n\n### 1. **PagerDuty Client Integration**\n\n```javascript\n\u002F\u002F pagerduty-client.js\nconst axios = require('axios');\n\nclass PagerDutyClient {\n  constructor(apiToken) {\n    this.apiToken = apiToken;\n    this.baseUrl = 'https:\u002F\u002Fapi.pagerduty.com';\n    this.eventUrl = 'https:\u002F\u002Fevents.pagerduty.com\u002Fv2\u002Fenqueue';\n\n    this.client = axios.create({\n      baseURL: this.baseUrl,\n      headers: {\n        'Authorization': `Token token=${apiToken}`,\n        'Accept': 'application\u002Fvnd.pagerduty+json;version=2'\n      }\n    });\n  }\n\n  async triggerEvent(config) {\n    const event = {\n      routing_key: config.routingKey,\n      event_action: config.eventAction || 'trigger',\n      dedup_key: config.dedupKey || `event-${Date.now()}`,\n      payload: {\n        summary: config.summary,\n        timestamp: new Date().toISOString(),\n        severity: config.severity || 'error',\n        source: config.source || 'Monitoring System',\n        component: config.component,\n        custom_details: config.customDetails || {}\n      }\n    };\n\n    try {\n      const response = await axios.post(this.eventUrl, event);\n      return response.data;\n    } catch (error) {\n      console.error('Failed to trigger PagerDuty event:', error);\n      throw error;\n    }\n  }\n\n  async resolveEvent(dedupKey) {\n    const event = {\n      routing_key: process.env.PAGERDUTY_ROUTING_KEY,\n      event_action: 'resolve',\n      dedup_key: dedupKey\n    };\n\n    try {\n      return await axios.post(this.eventUrl, event);\n    } catch (error) {\n      console.error('Failed to resolve event:', error);\n      throw error;\n    }\n  }\n\n  async getServices() {\n    const response = await this.client.get('\u002Fservices');\n    return response.data.services;\n  }\n\n  async getEscalationPolicies() {\n    const response = await this.client.get('\u002Fescalation_policies');\n    return response.data.escalation_policies;\n  }\n\n  async createIncident(config) {\n    const incident = {\n      type: 'incident',\n      title: config.title,\n      service: {\n        id: config.serviceId,\n        type: 'service_reference'\n      },\n      escalation_policy: {\n        id: config.escalationPolicyId,\n        type: 'escalation_policy_reference'\n      },\n      body: {\n        type: 'incident_body',\n        details: config.details || ''\n      }\n    };\n\n    try {\n      const response = await this.client.post('\u002Fincidents', incident, {\n        headers: { 'From': process.env.PAGERDUTY_EMAIL }\n      });\n      return response.data.incident;\n    } catch (error) {\n      console.error('Failed to create incident:', error);\n      throw error;\n    }\n  }\n\n  async acknowledgeIncident(incidentId, userId) {\n    try {\n      const response = await this.client.put(\n        `\u002Fincidents\u002F${incidentId}`,\n        {\n          incidents: [{\n            id: incidentId,\n            type: 'incident_reference',\n            status: 'acknowledged'\n          }]\n        },\n        { headers: { 'From': process.env.PAGERDUTY_EMAIL } }\n      );\n      return response.data.incidents[0];\n    } catch (error) {\n      console.error('Failed to acknowledge:', error);\n      throw error;\n    }\n  }\n\n  async resolveIncident(incidentId) {\n    try {\n      const response = await this.client.put(\n        `\u002Fincidents\u002F${incidentId}`,\n        {\n          incidents: [{\n            id: incidentId,\n            type: 'incident_reference',\n            status: 'resolved'\n          }]\n        },\n        { headers: { 'From': process.env.PAGERDUTY_EMAIL } }\n      );\n      return response.data.incidents[0];\n    } catch (error) {\n      console.error('Failed to resolve:', error);\n      throw error;\n    }\n  }\n}\n\nmodule.exports = PagerDutyClient;\n```\n\n### 2. **Alertmanager Configuration**\n\n```yaml\n# \u002Fetc\u002Falertmanager\u002Falertmanager.yml\nglobal:\n  resolve_timeout: 5m\n  slack_api_url: '${SLACK_WEBHOOK_URL}'\n\ntemplates:\n  - '\u002Fetc\u002Falertmanager\u002Ftemplates\u002F*.tmpl'\n\nroute:\n  receiver: 'default'\n  group_by: ['alertname', 'cluster', 'service']\n  group_wait: 10s\n  group_interval: 10s\n  repeat_interval: 4h\n\n  routes:\n    - match:\n        severity: critical\n      receiver: pagerduty\n      continue: true\n      group_wait: 0s\n\n    - match:\n        severity: warning\n      receiver: slack\n\n    - match:\n        service: payment-service\n      receiver: payment-team\n      group_wait: 30s\n\nreceivers:\n  - name: 'default'\n    slack_configs:\n      - channel: '#alerts'\n        title: 'Alert: {{ .GroupLabels.alertname }}'\n\n  - name: 'pagerduty'\n    pagerduty_configs:\n      - service_key: '${PAGERDUTY_SERVICE_KEY}'\n        description: '{{ .GroupLabels.alertname }}'\n\n  - name: 'slack'\n    slack_configs:\n      - channel: '#alerts'\n        title: 'Warning: {{ .GroupLabels.alertname }}'\n\n  - name: 'payment-team'\n    pagerduty_configs:\n      - service_key: '${PAYMENT_PAGERDUTY_KEY}'\n    slack_configs:\n      - channel: '#payment-alerts'\n\ninhibit_rules:\n  - source_match:\n      severity: 'critical'\n    target_match:\n      severity: 'warning'\n    equal: ['alertname', 'service']\n```\n\n### 3. **Alert Handler Middleware**\n\n```javascript\n\u002F\u002F alert-handler.js\nconst PagerDutyClient = require('.\u002Fpagerduty-client');\n\nconst pdClient = new PagerDutyClient(process.env.PAGERDUTY_API_TOKEN);\n\nclass AlertHandler {\n  constructor() {\n    this.alertCache = new Map();\n    this.deduplicationWindow = 300000; \u002F\u002F 5 minutes\n  }\n\n  shouldSendAlert(dedupKey) {\n    const cacheEntry = this.alertCache.get(dedupKey);\n\n    if (!cacheEntry) return true;\n\n    const timeSinceLastAlert = Date.now() - cacheEntry.timestamp;\n    return timeSinceLastAlert >= this.deduplicationWindow;\n  }\n\n  recordAlert(dedupKey) {\n    this.alertCache.set(dedupKey, { timestamp: Date.now() });\n  }\n\n  determineSeverity(value, thresholds) {\n    if (value >= thresholds.critical) return 'critical';\n    if (value >= thresholds.warning) return 'warning';\n    return 'info';\n  }\n\n  async sendAlert(config) {\n    const dedupKey = config.dedupKey || `alert-${config.alertName}-${Date.now()}`;\n\n    try {\n      if (!this.shouldSendAlert(dedupKey)) {\n        console.log('Alert recently sent, skipping');\n        return;\n      }\n\n      const event = {\n        routingKey: config.routingKey,\n        eventAction: config.eventAction || 'trigger',\n        dedupKey: dedupKey,\n        summary: config.summary,\n        severity: config.severity,\n        source: config.source || 'Monitoring System',\n        component: config.component,\n        customDetails: {\n          ...config.customDetails,\n          alertName: config.alertName,\n          timestamp: new Date().toISOString()\n        }\n      };\n\n      const result = await pdClient.triggerEvent(event);\n      this.recordAlert(dedupKey);\n\n      console.log('Alert sent', {\n        alertName: config.alertName,\n        severity: config.severity\n      });\n\n      return result;\n    } catch (error) {\n      console.error('Failed to send alert:', error);\n      await this.sendSlackAlert(config);\n    }\n  }\n\n  async sendSlackAlert(config) {\n    const axios = require('axios');\n    const webhookUrl = process.env.SLACK_WEBHOOK_URL;\n\n    const message = {\n      color: config.severity === 'critical' ? 'danger' : 'warning',\n      title: config.summary,\n      text: config.customDetails?.description || '',\n      fields: [\n        { title: 'Severity', value: config.severity, short: true },\n        { title: 'Component', value: config.component, short: true }\n      ]\n    };\n\n    try {\n      await axios.post(webhookUrl, { attachments: [message] });\n    } catch (error) {\n      console.error('Failed to send Slack alert:', error);\n    }\n  }\n\n  async resolveAlert(dedupKey) {\n    try {\n      await pdClient.resolveEvent(dedupKey);\n      console.log('Alert resolved');\n    } catch (error) {\n      console.error('Failed to resolve alert:', error);\n    }\n  }\n}\n\nmodule.exports = new AlertHandler();\n```\n\n### 4. **Alert Routing Engine**\n\n```javascript\n\u002F\u002F alert-router.js\nclass AlertRouter {\n  constructor() {\n    this.routes = [];\n  }\n\n  addRoute(rule) {\n    this.routes.push({\n      priority: rule.priority || 0,\n      condition: rule.condition,\n      handler: rule.handler,\n      escalation: rule.escalation\n    });\n    this.routes.sort((a, b) => b.priority - a.priority);\n  }\n\n  async route(alert) {\n    for (const route of this.routes) {\n      if (route.condition(alert)) {\n        return await route.handler(alert, route.escalation);\n      }\n    }\n    return this.defaultHandler(alert);\n  }\n\n  async defaultHandler(alert) {\n    console.log('Routing to default handler:', alert.name);\n    return { routed: true, handler: 'default' };\n  }\n}\n\n\u002F\u002F Usage\nconst router = new AlertRouter();\n\nrouter.addRoute({\n  priority: 100,\n  condition: (alert) => alert.severity === 'critical' && alert.component === 'database',\n  handler: async (alert) => {\n    console.log('Routing critical database alert to DBA team');\n    return { team: 'dba', escalation: 'immediate' };\n  }\n});\n\nrouter.addRoute({\n  priority: 90,\n  condition: (alert) => alert.component === 'payment-service',\n  handler: async (alert) => {\n    console.log('Routing to payment team');\n    return { team: 'payment', escalation: 'payment-policy' };\n  }\n});\n\nrouter.addRoute({\n  priority: 10,\n  condition: (alert) => alert.severity === 'warning',\n  handler: async (alert) => {\n    console.log('Routing warning to Slack');\n    return { handler: 'slack-only' };\n  }\n});\n\nmodule.exports = router;\n```\n\n### 5. **Docker Compose Alert Stack**\n\n```yaml\n# docker-compose.yml\nversion: '3.8'\nservices:\n  prometheus:\n    image: prom\u002Fprometheus:latest\n    ports:\n      - \"9090:9090\"\n    volumes:\n      - .\u002Fprometheus.yml:\u002Fetc\u002Fprometheus\u002Fprometheus.yml\n\n  alertmanager:\n    image: prom\u002Falertmanager:latest\n    ports:\n      - \"9093:9093\"\n    volumes:\n      - .\u002Falertmanager.yml:\u002Fetc\u002Falertmanager\u002Falertmanager.yml\n    environment:\n      SLACK_WEBHOOK_URL: ${SLACK_WEBHOOK_URL}\n      PAGERDUTY_SERVICE_KEY: ${PAGERDUTY_SERVICE_KEY}\n    depends_on:\n      - prometheus\n\n  alert-handler:\n    build: .\n    environment:\n      PAGERDUTY_API_TOKEN: ${PAGERDUTY_API_TOKEN}\n      SLACK_WEBHOOK_URL: ${SLACK_WEBHOOK_URL}\n    ports:\n      - \"3000:3000\"\n    depends_on:\n      - alertmanager\n```\n\n## Best Practices\n\n### ✅ DO\n- Set appropriate thresholds\n- Implement alert deduplication\n- Use clear alert names\n- Include runbook links\n- Configure escalation properly\n- Test alert rules\n- Monitor alert quality\n- Set repeat intervals\n- Track alert metrics\n- Document alert meanings\n\n### ❌ DON'T\n- Alert on every anomaly\n- Ignore alert fatigue\n- Set thresholds arbitrarily\n- Skip runbooks\n- Alert without action\n- Disable alerts in production\n- Use vague alert names\n- Forget escalation policies\n- Re-alert too frequently\n\n## Alert Severity Levels\n\n- **Critical**: Immediate action required, customer impact\n- **Warning**: Investigation needed, potential issues\n- **Info**: Informational, no action required\n\n## Key Metrics\n\n- Alert volume\n- Resolution time\n- False positive rate\n- Escalation frequency\n- MTTD (Mean Time to Detection)\n- MTTR (Mean Time to Resolution)\n","# Alert Management\n\n## Overview\n\nDesign and implement sophisticated alert management systems with PagerDuty integration, escalation policies, alert routing, and incident coordination.\n\n## When to Use\n\n- Setting up alert routing\n- Managing on-call schedules\n- Coordinating incident response\n- Creating escalation policies\n- Integrating alerting systems\n\n## Instructions\n\n### 1. **PagerDuty Client Integration**\n\n```javascript\n\u002F\u002F pagerduty-client.js\nconst axios = require('axios');\n\nclass PagerDutyClient {\n  constructor(apiToken) {\n    this.apiToken = apiToken;\n    this.baseUrl = 'https:\u002F\u002Fapi.pagerduty.com';\n    this.eventUrl = 'https:\u002F\u002Fevents.pagerduty.com\u002Fv2\u002Fenqueue';\n\n    this.client = axios.create({\n      baseURL: this.baseUrl,\n      headers: {\n        'Authorization': `Token token=${apiToken}`,\n        'Accept': 'application\u002Fvnd.pagerduty+json;version=2'\n      }\n    });\n  }\n\n  async triggerEvent(config) {\n    const event = {\n      routing_key: config.routingKey,\n      event_action: config.eventAction || 'trigger',\n      dedup_key: config.dedupKey || `event-${Date.now()}`,\n      payload: {\n        summary: config.summary,\n        timestamp: new Date().toISOString(),\n        severity: config.severity || 'error',\n        source: config.source || 'Monitoring System',\n        component: config.component,\n        custom_details: config.customDetails || {}\n      }\n    };\n\n    try {\n      const response = await axios.post(this.eventUrl, event);\n      return response.data;\n    } catch (error) {\n      console.error('Failed to trigger PagerDuty event:', error);\n      throw error;\n    }\n  }\n\n  async resolveEvent(dedupKey) {\n    const event = {\n      routing_key: process.env.PAGERDUTY_ROUTING_KEY,\n      event_action: 'resolve',\n      dedup_key: dedupKey\n    };\n\n    try {\n      return await axios.post(this.eventUrl, event);\n    } catch (error) {\n      console.error('Failed to resolve event:', error);\n      throw error;\n    }\n  }\n\n  async getServices() {\n    const response = await this.client.get('\u002Fservices');\n    return response.data.services;\n  }\n\n  async getEscalationPolicies() {\n    const response = await this.client.get('\u002Fescalation_policies');\n    return response.data.escalation_policies;\n  }\n\n  async createIncident(config) {\n    const incident = {\n      type: 'incident',\n      title: config.title,\n      service: {\n        id: config.serviceId,\n        type: 'service_reference'\n      },\n      escalation_policy: {\n        id: config.escalationPolicyId,\n        type: 'escalation_policy_reference'\n      },\n      body: {\n        type: 'incident_body',\n        details: config.details || ''\n      }\n    };\n\n    try {\n      const response = await this.client.post('\u002Fincidents', incident, {\n        headers: { 'From': process.env.PAGERDUTY_EMAIL }\n      });\n      return response.data.incident;\n    } catch (error) {\n      console.error('Failed to create incident:', error);\n      throw error;\n    }\n  }\n\n  async acknowledgeIncident(incidentId, userId) {\n    try {\n      const response = await this.client.put(\n        `\u002Fincidents\u002F${incidentId}`,\n        {\n          incidents: [{\n            id: incidentId,\n            type: 'incident_reference',\n            status: 'acknowledged'\n          }]\n        },\n        { headers: { 'From': process.env.PAGERDUTY_EMAIL } }\n      );\n      return response.data.incidents[0];\n    } catch (error) {\n      console.error('Failed to acknowledge:', error);\n      throw error;\n    }\n  }\n\n  async resolveIncident(incidentId) {\n    try {\n      const response = await this.client.put(\n        `\u002Fincidents\u002F${incidentId}`,\n        {\n          incidents: [{\n            id: incidentId,\n            type: 'incident_reference',\n            status: 'resolved'\n          }]\n        },\n        { headers: { 'From': process.env.PAGERDUTY_EMAIL } }\n      );\n      return response.data.incidents[0];\n    } catch (error) {\n      console.error('Failed to resolve:', error);\n      throw error;\n    }\n  }\n}\n\nmodule.exports = PagerDutyClient;\n```\n\n### 2. **Alertmanager Configuration**\n\n```yaml\n# \u002Fetc\u002Falertmanager\u002Falertmanager.yml\nglobal:\n  resolve_timeout: 5m\n  slack_api_url: '${SLACK_WEBHOOK_URL}'\n\ntemplates:\n  - '\u002Fetc\u002Falertmanager\u002Ftemplates\u002F*.tmpl'\n\nroute:\n  receiver: 'default'\n  group_by: ['alertname', 'cluster', 'service']\n  group_wait: 10s\n  group_interval: 10s\n  repeat_interval: 4h\n\n  routes:\n    - match:\n        severity: critical\n      receiver: pagerduty\n      continue: true\n      group_wait: 0s\n\n    - match:\n        severity: warning\n      receiver: slack\n\n    - match:\n        service: payment-service\n      receiver: payment-team\n      group_wait: 30s\n\nreceivers:\n  - name: 'default'\n    slack_configs:\n      - channel: '#alerts'\n        title: 'Alert: {{ .GroupLabels.alertname }}'\n\n  - name: 'pagerduty'\n    pagerduty_configs:\n      - service_key: '${PAGERDUTY_SERVICE_KEY}'\n        description: '{{ .GroupLabels.alertname }}'\n\n  - name: 'slack'\n    slack_configs:\n      - channel: '#alerts'\n        title: 'Warning: {{ .GroupLabels.alertname }}'\n\n  - name: 'payment-team'\n    pagerduty_configs:\n      - service_key: '${PAYMENT_PAGERDUTY_KEY}'\n    slack_configs:\n      - channel: '#payment-alerts'\n\ninhibit_rules:\n  - source_match:\n      severity: 'critical'\n    target_match:\n      severity: 'warning'\n    equal: ['alertname', 'service']\n```\n\n### 3. **Alert Handler Middleware**\n\n```javascript\n\u002F\u002F alert-handler.js\nconst PagerDutyClient = require('.\u002Fpagerduty-client');\n\nconst pdClient = new PagerDutyClient(process.env.PAGERDUTY_API_TOKEN);\n\nclass AlertHandler {\n  constructor() {\n    this.alertCache = new Map();\n    this.deduplicationWindow = 300000; \u002F\u002F 5 minutes\n  }\n\n  shouldSendAlert(dedupKey) {\n    const cacheEntry = this.alertCache.get(dedupKey);\n\n    if (!cacheEntry) return true;\n\n    const timeSinceLastAlert = Date.now() - cacheEntry.timestamp;\n    return timeSinceLastAlert >= this.deduplicationWindow;\n  }\n\n  recordAlert(dedupKey) {\n    this.alertCache.set(dedupKey, { timestamp: Date.now() });\n  }\n\n  determineSeverity(value, thresholds) {\n    if (value >= thresholds.critical) return 'critical';\n    if (value >= thresholds.warning) return 'warning';\n    return 'info';\n  }\n\n  async sendAlert(config) {\n    const dedupKey = config.dedupKey || `alert-${config.alertName}-${Date.now()}`;\n\n    try {\n      if (!this.shouldSendAlert(dedupKey)) {\n        console.log('Alert recently sent, skipping');\n        return;\n      }\n\n      const event = {\n        routingKey: config.routingKey,\n        eventAction: config.eventAction || 'trigger',\n        dedupKey: dedupKey,\n        summary: config.summary,\n        severity: config.severity,\n        source: config.source || 'Monitoring System',\n        component: config.component,\n        customDetails: {\n          ...config.customDetails,\n          alertName: config.alertName,\n          timestamp: new Date().toISOString()\n        }\n      };\n\n      const result = await pdClient.triggerEvent(event);\n      this.recordAlert(dedupKey);\n\n      console.log('Alert sent', {\n        alertName: config.alertName,\n        severity: config.severity\n      });\n\n      return result;\n    } catch (error) {\n      console.error('Failed to send alert:', error);\n      await this.sendSlackAlert(config);\n    }\n  }\n\n  async sendSlackAlert(config) {\n    const axios = require('axios');\n    const webhookUrl = process.env.SLACK_WEBHOOK_URL;\n\n    const message = {\n      color: config.severity === 'critical' ? 'danger' : 'warning',\n      title: config.summary,\n      text: config.customDetails?.description || '',\n      fields: [\n        { title: 'Severity', value: config.severity, short: true },\n        { title: 'Component', value: config.component, short: true }\n      ]\n    };\n\n    try {\n      await axios.post(webhookUrl, { attachments: [message] });\n    } catch (error) {\n      console.error('Failed to send Slack alert:', error);\n    }\n  }\n\n  async resolveAlert(dedupKey) {\n    try {\n      await pdClient.resolveEvent(dedupKey);\n      console.log('Alert resolved');\n    } catch (error) {\n      console.error('Failed to resolve alert:', error);\n    }\n  }\n}\n\nmodule.exports = new AlertHandler();\n```\n\n### 4. **Alert Routing Engine**\n\n```javascript\n\u002F\u002F alert-router.js\nclass AlertRouter {\n  constructor() {\n    this.routes = [];\n  }\n\n  addRoute(rule) {\n    this.routes.push({\n      priority: rule.priority || 0,\n      condition: rule.condition,\n      handler: rule.handler,\n      escalation: rule.escalation\n    });\n    this.routes.sort((a, b) => b.priority - a.priority);\n  }\n\n  async route(alert) {\n    for (const route of this.routes) {\n      if (route.condition(alert)) {\n        return await route.handler(alert, route.escalation);\n      }\n    }\n    return this.defaultHandler(alert);\n  }\n\n  async defaultHandler(alert) {\n    console.log('Routing to default handler:', alert.name);\n    return { routed: true, handler: 'default' };\n  }\n}\n\n\u002F\u002F Usage\nconst router = new AlertRouter();\n\nrouter.addRoute({\n  priority: 100,\n  condition: (alert) => alert.severity === 'critical' && alert.component === 'database',\n  handler: async (alert) => {\n    console.log('Routing critical database alert to DBA team');\n    return { team: 'dba', escalation: 'immediate' };\n  }\n});\n\nrouter.addRoute({\n  priority: 90,\n  condition: (alert) => alert.component === 'payment-service',\n  handler: async (alert) => {\n    console.log('Routing to payment team');\n    return { team: 'payment', escalation: 'payment-policy' };\n  }\n});\n\nrouter.addRoute({\n  priority: 10,\n  condition: (alert) => alert.severity === 'warning',\n  handler: async (alert) => {\n    console.log('Routing warning to Slack');\n    return { handler: 'slack-only' };\n  }\n});\n\nmodule.exports = router;\n```\n\n### 5. **Docker Compose Alert Stack**\n\n```yaml\n# docker-compose.yml\nversion: '3.8'\nservices:\n  prometheus:\n    image: prom\u002Fprometheus:latest\n    ports:\n      - \"9090:9090\"\n    volumes:\n      - .\u002Fprometheus.yml:\u002Fetc\u002Fprometheus\u002Fprometheus.yml\n\n  alertmanager:\n    image: prom\u002Falertmanager:latest\n    ports:\n      - \"9093:9093\"\n    volumes:\n      - .\u002Falertmanager.yml:\u002Fetc\u002Falertmanager\u002Falertmanager.yml\n    environment:\n      SLACK_WEBHOOK_URL: ${SLACK_WEBHOOK_URL}\n      PAGERDUTY_SERVICE_KEY: ${PAGERDUTY_SERVICE_KEY}\n    depends_on:\n      - prometheus\n\n  alert-handler:\n    build: .\n    environment:\n      PAGERDUTY_API_TOKEN: ${PAGERDUTY_API_TOKEN}\n      SLACK_WEBHOOK_URL: ${SLACK_WEBHOOK_URL}\n    ports:\n      - \"3000:3000\"\n    depends_on:\n      - alertmanager\n```\n\n## Best Practices\n\n### ✅ DO\n- Set appropriate thresholds\n- Implement alert deduplication\n- Use clear alert names\n- Include runbook links\n- Configure escalation properly\n- Test alert rules\n- Monitor alert quality\n- Set repeat intervals\n- Track alert metrics\n- Document alert meanings\n\n### ❌ DON'T\n- Alert on every anomaly\n- Ignore alert fatigue\n- Set thresholds arbitrarily\n- Skip runbooks\n- Alert without action\n- Disable alerts in production\n- Use vague alert names\n- Forget escalation policies\n- Re-alert too frequently\n\n## Alert Severity Levels\n\n- **Critical**: Immediate action required, customer impact\n- **Warning**: Investigation needed, potential issues\n- **Info**: Informational, no action required\n\n## Key Metrics\n\n- Alert volume\n- Resolution time\n- False positive rate\n- Escalation frequency\n- MTTD (Mean Time to Detection)\n- MTTR (Mean Time to Resolution)\n",{"name":5,"description":7},"main","716b17df3ef6719d88aeac180015008b7ddfff6f",".agents\u002Fskills\u002Falert-management",0,"https:\u002F\u002Fgithub.com\u002Fray-manaloto\u002Fmacos-development-environment","https:\u002F\u002Fgithub.com\u002Fray-manaloto","2026-08-03 16:55:50",{"source":8,"skillName":5,"commands":41,"prompt":51,"zipAvailable":52},[42,45,48],{"tool":43,"command":44},"npx","npx skills add ray-manaloto\u002Fmacos-development-environment --skill alert-management",{"tool":46,"command":47},"bunx","bunx skills add ray-manaloto\u002Fmacos-development-environment --skill alert-management",{"tool":49,"command":50},"pnpm","pnpm dlx skills add ray-manaloto\u002Fmacos-development-environment --skill alert-management","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fray-manaloto\u002Fmacos-development-environment\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Falert-management\u002FSKILL.md",true,[54,60],{"path":55,"resourceType":56,"resourceTypeDesc":57,"sizeBytes":58,"sourceHtmlUrl":59},"SOURCE.md","REFERENCE","参考文档",180,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fdefi\u002Faxelrod-swap-agent\u002FSOURCE.md",{"path":61,"resourceType":56,"resourceTypeDesc":57,"sizeBytes":62,"sourceHtmlUrl":63},"TRUST.auto.yaml",2217,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fdefi\u002Faxelrod-swap-agent\u002FTRUST.auto.yaml",[65,86,103,122,142,156],{"skillNo":66,"name":67,"nameZh":6,"description":68,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":69,"categories":70,"keywords":76,"publishedAt":28},"01M6CC8DXNJ39YWERYTWCGGCGG","next-workflow-step","Use this skill when the user wants to transition to the next workflow step, wrap up a session cleanly, prepare a handoff, or says things like \"next step\", \"continue the workflow\", \"wrap up\", \"hand off\", \"move to the next phase\", \"what's next in embrace\", or \"prepare for \u002Fclear\". Also triggers when the current octo:embrace phase appears complete and no explicit next action is set.","https:\u002F\u002Fgithub.com\u002Fray-manaloto\u002Fmacos-development-environment\u002Fblob\u002Fmain\u002Frsm-subagents\u002Fplugins\u002Fworkflow-toolkit\u002Fskills\u002Fnext-workflow-step\u002FSKILL.md",[71],{"categoryNo":72,"categoryName":73,"taxonomyType":74,"taxonomyTypeDesc":75},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[77,78,27,26,79,80,81,82,83,84,85],"next workflow step","workflow","session","user","wrap up","continue","handoff","prepare","SET",{"skillNo":87,"name":88,"nameZh":6,"description":89,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":92,"publishedAt":28},"01M6CC8BRZBQHEBXGMKPDM422P","source-discovery","This skill should be used when the user asks to \"find sources\", \"discover URLs\", \"catalog a source\", \"classify a URL\", \"search for libraries\", \"check what exists\", or mentions source discovery, URL cataloging, source classification, or research source management.","https:\u002F\u002Fgithub.com\u002Fray-manaloto\u002Fmacos-development-environment\u002Fblob\u002Fmain\u002Frsm-subagents\u002Fplugins\u002Fresearch-review-toolkit\u002Fskills\u002Fsource-discovery\u002FSKILL.md",[],[93,94,95,96,97,98,99,100,18,80,101,102],"discovery","source discovery","research","libraries","search","classification","find","check","catalog","find sources",{"skillNo":104,"name":105,"nameZh":6,"description":106,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":107,"categories":108,"keywords":109,"publishedAt":28},"01M6CC89CGJP69A0PS22G2H1FV","review-synthesis","This skill should be used when the user asks to \"summarize review findings\", \"prioritize fixes\", \"rank review issues\", \"combine reviewer feedback\", \"create action items from review\", or mentions review synthesis, finding prioritization, severity ranking, or review result summarization.","https:\u002F\u002Fgithub.com\u002Fray-manaloto\u002Fmacos-development-environment\u002Fblob\u002Fmain\u002Frsm-subagents\u002Fplugins\u002Fresearch-review-toolkit\u002Fskills\u002Freview-synthesis\u002FSKILL.md",[],[110,111,112,113,114,115,116,80,117,118,119,120,121],"review","review synthesis","Synthesis","prioritize","create action","feedback","reviewer","summarize","prioritization","create","issues","severity",{"skillNo":123,"name":124,"nameZh":6,"description":125,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":126,"categories":127,"keywords":131,"publishedAt":28},"01M6CC872EZ9GRJY0HRCG0RT2M","research-scoring","This skill should be used when the user asks to \"score research\", \"check research quality\", \"evaluate coverage\", \"measure improvement\", \"assess research completeness\", or mentions research scoring, quality metrics, coverage gaps, improvement baseline, or research pipeline status.","https:\u002F\u002Fgithub.com\u002Fray-manaloto\u002Fmacos-development-environment\u002Fblob\u002Fmain\u002Frsm-subagents\u002Fplugins\u002Fresearch-review-toolkit\u002Fskills\u002Fresearch-scoring\u002FSKILL.md",[128],{"categoryNo":129,"categoryName":130,"taxonomyType":74,"taxonomyTypeDesc":75},"01JBSEEDCAT000000000000021","资料检索与研究",[132,95,133,134,135,136,137,138,100,80,139,140,141],"research scoring","status","coverage gaps","metrics","pipeline","baseline","quality","coverage","pipeline status","research quality",{"skillNo":143,"name":144,"nameZh":6,"description":145,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":146,"categories":147,"keywords":148,"publishedAt":28},"01M6CC852HSDS1FE4EJAT0RHGR","notebooklm-integration","This skill should be used when the user asks to \"ingest into NotebookLM\", \"query NotebookLM\", \"add sources to notebook\", \"cross-source synthesis\", \"check stale sources\", or mentions NotebookLM, notebook integration, source ingestion, or knowledge consolidation.","https:\u002F\u002Fgithub.com\u002Fray-manaloto\u002Fmacos-development-environment\u002Fblob\u002Fmain\u002Frsm-subagents\u002Fplugins\u002Fresearch-review-toolkit\u002Fskills\u002Fnotebooklm-integration\u002FSKILL.md",[],[149,150,151,152,100,80,153,154,155,112],"notebooklm integration","notebooklm","integration","knowledge","ingestion","ingest","stale",{"skillNo":157,"name":158,"nameZh":6,"description":159,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":160,"categories":161,"keywords":163,"publishedAt":28},"01M6CC82Z4V3205KCJWQZPS2VG","evidence-synthesis","This skill should be used when the user asks to \"synthesize findings\", \"combine research\", \"cross-reference sources\", \"summarize evidence\", \"write a deep review\", or mentions evidence synthesis, finding consolidation, cross-source analysis, or research summarization.","https:\u002F\u002Fgithub.com\u002Fray-manaloto\u002Fmacos-development-environment\u002Fblob\u002Fmain\u002Frsm-subagents\u002Fplugins\u002Fresearch-review-toolkit\u002Fskills\u002Fevidence-synthesis\u002FSKILL.md",[162],{"categoryNo":129,"categoryName":130,"taxonomyType":74,"taxonomyTypeDesc":75},[164,112,165,117,95,166,167,168,80,169,110],"evidence synthesis","evidence","deep review","analysis","write","reference"]