From cf24d34b288b7896071b7b66582d0ede7cffd0fa Mon Sep 17 00:00:00 2001 From: tegwick Date: Fri, 21 Aug 2026 00:21:53 +0200 Subject: [PATCH] feat: accept Glas execution overrides --- README.md | 11 +++++++++++ rein_aharness/cli.py | 20 ++++++++++++++++++++ rein_aharness/runner.py | 26 +++++++++++++++++++++----- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c7a5be3..3fc409b 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,13 @@ rein-aharness profiles # Run exactly one task (local JSON task-file path — dev) rein-aharness run --task-file examples/task-hello-sandbox.json [--no-hub] [--no-metrics] +# Execution-profile overrides supplied by glas-harness +rein-aharness run --task-file examples/task-hello-sandbox.json \ + --model claude-sonnet-4-6 \ + --tool-profile green-commit-only \ + --budget-tokens 60000 \ + --no-hub --no-metrics + # Primary production intake: activity-core ops_run claim (ACT-ADR-005 / REIN-A-0002) export ACTIVITY_CORE_URL=http://127.0.0.1:8010 export ACTIVITY_CORE_WORKER_TOKEN=… @@ -78,6 +85,10 @@ repo's instance manifest (default `green-commit-only`), loads a persona bundle (`kaizen-agentic schedule prepare`), runs a bounded agentic session (cwd-pinned, hard allow-list, never pushes), verifies a local commit, writes `.kaizen/metrics`, and posts a State Hub progress event. +When invoked through `glas-harness`, the explicit versioned Glas profile may +override model, tool profile, and budget for that bounded run. Workforce and +activity consumers should reference the Glas profile rather than encode these +rein CLI details in an assignment. Instance manifest contract: [docs/instance-manifest.md](docs/instance-manifest.md). Example: [examples/schedule.harness.yml](examples/schedule.harness.yml). diff --git a/rein_aharness/cli.py b/rein_aharness/cli.py index e5f75d5..6a6a634 100644 --- a/rein_aharness/cli.py +++ b/rein_aharness/cli.py @@ -235,6 +235,9 @@ def _cmd_run(args: argparse.Namespace) -> int: write_metrics=not args.no_metrics, emit_tool_events=args.stream_tool_events, on_tool_event=_print_event if args.stream_tool_events else None, + model=args.model, + tool_profile_override=args.tool_profile, + budget_tokens_override=args.budget_tokens, ) closed = False @@ -262,6 +265,7 @@ def _cmd_run(args: argparse.Namespace) -> int: "tokens_spent": result.tokens_spent, "execution_time_s": round(result.execution_time_s, 3), "reason": result.reason, + "model": result.model, "issue_id": issue_id, "issue_closed": closed, "issue_close_error": close_error, @@ -313,6 +317,22 @@ def main(argv: list[str] | None = None) -> int: "-- HARNESS-WP-0002-T03)" ), ) + run.add_argument( + "--model", + default=None, + help="Explicit Claude Code model identifier supplied by the execution profile", + ) + run.add_argument( + "--tool-profile", + default=None, + help="Override the instance tool profile for this explicitly governed run", + ) + run.add_argument( + "--budget-tokens", + type=int, + default=None, + help="Override the instance token budget for this explicitly governed run", + ) scan = sub.add_parser( "mail-scan", help="Deterministic company-mailbox scan (no LLM session)" diff --git a/rein_aharness/runner.py b/rein_aharness/runner.py index 64676b0..f1ef908 100644 --- a/rein_aharness/runner.py +++ b/rein_aharness/runner.py @@ -50,6 +50,7 @@ class RunResult: persona_source: str session_output: str reason: str = "" + model: str | None = None tool_profile: str = "" budget_tokens: int | None = None tokens_spent: int | None = None @@ -79,11 +80,18 @@ def run_task( write_metrics: bool = True, emit_tool_events: bool = False, on_tool_event: Callable[[dict[str, Any]], None] | None = None, + model: str | None = None, + tool_profile_override: str | None = None, + budget_tokens_override: int | None = None, ) -> RunResult: try: profile_name, budget_tokens, lane, blueprint = resolve_run_policy( spec.target_repo, spec.agent ) + if tool_profile_override: + profile_name = tool_profile_override + if budget_tokens_override is not None: + budget_tokens = budget_tokens_override profile = get_profile(profile_name) except UnknownToolProfileError as exc: return RunResult( @@ -96,6 +104,7 @@ def run_task( reason=f"refused: {exc}", tool_profile="", budget_tokens=None, + model=model, ) except Exception as exc: return RunResult( @@ -108,6 +117,7 @@ def run_task( reason=f"manifest resolution failed: {exc}", tool_profile="", budget_tokens=None, + model=model, ) collected_events: list[dict[str, Any]] = [] @@ -127,11 +137,14 @@ def run_task( if adapter is None: from rein_aharness.adapter import AgenticClaudeCodeAdapter - adapter = AgenticClaudeCodeAdapter( - workdir=spec.target_repo, - tool_profile=profile, - on_tool_event=_on_event if (emit_tool_events or on_tool_event) else None, - ) + adapter_kwargs = { + "workdir": spec.target_repo, + "tool_profile": profile, + "on_tool_event": _on_event if (emit_tool_events or on_tool_event) else None, + } + if model is not None: + adapter_kwargs["model"] = model + adapter = AgenticClaudeCodeAdapter(**adapter_kwargs) head_before = _git(spec.target_repo, "rev-parse", "HEAD") persona, persona_source = load_persona_bundle(blueprint, spec.target_repo) @@ -156,12 +169,14 @@ def run_task( try: response = adapter.execute_prompt(prompt, config) session_output = response.content + resolved_model = response.model session_ok = True reason = "" except Exception as exc: # adapter / budget failures must still be reported session_output = "" session_ok = False reason = f"session failed: {exc}" + resolved_model = model execution_time_s = time.monotonic() - started head_after = _git(spec.target_repo, "rev-parse", "HEAD") @@ -180,6 +195,7 @@ def run_task( persona_source=persona_source, session_output=session_output, reason=reason, + model=resolved_model, tool_profile=profile.name, budget_tokens=budget_tokens, tokens_spent=tokens_spent,