"""One-task run orchestration. Flow: lock target repo → snapshot HEAD → persona bundle → prompt → agentic session → verify a new commit exists → hub progress event (+ task close). The run *fails* if the session pushed anywhere or left the repo dirty in a way it should not — the worker never pushes; publishing is a separate, explicitly-granted lane (see integrations/executor-worker-secrets.md in binky-control). """ from __future__ import annotations import subprocess from dataclasses import dataclass from pathlib import Path from agent_harness import hub from agent_harness.persona import load_persona_bundle from agent_harness.taskspec import TaskSpec PROMPT_TEMPLATE = """\ You are an unattended executor session (agent persona below, if any). Operating rules, non-negotiable: - Work ONLY inside the current repository working directory. - Green/Blue lane: file edits and local git add/commit only. Never push, never touch the network, never run destructive commands. - Bounded effort: complete the single task below, commit with a clear message, then stop. If the task cannot be completed, commit nothing and say why in your final output. {persona} ## Task: {title} {description} """ @dataclass class RunResult: ok: bool committed: bool head_before: str head_after: str persona_source: str session_output: str reason: str = "" def _git(repo: Path, *args: str) -> str: result = subprocess.run( ["git", "-C", str(repo), *args], capture_output=True, text=True, timeout=60, ) if result.returncode != 0: raise RuntimeError(f"git {' '.join(args)} failed: {result.stderr.strip()}") return result.stdout.strip() def run_task(spec: TaskSpec, adapter=None, report_to_hub: bool = True) -> RunResult: if adapter is None: from agent_harness.adapter import AgenticClaudeCodeAdapter adapter = AgenticClaudeCodeAdapter(workdir=spec.target_repo) head_before = _git(spec.target_repo, "rev-parse", "HEAD") persona, persona_source = load_persona_bundle(spec.agent, spec.target_repo) prompt = PROMPT_TEMPLATE.format( persona=persona or "(no persona bundle available for this run)", title=spec.title, description=spec.description, ) from llm_connect.models import RunConfig config = RunConfig(timeout_seconds=spec.timeout_seconds, skip_if_exists=False) try: response = adapter.execute_prompt(prompt, config) session_output = response.content session_ok = True reason = "" except Exception as exc: # adapter failures must still be reported session_output = "" session_ok = False reason = f"session failed: {exc}" head_after = _git(spec.target_repo, "rev-parse", "HEAD") committed = head_after != head_before ok = session_ok and committed if session_ok and not committed: reason = "session completed without committing" result = RunResult( ok=ok, committed=committed, head_before=head_before, head_after=head_after, persona_source=persona_source, session_output=session_output, reason=reason, ) if report_to_hub: detail = { "repo": spec.target_repo.name, "task_title": spec.title, "agent": spec.agent, "labels": spec.labels, "persona_source": persona_source, "committed": committed, "head_after": head_after, "ok": ok, "reason": reason, } hub.post_progress_event( summary=f"executor run: {spec.title} ({'ok' if ok else 'failed'})", event_type=spec.completion_event_type, detail=detail, task_id=spec.hub_task_id, ) if ok and spec.hub_task_id: hub.close_task(spec.hub_task_id) return result