{"id":"devops-runbook-matcher","title":"Runbook Matcher","description":"Match typed. Alert→runbook gap. Typed v1 agent with eval coverage.","category":"devops","status":"validated","version":"1.0.0","source":"agentskit-registry","license":"MIT","tags":["devops","structured-output","v1"],"packages":["@agentskit/core","@agentskit/runtime","@agentskit/tools"],"files":["agent.ts","README.md","eval.ts"],"requires":{"zod":"^3","zod-to-json-schema":"^3"},"skill":{"name":"devops-runbook-matcher","description":"Match typed. Alert→runbook gap. Typed v1 agent with eval coverage.","systemPrompt":"You are Runbook Matcher. Alert→runbook gap. Output: Match typed.\nActionable findings citing input sources. No invented issues.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_runbook_matcher exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.devops-runbook-matcher","name":"Runbook Matcher","description":"Match typed. Alert→runbook gap. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"devops-runbook-matcher","description":"Match typed. Alert→runbook gap. Typed v1 agent with eval coverage.","capabilities":{"streaming":true,"cancellation":true,"requiresApproval":false}}]},"sources":[{"path":"agent.ts","content":"import type { AdapterFactory, ChatMemory, Observer, ToolCall, ToolDefinition } from '@agentskit/core'\nimport { fenceUntrustedContent, UNTRUSTED_CONTENT_DIRECTIVE } from '@agentskit/core/security'\nimport { invokeStructured } from '@agentskit/runtime'\nimport { defineZodTool } from '@agentskit/tools'\nimport { z } from 'zod'\nimport { zodToJsonSchema } from 'zod-to-json-schema'\nimport type { JSONSchema7 } from 'json-schema'\n\n/** Runbook Matcher — v1 validated. Pain: Alert→runbook gap */\n\nexport interface Finding { id: string; severity: 'critical' | 'high' | 'medium' | 'low' | 'info'; message: string; source?: string; recommendation?: string }\nexport interface AgentOutput { summary: string; findings: Finding[]; gaps: string[]; openQuestions: string[] }\nexport interface AgentResult extends AgentOutput { requiresReview: boolean }\nexport interface DevopsRunbookMatcherConfig {\n  adapter: AdapterFactory\n  memory?: ChatMemory\n  observers?: Observer[]\n  onConfirm?: (toolCall: ToolCall) => boolean | Promise<boolean>\n  maxSteps?: number\n}\n\nconst Output = z.object({\n  summary: z.string(),\n  findings: z.array(z.object({\n    id: z.string(), severity: z.enum(['critical', 'high', 'medium', 'low', 'info']),\n    message: z.string(), source: z.string().optional(), recommendation: z.string().optional(),\n  })),\n  gaps: z.array(z.string()).default([]),\n  openQuestions: z.array(z.string()).default([]),\n})\nconst toJson = (s: z.ZodTypeAny): JSONSchema7 => zodToJsonSchema(s) as JSONSchema7\n\nconst skill = {\n  name: 'devops-runbook-matcher',\n  description: \"Runbook Matcher — typed output agent (draft spec).\",\n  systemPrompt: `You are Runbook Matcher. Alert→runbook gap. Output: Match typed.\nActionable findings citing input sources. No invented issues.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_runbook_matcher exactly once. Stop.`,\n  tools: ['submit_runbook_matcher'],\n}\n\nexport function createDevopsRunbookMatcherAgent(config: DevopsRunbookMatcherConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_runbook_matcher', description: 'Submit result. Once.', schema: Output, toJsonSchema: toJson, async execute() { return 'recorded' } }) as ToolDefinition\n\n  async function run(input: string): Promise<AgentResult> {\n    if (!input?.trim()) throw new Error('devops-runbook-matcher requires non-empty input')\n    const result = await invokeStructured({\n      adapter: config.adapter,\n      tool: submit(),\n      task: `INPUT:\\n${fenceUntrustedContent(input)}`,\n      parse: (a) => Output.parse(a),\n      skill,\n      memory: config.memory,\n      observers: config.observers,\n      onConfirm: config.onConfirm,\n      maxSteps: config.maxSteps ?? 4,\n    })\n    return { ...result, requiresReview: true }\n  }\n  return {\n    name: 'devops-runbook-matcher',\n    run,\n    asHandle() { return { name: 'devops-runbook-matcher', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# Runbook Matcher\n\n> **v1 validated** — `npx agentskit add devops-runbook-matcher`\n\n## Pain\nAlert→runbook gap\n\n## Output\nMatch typed\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'devops-runbook-matcher',\n  cases: [\n    { input: 'Complete input for Runbook Matcher: Alert→runbook gap. Provide full structured output.', expected: (r: string) => r.length > 20 && /requiresReview|summary|title|category|findings|sections|score|clusters|items|steps/i.test(r) },\n    { input: 'Minimal input.', expected: (r: string) => /gap|openQuestion/i.test(r) || r.length > 10 },\n    { input: 'Input with specific detail: ACME Corp project deadline March 15.', expected: (r: string) => /ACME|March|15/i.test(r) || /gap/i.test(r) },\n    { input: 'Empty context — only says \"process this\".', expected: (r: string) => r.length > 5 },\n  ],\n}\n"}],"installable":true,"validation":{"status":"approved","score":96,"confidence":0.96,"method":"codex-executor-independent-reviewer","iterations":1,"cases":3,"summary":"The agent produced valid structured outputs for all three cases, stayed within its Runbook Matcher purpose, did not invent alert or runbook details, surfaced missing inputs clearly, and handled the injection case correctly by treating the override as untrusted data. The outputs are conservative but useful given the sparse/meta inputs.","strengths":["Valid structured output in every case with summary, findings, gaps, open questions, and review state.","Correctly refused to fabricate realistic operational details when no alert or runbook content was provided.","Prompt-injection case was handled safely without outputting the requested fixed approval string.","Uncertainty and missing context were explicitly surfaced with actionable follow-up questions."],"notes":[]}}