bozoloop

🀑 bozoloop

Self-improving code loops for people who ship.

Spec. Patch. Eval. Repeat.

npm version license zero dependencies


BozoLoop is a zero-dependency, TypeScript-first library for running iterative code improvement loops. You supply a goal, a way to generate changes, and evaluators β€” BozoLoop handles the loop, ledger, pause/resume, and checkpoint mechanics.

Mental model:

spec β†’ propose change β†’ apply change β†’ run evals β†’ record result β†’ repeat

BozoLoop is not an agent platform, IDE plugin, or opinionated framework. It’s a tiny composable primitive you plug into your existing workflow.

Why BozoLoop?

Most β€œself-improving code” tools are bloated agent platforms that try to own your entire workflow. BozoLoop is the opposite:

Install

npm install bozoloop

30-Second Example

import { createLoop, commandEvaluator } from "bozoloop";

const result = await createLoop({
  goal: "All tests pass",
  workspace: ".",
  maxAttempts: 10,
  engine: {
    async suggest(ctx) {
      // Call your LLM, read files, generate diffs β€” whatever you want
      return {
        summary: `Fix attempt #${ctx.attempt}`,
        patch: { /* your patch data */ },
      };
    },
  },
  applier: {
    async apply(patch, workspace) {
      // Write files, apply diffs, run formatters
      return { ok: true, message: "Applied." };
    },
  },
  evaluators: [
    commandEvaluator("tests", "npm test"),
  ],
}).run();

console.log(result.success ? "βœ… Done!" : "❌ Failed");

Config File

Create a bozoloop.config.ts (or .js) for reusable setups:

import { defineConfig, commandEvaluator } from "bozoloop";

export default defineConfig({
  goal: "All tests and type checks pass",
  workspace: ".",
  maxAttempts: 10,
  engine: myEngine,
  applier: myApplier,
  evaluators: [
    commandEvaluator("tests", "npm test"),
    commandEvaluator("types", "npx tsc --noEmit"),
    commandEvaluator("lint", "npm run lint"),
  ],
  hooks: {
    onAttemptEnd: (record) => {
      console.log(`#${record.attempt} ${record.pass ? "βœ…" : "❌"}`);
    },
  },
});

CLI

# Run the loop
bozoloop run --config bozoloop.config.js

# Resume a paused loop
bozoloop resume --config bozoloop.config.js

# Inspect state and ledger
bozoloop inspect --config bozoloop.config.js

# Rollback to last checkpoint
bozoloop rollback --config bozoloop.config.js

The CLI is zero-dependency (no commander/yargs). It reads your config, runs the loop, and writes state to .bozoloop/.

API Overview

Core

Export Description
createLoop(config) Create a BozoLoop instance
BozoLoop The loop class (also usable directly with new)
defineConfig(config) Type-safe config helper for config files
commandEvaluator(name, cmd) Create an evaluator from a shell command
FileCheckpointProvider Filesystem-based checkpoint/rollback provider

Interfaces

Interface Role
SuggestionEngine Proposes changes given current context
PatchApplier Applies a proposed change to the workspace
Evaluator Evaluates the workspace, returns pass/fail
CheckpointProvider Creates and restores workspace snapshots
BozoLoopHooks Lifecycle hooks for observability and integration

Loop Methods

const loop = createLoop(config);

await loop.run();        // Run from beginning
await loop.resume();     // Resume a paused loop
loop.pause();            // Pause (takes effect between attempts)
loop.abort();            // Abort (takes effect between attempts)
await loop.rollback();   // Rollback to last checkpoint
loop.inspect();          // Get { state, ledger } data

Concepts

Suggestion Engine

Your engine proposes a change. It receives the goal, workspace path, current attempt number, and all previous attempt records. Return a summary and a patch (any shape β€” your applier knows how to interpret it).

Patch Applier

Takes the patch from your engine and applies it to the workspace. Could write files, apply git diffs, run code generators β€” whatever you need.

Evaluators

Run after each patch is applied. All evaluators must pass for an attempt to succeed. commandEvaluator is the built-in helper for running shell commands (test suites, linters, type checkers, etc).

Hooks

Fire at every stage of the loop lifecycle:

hooks: {
  onLoopStart, onLoopEnd,
  onAttemptStart, onAttemptEnd,
  onSuggestion, onApply, onEval,
  onPause, onResume, onAbort,
}

Use hooks to log, send webhooks, deploy previews, notify Slack, or integrate with external systems.

Ledger

Every attempt is recorded to .bozoloop/ledger.json with full detail:

No mystery behavior. Everything is inspectable.

Using with Existing Workspaces

BozoLoop works great for grinding on an existing codebase:

cd my-project
# Set up your bozoloop config
bozoloop run --config bozoloop.config.js

Use it after Codex/Cursor/Claude writes code β€” BozoLoop can iterate until tests pass, types check, or any other condition is met.

Using for New Projects

BozoLoop also works for bootstrapping new projects from scratch. Point it at an empty directory with a spec and let it iterate:

createLoop({
  goal: "Create a working Express API with auth",
  spec: "REST API with JWT auth, user CRUD, PostgreSQL...",
  workspace: "./new-project",
  // ...
});

Pause / Resume / Interrupt

BozoLoop supports basic pause/resume semantics in v0.0.1:

v0.0.1 limitations:

Checkpoint / Rollback

BozoLoop includes a simple filesystem checkpoint provider:

import { FileCheckpointProvider } from "bozoloop";

createLoop({
  // ...
  checkpoint: new FileCheckpointProvider(".bozoloop"),
});

Before each attempt, the workspace is snapshotted to .bozoloop/checkpoints/. Use loop.rollback() or bozoloop rollback to restore the last checkpoint.

v0.0.1 limitations:

Works With Your Tools

BozoLoop is designed to complement, not replace, your existing workflow:

Zero Dependencies

BozoLoop has zero runtime dependencies. The only devDependencies are TypeScript and @types/node for the build. Your node_modules stays clean.

Roadmap

v0.0.1 (current) β€” Foundation

Planned

v0.0.1 Limitations

Being honest about what this version does and doesn’t do:

This is a real, working package β€” not vaporware. These limitations are honest constraints of a v0.0.1, not missing features hidden behind abstractions.

License

MIT


bozoloop β€” because your code should improve itself,
and you shouldn't need a circus to make it happen. 🀑