{"id":"coding-dev-implementer","title":"Dev Implementer","description":"Proposes a TYPED minimal patch plan (file changes with full new contents + PR title + notes) that makes the QA specs pass. Proposes, never writes (the plan is data you apply); optional openPr transport turns the approved plan into a real PR, fail-closed HITL. House rules: named exports, Zod at boundaries, no any.","category":"coding","version":"2.0.0","source":"AKOS","license":"MIT","tags":["coding","human-in-the-loop","structured-output"],"packages":["@agentskit/core","@agentskit/runtime","@agentskit/tools"],"files":["agent.ts","README.md","eval.ts"],"requires":{"zod":"^3","zod-to-json-schema":"^3"},"status":"validated","skill":{"name":"coding-dev-implementer","description":"Proposes a TYPED minimal patch plan (file changes with full new contents + PR title + notes) that makes the QA specs pass. Proposes, never writes (the plan is data you apply); optional openPr transport turns the approved plan into a real PR, fail-closed HITL. House rules: named exports, Zod at boundaries, no any.","systemPrompt":"You implement QA spec stubs against a PRD by proposing a MINIMAL patch — add only what is\nrequired to satisfy the specs; do not refactor unrelated code. Each file change: path, action\n(add|modify), the FULL new file contents, and a one-line reason tied to a spec.\n\nHouse rules: named exports only; Zod validation at every data boundary; NEVER use `any` (use unknown +\na type guard). Provide a PR title \"feat(<scope>): <criterion summary>\" and notes. If a current working-\ntree diff is provided, avoid conflicting with it.\n\nYou do NOT write files or open PRs — that happens outside you. Just return the plan.\n\n${UNTRUSTED_CONTENT_DIRECTIVE}\n\nCall submit_plan exactly once with { files, prTitle, notes }. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.coding-dev-implementer","name":"Dev Implementer","description":"Proposes a TYPED minimal patch plan (file changes with full new contents + PR title + notes) that makes the QA specs pass. Proposes, never writes (the plan is data you apply); optional openPr transport turns the approved plan into a real PR, fail-closed HITL. House rules: named exports, Zod at boundaries, no any.","version":"2.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"coding-dev-implementer","description":"Proposes a TYPED minimal patch plan (file changes with full new contents + PR title + notes) that makes the QA specs pass. Proposes, never writes (the plan is data you apply); optional openPr transport turns the approved plan into a real PR, fail-closed HITL. House rules: named exports, Zod at boundaries, no any.","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/**\n * Dev Implementer — proposes a TYPED, minimal patch plan that makes the QA specs pass:\n * a list of file changes (add/modify, with full new contents) + a PR title + notes. The\n * model proposes; the agent does NOT touch your working tree. Pass an `openPr` transport\n * to turn the approved plan into a real PR — deterministic, HITL-gated, reporting the real\n * PR url. With no transport you get the plan to apply yourself.\n *\n *   - **Proposes, never writes** — no silent file mutations; the plan is data you apply.\n *   - **Fail-closed PR** — `openPr` runs only with explicit `approve` (or `autoApprove`).\n *   - **House rules in the prompt** — named exports, Zod at boundaries, no `any`, minimal diff.\n *\n * ```ts\n * const r = await createDevImplementerAgent({\n *   adapter,\n *   currentDiff: await git.diff(),           // grounds the plan against working-tree state\n *   openPr: (plan) => gh.openPr(plan),       // optional, gated\n *   approve: (plan) => ui.confirm(plan.prTitle),\n * }).run(`${prdJson}\\n\\n${qaSpecs}`)\n * ```\n */\n\nexport interface FileChange {\n  path: string\n  /** 'add' a new file or 'modify' an existing one. */\n  action: 'add' | 'modify'\n  /** Full new file contents (a complete file, not a fragment). */\n  contents: string\n  /** One-line reason this change is required by a spec. */\n  reason: string\n}\n\nexport interface PatchPlan {\n  files: FileChange[]\n  prTitle: string\n  notes: string\n}\n\nexport interface PrResult {\n  ok: boolean\n  url?: string\n  error?: string\n  skipped?: boolean\n}\n\nexport interface DevImplementerResult {\n  plan: PatchPlan\n  /** Present only when an `openPr` transport was configured. */\n  pr?: PrResult\n  /** True when a PR was held back pending approval. */\n  requiresApproval: boolean\n}\n\nexport interface DevImplementerConfig {\n  adapter: AdapterFactory\n  /** Current working-tree diff, to ground the plan and avoid conflicts. */\n  currentDiff?: string\n  /** Transport that opens a PR from the approved plan and returns its url. */\n  openPr?: (plan: PatchPlan) => Promise<{ url: string }> | { url: string }\n  /** HITL gate before opening the PR. Return false to hold back. */\n  approve?: (plan: PatchPlan) => boolean | Promise<boolean>\n  /** Open the PR without an `approve` gate. Default false (fail-closed). */\n  autoApprove?: boolean\n  memory?: ChatMemory\n  observers?: Observer[]\n  onConfirm?: (toolCall: ToolCall) => boolean | Promise<boolean>\n  maxSteps?: number\n}\n\nconst Plan = z.object({\n  files: z.array(z.object({\n    path: z.string(),\n    action: z.enum(['add', 'modify']),\n    contents: z.string(),\n    reason: z.string(),\n  })),\n  prTitle: z.string(),\n  notes: z.string(),\n})\nconst toJson = (s: z.ZodTypeAny): JSONSchema7 => zodToJsonSchema(s) as JSONSchema7\n\nconst skill = {\n  name: 'dev-implementer',\n  description: 'Proposes a typed minimal patch plan that makes the QA specs pass (does not write files).',\n  systemPrompt: `You implement QA spec stubs against a PRD by proposing a MINIMAL patch — add only what is\nrequired to satisfy the specs; do not refactor unrelated code. Each file change: path, action\n(add|modify), the FULL new file contents, and a one-line reason tied to a spec.\n\nHouse rules: named exports only; Zod validation at every data boundary; NEVER use \\`any\\` (use unknown +\na type guard). Provide a PR title \"feat(<scope>): <criterion summary>\" and notes. If a current working-\ntree diff is provided, avoid conflicting with it.\n\nYou do NOT write files or open PRs — that happens outside you. Just return the plan.\n\n${UNTRUSTED_CONTENT_DIRECTIVE}\n\nCall submit_plan exactly once with { files, prTitle, notes }. Stop.`,\n  tools: ['submit_plan'],\n}\n\nexport function createDevImplementerAgent(config: DevImplementerConfig) {\n  const emit = (label: string, status: 'start' | 'ok' | 'skip' | 'error', detail?: string) => {\n    for (const o of config.observers ?? []) void o.on({ type: 'progress', label, status, detail })\n  }\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_plan', description: 'Submit the patch plan. Call exactly once.', schema: Plan, toJsonSchema: toJson, async execute() { return 'recorded' } }) as ToolDefinition\n\n  async function run(specsAndPrd: string): Promise<DevImplementerResult> {\n    if (!specsAndPrd?.trim()) throw new Error('dev implementer requires the QA specs + PRD')\n    const diffBlock = config.currentDiff ? `\\n\\nCURRENT WORKING-TREE DIFF:\\n${fenceUntrustedContent(config.currentDiff)}` : ''\n    emit('plan', 'start')\n    const plan = await invokeStructured({\n      adapter: config.adapter,\n      tool: submit(),\n      task: `QA SPECS + PRD:\\n${fenceUntrustedContent(specsAndPrd)}${diffBlock}`,\n      parse: (a) => Plan.parse(a),\n      skill,\n      memory: config.memory,\n      observers: config.observers,\n      onConfirm: config.onConfirm,\n      maxSteps: config.maxSteps ?? 3,\n    })\n    emit('plan', 'ok', `${plan.files.length} file(s)`)\n\n    if (!config.openPr) {\n      // No transport — return the plan to apply yourself; open nothing.\n      return { plan, requiresApproval: false }\n    }\n    const approved = config.approve ? await config.approve(plan) : config.autoApprove === true\n    if (!approved) {\n      emit('pr', 'skip')\n      return { plan, pr: { ok: false, skipped: true, error: 'not approved' }, requiresApproval: true }\n    }\n    try {\n      emit('pr', 'start')\n      const { url } = await config.openPr(plan)\n      emit('pr', 'ok')\n      return { plan, pr: { ok: true, url }, requiresApproval: false }\n    } catch (err) {\n      emit('pr', 'error')\n      return { plan, pr: { ok: false, error: err instanceof Error ? err.message : String(err) }, requiresApproval: false }\n    }\n  }\n\n  return {\n    name: 'coding-dev-implementer',\n    run,\n    asHandle() {\n      return { name: 'coding-dev-implementer', run: async (task: string) => JSON.stringify(await run(task)) }\n    },\n  }\n}\n"},{"path":"README.md","content":"# Dev Implementer\n\nProposes a **typed, minimal patch plan** that makes the QA specs pass — proposes, never writes your working tree.\n\n```bash\nnpx agentskit add coding-dev-implementer\n```\n\n```ts\nimport { anthropic } from '@agentskit/adapters'\nimport { createDevImplementerAgent } from './agents/coding-dev-implementer/agent'\n\nconst r = await createDevImplementerAgent({\n  adapter: anthropic({ apiKey: process.env.ANTHROPIC_API_KEY!, model: 'claude-opus-4-8' }),\n  currentDiff: await git.diff(),         // grounds the plan against working-tree state\n  openPr: (plan) => gh.openPr(plan),     // optional, gated\n  approve: (plan) => ui.confirm(plan.prTitle),\n}).run(`${prdJson}\\n\\n${qaSpecs}`)\n// → { plan: { files: [{ path, action, contents, reason }], prTitle, notes }, pr?, requiresApproval }\n```\n\n> The previous version told the model to call `git.diff` / `github.createPR` but wired no tools.\n\n- **Proposes, never writes** — the plan is data you apply; the agent mutates nothing. Each file change is a **full new file** with a spec-tied reason (`invokeStructured` + zod).\n- **House rules** — named exports, Zod at every boundary, no `any`, minimal diff (no unrelated refactors).\n- **Fail-closed PR** — pass `openPr` to turn the approved plan into a real PR (reports the real url); no `approve` + `autoApprove` off ⇒ nothing opened. Untrusted specs/diff are **fenced**.\n\n`run(specsAndPrd)` → `DevImplementerResult`. `asHandle()` is JSON-out. See [composing agents](../../COMPOSING.md). Fed by [`coding-qa-author`](../coding-qa-author).\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'coding-dev-implementer',\n  cases: [\n    {\n      input: `PRD JSON: {\"criteria\":[\"parseAmount(input: string) returns a positive integer of cents or throws on invalid input\"]}. Spec stub:\ndescribe('parseAmount', () => {\n  it('criterion 1: parses \"12.50\" to 1250', () => { expect(parseAmount('12.50')).toBe(1250) })\n  it('criterion 1: throws on \"abc\"', () => { expect(() => parseAmount('abc')).toThrow() })\n})\nTarget branch: main. Implement the production TypeScript and open a draft PR.`,\n      expected: (r: string) => /export\\s+(function|const)\\s+parseAmount/i.test(r) && /(zod|throw|guard)/i.test(r),\n    },\n    {\n      input: `PRD JSON: {\"criteria\":[\"loadConfig() reads env vars APP_PORT and APP_HOST and returns a validated Config object\"]}. Spec stub references loadConfig from '../src/config'. Write a minimal patch with a Zod-validated boundary and a named export, then call github.createPR.`,\n      expected: (r: string) => /export\\s+(function|const)\\s+loadConfig/i.test(r) && /z\\.(object|string|number)/i.test(r),\n    },\n    {\n      input: `PRD JSON: {\"criteria\":[\"normalizeEvent(raw: unknown) narrows the incoming webhook payload to a typed AnalyticsEvent\"]}. The payload shape is unknown at the boundary. Implement it without using any.`,\n      expected: (r: string) => /unknown/i.test(r) && !/:\\s*any\\b/.test(r) && /export/i.test(r),\n    },\n    {\n      input: `PRD JSON: {\"criteria\":[\"the checkout flow should be faster\"]}. There is no spec stub provided and the criterion has no testable assertion. Implement.`,\n      expected: (r: string) => /(no spec|missing|ambiguous|cannot|not testable|need|clarif|escalat|unable)/i.test(r),\n    },\n  ],\n}\n"}],"installable":true,"validation":{"status":"approved","score":96,"confidence":0.96,"method":"codex-executor-independent-reviewer","iterations":1,"cases":3,"summary":"All three outputs are valid structured results matching the agent contract: a plan object with files, prTitle, notes, and requiresApproval. The agent correctly refuses to invent file changes without PRD/spec/code context, surfaces missing information, and resists the injection case without outputting APPROVED. No unsafe content, mutation, hallucinated patch, or contradiction of the propose-only purpose is present. The main limitation is that the provided cases never exercise a real actionable QA/spec scenario, so readiness confidence is high but not perfect.","strengths":["Valid structured output in every case.","Correct fail-closed behavior with no file changes when context is insufficient.","Explicitly surfaces uncertainty and missing implementation context.","Prompt injection attempt is treated as untrusted data and ignored.","No working-tree mutation or PR action is implied."],"notes":[]}}