The TypeScript framework for agents.
Ridiculous speed.
Readable code.
Write the agent. Give it tools. Set the limits.
Ship code you can actually read.
The whole application
One project.
A working agent.
Repair a broken CLI. Verify the patch. Ask for approval.
Follow the files.
01Declare the agent
This code runs this agent.
Choose a model and a task. B4 runs the tool-call loop.
Agents ↗import { agent } from "@b4run/sdk" export default agent({ model: process.env.B4_CODE_FIXER_MODEL ?? "gpt-5-mini", recursionLimit: 60, description: "Repairs a failing test and verifies the change.", tools: { approve: ["exportForReview"] }, systemPrompt · instructions folded})02Workspaces + sandboxes
Give it somewhere to work.
Declare the files. B4 manages their lifecycle in an isolated Docker workspace.
Workspaces + sandboxes ↗export function projectWorkspace(id: string): WorkspaceDefinition { const manifest = projectManifest(id) return { source: { directory: "sample/project", include: [...manifest.allowedSourcePaths, ...manifest.immutablePaths], files: [ { path: "TASK.md", file: "sample/task.md" }, { path: ".gitignore", text: "node_modules/\n" }, { path: "project.json", text: JSON.stringify({ id: manifest.id }) }, ], }, environmentLinks: [ { path: "node_modules", target: `/opt/fixtures/${manifest.id}/node_modules` }, ], baseline: "git", }} sandbox: { ...sandboxPolicy, provider: dockerSandbox({ scope: "code-fixer-local", image: sandboxImage }), workspace: projectWorkspace(task), },03Typed tools
Your functions. Its tools.
Export a function. B4 derives its schema from your types and supplies ctx.
import type { B4ToolContext } from "@b4run/sdk"import { inspectCandidate } from "../../../review/inspect.js"import { renderReviewDiff } from "../../../review/patch.js"import { verifyChanges } from "../../../review/verifier.js" /** Verify the source repair independently and return the exact candidate for review. */export default async function prepareReview(_input: Record<string, never>, ctx: B4ToolContext) { // Compare the workspace with its captured source and reject edits outside the allowed files. const { manifest, candidate, baseline, initial } = await inspectCandidate(ctx) // Apply these exact changes in a fresh workspace and run both test suites. const verification = await verifyChanges(manifest.id, candidate.changes, ctx.signal, initial) if (!verification.passed) throw new Error("Independent verification failed") // Give the agent a readable diff and the exact candidate it must submit for approval. return { task: manifest.id, candidate, diff: renderReviewDiff(baseline, candidate.changes), verification, }}04Plans + skills
Give it a working method.
A plan seeds the checklist. Skills provide reusable instructions.
Plans + skills ↗- [ ] Read the task and reproduce the failing test- [ ] Inspect the relevant source and identify the cause- [ ] Make a focused source repair- [ ] Run the test, check preservation requirements, and explain the verified result- [ ] Call prepareReview and inspect the independently verified candidate- [ ] Pass that exact candidate to exportForReview for runtime approvalReproduce. Repair. Verify. Request review.
05Independent verification
Define what “done” means.
Test the patch in a fresh workspace. Require every named check to pass.
Evaluate the workflow ↗{ "visible": { "file": "test/cli.test.ts", "assertions": [ "documented dry-run flag reaches the handler" ] }, "independent": { "file": "checks/independent.test.ts", "assertions": [ "forwards cap and memory-level cwd", "rejects unknown and incomplete arguments", "dry-run preserves memory state and creates no files" ] }}06Human approval
The next action is your call.
B4 pauses before export. You approve the exact patch; the tool rechecks it.
Approval ↗ tools: { approve: ["exportForReview"] }, const candidate = validateCandidate(input.candidate) const inspected = await inspectCandidate(ctx) if (candidate.receiptDigest !== inspected.candidate.receiptDigest) throw new Error("Workspace changed since review; prepare and approve a new candidate") const verification = await verifyChanges( inspected.manifest.id, candidate.changes, ctx.signal, inspected.initial, ) if (!verification.passed) throw new Error("Independent verification failed")The pieces in motion
One request. The whole workflow.
- 01Request/fix#agent
- 02RepairIsolated workspace
- 03VerifyFresh workspace
- 04PauseB4 approval gate
- 05ApproveYour decision
- 06ExportRechecked patch
You write the task, tools, and acceptance rules.
B4 runs the agent loop, workspaces, streaming, and approval.
Current example source. Recording and installation use earlier versions.
See it in actionWatch the recorded repair.1m 53s · edited highlights
Historical defect, earlier implementation. Recorded timing applies to this run only.
This code runs this agent.
Recorded run · 1m 53s
Edited highlights · gpt-5
✓ Independent verification passed
Fixed. Verified.
Ready for your review.
A fresh sandbox checked the agent’s patch.
VISIBLE TESTS 1 / 1 passed INDEPENDENT CHECKS 3 / 3 passed
- documented dry-run flag reaches the handler
- forwards cap and memory-level cwd
- rejects unknown and incomplete arguments
- dry-run preserves memory state and creates no files
Recorded implementation
import { agent } from "@b4run/sdk" export default agent({ model: process.env.B4_CODE_FIXER_MODEL ?? "gpt-5-mini", recursionLimit: 60, description: "Repairs a failing test and verifies the change.", tools: { approve: ["exportForReview"] }, systemPrompt · instructions folded})Your next commit starts here
Read it.
Run it.
Make it yours.
Start with this agent. Make it yours.
Open the installation guideThe B4 CLI prints the installation guide for your coding agent:
b4 add code-fixerQualified installation · B4 0.8.32 · Earlier source.
Node 24 · Git · Docker · API key for live runs.
Replay the sample without a model call.
Read the code walkthrough ↗
See every attempt, including the failures ↗