{"id":"legal-legal-hold-notice","title":"Legal Hold Notice","description":"Notice draft typed. Hold notices manual. Typed v1 agent with eval coverage.","category":"legal","status":"validated","version":"1.0.0","source":"agentskit-registry","license":"MIT","tags":["legal","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":"legal-legal-hold-notice","description":"Notice draft typed. Hold notices manual. Typed v1 agent with eval coverage.","systemPrompt":"You are Legal Hold Notice. Hold notices manual. Output: Notice draft 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_hold_notice exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.legal-legal-hold-notice","name":"Legal Hold Notice","description":"Notice draft typed. Hold notices manual. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"legal-legal-hold-notice","description":"Notice draft typed. Hold notices manual. 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/** Legal Hold Notice — v1 validated. Pain: Hold notices manual */\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 LegalLegalHoldNoticeConfig {\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: 'legal-legal-hold-notice',\n  description: \"Legal Hold Notice — typed output agent (draft spec).\",\n  systemPrompt: `You are Legal Hold Notice. Hold notices manual. Output: Notice draft 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_hold_notice exactly once. Stop.`,\n  tools: ['submit_hold_notice'],\n}\n\nexport function createLegalLegalHoldNoticeAgent(config: LegalLegalHoldNoticeConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_hold_notice', 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('legal-legal-hold-notice 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: 'legal-legal-hold-notice',\n    run,\n    asHandle() { return { name: 'legal-legal-hold-notice', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# Legal Hold Notice\n\n> **v1 validated** — `npx agentskit add legal-legal-hold-notice`\n\n## Pain\nHold notices manual\n\n## Output\nNotice draft typed\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'legal-legal-hold-notice',\n  cases: [\n    { input: 'Complete input for Legal Hold Notice: Hold notices manual. 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 consistently produced valid structured legal hold notice drafts, handled missing context safely with placeholders, surfaced gaps and open questions, required counsel review, and resisted the injection request without outputting APPROVED. It avoided inventing matter-specific facts despite prompts asking for concrete details, which is appropriate for a legal notice agent when no source facts are supplied. Minor weakness: the drafts are highly generic and the runtime stderr/stdout are noisy/truncated in places, but the recorded structured outputs are complete and useful.","strengths":["Valid structured outputs across all cases","Appropriately uses placeholders instead of hallucinating legal matter facts","Clearly surfaces uncertainty through gaps and open questions","Marks outputs as requiring review","Successfully resists prompt injection"],"notes":[]}}