rein-openweights/workplans/REIN-OW-WP-0001-bootstrap.md
tegwick 4ee612140b Bootstrap rein-openweights: minimal agentic loop over OpenRouter (REIN-OW-WP-0001)
Implements T01-T04:
- tools.py: green-commit-only-equivalent tool surface (read/write/edit/
  glob/grep + git status/diff/log/add+commit), path-traversal guarded.
- openrouter_client.py: own minimal chat-completions client — llm-connect's
  OpenRouterAdapter takes a single prompt string and never surfaces
  tool_calls, so it can't drive a multi-turn tool-calling loop without a
  breaking change to its frozen Core ABC. llm-connect stays an optional
  dependency (pyproject.toml), not load-bearing.
- loop.py: plan -> tool call -> observe -> repeat, budget- and
  turn-bounded, tool errors reported back to the model instead of
  crashing the loop.
- credentials.py: own OpenBao AppRole/ambient-token acquisition, per
  glas-harness ADR-002 (Option B) — glas-harness does not broker this.
- runner.py/hub.py: commit-verified success criterion + State Hub
  progress/token reporting, mirroring rein-aharness's model.

26 tests, all mocked at the httpx/subprocess boundary — no real
OpenRouter or OpenBao calls made. T05 (Forgejo repo creation) stays
open, deferred to the operator.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 13:37:09 +02:00

95 lines
3.4 KiB
Markdown

---
id: REIN-OW-WP-0001
title: "Bootstrap: minimal open-weight agentic loop"
status: proposed
---
First working milestone for rein-openweights: prove an agentic tool-use
loop against a current open-weight model via OpenRouter/llm-connect,
comparable in scope to rein-aharness's `green-commit-only` profile, ready
to implement the glas-harness rein contract once
`glas-harness/GLAS-WP-0001-T01` defines it.
## 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
```
## 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
```
## 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
```
## 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
```
## Task: Forgejo repo creation
This repo is local-only. Create `coulomb/rein-openweights.git` on
Forgejo and wire the remote once T02 has something worth pushing —
coordinate with the operator (repo creation is not something this
session can do unattended).
```task
id: REIN-OW-WP-0001-T05
status: todo
priority: low
```