--- id: REIN-OW-WP-0001 title: "Bootstrap: minimal open-weight agentic loop" status: active state_hub_workstream_id: "f73c1db1-0364-431f-9b3b-34e84ff2d86b" --- First working milestone for rein-openweights: prove an agentic tool-use loop against a current open-weight model via OpenRouter, comparable in scope to rein-aharness's `green-commit-only` profile, implementing the glas-harness rein contract (`glas-harness/GLAS-WP-0001-T01`). **Live-proven end-to-end (2026-07-26):** via glas-harness's gateway (`glas_harness.reins.rein_openweights.ReinOpenWeights`), inside a real `ext.bwrap` sandbox, against the real OpenRouter API with model `qwen/qwen-2.5-72b-instruct` — a 2-turn tool-calling loop produced a real git commit (`2effe57a`), verified via `git rev-parse HEAD`, 2449 tokens spent. Not a mock; real credentials, real API cost, run with the user's explicit go-ahead. `executor-sandbox` (the disposable target repo) was left untouched — bwrap only mutates its ephemeral copy. ## Task: Pick the starter open-weight model + OpenRouter path Checked `llm-connect`'s existing OpenRouter integration (`OpenRouterAdapter.execute_prompt`): it takes a single prompt string, builds a fixed `[system, user]` message pair itself, and never surfaces `message.tool_calls` in its response — it cannot drive a multi-turn tool-calling loop without a breaking change to llm-connect's frozen Core `LLMAdapter` ABC. Decision: rein-openweights uses its own minimal OpenRouter client (`openrouter_client.py`) for the agentic loop instead; `tools`/`tool_choice` already pass through llm-connect's own `OPENAI_CHAT_PASSTHROUGH_FIELDS` allow-list, confirming the request shape is standard OpenAI-compatible function-calling, just not round-tripped by that adapter today. Starter model is a `--model`-configurable default (`meta-llama/llama-3.1-70b-instruct`), not hardcoded. ```task id: REIN-OW-WP-0001-T01 status: done priority: high state_hub_task_id: "e13d28f0-b203-4af4-8f32-0a60fbe9eee0" ``` ## Task: Minimal agentic loop Implemented in `loop.py` + `tools.py`: plan → tool call → observe → repeat with a hard tool allow-list matching rein-aharness's `green-commit-only` (`read_file`/`write_file`/`edit_file`/`glob_files`/ `grep_files` + `git_status`/`git_diff`/`git_log`/`git_add_commit`, no push/network/shell), bounded by `max_turns` and a token budget. Budget tracker is vendored locally (`budget.py`), not `llm-connect`'s — consistent with T01/ADR-002 keeping llm-connect optional. Path-traversal guarded (`_resolve`); tool errors are reported back to the model as a `role: tool` message rather than crashing the loop. 26 tests, all mocked at the `httpx`/subprocess boundary. ```task id: REIN-OW-WP-0001-T02 status: done priority: high state_hub_task_id: "4fd66d93-9b83-4418-849b-3ed517e08203" ``` ## Task: Success criterion + reporting Implemented in `runner.py`/`hub.py`: a local git commit is the sole success signal (`RunResult.ok == committed`), State Hub progress event (`executor_run`) and token event posted on completion via a hub module mirroring rein-aharness's, `--no-hub` to skip. Not yet exercised against a live State Hub call in this pass (mocked in tests) — same caveat as rein-aharness/glas-harness's own not-yet-live-run notes elsewhere in this rein family. ```task id: REIN-OW-WP-0001-T03 status: done priority: medium state_hub_task_id: "3d23058d-4368-4319-8929-6df294cf1ed5" ``` ## Task: Credential brokering Resolved by glas-harness `docs/adr/ADR-002-credential-brokering-and-composable-reins.md` (Option B): rein-openweights acquires its own OpenRouter credential. Implemented in `credentials.py`, mirroring rein-aharness's mailscan.py OpenBao AppRole/ambient-token pattern (explicit env var → AppRole exchange → ambient token → single `kv get`). glas-harness does not broker this. ```task id: REIN-OW-WP-0001-T04 status: done priority: medium state_hub_task_id: "d7d35b1b-8381-4b18-958d-101216439458" ``` ## Task: Forgejo repo creation Operator created `coulomb/rein-openweights.git` on Forgejo (stub with LICENSE + README). Local history merged in with `--allow-unrelated-histories` (kept the local README, took the stub's MIT LICENSE — matches the sibling rein repos), pushed to `origin/main`, registered with State Hub (`domain: infotech`, `wp-prefix: REIN-OW`). Repo is no longer local-only. ```task id: REIN-OW-WP-0001-T05 status: done priority: low state_hub_task_id: "ae2f0032-2be8-42db-9c82-31ce1042a039" ```