4. Operators
How one attempt is made, the prompt the coding agent starts from.
An operator turns an action into an attempt: the prompt the coding agent gets, and what to put in
its working folder. It never runs anything itself. The built-in ones are draft (a fresh
attempt), debug (fix a failing one), improve (build on a scored one) and ensemble (combine
several).
# crossover.py
from hillclimb.sdk import Attempt, Operator, inspiration_filename
class Crossover(Operator):
name, kind, needs_target = "crossover", "combine", True
def prepare(self, ctx):
files = ", ".join(inspiration_filename(i) for i, _ in enumerate(ctx.inspirations, 1))
return Attempt(prompt=f"Combine the parent with {files}.\n\n{{{{contract}}}}", copy_parent=True)climber: {operators: [draft, debug, improve, crossover.py:Crossover]}kind says what the operator does: create, repair, refine or combine. The Attempt says
what the harness should prepare: a copy of the parent's solution (copy_parent), its tuned
parameter values as new defaults (inherit_params), the inspirations (copy_inspirations), or
extra files. The problem's contract always reaches the agent: the harness puts it where
{{contract}} stands, or appends it.
An operator policy names operators by their name, so adding one to the list makes it available,
and a policy decides when to use it.
Changing the built-in prompts
prompts: in the block names a folder of templates (draft.md, improve.md, debug.md,
ensemble.md, …) that replace the built-in ones of the same name. A template may leave out a
{{token}} but not add one nothing fills, and the contract templates cannot be replaced. A search
refuses to start on a template that breaks these rules.