Optimization (GEPA)

Define a target — TypeScript

No Python, no decorators, no rebuild. You define a target and expose it as a fetch handler; the CLI sends each (task, candidate) over HTTP and scores the output. Your provider keys never leave your process.

Note

The TypeScript optimization API lives in the @mv37/rollout/optimization subpath. GEPA, verifier scoring, dataset upload, and run bookkeeping all happen in the Rollout CLI — your endpoint only runs the agent and returns its output.

Define a target

defineOptimizationTarget describes one target: its id, its baseline artifact, and a run(task, candidate) function that executes your agent with the candidate applied and returns the output.

target.ts
import { generateText } from "ai";import { openrouter } from "@openrouter/ai-sdk-provider";import {  createOptimizationHandler,  defineOptimizationTarget,} from "@mv37/rollout/optimization";const aimeSolver = defineOptimizationTarget({  id: "aime_solver",  baseline: "Solve the problem and return only the final integer.",  async run(task, candidate) {    const result = await generateText({      model: openrouter("deepseek/deepseek-r1"),      system: candidate.text,                    // GEPA proposes this      prompt: String(task.instruction ?? task.input),    });    return { output: result.text, metadata: { usage: result.usage } };  },});export const rolloutHandler = createOptimizationHandler([aimeSolver]);

Create the handler

createOptimizationHandler takes one or more targets and returns a universal (Request) => Promise<Response>. It is transport-only and has no Node dependencies, so it runs on edge runtimes and Workers as well as Node.

Mount it anywhere

Because it is a plain fetch handler, it drops into any runtime:

mounts.ts
// Next.js app router — app/api/rollout/route.tsexport const POST = rolloutHandler;// Hono / Cloudflare Workersapp.post("/rollout", (c) => rolloutHandler(c.req.raw));// Plain Node (>=20)import { createServer } from "node:http";import { createServerAdapter } from "@whatwg-node/server";createServer(createServerAdapter(rolloutHandler)).listen(3000);

Point the CLI at it

Start your endpoint, then run the CLI with --target-url instead of --module. Everything else — dataset, verifier, reflection model — is identical to a Python run:

shell
rollout optimize run \  --target-url http://localhost:3000/api/rollout \  --target aime_solver \  --dataset ./datasets/aime --verifier ./verifiers/exact.json \  --reflection-model openrouter/openai/gpt-4.1-mini

What stays where

The CLI owns GEPA, verifier scoring, and uploads to Rollout. Your endpoint owns the agent and the model call. Provider keys stay in your own process — they never reach Rollout or the CLI host if those run elsewhere. See the control plane vs compute plane split for the full picture, and Datasets / Verifiers for the inputs the CLI needs.