# Harness contract Contract version: `1.0` (`glas_harness.contract.CONTRACT_VERSION`). This is the stable boundary between Glas, its consumers, and concrete harness backends (reins). Glas owns profile resolution and the outer lifecycle; a rein owns its inner agentic loop. Sand-boxer owns environment provisioning. ## Consumer boundary `ExecutionRequest` requires an explicit `harness_profile_ref`, repository, title, and description. It may carry correlation and organizational references (`assignment_ref`, `role_ref`, `duty_ref`, `goal_refs`, and `resource_envelope_refs`). Those references link execution evidence to leadership/workforce records; they do not transfer organizational authority to Glas. The gateway returns `GatewayResult` with: - `ok`, derived from normalized outcome; - `evidence`, safe for compact State Hub reporting; and - direct-caller-only `tool_output` and `tool_error`. Raw prompts, model output, tool output, and credential material are excluded from the State Hub detail. ## Rein lifecycle ```python class Rein(ABC): def start_session( self, profile: HarnessProfile, inputs: dict[str, str], sandbox: SandboxHandle ) -> dict[str, Any]: ... def dispatch_tool( self, session: dict[str, Any], tool_call: ToolCall ) -> ToolResult: ... def end_session(self, session: dict[str, Any]) -> ExecutionSummary: ... def cleanup_session(self, session: dict[str, Any]) -> None: ... ``` ```text Glas rein sand-boxer ---- ---- ---------- resolve profile + rein descriptor create sandbox ------------------------------------------> create derive workspace + transport from handle start_session(profile, inputs, handle) -> sandbox-local setup dispatch_tool(session, call) -> inner loop across transport end_session(session) -> normalized facts cleanup_session(session) -> remove ephemeral task material destroy sandbox -----------------------------------------> destroy publish compact ExecutionEvidence ``` After sandbox creation, the caller's source checkout is no longer an execution path. A same-host descriptor must contain `pid` plus `workspace_dir` and every rein command is wrapped with `nsenter`; a remote descriptor must contain `ssh` plus `remote_dir` and every command crosses SSH. Incomplete, mixed, or unknown reachability refuses at session start. The transport also bounds the outer rein subprocess with the profile timeout. A host must make the selected rein command and its dependencies available inside that transport; host-only installation is not treated as sandbox availability. There is no production default rein. Direct `Rein` injection remains a narrow library/test seam but still requires a valid profile so profile, sandbox, model, tool policy, and evidence are explicit. ## Stability and extension rules All contract models use Pydantic with unknown fields forbidden. Stable `1.0` fields are the declared fields in `src/glas_harness/contract.py`. Optional measurements such as tokens, duration, resolved model, commit, and artifacts remain `null` when unknown; unsupported tool-event visibility is `unavailable`, not an empty claim of completeness. Rein-specific, non-secret additions belong only in declared `metadata` fields. Adding a required field, changing a field meaning/type, or removing a field requires a new contract version. Adding an optional field may remain compatible only when old consumers can safely ignore it and every strict boundary model is updated together. A profile and rein descriptor must both declare the exact supported contract version. Sensitive values are never contract extensions. Profiles may contain credential-route references, while credential resolution and provider setup remain rein-local under ADR-002. ## Failure semantics The gateway returns evidence for every normal refusal/failure path: - `resolution`: unknown, disabled, ambiguous, incompatible, or unsafe profile; - `sandbox_create`; - `session_start`; - `execution` (including a rein-declared unsuccessful result); - `session_end`; and - `teardown`. Profile resolution happens before sandbox creation. Once a sandbox exists, rein cleanup and sandbox teardown are attempted on every path. `refused` means governed execution did not proceed; `failed` means an attempted lifecycle did not complete successfully. ## Deliberate non-goals The contract does not schedule work, source blueprints, allocate workers, resolve leadership, broker credentials, select an unapproved model by price, or standardize rein internals. Composable rein middleware remains deferred by ADR-004 until a second concrete need exists.