Define the harness contract (GLAS-WP-0001-T01)
start_session/dispatch_tool/end_session, mirroring sand-boxer's SandboxExtension ABC one layer up: sand-boxer establishes where work runs, this contract governs how an agent session runs on top of it. Unblocks the rein-aharness parity proof (T04) and rein-openweights bootstrap (T05). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
7a3c8669c7
commit
97a50fc780
2 changed files with 87 additions and 1 deletions
86
docs/harness-contract.md
Normal file
86
docs/harness-contract.md
Normal file
|
|
@ -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.
|
||||||
|
|
@ -25,7 +25,7 @@ harness level: something like `start_session`/`dispatch_tool`/
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: GLAS-WP-0001-T01
|
id: GLAS-WP-0001-T01
|
||||||
status: todo
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "e4e6e7e4-ad30-42b7-a278-39d24ec5cecc"
|
state_hub_task_id: "e4e6e7e4-ad30-42b7-a278-39d24ec5cecc"
|
||||||
```
|
```
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue