[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6F8D7166X13569FMN8FVM78":3,"skill-same:01M6F8D7166X13569FMN8FVM78":74},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":42,"linkOnly":43,"markdownContent":44,"markdownBody":45,"frontMatter":46,"refName":51,"commitSha":52,"skillDirectory":53,"forksCount":54,"repositoryHtmlUrl":55,"repositoryHomepageUrl":6,"ownerHtmlUrl":56,"ownerBlogUrl":57,"ownerDescription":58,"updatedAt":59,"install":60,"resources":73},"01M6F8D7166X13569FMN8FVM78","openevidence-observability",null,"Set up comprehensive observability for OpenEvidence integrations with metrics, traces, and alerts.\nUse when implementing monitoring for clinical AI operations, setting up dashboards,\nor configuring alerting for healthcare application health.\nTrigger with phrases like \"openevidence monitoring\", \"openevidence metrics\",\n\"openevidence observability\", \"monitor openevidence\", \"openevidence alerts\".","Dicklesworthstone\u002Fpi_agent_rust","Dicklesworthstone","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F35050222?v=4","01M6CG26AR942CSVMN1M5E3DSE","Jeff Emanuel","01M6CG26EPP71PSHW1VDS71121",1992,"MIT","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fopenevidence-pack\u002Fskills\u002Fopenevidence-observability\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41],"observability","openevidence observability","write","when","for","implementing","trigger","io","clinical","alerts","up","use","edit","monitor","read","integrations","dashboards","healthcare","health","SET","monitoring","alerting","metrics","2026-11-10 10:12:30",false,"---\nname: openevidence-observability\ndescription: |\n  Set up comprehensive observability for OpenEvidence integrations with metrics, traces, and alerts.\n  Use when implementing monitoring for clinical AI operations, setting up dashboards,\n  or configuring alerting for healthcare application health.\n  Trigger with phrases like \"openevidence monitoring\", \"openevidence metrics\",\n  \"openevidence observability\", \"monitor openevidence\", \"openevidence alerts\".\nallowed-tools: Read, Write, Edit\nversion: 1.0.0\nlicense: MIT\nauthor: Jeremy Longshore \u003Cjeremy@intentsolutions.io>\n---\n\n# OpenEvidence Observability\n\n## Overview\nSet up comprehensive observability for OpenEvidence clinical AI integrations in healthcare environments.\n\n## Prerequisites\n- Prometheus or compatible metrics backend\n- OpenTelemetry SDK installed\n- Grafana or similar dashboarding tool\n- AlertManager or PagerDuty configured\n\n## Key Metrics\n\n| Metric | Type | Description | Alert Threshold |\n|--------|------|-------------|-----------------|\n| `openevidence_requests_total` | Counter | Total API requests | N\u002FA |\n| `openevidence_request_duration_seconds` | Histogram | Request latency | P95 > 15s |\n| `openevidence_errors_total` | Counter | Error count by type | > 5% rate |\n| `openevidence_cache_hits_total` | Counter | Cache hit count | \u003C 50% rate |\n| `openevidence_rate_limit_remaining` | Gauge | Rate limit headroom | \u003C 10% |\n| `openevidence_deepconsult_active` | Gauge | Active DeepConsults | > 50 |\n\n## Instructions\n\n### Step 1: Prometheus Metrics\n```typescript\n\u002F\u002F src\u002Fmonitoring\u002Fmetrics.ts\nimport { Registry, Counter, Histogram, Gauge, Summary } from 'prom-client';\n\nconst registry = new Registry();\n\n\u002F\u002F Request metrics\nexport const requestCounter = new Counter({\n  name: 'openevidence_requests_total',\n  help: 'Total OpenEvidence API requests',\n  labelNames: ['method', 'specialty', 'status'],\n  registers: [registry],\n});\n\nexport const requestDuration = new Histogram({\n  name: 'openevidence_request_duration_seconds',\n  help: 'OpenEvidence request duration',\n  labelNames: ['method', 'specialty'],\n  buckets: [0.5, 1, 2, 5, 10, 15, 30, 60],\n  registers: [registry],\n});\n\n\u002F\u002F Error metrics\nexport const errorCounter = new Counter({\n  name: 'openevidence_errors_total',\n  help: 'OpenEvidence errors by type',\n  labelNames: ['error_type', 'specialty'],\n  registers: [registry],\n});\n\n\u002F\u002F Cache metrics\nexport const cacheHits = new Counter({\n  name: 'openevidence_cache_hits_total',\n  help: 'Cache hit count',\n  registers: [registry],\n});\n\nexport const cacheMisses = new Counter({\n  name: 'openevidence_cache_misses_total',\n  help: 'Cache miss count',\n  registers: [registry],\n});\n\n\u002F\u002F Rate limit metrics\nexport const rateLimitRemaining = new Gauge({\n  name: 'openevidence_rate_limit_remaining',\n  help: 'Remaining rate limit',\n  registers: [registry],\n});\n\nexport const rateLimitPercent = new Gauge({\n  name: 'openevidence_rate_limit_usage_percent',\n  help: 'Rate limit usage percentage',\n  registers: [registry],\n});\n\n\u002F\u002F DeepConsult metrics\nexport const deepConsultActive = new Gauge({\n  name: 'openevidence_deepconsult_active',\n  help: 'Active DeepConsult requests',\n  registers: [registry],\n});\n\nexport const deepConsultDuration = new Histogram({\n  name: 'openevidence_deepconsult_duration_seconds',\n  help: 'DeepConsult completion time',\n  labelNames: ['specialty', 'status'],\n  buckets: [30, 60, 120, 180, 300, 600],\n  registers: [registry],\n});\n\n\u002F\u002F Confidence metrics\nexport const confidenceScore = new Summary({\n  name: 'openevidence_confidence_score',\n  help: 'Response confidence score distribution',\n  labelNames: ['specialty'],\n  percentiles: [0.5, 0.9, 0.95, 0.99],\n  registers: [registry],\n});\n\nexport { registry };\n```\n\n### Step 2: Instrumented Client Wrapper\n```typescript\n\u002F\u002F src\u002Fmonitoring\u002Finstrumented-client.ts\nimport { OpenEvidenceClient } from '@openevidence\u002Fsdk';\nimport {\n  requestCounter,\n  requestDuration,\n  errorCounter,\n  cacheHits,\n  cacheMisses,\n  rateLimitRemaining,\n  rateLimitPercent,\n  confidenceScore,\n} from '.\u002Fmetrics';\nimport { trace, SpanStatusCode, Span } from '@opentelemetry\u002Fapi';\n\nconst tracer = trace.getTracer('openevidence-client');\n\nexport class InstrumentedOpenEvidenceClient {\n  private client: OpenEvidenceClient;\n  private cache: ClinicalQueryCache;\n\n  constructor(config: any, cache: ClinicalQueryCache) {\n    this.client = new OpenEvidenceClient(config);\n    this.cache = cache;\n  }\n\n  async query(request: ClinicalQueryRequest): Promise\u003CClinicalQueryResponse> {\n    const { specialty } = request.context;\n\n    return tracer.startActiveSpan('openevidence.query', async (span: Span) => {\n      const timer = requestDuration.startTimer({ method: 'query', specialty });\n\n      try {\n        \u002F\u002F Add span attributes\n        span.setAttribute('openevidence.specialty', specialty);\n        span.setAttribute('openevidence.urgency', request.context.urgency);\n\n        \u002F\u002F Check cache first\n        const cached = await this.cache.get(request.question, request.context);\n        if (cached) {\n          cacheHits.inc();\n          span.setAttribute('cache.hit', true);\n          timer({ cached: 'true' });\n          requestCounter.inc({ method: 'query', specialty, status: 'cache_hit' });\n          return cached;\n        }\n        cacheMisses.inc();\n        span.setAttribute('cache.hit', false);\n\n        \u002F\u002F Make API request\n        const response = await this.client.query(request);\n\n        \u002F\u002F Update rate limit metrics from headers\n        this.updateRateLimitMetrics(response.headers);\n\n        \u002F\u002F Record confidence score\n        confidenceScore.observe({ specialty }, response.confidence);\n\n        \u002F\u002F Cache response\n        await this.cache.set(request.question, request.context, response);\n\n        \u002F\u002F Record success\n        timer({ cached: 'false' });\n        requestCounter.inc({ method: 'query', specialty, status: 'success' });\n        span.setStatus({ code: SpanStatusCode.OK });\n\n        return response;\n      } catch (error: any) {\n        \u002F\u002F Record error\n        timer({ cached: 'false' });\n        requestCounter.inc({ method: 'query', specialty, status: 'error' });\n        errorCounter.inc({ error_type: error.code || 'unknown', specialty });\n\n        span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n        span.recordException(error);\n\n        throw error;\n      } finally {\n        span.end();\n      }\n    });\n  }\n\n  private updateRateLimitMetrics(headers: any): void {\n    const remaining = parseInt(headers['x-ratelimit-remaining'] || '0');\n    const limit = parseInt(headers['x-ratelimit-limit'] || '100');\n\n    rateLimitRemaining.set(remaining);\n    rateLimitPercent.set(((limit - remaining) \u002F limit) * 100);\n  }\n}\n```\n\n### Step 3: Distributed Tracing Setup\n```typescript\n\u002F\u002F src\u002Fmonitoring\u002Ftracing.ts\nimport { NodeSDK } from '@opentelemetry\u002Fsdk-node';\nimport { Resource } from '@opentelemetry\u002Fresources';\nimport { SemanticResourceAttributes } from '@opentelemetry\u002Fsemantic-conventions';\nimport { TraceExporter } from '@google-cloud\u002Fopentelemetry-cloud-trace-exporter';\nimport { HttpInstrumentation } from '@opentelemetry\u002Finstrumentation-http';\nimport { ExpressInstrumentation } from '@opentelemetry\u002Finstrumentation-express';\n\nexport function initTracing(): void {\n  const sdk = new NodeSDK({\n    resource: new Resource({\n      [SemanticResourceAttributes.SERVICE_NAME]: 'clinical-evidence-api',\n      [SemanticResourceAttributes.SERVICE_VERSION]: process.env.npm_package_version,\n      [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV,\n    }),\n    traceExporter: new TraceExporter(),\n    instrumentations: [\n      new HttpInstrumentation({\n        requestHook: (span, request) => {\n          \u002F\u002F Don't trace health checks\n          if (request.url?.includes('\u002Fhealth')) {\n            span.setAttribute('http.skip', true);\n          }\n        },\n      }),\n      new ExpressInstrumentation(),\n    ],\n  });\n\n  sdk.start();\n\n  process.on('SIGTERM', () => {\n    sdk.shutdown().catch(console.error);\n  });\n}\n```\n\n### Step 4: Structured Logging\n```typescript\n\u002F\u002F src\u002Fmonitoring\u002Flogger.ts\nimport pino from 'pino';\n\nexport const logger = pino({\n  name: 'clinical-evidence-api',\n  level: process.env.LOG_LEVEL || 'info',\n  formatters: {\n    level: (label) => ({ level: label }),\n  },\n  \u002F\u002F Redact PHI fields\n  redact: {\n    paths: ['patient.*', 'patientId', 'mrn', '*.ssn'],\n    censor: '[REDACTED]',\n  },\n});\n\n\u002F\u002F OpenEvidence-specific logger\nexport const oeLogger = logger.child({ service: 'openevidence' });\n\nexport function logClinicalQuery(\n  queryId: string,\n  specialty: string,\n  duration: number,\n  cached: boolean,\n  confidence?: number\n): void {\n  oeLogger.info({\n    event: 'clinical_query',\n    queryId,\n    specialty,\n    durationMs: duration,\n    cached,\n    confidence,\n  });\n}\n\nexport function logDeepConsult(\n  consultId: string,\n  specialty: string,\n  status: string,\n  duration?: number\n): void {\n  oeLogger.info({\n    event: 'deep_consult',\n    consultId,\n    specialty,\n    status,\n    durationMs: duration,\n  });\n}\n\nexport function logError(\n  error: Error,\n  context: Record\u003Cstring, any>\n): void {\n  oeLogger.error({\n    event: 'error',\n    errorType: error.name,\n    errorMessage: error.message,\n    ...context,\n  });\n}\n```\n\n### Step 5: Alert Rules\n```yaml\n# prometheus\u002Fopenevidence_alerts.yaml\ngroups:\n  - name: openevidence_alerts\n    rules:\n      # High error rate\n      - alert: OpenEvidenceHighErrorRate\n        expr: |\n          rate(openevidence_errors_total[5m]) \u002F\n          rate(openevidence_requests_total[5m]) > 0.05\n        for: 5m\n        labels:\n          severity: warning\n          service: openevidence\n        annotations:\n          summary: \"OpenEvidence error rate > 5%\"\n          description: \"Error rate is {{ $value | humanizePercentage }}\"\n\n      # Critical error rate\n      - alert: OpenEvidenceCriticalErrorRate\n        expr: |\n          rate(openevidence_errors_total[5m]) \u002F\n          rate(openevidence_requests_total[5m]) > 0.20\n        for: 2m\n        labels:\n          severity: critical\n          service: openevidence\n        annotations:\n          summary: \"OpenEvidence error rate > 20%\"\n          description: \"Critical error rate - possible outage\"\n\n      # High latency\n      - alert: OpenEvidenceHighLatency\n        expr: |\n          histogram_quantile(0.95,\n            rate(openevidence_request_duration_seconds_bucket[5m])\n          ) > 15\n        for: 5m\n        labels:\n          severity: warning\n          service: openevidence\n        annotations:\n          summary: \"OpenEvidence P95 latency > 15s\"\n          description: \"95th percentile latency is {{ $value | humanizeDuration }}\"\n\n      # Low cache hit rate\n      - alert: OpenEvidenceLowCacheHitRate\n        expr: |\n          rate(openevidence_cache_hits_total[1h]) \u002F\n          (rate(openevidence_cache_hits_total[1h]) + rate(openevidence_cache_misses_total[1h])) \u003C 0.5\n        for: 30m\n        labels:\n          severity: warning\n          service: openevidence\n        annotations:\n          summary: \"OpenEvidence cache hit rate \u003C 50%\"\n          description: \"Consider reviewing cache configuration\"\n\n      # Rate limit warning\n      - alert: OpenEvidenceRateLimitWarning\n        expr: openevidence_rate_limit_remaining \u003C 10\n        for: 1m\n        labels:\n          severity: warning\n          service: openevidence\n        annotations:\n          summary: \"OpenEvidence rate limit \u003C 10 remaining\"\n          description: \"Consider throttling requests\"\n\n      # Service down\n      - alert: OpenEvidenceDown\n        expr: up{job=\"openevidence\"} == 0\n        for: 1m\n        labels:\n          severity: critical\n          service: openevidence\n        annotations:\n          summary: \"OpenEvidence integration is down\"\n          description: \"No successful health checks for 1 minute\"\n```\n\n### Step 6: Grafana Dashboard\n```json\n{\n  \"dashboard\": {\n    \"title\": \"OpenEvidence Clinical AI\",\n    \"panels\": [\n      {\n        \"title\": \"Request Rate\",\n        \"type\": \"stat\",\n        \"targets\": [{\n          \"expr\": \"sum(rate(openevidence_requests_total[5m]))\",\n          \"legendFormat\": \"req\u002Fs\"\n        }]\n      },\n      {\n        \"title\": \"Error Rate\",\n        \"type\": \"gauge\",\n        \"targets\": [{\n          \"expr\": \"sum(rate(openevidence_errors_total[5m])) \u002F sum(rate(openevidence_requests_total[5m])) * 100\"\n        }],\n        \"fieldConfig\": {\n          \"defaults\": {\n            \"max\": 100,\n            \"thresholds\": {\n              \"mode\": \"absolute\",\n              \"steps\": [\n                {\"color\": \"green\", \"value\": 0},\n                {\"color\": \"yellow\", \"value\": 5},\n                {\"color\": \"red\", \"value\": 20}\n              ]\n            }\n          }\n        }\n      },\n      {\n        \"title\": \"Latency Distribution\",\n        \"type\": \"heatmap\",\n        \"targets\": [{\n          \"expr\": \"sum(rate(openevidence_request_duration_seconds_bucket[5m])) by (le)\"\n        }]\n      },\n      {\n        \"title\": \"Cache Hit Rate\",\n        \"type\": \"timeseries\",\n        \"targets\": [{\n          \"expr\": \"sum(rate(openevidence_cache_hits_total[5m])) \u002F (sum(rate(openevidence_cache_hits_total[5m])) + sum(rate(openevidence_cache_misses_total[5m])))\",\n          \"legendFormat\": \"Hit Rate\"\n        }]\n      },\n      {\n        \"title\": \"Rate Limit Usage\",\n        \"type\": \"gauge\",\n        \"targets\": [{\n          \"expr\": \"openevidence_rate_limit_usage_percent\"\n        }],\n        \"fieldConfig\": {\n          \"defaults\": {\n            \"max\": 100,\n            \"thresholds\": {\n              \"mode\": \"absolute\",\n              \"steps\": [\n                {\"color\": \"green\", \"value\": 0},\n                {\"color\": \"yellow\", \"value\": 70},\n                {\"color\": \"red\", \"value\": 90}\n              ]\n            }\n          }\n        }\n      },\n      {\n        \"title\": \"Confidence Score Distribution\",\n        \"type\": \"histogram\",\n        \"targets\": [{\n          \"expr\": \"openevidence_confidence_score\"\n        }]\n      }\n    ]\n  }\n}\n```\n\n## Metrics Endpoint\n```typescript\n\u002F\u002F src\u002Froutes\u002Fmetrics.ts\nimport { Router } from 'express';\nimport { registry } from '..\u002Fmonitoring\u002Fmetrics';\n\nconst router = Router();\n\nrouter.get('\u002Fmetrics', async (req, res) => {\n  res.set('Content-Type', registry.contentType);\n  res.send(await registry.metrics());\n});\n\nexport default router;\n```\n\n## Output\n- Prometheus metrics collection\n- Distributed tracing with OpenTelemetry\n- Structured logging with PHI redaction\n- Alert rules for critical conditions\n- Grafana dashboard\n\n## Observability Checklist\n- [ ] Metrics endpoint exposed\n- [ ] Request counters and histograms\n- [ ] Error counters with labels\n- [ ] Cache hit\u002Fmiss tracking\n- [ ] Rate limit monitoring\n- [ ] Distributed tracing enabled\n- [ ] Structured logging configured\n- [ ] Alert rules deployed\n- [ ] Dashboard created\n\n## Resources\n- [Prometheus Best Practices](https:\u002F\u002Fprometheus.io\u002Fdocs\u002Fpractices\u002Fnaming\u002F)\n- [OpenTelemetry Documentation](https:\u002F\u002Fopentelemetry.io\u002Fdocs\u002F)\n- [Grafana Dashboards](https:\u002F\u002Fgrafana.com\u002Fdocs\u002Fgrafana\u002Flatest\u002Fdashboards\u002F)\n\n## Next Steps\nFor incident response, see `openevidence-incident-runbook`.\n","# OpenEvidence Observability\n\n## Overview\nSet up comprehensive observability for OpenEvidence clinical AI integrations in healthcare environments.\n\n## Prerequisites\n- Prometheus or compatible metrics backend\n- OpenTelemetry SDK installed\n- Grafana or similar dashboarding tool\n- AlertManager or PagerDuty configured\n\n## Key Metrics\n\n| Metric | Type | Description | Alert Threshold |\n|--------|------|-------------|-----------------|\n| `openevidence_requests_total` | Counter | Total API requests | N\u002FA |\n| `openevidence_request_duration_seconds` | Histogram | Request latency | P95 > 15s |\n| `openevidence_errors_total` | Counter | Error count by type | > 5% rate |\n| `openevidence_cache_hits_total` | Counter | Cache hit count | \u003C 50% rate |\n| `openevidence_rate_limit_remaining` | Gauge | Rate limit headroom | \u003C 10% |\n| `openevidence_deepconsult_active` | Gauge | Active DeepConsults | > 50 |\n\n## Instructions\n\n### Step 1: Prometheus Metrics\n```typescript\n\u002F\u002F src\u002Fmonitoring\u002Fmetrics.ts\nimport { Registry, Counter, Histogram, Gauge, Summary } from 'prom-client';\n\nconst registry = new Registry();\n\n\u002F\u002F Request metrics\nexport const requestCounter = new Counter({\n  name: 'openevidence_requests_total',\n  help: 'Total OpenEvidence API requests',\n  labelNames: ['method', 'specialty', 'status'],\n  registers: [registry],\n});\n\nexport const requestDuration = new Histogram({\n  name: 'openevidence_request_duration_seconds',\n  help: 'OpenEvidence request duration',\n  labelNames: ['method', 'specialty'],\n  buckets: [0.5, 1, 2, 5, 10, 15, 30, 60],\n  registers: [registry],\n});\n\n\u002F\u002F Error metrics\nexport const errorCounter = new Counter({\n  name: 'openevidence_errors_total',\n  help: 'OpenEvidence errors by type',\n  labelNames: ['error_type', 'specialty'],\n  registers: [registry],\n});\n\n\u002F\u002F Cache metrics\nexport const cacheHits = new Counter({\n  name: 'openevidence_cache_hits_total',\n  help: 'Cache hit count',\n  registers: [registry],\n});\n\nexport const cacheMisses = new Counter({\n  name: 'openevidence_cache_misses_total',\n  help: 'Cache miss count',\n  registers: [registry],\n});\n\n\u002F\u002F Rate limit metrics\nexport const rateLimitRemaining = new Gauge({\n  name: 'openevidence_rate_limit_remaining',\n  help: 'Remaining rate limit',\n  registers: [registry],\n});\n\nexport const rateLimitPercent = new Gauge({\n  name: 'openevidence_rate_limit_usage_percent',\n  help: 'Rate limit usage percentage',\n  registers: [registry],\n});\n\n\u002F\u002F DeepConsult metrics\nexport const deepConsultActive = new Gauge({\n  name: 'openevidence_deepconsult_active',\n  help: 'Active DeepConsult requests',\n  registers: [registry],\n});\n\nexport const deepConsultDuration = new Histogram({\n  name: 'openevidence_deepconsult_duration_seconds',\n  help: 'DeepConsult completion time',\n  labelNames: ['specialty', 'status'],\n  buckets: [30, 60, 120, 180, 300, 600],\n  registers: [registry],\n});\n\n\u002F\u002F Confidence metrics\nexport const confidenceScore = new Summary({\n  name: 'openevidence_confidence_score',\n  help: 'Response confidence score distribution',\n  labelNames: ['specialty'],\n  percentiles: [0.5, 0.9, 0.95, 0.99],\n  registers: [registry],\n});\n\nexport { registry };\n```\n\n### Step 2: Instrumented Client Wrapper\n```typescript\n\u002F\u002F src\u002Fmonitoring\u002Finstrumented-client.ts\nimport { OpenEvidenceClient } from '@openevidence\u002Fsdk';\nimport {\n  requestCounter,\n  requestDuration,\n  errorCounter,\n  cacheHits,\n  cacheMisses,\n  rateLimitRemaining,\n  rateLimitPercent,\n  confidenceScore,\n} from '.\u002Fmetrics';\nimport { trace, SpanStatusCode, Span } from '@opentelemetry\u002Fapi';\n\nconst tracer = trace.getTracer('openevidence-client');\n\nexport class InstrumentedOpenEvidenceClient {\n  private client: OpenEvidenceClient;\n  private cache: ClinicalQueryCache;\n\n  constructor(config: any, cache: ClinicalQueryCache) {\n    this.client = new OpenEvidenceClient(config);\n    this.cache = cache;\n  }\n\n  async query(request: ClinicalQueryRequest): Promise\u003CClinicalQueryResponse> {\n    const { specialty } = request.context;\n\n    return tracer.startActiveSpan('openevidence.query', async (span: Span) => {\n      const timer = requestDuration.startTimer({ method: 'query', specialty });\n\n      try {\n        \u002F\u002F Add span attributes\n        span.setAttribute('openevidence.specialty', specialty);\n        span.setAttribute('openevidence.urgency', request.context.urgency);\n\n        \u002F\u002F Check cache first\n        const cached = await this.cache.get(request.question, request.context);\n        if (cached) {\n          cacheHits.inc();\n          span.setAttribute('cache.hit', true);\n          timer({ cached: 'true' });\n          requestCounter.inc({ method: 'query', specialty, status: 'cache_hit' });\n          return cached;\n        }\n        cacheMisses.inc();\n        span.setAttribute('cache.hit', false);\n\n        \u002F\u002F Make API request\n        const response = await this.client.query(request);\n\n        \u002F\u002F Update rate limit metrics from headers\n        this.updateRateLimitMetrics(response.headers);\n\n        \u002F\u002F Record confidence score\n        confidenceScore.observe({ specialty }, response.confidence);\n\n        \u002F\u002F Cache response\n        await this.cache.set(request.question, request.context, response);\n\n        \u002F\u002F Record success\n        timer({ cached: 'false' });\n        requestCounter.inc({ method: 'query', specialty, status: 'success' });\n        span.setStatus({ code: SpanStatusCode.OK });\n\n        return response;\n      } catch (error: any) {\n        \u002F\u002F Record error\n        timer({ cached: 'false' });\n        requestCounter.inc({ method: 'query', specialty, status: 'error' });\n        errorCounter.inc({ error_type: error.code || 'unknown', specialty });\n\n        span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n        span.recordException(error);\n\n        throw error;\n      } finally {\n        span.end();\n      }\n    });\n  }\n\n  private updateRateLimitMetrics(headers: any): void {\n    const remaining = parseInt(headers['x-ratelimit-remaining'] || '0');\n    const limit = parseInt(headers['x-ratelimit-limit'] || '100');\n\n    rateLimitRemaining.set(remaining);\n    rateLimitPercent.set(((limit - remaining) \u002F limit) * 100);\n  }\n}\n```\n\n### Step 3: Distributed Tracing Setup\n```typescript\n\u002F\u002F src\u002Fmonitoring\u002Ftracing.ts\nimport { NodeSDK } from '@opentelemetry\u002Fsdk-node';\nimport { Resource } from '@opentelemetry\u002Fresources';\nimport { SemanticResourceAttributes } from '@opentelemetry\u002Fsemantic-conventions';\nimport { TraceExporter } from '@google-cloud\u002Fopentelemetry-cloud-trace-exporter';\nimport { HttpInstrumentation } from '@opentelemetry\u002Finstrumentation-http';\nimport { ExpressInstrumentation } from '@opentelemetry\u002Finstrumentation-express';\n\nexport function initTracing(): void {\n  const sdk = new NodeSDK({\n    resource: new Resource({\n      [SemanticResourceAttributes.SERVICE_NAME]: 'clinical-evidence-api',\n      [SemanticResourceAttributes.SERVICE_VERSION]: process.env.npm_package_version,\n      [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV,\n    }),\n    traceExporter: new TraceExporter(),\n    instrumentations: [\n      new HttpInstrumentation({\n        requestHook: (span, request) => {\n          \u002F\u002F Don't trace health checks\n          if (request.url?.includes('\u002Fhealth')) {\n            span.setAttribute('http.skip', true);\n          }\n        },\n      }),\n      new ExpressInstrumentation(),\n    ],\n  });\n\n  sdk.start();\n\n  process.on('SIGTERM', () => {\n    sdk.shutdown().catch(console.error);\n  });\n}\n```\n\n### Step 4: Structured Logging\n```typescript\n\u002F\u002F src\u002Fmonitoring\u002Flogger.ts\nimport pino from 'pino';\n\nexport const logger = pino({\n  name: 'clinical-evidence-api',\n  level: process.env.LOG_LEVEL || 'info',\n  formatters: {\n    level: (label) => ({ level: label }),\n  },\n  \u002F\u002F Redact PHI fields\n  redact: {\n    paths: ['patient.*', 'patientId', 'mrn', '*.ssn'],\n    censor: '[REDACTED]',\n  },\n});\n\n\u002F\u002F OpenEvidence-specific logger\nexport const oeLogger = logger.child({ service: 'openevidence' });\n\nexport function logClinicalQuery(\n  queryId: string,\n  specialty: string,\n  duration: number,\n  cached: boolean,\n  confidence?: number\n): void {\n  oeLogger.info({\n    event: 'clinical_query',\n    queryId,\n    specialty,\n    durationMs: duration,\n    cached,\n    confidence,\n  });\n}\n\nexport function logDeepConsult(\n  consultId: string,\n  specialty: string,\n  status: string,\n  duration?: number\n): void {\n  oeLogger.info({\n    event: 'deep_consult',\n    consultId,\n    specialty,\n    status,\n    durationMs: duration,\n  });\n}\n\nexport function logError(\n  error: Error,\n  context: Record\u003Cstring, any>\n): void {\n  oeLogger.error({\n    event: 'error',\n    errorType: error.name,\n    errorMessage: error.message,\n    ...context,\n  });\n}\n```\n\n### Step 5: Alert Rules\n```yaml\n# prometheus\u002Fopenevidence_alerts.yaml\ngroups:\n  - name: openevidence_alerts\n    rules:\n      # High error rate\n      - alert: OpenEvidenceHighErrorRate\n        expr: |\n          rate(openevidence_errors_total[5m]) \u002F\n          rate(openevidence_requests_total[5m]) > 0.05\n        for: 5m\n        labels:\n          severity: warning\n          service: openevidence\n        annotations:\n          summary: \"OpenEvidence error rate > 5%\"\n          description: \"Error rate is {{ $value | humanizePercentage }}\"\n\n      # Critical error rate\n      - alert: OpenEvidenceCriticalErrorRate\n        expr: |\n          rate(openevidence_errors_total[5m]) \u002F\n          rate(openevidence_requests_total[5m]) > 0.20\n        for: 2m\n        labels:\n          severity: critical\n          service: openevidence\n        annotations:\n          summary: \"OpenEvidence error rate > 20%\"\n          description: \"Critical error rate - possible outage\"\n\n      # High latency\n      - alert: OpenEvidenceHighLatency\n        expr: |\n          histogram_quantile(0.95,\n            rate(openevidence_request_duration_seconds_bucket[5m])\n          ) > 15\n        for: 5m\n        labels:\n          severity: warning\n          service: openevidence\n        annotations:\n          summary: \"OpenEvidence P95 latency > 15s\"\n          description: \"95th percentile latency is {{ $value | humanizeDuration }}\"\n\n      # Low cache hit rate\n      - alert: OpenEvidenceLowCacheHitRate\n        expr: |\n          rate(openevidence_cache_hits_total[1h]) \u002F\n          (rate(openevidence_cache_hits_total[1h]) + rate(openevidence_cache_misses_total[1h])) \u003C 0.5\n        for: 30m\n        labels:\n          severity: warning\n          service: openevidence\n        annotations:\n          summary: \"OpenEvidence cache hit rate \u003C 50%\"\n          description: \"Consider reviewing cache configuration\"\n\n      # Rate limit warning\n      - alert: OpenEvidenceRateLimitWarning\n        expr: openevidence_rate_limit_remaining \u003C 10\n        for: 1m\n        labels:\n          severity: warning\n          service: openevidence\n        annotations:\n          summary: \"OpenEvidence rate limit \u003C 10 remaining\"\n          description: \"Consider throttling requests\"\n\n      # Service down\n      - alert: OpenEvidenceDown\n        expr: up{job=\"openevidence\"} == 0\n        for: 1m\n        labels:\n          severity: critical\n          service: openevidence\n        annotations:\n          summary: \"OpenEvidence integration is down\"\n          description: \"No successful health checks for 1 minute\"\n```\n\n### Step 6: Grafana Dashboard\n```json\n{\n  \"dashboard\": {\n    \"title\": \"OpenEvidence Clinical AI\",\n    \"panels\": [\n      {\n        \"title\": \"Request Rate\",\n        \"type\": \"stat\",\n        \"targets\": [{\n          \"expr\": \"sum(rate(openevidence_requests_total[5m]))\",\n          \"legendFormat\": \"req\u002Fs\"\n        }]\n      },\n      {\n        \"title\": \"Error Rate\",\n        \"type\": \"gauge\",\n        \"targets\": [{\n          \"expr\": \"sum(rate(openevidence_errors_total[5m])) \u002F sum(rate(openevidence_requests_total[5m])) * 100\"\n        }],\n        \"fieldConfig\": {\n          \"defaults\": {\n            \"max\": 100,\n            \"thresholds\": {\n              \"mode\": \"absolute\",\n              \"steps\": [\n                {\"color\": \"green\", \"value\": 0},\n                {\"color\": \"yellow\", \"value\": 5},\n                {\"color\": \"red\", \"value\": 20}\n              ]\n            }\n          }\n        }\n      },\n      {\n        \"title\": \"Latency Distribution\",\n        \"type\": \"heatmap\",\n        \"targets\": [{\n          \"expr\": \"sum(rate(openevidence_request_duration_seconds_bucket[5m])) by (le)\"\n        }]\n      },\n      {\n        \"title\": \"Cache Hit Rate\",\n        \"type\": \"timeseries\",\n        \"targets\": [{\n          \"expr\": \"sum(rate(openevidence_cache_hits_total[5m])) \u002F (sum(rate(openevidence_cache_hits_total[5m])) + sum(rate(openevidence_cache_misses_total[5m])))\",\n          \"legendFormat\": \"Hit Rate\"\n        }]\n      },\n      {\n        \"title\": \"Rate Limit Usage\",\n        \"type\": \"gauge\",\n        \"targets\": [{\n          \"expr\": \"openevidence_rate_limit_usage_percent\"\n        }],\n        \"fieldConfig\": {\n          \"defaults\": {\n            \"max\": 100,\n            \"thresholds\": {\n              \"mode\": \"absolute\",\n              \"steps\": [\n                {\"color\": \"green\", \"value\": 0},\n                {\"color\": \"yellow\", \"value\": 70},\n                {\"color\": \"red\", \"value\": 90}\n              ]\n            }\n          }\n        }\n      },\n      {\n        \"title\": \"Confidence Score Distribution\",\n        \"type\": \"histogram\",\n        \"targets\": [{\n          \"expr\": \"openevidence_confidence_score\"\n        }]\n      }\n    ]\n  }\n}\n```\n\n## Metrics Endpoint\n```typescript\n\u002F\u002F src\u002Froutes\u002Fmetrics.ts\nimport { Router } from 'express';\nimport { registry } from '..\u002Fmonitoring\u002Fmetrics';\n\nconst router = Router();\n\nrouter.get('\u002Fmetrics', async (req, res) => {\n  res.set('Content-Type', registry.contentType);\n  res.send(await registry.metrics());\n});\n\nexport default router;\n```\n\n## Output\n- Prometheus metrics collection\n- Distributed tracing with OpenTelemetry\n- Structured logging with PHI redaction\n- Alert rules for critical conditions\n- Grafana dashboard\n\n## Observability Checklist\n- [ ] Metrics endpoint exposed\n- [ ] Request counters and histograms\n- [ ] Error counters with labels\n- [ ] Cache hit\u002Fmiss tracking\n- [ ] Rate limit monitoring\n- [ ] Distributed tracing enabled\n- [ ] Structured logging configured\n- [ ] Alert rules deployed\n- [ ] Dashboard created\n\n## Resources\n- [Prometheus Best Practices](https:\u002F\u002Fprometheus.io\u002Fdocs\u002Fpractices\u002Fnaming\u002F)\n- [OpenTelemetry Documentation](https:\u002F\u002Fopentelemetry.io\u002Fdocs\u002F)\n- [Grafana Dashboards](https:\u002F\u002Fgrafana.com\u002Fdocs\u002Fgrafana\u002Flatest\u002Fdashboards\u002F)\n\n## Next Steps\nFor incident response, see `openevidence-incident-runbook`.\n",{"name":5,"author":47,"license":15,"version":48,"description":49,"allowed-tools":50},"Jeremy Longshore \u003Cjeremy@intentsolutions.io>","1.0.0","Set up comprehensive observability for OpenEvidence integrations with metrics, traces, and alerts.\nUse when implementing monitoring for clinical AI operations, setting up dashboards,\nor configuring alerting for healthcare application health.\nTrigger with phrases like \"openevidence monitoring\", \"openevidence metrics\",\n\"openevidence observability\", \"monitor openevidence\", \"openevidence alerts\".\n","Read, Write, Edit","main","90b50ed0778745a80fd5bfb13b1843d45b9e82f7","tests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fopenevidence-pack\u002Fskills\u002Fopenevidence-observability",233,"https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust","https:\u002F\u002Fgithub.com\u002FDicklesworthstone","https:\u002F\u002Fwww.jeffreyemanuel.com\u002F","Building in NY","2026-11-15 01:54:15",{"source":8,"skillName":5,"commands":61,"prompt":71,"zipAvailable":72},[62,65,68],{"tool":63,"command":64},"npx","npx skills add Dicklesworthstone\u002Fpi_agent_rust --skill openevidence-observability",{"tool":66,"command":67},"bunx","bunx skills add Dicklesworthstone\u002Fpi_agent_rust --skill openevidence-observability",{"tool":69,"command":70},"pnpm","pnpm dlx skills add Dicklesworthstone\u002Fpi_agent_rust --skill openevidence-observability","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fopenevidence-pack\u002Fskills\u002Fopenevidence-observability\u002FSKILL.md",true,[],[75,114,139,164,190,212],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":79,"licenseFileUrl":80,"sourceHtmlUrl":81,"categories":82,"keywords":88,"publishedAt":42},"01M6FEGPPK0ZTKCCM0R3E3KS33","web-artifacts-builder","Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn\u002Fui). Use for complex artifacts requiring state management, routing, or shadcn\u002Fui components - not for simple single-file HTML\u002FJSX artifacts.","Apache-2.0","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Futilities\u002Fweb-artifacts-builder\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Futilities\u002Fweb-artifacts-builder\u002FSKILL.md",[83],{"categoryNo":84,"categoryName":85,"taxonomyType":86,"taxonomyTypeDesc":87},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,30,107,108,109,110,111,23,112,113],"web artifacts builder","web","artifacts","artifacts builder","builder","frontend","css","components","react","component","routing","state management","state","shadcn","file","ui","Tools","Tailwind","html","single-file","simple","ui components","multi","jsx","suite",{"skillNo":115,"name":116,"nameZh":6,"description":117,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":79,"licenseFileUrl":118,"sourceHtmlUrl":119,"categories":120,"keywords":125,"publishedAt":42},"01M6FEE9VTK1W4GY21AKREJXRG","webapp-testing","Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fsecurity\u002Fwebapp-testing\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fsecurity\u002Fwebapp-testing\u002FSKILL.md",[121,124],{"categoryNo":122,"categoryName":123,"taxonomyType":86,"taxonomyTypeDesc":87},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":84,"categoryName":85,"taxonomyType":86,"taxonomyTypeDesc":87},[126,127,128,94,129,130,90,131,132,133,104,134,135,136,137,138,23],"testing","webapp testing","webapp","screenshots","playwright","debugging","toolkit","browser","logs","applications","behavior","local","with",{"skillNo":140,"name":141,"nameZh":6,"description":142,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":143,"sourceHtmlUrl":144,"categories":145,"keywords":146,"publishedAt":42},"01M6FE20F7ZTQBFWKF4MPJ2SBX","neuropixels-analysis","Neuropixels neural recording analysis. Load SpikeGLX\u002FOpenEphys data, preprocess, motion correction, Kilosort4 spike sorting, quality metrics, Allen\u002FIBL curation, AI-assisted visual analysis, for Neuropixels 1.0\u002F2.0 extracellular electrophysiology. Use when working with neural recordings, spike sorting, extracellular electrophysiology, or when the user mentions Neuropixels, SpikeGLX, Open Ephys, Kilosort, quality metrics, or unit curation.","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Fneuropixels-analysis\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Fneuropixels-analysis\u002FSKILL.md",[],[147,148,149,41,150,151,152,153,30,154,155,156,157,158,159,160,138,161,162,163,23,22],"analysis","neuropixels analysis","spike","data","open","quality","user","recordings","Neural","motion","visual","quality metrics","unit","sorting","curation","recording","load",{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":79,"licenseFileUrl":168,"sourceHtmlUrl":169,"categories":170,"keywords":174,"publishedAt":42},"01M6FDP0PDK6F1GGX395C7625Z","skill-creator","Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fskill-creator\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fskill-creator\u002FSKILL.md",[171],{"categoryNo":172,"categoryName":173,"taxonomyType":86,"taxonomyTypeDesc":87},"01JBSEEDCAT000000000000023","Skill与智能体开发",[175,176,177,178,179,180,181,182,34,183,184,185,186,187,138,23,188,22,189],"skill creator","creator","workflows","create","update","capabilities","knowledge","tool","specialized","guide","new skill","existing skill","users","Existing","new",{"skillNo":191,"name":192,"nameZh":6,"description":193,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":194,"sourceHtmlUrl":195,"categories":196,"keywords":198,"publishedAt":42},"01M6FDM8Y7VK7NYG9SM7QPA3PW","notebooklm","Use this skill to query your Google NotebookLM notebooks directly from Claude Code for source-grounded, citation-backed answers from Gemini. Browser automation, library management, persistent auth. Drastically reduced hallucinations through document-only responses.","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fnotebooklm\u002FLICENSE","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fnotebooklm\u002FSKILL.md",[197],{"categoryNo":172,"categoryName":173,"taxonomyType":86,"taxonomyTypeDesc":87},[192,199,200,201,202,203,204,133,205,206,30,207,208,209,210,23,211],"google","browser automation","gemini","automation","auth","code","library","management","only","document","query","Citation","source",{"skillNo":213,"name":214,"nameZh":6,"description":215,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":79,"licenseFileUrl":216,"sourceHtmlUrl":217,"categories":218,"keywords":225,"publishedAt":42},"01M6FDHPXE10J3XGTCH5HBHS1M","slack-gif-creator","Knowledge and utilities for creating animated GIFs optimized for Slack. Provides constraints, validation tools, and animation concepts. Use when users request animated GIFs for Slack like \"make me a GIF of X doing Y for Slack.\"","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fenterprise-communication\u002Fslack-gif-creator\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fenterprise-communication\u002Fslack-gif-creator\u002FSKILL.md",[219,222],{"categoryNo":220,"categoryName":221,"taxonomyType":86,"taxonomyTypeDesc":87},"01JBSEEDCAT000000000000005","邮件与沟通",{"categoryNo":223,"categoryName":224,"taxonomyType":86,"taxonomyTypeDesc":87},"01JBSEEDCAT000000000000016","图像与多媒体",[226,227,228,176,229,105,230,231,181,30,232,187,233,234,235,23,236,22],"slack gif creator","slack","gif","validation","constraints","Animation","me","make","Utilities","concepts","request"]