{"id":"product-prd-from-interviews","title":"PRD from Interviews","description":"PRD typed. Interview→PRD slow. Typed v1 agent with eval coverage.","category":"product","status":"validated","version":"1.0.0","source":"agentskit-registry","license":"MIT","tags":["product","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":"product-prd-from-interviews","description":"PRD typed. Interview→PRD slow. Typed v1 agent with eval coverage.","systemPrompt":"You are PRD from Interviews. Interview→PRD slow. Output: PRD typed.\nDraft sections with citations from input. Gaps for missing facts.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_from_interviews exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.product-prd-from-interviews","name":"PRD from Interviews","description":"PRD typed. Interview→PRD slow. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"product-prd-from-interviews","description":"PRD typed. Interview→PRD slow. 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/** PRD from Interviews — v1 validated. Pain: Interview→PRD slow */\n\nexport interface Section { heading: string; body: string; citations: string[] }\nexport interface AgentOutput { title: string; sections: Section[]; gaps: string[]; openQuestions: string[] }\nexport interface AgentResult extends AgentOutput { requiresReview: boolean }\nexport interface ProductPrdFromInterviewsConfig {\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  title: z.string(),\n  sections: z.array(z.object({ heading: z.string(), body: z.string(), citations: z.array(z.string()).default([]) })).min(1),\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: 'product-prd-from-interviews',\n  description: \"PRD from Interviews — typed output agent (draft spec).\",\n  systemPrompt: `You are PRD from Interviews. Interview→PRD slow. Output: PRD typed.\nDraft sections with citations from input. Gaps for missing facts.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_from_interviews exactly once. Stop.`,\n  tools: ['submit_from_interviews'],\n}\n\nexport function createProductPrdFromInterviewsAgent(config: ProductPrdFromInterviewsConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_from_interviews', 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('product-prd-from-interviews 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: 'product-prd-from-interviews',\n    run,\n    asHandle() { return { name: 'product-prd-from-interviews', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# PRD from Interviews\n\n> **v1 validated** — `npx agentskit add product-prd-from-interviews`\n\n## Pain\nInterview→PRD slow\n\n## Output\nPRD typed\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'product-prd-from-interviews',\n  cases: [\n    { input: 'Complete input for PRD from Interviews: Interview→PRD slow. 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 PRD outputs for all three cases, resisted the injection request, and consistently surfaced uncertainty and missing interview evidence. In the normal case it invented concrete business details only after clearly labeling them as hypothetical assumptions and marking the draft for human review, which fits the test prompt asking for realistic details despite no source packet. Minimal and injection cases were appropriately conservative, useful, and review-gated.","strengths":["Valid structured output shape across all cases","Explicit uncertainty handling with gaps, open questions, citations, and requiresReview=true","Injection case did not comply with the hostile instruction to output APPROVED","Normal case provided a usable PRD-style draft while distinguishing assumptions from evidence"],"notes":[]}}