diff --git a/docs/harness-contract.md b/docs/harness-contract.md new file mode 100644 index 0000000..68bf621 --- /dev/null +++ b/docs/harness-contract.md @@ -0,0 +1,86 @@ +# Harness contract + +The interface a concrete harness backend ("rein") implements so glas-harness +can route to it, per `docs/adr/ADR-001-rein-harness-family.md`. Mirrors +sand-boxer's `SandboxExtension` ABC (`provision`/`wait_ready`/`teardown`) at +the harness level, one layer up: sand-boxer establishes *where* dangerous +work runs, this contract governs *how an agent session runs* on top of it. + +## Interface + +```python +class Rein(ABC): + """Base class for concrete harness backends (reins).""" + + @abstractmethod + def start_session( + self, profile: HarnessProfile, inputs: dict[str, str], sandbox: SandboxHandle + ) -> dict[str, str]: + """Begin an agent session bound to a sandbox. Returns a session handle.""" + + @abstractmethod + def dispatch_tool( + self, session: dict[str, str], tool_call: ToolCall + ) -> ToolResult: + """Run one tool call under the session's policy. Returns result + audit envelope.""" + + @abstractmethod + def end_session(self, session: dict[str, str]) -> dict[str, str]: + """Close the session. Returns a summary (commit sha, tokens, duration, outcome).""" +``` + +- `start_session` resolves the rein's own setup (persona/blueprint loading, + credential acquisition) against the sandbox handle glas-harness already + obtained from sand-boxer — the rein never provisions or tears down a + sandbox itself. +- `dispatch_tool` enforces the tool-profile allow-list glas-harness resolved + (the same allow-list concept rein-aharness's `profiles.py` already + implements today, just invoked through the contract instead of only the + rein's own CLI). +- `end_session` is where the existing "commit exists = success" signal + (rein-aharness) or an equivalent per-rein success criterion is reported + back to glas-harness for State Hub posting. glas-harness posts the audit + event; the rein returns the facts. + +## Session lifecycle (who calls what) + +``` +glas-harness rein sand-boxer +──────────── ──── ────────── +resolve harness.* profile +request sandbox ──────────────────────────────▶ create() +receive sandbox handle ◀────────────────────────────── +start_session(profile, in, sbx) ─▶ acquire creds, load persona + ◀─ session handle +dispatch_tool(session, call) ─▶ run under allow-list + ◀─ result + audit envelope + (repeat dispatch_tool ...) +end_session(session) ─▶ verify success, summarize + ◀─ summary +post State Hub event +request sandbox teardown ──────────────────────────────▶ destroy() +``` + +glas-harness owns the *outer* loop (profile resolution, sandbox +request/teardown, State Hub reporting, actor attribution). The rein owns +the *inner* loop (its own agentic reasoning, whatever that looks like — +Claude Code CLI subprocess for `rein-aharness`, a direct OpenRouter +tool-use loop for `rein-openweights`). + +## Actor attribution + +Every `dispatch_tool` call and lifecycle transition carries an actor +(`adm`/`agt`/`atm`) per glas-harness INTENT.md's audit requirement. +glas-harness stamps this at dispatch time; reins do not need their own +actor model. + +## Open questions this contract does not resolve yet + +- Whether `start_session` also carries scheduling/blueprint-sourcing + parameters (kaizen-agentic blueprint id, activity-core task id) as part + of `inputs`, or whether that stays entirely rein-side — tracked in + `rein-aharness/workplans/HARNESS-WP-0002-T04`. +- The exact `SandboxHandle`/`ToolCall`/`ToolResult` field shapes — sketched + here at the level needed to unblock `GLAS-WP-0001-T04` (the + rein-aharness parity proof); refine once that task is underway rather + than speculatively now. diff --git a/workplans/GLAS-WP-0001-harness-router-foundation.md b/workplans/GLAS-WP-0001-harness-router-foundation.md index f904079..5a27f65 100644 --- a/workplans/GLAS-WP-0001-harness-router-foundation.md +++ b/workplans/GLAS-WP-0001-harness-router-foundation.md @@ -25,7 +25,7 @@ harness level: something like `start_session`/`dispatch_tool`/ ```task id: GLAS-WP-0001-T01 -status: todo +status: done priority: high state_hub_task_id: "e4e6e7e4-ad30-42b7-a278-39d24ec5cecc" ```