diff --git a/docs/adr/ADR-001-rein-harness-family.md b/docs/adr/ADR-001-rein-harness-family.md new file mode 100644 index 0000000..74a0eb4 --- /dev/null +++ b/docs/adr/ADR-001-rein-harness-family.md @@ -0,0 +1,93 @@ +# ADR-001: The "rein" harness family, routed by glas-harness + +- Status: accepted +- Date: 2026-07-26 +- Deciders: Bernd Worsch + +## Context + +Two harness efforts existed in parallel with no relationship documented +between them: + +- **agent-harness** — a working v0.1 runtime, deployed on Railiance, + driving Claude Code CLI sessions for one tenant (`binky-control`). Its + only isolation is a `--allowedTools` allow-list string plus cwd-pinning; + it has no OS-level sandbox and no awareness of glas-harness or + sand-boxer. +- **glas-harness** — a charter-only meta-framework (`INTENT.md` plus a CI + smoke stub) that names sand-boxer as its sandbox provider but has no + gateway, session loop, or tool dispatch implemented yet. + +Neither repo referenced the other. Left alone, this heads toward "two +harnesses that both think they're the runtime," with no shared contract +and duplicated wiring to `kaizen-agentic`, `activity-core`, and +`llm-connect`. + +Separately: every current agent-facing harness in the ecosystem (Claude +Code, Grok's CLI, GPT/Codex's CLI) is a **frontier-model-vendor harness** +— it only drives that vendor's own model. There is no harness in the +ecosystem today that can run a current open-weight model (via OpenRouter) +through an equivalent agentic tool-use loop. + +## Decision + +1. **glas-harness is the framework.** It owns the harness *contract* + (session lifecycle, tool dispatch, actor attribution, sandbox + consumption via sand-boxer) and routes between pluggable, concrete + harness backends — mirroring how sand-boxer owns a sandbox contract + and routes between pluggable extensions (`ext.compose-ssh`, + `ext.vm-packer`, `ext.e2b`, ...). + +2. **Concrete harness backends are called "reins."** The name mirrors + "rails" (operations models for running workloads): different reins + suit different circumstances, and more can be added without changing + the framework. Each rein is its own repo, prefixed `rein-*`. + +3. **`agent-harness` is renamed `rein-aharness`** and becomes the first + rein: the Claude-Code-CLI-driven harness for governed, unattended/ + scheduled tenant work (its existing `binky-control` role is unchanged). + Repo and Forgejo remote already renamed + (`coulomb/rein-aharness.git`); local directory, git remote, and + self-referencing docs (`README.md`, `INTENT.md`, `pyproject.toml` + project name) are updated as part of this ADR landing. The CLI command + name, Python package name, and deploy artifacts (Docker image tag, k8s + namespace, Railiance host paths) are **deliberately left unrenamed for + now** — see `rein-aharness/workplans/REIN-A-WP-0002` — because they + touch a live deployment and deserve their own reviewed change, not a + silent mechanical rename bundled into an architecture decision. + +4. **A new rein, `rein-openweights`, is chartered** to close the + frontier-vendor-harness gap: an agentic tool-use loop that drives + current open-weight models via OpenRouter (through `llm-connect`) as + an alternative to Claude Code / Grok CLI / Codex, usable wherever a + rein-aharness-equivalent session is wanted but a frontier vendor + dependency is not. Scaffolded at `~/rein-openweights` (local only — + no Forgejo remote yet). + +## Consequences + +- glas-harness's first implementation milestone is now concrete: define + the harness contract that both `rein-aharness` and `rein-openweights` + implement, plus a minimal router, rather than an abstract charter with + no consumer. +- `rein-aharness` keeps running unchanged in production (`binky-control`) + while glas-harness matures — no forced cutover, no risk to the live + Railiance deployment. +- The "retire agent-harness" question raised earlier is superseded: it + isn't retired, it's incorporated as a rein. Whether it's ever folded + directly into glas-harness's own process (vs. staying a separate + routed repo) is deferred until glas-harness's contract exists and at + least two reins have implemented it. +- Future reins (e.g. a channel-bot rein, a subagent-delegation rein) slot + into the same contract without new framework work, the same way a new + sand-boxer extension doesn't require sand-boxer's core API to change. + +## Open questions (for the workplans below) + +- Does the harness contract abstract scheduling/blueprint-sourcing + (kaizen-agentic, activity-core), or does only `rein-aharness` depend on + those while `rein-openweights` is triggered differently (e.g. directly + by glas-harness channels)? +- Where does credential brokering for `rein-openweights`'s OpenRouter/ + llm-connect calls live — glas-harness (per the sandbox-consumption + pattern) or the rein itself? diff --git a/workplans/GLAS-WP-0001-harness-router-foundation.md b/workplans/GLAS-WP-0001-harness-router-foundation.md new file mode 100644 index 0000000..8e156ad --- /dev/null +++ b/workplans/GLAS-WP-0001-harness-router-foundation.md @@ -0,0 +1,105 @@ +--- +id: GLAS-WP-0001 +title: "Harness router foundation: contract + first two reins" +status: proposed +--- + +Turn glas-harness from a charter into the actual harness router per +`docs/adr/ADR-001-rein-harness-family.md`. Define the contract concrete +harness backends ("reins") implement, register the first two +(`rein-aharness`, `rein-openweights`), and stand up a minimal gateway +that can run a session through either. No channel work, no memory/skills +layer yet — this workplan is the sand-boxer-extension-model equivalent +for harnesses: contract + registry + one working round trip. + +## Task: Define the harness contract + +Specify the interface a rein implements: session start/resume/end, tool +dispatch + policy check, actor attribution (`adm`/`agt`/`atm`), sandbox +policy resolution (mode/scope/workspaceAccess) handed to sand-boxer, and +the audit envelope reported to State Hub. Mirror sand-boxer's +`SandboxExtension` ABC shape (`provision`/`wait_ready`/`teardown`) at the +harness level: something like `start_session`/`dispatch_tool`/ +`end_session`. Document in `docs/harness-contract.md`. + +```task +id: GLAS-WP-0001-T01 +status: todo +priority: high +``` + +## Task: Rein registry + +A named, versioned registry of reins (`registry/reins/rein-aharness.yaml`, +`registry/reins/rein-openweights.yaml`) analogous to sand-boxer's +`extensions/ext.*.yaml` — each entry declares its capabilities (e.g. +`unattended`/`interactive`, `model-class: frontier|open-weight`, +`credential-source`) and a handler reference. Extend +`registry/indexes/capabilities.yaml` with a `capability.platform. +glas-harness` entry per the registry-first-reuse principle. + +```task +id: GLAS-WP-0001-T02 +status: todo +priority: medium +``` + +## Task: Harness profile catalog seed + +First harness profile, `harness.agent-dev`, paired with sand-boxer's +`profile.agent-dev` (existing `docs/integrations/glas-harness.md` contract +in sand-boxer already assumes this pairing — verify it still matches). +Add a second profile, `harness.agent-dev-local`, paired with sand-boxer's +forthcoming `profile.bwrap-local` (SAND-WP-0013) once that lands, for +fast local iteration without an SSH hop. + +```task +id: GLAS-WP-0001-T03 +status: todo +priority: medium +``` + +## Task: Minimal CLI gateway — prove the contract against rein-aharness + +Implement just enough of the harness contract to run one existing +rein-aharness `run` (task-file path) *through* glas-harness: resolve +`harness.agent-dev`, request a sandbox from sand-boxer, dispatch to +rein-aharness's adapter, verify commit, report to State Hub. This is the +parity proof gating any later "retire agent-harness as a standalone +concern" conversation — deliberately not attempted until this exists. + +```task +id: GLAS-WP-0001-T04 +status: todo +priority: high +``` + +## Task: Charter and bootstrap rein-openweights + +Turn the `~/rein-openweights` scaffold into a working minimal rein: an +agentic tool-use loop (plan → tool call → observe → repeat) driving an +open-weight model via `llm-connect`'s OpenRouter path, implementing the +GLAS-WP-0001-T01 contract. Start with the same tool surface as +rein-aharness's `green-commit-only` profile (Read/Write/Edit/Glob/Grep + +local git) so it's directly comparable. Needs its own Forgejo remote +before anything is pushed — coordinate repo creation with the operator. + +```task +id: GLAS-WP-0001-T05 +status: todo +priority: high +``` + +## Task: Decide credential-brokering ownership for rein-openweights + +Resolve the open question from ADR-001: does glas-harness broker the +OpenRouter/llm-connect credential the same way it will broker sand-boxer +sandbox handles, or does rein-openweights acquire it directly (OpenBao/ +ops-warden) the way rein-aharness does today? Record as an ADR addendum +before T05 lands, not after. + +```task +id: GLAS-WP-0001-T06 +status: todo +priority: medium +```