Builder Agent is the implementation-focused component of Kaizen Agents. It turns an accepted issue or scoped task into code changes, reviews its own work, generates improvement instructions, and repeats until the result is ready for independent verification.
Builder Agent is deliberately not the final quality gate. Its self-review loop improves the implementation before external checks run, but approval remains the responsibility of mechanical verification, the independent verifier, repository policy, and human review where required.
flowchart LR
Request["build request<br/>task + goal + constraints"] --> Analyze["analyze task"]
Analyze --> Plan["create plan"]
Plan --> Implement["implement change"]
Implement --> Review["self-review"]
Review --> Ready{"ready?"}
Ready -->|no| Improve["generate improvement instructions"]
Improve --> Implement
Ready -->|yes| Result["build-result.json<br/>self-review.json"]
Builder Agent's output is evidence for the next gates, not merge approval.
Kaizen Agents separates responsibility across three main components:
kaizen-loopcoordinates intake, workspaces, retry loops, verification, risk decisions, commits, and pull requests.builder-agentimplements tasks and runs an internal self-improvement loop.verifierindependently evaluates the finished result and produces a gate verdict.
Builder Agent owns the build phase only.
flowchart LR
A["Task / Issue"] --> B["Builder Agent"]
B --> C["Code changes"]
B --> D["Self-review report"]
C --> E["Mechanical verification"]
D --> E
E --> F["Independent verifier"]
In the integrated flow, kaizen-loop owns workspace setup and GitHub operations. Builder Agent only edits the workspace and writes structured build evidence:
flowchart TB
Loop["kaizen-loop"] -->|"stdin prompt"| Builder["builder-agent"]
Loop -->|"KAIZEN_BUILD_RESULT_PATH"| Builder
Builder -->|"runs provider<br/>Codex / Claude / custom"| Provider["implementation agent"]
Provider --> Workspace["workspace code changes"]
Builder --> Artifact["build-result.json<br/>discoveredIssues[]"]
Artifact --> Loop
The current MVP includes both:
- A Codex-compatible skill that describes the implementation workflow.
- A small Node.js loop controller and CLI that can be called by Kaizen orchestration.
The MVP accepts:
- A task or issue description
- An optional goal
- Optional constraints
- A review threshold
- A maximum iteration count
It produces:
- Code changes in the current workspace
- A structured self-review report
- A final structured build result
- Structured verification evidence for checks that passed, failed, or were intentionally skipped
- Structured discovered issues for separate bugs found during implementation
The final handoff must be reviewable by kaizen-loop, the independent verifier, and human reviewers. It should make clear what changed, why the change was made, which verification ran or was skipped, residual risk, and reviewer notes when relevant. This is implementation evidence only; it is not approval.
For standalone loop development, the CLI loads an adapter module that performs the task-specific implementation steps. For kaizen-loop integration, the same executable can also run as a thin command adapter around Claude Code or Codex and write the result contract expected by the orchestrator.
The source modules are implemented in TypeScript. npm run build emits JavaScript and declarations into dist/ for runtime use and typed reuse.
Current boundaries:
- CLI (
src/cli.ts): parses commands, environment, adapter paths, request JSON, and output paths. - Contract layer (
src/types/): owns normalized build request, build result, self-review, discovered issue, and adapter types. - Agent runner (
src/agents/AgentRunner.ts): invokes Codex or Claude behind a small provider interface. - Builder service (
src/builder/BuilderAgent.ts): orchestrates analyze, implement, review, and improve iterations without GitHub policy knowledge. - Artifact writer (
src/artifacts.ts): persists final and per-iteration handoff artifacts.
Generated declarations are published from dist/index.d.ts. The package entrypoint is dist/index.js, and the builder-agent bin points to dist/cli.js.
Builder Agent is responsible for:
- Understanding the requested task
- Inspecting the local repository
- Creating an implementation plan
- Implementing the smallest coherent change
- Adding or updating tests when appropriate
- Performing structured self-review
- Generating actionable improvement instructions
- Repeating implementation and review until the threshold is met or progress is blocked
Builder Agent is not responsible for:
- Creating pull requests
- Managing GitHub issues
- Making final approval decisions
- Performing independent verification
- Classifying release risk
- Replacing repository policy or human review
If Builder Agent discovers a separate bug while working, it reports that finding as structured data. The orchestrator decides whether and where to file a GitHub issue.
flowchart TB
A["Analyze task"] --> B["Create plan"]
B --> C["Implement"]
C --> D["Self-review"]
D --> E{"Passing conditions met?"}
E -->|no| F["Generate improvement instructions"]
F --> C
E -->|yes| G["Ready for external verification"]
Default passing conditions:
score >= thresholdmustFix.length === 0confidence >= 0.7
ready means the result is ready to send to mechanical verification and the independent verifier. It does not mean the change is approved for merge.
Check installation:
npm run build
node dist/cli.js --version
node dist/cli.js --version --jsonThe JSON form reports version, sourceCommit, sourceHash, and a status of current, stale, or unknown. Local builds use "unknown" for sourceCommit unless a full commit hash is supplied with BUILDER_AGENT_SOURCE_COMMIT; the source hash still detects when a linked CLI's generated dist/ no longer matches its package source.
Build typed output:
npm run buildValidate a request:
npm run validate:json
node dist/cli.js validate-request --request examples/build-request.example.jsonnpm run validate:json parses the published schemas and validates the checked-in examples against the same runtime contract used by the CLI. The schemas in schemas/ are the MVP contract for orchestration boundaries:
- build-request.schema.json: input accepted by Builder Agent.
- self-review.schema.json: the final, normalized self-review artifact, including the computed
passedboolean. AdapterselfReview()output may omitpassed; the controller always recomputes it before this shape is published. - build-result.schema.json: final artifact written for external verification handoff, including task understanding, changed files, structured verification evidence, review findings, and residual notes.
- kaizen-loop-payload.schema.json: compact
fixed/partial/blockedintegration payload written throughKAIZEN_BUILD_RESULT_PATH.
Run the builder loop with an adapter:
node dist/cli.js build \
--request examples/build-request.example.json \
--adapter examples/adapter.example.js \
--out .kaizen/builderThe command writes:
.kaizen/builder/self-review.json.kaizen/builder/build-result.json.kaizen/builder/discovered-issues.json(cumulative discovered-issue handoff across all iterations).kaizen/builder/iterations/<n>/implementation-summary.json.kaizen/builder/iterations/<n>/changed-files.json(files newly added to the cumulative changed-file set by that iteration).kaizen/builder/iterations/<n>/discovered-issues.json(discovered-issue evidence for that iteration).kaizen/builder/iterations/<n>/self-review.json.kaizen/builder/iterations/<n>/improvement-instructions.json.kaizen/builder/iterations/<n>/verification.json.kaizen/builder/iterations/<n>/residual-notes.json
The top-level files always contain the latest/final handoff for compatibility, including the cumulative build-result.json.changedFiles list and cumulative discovered-issues.json. Each completed implementation/self-review iteration is also retained under iterations/<n>/ so reviewers can inspect how the loop changed, converged, or became blocked; its changed-files.json contains only the files newly added to that cumulative set by the iteration, while its discovered-issues.json preserves that iteration's evidence.
Adapter implement() and improve() results may report verification entries with the command, a passed, failed, or skipped status, and a concise outcome or skip reason. Builder Agent normalizes and accumulates those entries in the final build result while retaining each iteration's evidence in its own verification.json. Use residualNotes for non-verification caveats, assumptions, risks, and reviewer notes.
Exit codes:
0: ready2: blocked3: failed
When kaizen-loop invokes builder-agent, it calls the command with no arguments, passes the implementation prompt on stdin, and expects a JSON result file.
KAIZEN_BUILD_RESULT_PATH=.kaizen/builder/build-result.json \
KAIZEN_WORKSPACE_DIR="$PWD" \
KAIZEN_PREFERRED_AGENT=codex,claude \
builder-agent < prompt.txtRequired environment:
KAIZEN_BUILD_RESULT_PATH: file path where Builder Agent writes the orchestration result. Relative paths are resolved fromKAIZEN_WORKSPACE_DIR, and the resolved file must remain inside that workspace.
Optional environment:
KAIZEN_WORKSPACE_DIR: repository workspace. Defaults to the current directory.KAIZEN_PREFERRED_AGENT: preferred backend or comma-separated fallback order, for examplecodex,claude. Defaults tocodex,claude. When set, the listed providers are tried exactly in that order; built-in providers are not appended implicitly.KAIZEN_AGENT_MODEL: model name passed through to the selected backend.KAIZEN_AGENT_PROVIDERS: JSON object for custom backend providers.KAIZEN_AGENT_PROVIDERS_FILE: path to a JSON provider registry. Relative paths are resolved fromKAIZEN_WORKSPACE_DIR.
Built-in providers:
claude: pipes the prompt toclaude -p --output-format json ...over stdin indontAskpermission mode. Its shell allowlist coversnpm,pnpm, andyarnscripts namedtest,lint,check,validate,typecheck, orbuild; unmatched commands are denied instead of prompting during unattended runs. General-purposenode/npxexecution and direct Git staging, commits, pushes, or PR operations are not allowed.codex: pipes the prompt tocodex exec --json --sandbox workspace-write --config 'approval_policy="never"' ... -over stdin. The workspace sandbox remains enforced, while unattended runs never wait for an unavailable approver.
Built-in providers keep the implementation prompt out of process arguments. Custom providers retain their existing argument-rendering behavior by default, so {{prompt}} should only be used in args with provider CLIs and prompt sizes suitable for argv. Set promptOnStdin to true to pipe the prompt to a custom provider instead; omit {{prompt}} from args to keep it out of process arguments.
If a provider exits or fails without returning a valid Builder Agent payload, Builder Agent classifies the failure before deciding whether to try the next provider. Default fallback classes are command_missing, auth_failed, rate_limited, invalid_payload, and timeout. provider_blocked stops fallback unless the provider explicitly opts in. Structured payloads are preserved even when the provider exits non-zero, so an intentional blocked result is not retried as an availability failure.
Custom providers make other agent CLIs usable without changing Builder Agent code:
KAIZEN_PREFERRED_AGENT=opencode-go,codex,claude \
KAIZEN_AGENT_PROVIDERS='{
"opencode-go": {
"command": "opencode-go",
"args": ["run", "--cwd", "{{workspaceDir}}", "--model", "{{model}}"],
"promptOnStdin": true,
"output": "stdout"
},
"zai": {
"command": "zai",
"args": ["agent", "--workspace", "{{workspaceDir}}", "{{prompt}}"],
"output": "stdout"
}
}' \
builder-agent < prompt.txtProvider args support {{prompt}}, {{workspaceDir}}, {{model}}, and {{outputPath}} placeholders. {{model}} renders as an empty value when KAIZEN_AGENT_MODEL is unset. promptOnStdin defaults to false for compatibility; when true, Builder Agent writes the promptTemplate result to stdin. An explicit {{prompt}} in args is still rendered as well, so omit that placeholder when the prompt must only use stdin. output is stdout by default; use last-message for CLIs that write the final response to the {{outputPath}} file. Empty placeholder values are omitted; if the omitted value follows a flag-like argument such as --model, the flag is omitted too.
Captured stdout and stderr are each limited to 256 KiB, split between head and tail context so trailing payloads and diagnostics remain available. Truncated streams include an omission marker in raw output and are listed in provider evidence as truncatedOutput.
Provider registries can also live in a JSON file:
KAIZEN_PREFERRED_AGENT=hermes-agent,opencode-go,codex,claude \
KAIZEN_AGENT_PROVIDERS_FILE=.kaizen/agent-providers.json \
builder-agent < prompt.txtThe file may be either the provider object itself or { "providers": { ... } }. Provider entries support:
command: executable name or path.args: command arguments with{{prompt}},{{workspaceDir}},{{model}}, and{{outputPath}}placeholders.promptTemplate: provider-specific prompt wrapper. Defaults to{{prompt}}.promptOnStdin: whentrue, pipe the renderedpromptTemplateto provider stdin. Defaults tofalse.output:stdoutorlast-message.timeoutMs: execution timeout.healthCheck: optional{ "command", "args", "timeoutMs" }check run before execution. Omittedcommanduses the provider command.fallbackOn: failure classes that should try the next provider.
Unknown provider or healthCheck fields are rejected. Invalid output values are rejected instead of falling back to stdout; omit output to use the default.
Provider evidence is included in blocked run notes and appended to successful payload notes, including first-attempt success and fallback success. It records attempted providers, failure classes, fallback reasons, selected backend, and final payload source.
See provider-fallback-architecture.md for the Hermes-style research notes, design decisions, and example registries for opencode-go, z.ai, Copilot-like wrappers, Antigravity-like wrappers, Grok-like wrappers, and Hermes-style agents.
The integration payload is intentionally smaller than the standalone build artifact:
{
"status": "fixed",
"summary": "Short implementation summary.",
"notes": "",
"discoveredIssues": [
{
"title": "Verifier treats the word rejected in summaries as a hard failure",
"repo": "verifier",
"body": "The verifier rejected an otherwise passing run because the builder summary mentioned a legacy status name.",
"expected": "Only actual verification failures should block PR creation.",
"evidence": "verifier.log showed a must_fix from builder summary text."
}
]
}status is one of fixed, partial, or blocked:
fixed: the scoped issue or task is implemented and the builder does not know of remaining task scope.partial: the builder produced reviewable, PR-worthy code for part of the scoped task, but known non-blocking work remains. Use this when downstream verification and human review can still evaluate the change, for example when a low-risk sub-scope is complete and a clearly described caveat remains.blocked: the builder cannot produce PR-worthy changes without more information, missing credentials, explicit human approval, a safety decision, or an upstream fix. Do not usepartialfor unclear requirements, unapproved secrets or infrastructure changes, provider refusal, or work that should not proceed to verification.
When blocked depends on a concrete human answer or approval, include humanRequest with a schema-defined reasonCode, a stable lowercase requestKey identifying the semantic decision, and the exact question. Wording-only changes keep the same key; a genuinely different decision uses a new key. Omit humanRequest for technical failures, upstream-first routing, retry exhaustion, and other blocks that do not ask a human to decide or supply information. This distinction lets kaizen-loop reserve kaizen:needs-human for real unanswered requests.
partial exits successfully so kaizen-loop can continue into mechanical checks, independent verifier review, and PR policy gates. It is not an approval to merge or a promise that the task is complete. A partial payload must include non-empty Completed scope:, Incomplete scope:, Verification:, and Residual risk: sections in notes (in any order) so the verifier and reviewer can decide whether to stop, ask for follow-up, or allow a narrowly scoped PR. Each label must appear exactly once, use this exact capitalization, and have a non-empty value; use Verification: skipped — <reason> when verification did not run.
Completed scope: Added the schema validation.
Incomplete scope: Provider rollout remains.
Verification: npm test passed.
Residual risk: Older providers may need prompt updates.
The summary should state what changed and why; Builder Agent trims surrounding whitespace and rejects empty summaries. The notes field should capture verification run or skipped, residual risk, and reviewer notes when relevant. discoveredIssues is optional and defaults to an empty array. The published contract is kaizen-loop-payload.schema.json, and Builder Agent validates provider payloads with the same runtime normalizer before writing KAIZEN_BUILD_RESULT_PATH. builder-agent does not create pull requests, push branches, or file GitHub issues; those remain kaizen-loop responsibility.
An adapter module must export either createAdapter() or an object with these async methods:
export function createAdapter() {
return {
async analyzeTask({ request }) {},
async createPlan({ request, analysis }) {},
async implement({ request, analysis, plan, iteration }) {},
async selfReview({ request, analysis, plan, implementation, iteration, threshold }) {},
async improve({ request, analysis, plan, implementation, review, instructions, iteration }) {}
};
}selfReview() must return an object compatible with self-review.schema.json, except that passed may be omitted. The controller always recomputes passed from the default passing conditions, so adapters cannot blindly approve themselves by setting passed: true, and do not need to compute it at all. The final normalized self-review artifact (written to disk and included in the build result) always includes the computed passed boolean.
builder-agent/
├─ package.json
├─ SKILL.md
├─ src/
│ ├─ builder/
│ ├─ review/
│ └─ types/
├─ prompts/
│ ├─ analyze.md
│ ├─ implement.md
│ ├─ self-review.md
│ └─ improve.md
├─ schemas/
│ ├─ build-request.schema.json
│ ├─ build-result.schema.json
│ └─ self-review.schema.json
├─ examples/
│ ├─ adapter.example.js
│ ├─ build-request.example.json
│ ├─ build-result.example.json
│ └─ self-review.example.json
├─ test/
│ └─ builder-agent.test.js
└─ docs/
└─ implementation-plan.md
See Implementation Plan for the proposed build order.