From 61a9814b67712151b39515d75b51548db2e1894e Mon Sep 17 00:00:00 2001 From: Kayos Date: Wed, 29 Apr 2026 12:37:54 -0700 Subject: [PATCH] patcher: pin model='opus' on clawdforge sessions; CRAFTING_PATCHER_MODEL env override MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code-work prompts (read CVE/lint context, draft a unified diff that verifies cleanly against the failing recipe) reward Opus's longer context + careful reasoning. Cauldron-style high-frequency Sonnet calls are unaffected — this only changes what crafting-table's patcher asks clawdforge to use for its drafted-patch sessions. Pairs with clawdforge dbbead2 which adds the optional `model` field on POST /sessions and propagates ANTHROPIC_MODEL into the acpx subprocess env on both create + turn. Override knob: CRAFTING_PATCHER_MODEL env (e.g. "sonnet" if cost > quality). Tests: 16/16 patcher tests still green. --- crafting_table/patcher.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crafting_table/patcher.py b/crafting_table/patcher.py index 1a2c6ab..2fff823 100644 --- a/crafting_table/patcher.py +++ b/crafting_table/patcher.py @@ -98,6 +98,12 @@ class PatcherConfig: # HTTP timeout margin — clawdforge adds an internal margin, but we cap # transport-level too for hung connections. http_timeout_secs: int = 600 + # Model passed to clawdforge on session create. Pinned to "opus" by + # default — code-work prompts (read finding context, write a unified + # diff that doesn't break the verify recipe) reward Opus's longer + # context + deeper reasoning. Override via CRAFTING_PATCHER_MODEL env + # if you want sonnet for cost reasons. + model: str = "opus" @classmethod def from_env(cls, env: dict[str, str] | None = None) -> "PatcherConfig | None": @@ -127,6 +133,7 @@ class PatcherConfig: auto_patch_branch_prefix=e.get( "CRAFTING_PATCHER_BRANCH_PREFIX", "crafting-table/auto/" ), + model=e.get("CRAFTING_PATCHER_MODEL", "opus"), ) @@ -210,9 +217,12 @@ class ClawdforgeClient: self, *, agent: str = "claude", + model: str | None = None, meta: dict[str, Any] | None = None, ) -> dict[str, Any]: body: dict[str, Any] = {"agent": agent} + if model is not None: + body["model"] = model if meta is not None: body["meta"] = meta async with httpx.AsyncClient(timeout=self.timeout_secs) as ac: @@ -657,6 +667,7 @@ class Patcher: try: session_payload = await self.clawdforge.create_session( agent="claude", + model=self.config.model, meta={ "crafting_table_job_id": job["id"], "finding_id": finding_id,