Skip to content

GitHub radar: self-healing by regeneration

The examples/github_radar/ package watches a GitHub project's releases page and answers a question every scraper eventually faces: what happens when the site changes and your deterministic script breaks?

The Conatus answer is regeneration. A compiled recipe runs deterministically and free — until the site changes and it breaks. Then, instead of a human babysitting it, the agent is automatically re-triggered to re-author the recipe, and you are back to deterministic execution:

deterministic recipe --fails / bad output--> agent re-authors --> new recipe

How it works

gh.py mirrors the EDGAR example: typed actions (fetch_releases_page, extract_releases) that return a non-serializable HTML page and typed Release records, passed between steps by reference.

self_heal_regenerate.py stages the failure. stale_recipe plays the part of a recipe the agent authored months ago, before GitHub renamed the release container — its CSS selector now matches nothing. A small wrapper runs the recipe first, checks the output against a contract, and falls back to the agent task only when the recipe misbehaves:

def run_or_regenerate(recipe, agent_task, *args, ok):
    """Run the deterministic recipe; if it misbehaves, regenerate."""
    try:
        result = recipe(*args)
    except Exception as why:
        print(f"  ! recipe failed: {why}")
    else:
        if ok(result):
            return result, "deterministic recipe (free, no model)"
        print(f"  ! recipe output failed its contract: {result!r}")
    print("  -> re-triggering the agent to re-author the recipe...")
    return agent_task.run(*args), "REGENERATED by the agent"

The fallback is an ordinary task built from the same typed actions:

@task(actions=[fetch_releases_page, extract_releases])
def recent_releases(repo: str) -> list[Release]:
    """List a GitHub project's recent releases."""

Because the agent re-derives the result from the live page, the regenerated run also produces a fresh recipe — so the next execution is deterministic and free again. The model only gets involved when the world changes.

Run it

Needs an OPENAI_API_KEY (the stale recipe fails by design, so the agent path runs):

uv run python examples/github_radar/self_heal_regenerate.py

Source: examples/github_radar/