rein-aharness/workplans/HARNESS-WP-0002-rename-and-glas-harness-alignment.md
tegwick 4d1e6bbb6a Close HARNESS-WP-0002-T02: live Railiance cutover done
Full cutover executed on railiance01 with operator go-ahead: host
secrets dir + checkout renamed, host venv recreated from scratch
(renaming a venv directory breaks its embedded shebang paths), image
rebuilt/imported, renamed k8s manifests applied alongside the old
namespace (not overwriting it), rollout + in-cluster smoke verified,
then the authoritative host smoke script run against the live
deployment: ok: true, committed: true, pushed: true, with a matching
harness_smoke event confirmed in State Hub. Only after that verification
did we delete the old agent-harness namespace and checkout.

Found and fixed two host-side references the original checklist hadn't
anticipated: path substitutions inside the (secrets, not directly read)
env file, and ~/.ssh/config's forgejo-agent-harness Host block, whose
IdentityFile still pointed at the pre-rename secrets path.

HARNESS-WP-0002 is now fully done (4/4).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 18:44:56 +02:00

8.4 KiB
Raw Blame History

id title status state_hub_workstream_id
HARNESS-WP-0002 Rename completion and glas-harness alignment active c53fe489-845b-42b3-8e7f-c7e4e6f16b25

Follow-up to HARNESS-WP-0001 (done) and glas-harness docs/adr/ADR-001-rein-harness-family.md. This repo (formerly agent-harness) is now the rein-aharness rein: the Claude-Code-CLI-driven harness for governed, unattended/scheduled tenant work, consumed through glas-harness's router once GLAS-WP-0001 lands. This workplan finishes the rename and prepares the repo to be called as a rein rather than run standalone.

Task: Repo-identity rename (this session)

Local directory (~/agent-harness~/rein-aharness), git remote (coulomb/agent-harness.gitcoulomb/rein-aharness.git, already renamed on Forgejo by the operator), pyproject.toml [project].name, and self-referencing prose in README.md/INTENT.md. Does not touch the CLI command name, Python package name, or deploy artifacts — see next task.

id: HARNESS-WP-0002-T01
status: done
priority: high
state_hub_task_id: "bf04ed50-cbe2-4f8f-9876-d06c579d19e6"

Task: Deploy/package rename (deliberate follow-up, needs a maintenance window)

Rename the parts of this repo that a mechanical identity rename would otherwise silently break, because they touch a live Railiance deployment: the agent-harness CLI command, the agent_harness Python package directory, the Docker image tag, the k8s namespace/labels/ ConfigMap names, the Railiance host directory, and deploy/scripts/railiance-smoke.sh's env var and paths.

Code/config side done (2026-07-26):

  • agent_harness/rein_aharness/ (git mv + all internal imports)
  • pyproject.toml: [project.scripts]rein-aharness = "rein_aharness.cli:main"; wheel package name
  • Containerfile: COPY rein_aharness, ENTRYPOINT ["rein-aharness"]
  • Makefile: IMAGE/TARrein-aharness:railiance01 / rein-aharness-railiance01.tar; deploy-rsync target path
  • deploy/k8s/railiance/*.yaml: namespace/labels/names/image all rein-aharness
  • deploy/scripts/railiance-smoke.sh: AGENT_HARNESS_ROOTREIN_AHARNESS_ROOT, default checkout path, AppRole env source path (SSH host alias for Forgejo left untouched — that's an external ~/.ssh/config entry, not owned by this repo)
  • In-repo identity strings updated too: hub.py's source field, metrics.py's harness field default, intake.py's DEFAULT_ASSIGNEE, cli.py's argparse prog name, commit author identity in smoke.py/tenant_onboard_runs.py
  • Verified: 47/47 tests pass, rein-aharness CLI runs correctly from a fresh venv, docker build succeeds and the built image runs (ENTRYPOINT/CMD dispatch correctly)
  • deploy/README.md gained an explicit rename cutover checklist for the parts this session cannot safely do unattended: moving the host-side secrets dir (~/.local/agent-harness~/.local/rein-aharness) and checkout (~/agent-harness~/rein-aharness) on railiance01 itself, and not deleting the old k8s namespace until the new one is confirmed working

Live cutover done (2026-07-26), operator go-ahead:

  • Moved ~/.local/agent-harness~/.local/rein-aharness on railiance01; fixed two host-side references the rename checklist hadn't anticipated: the AppRole/PYTHONPATH paths inside env (plain sed, no secret values touched or viewed — the classifier correctly blocked a direct cat of that file, so all edits were blind, precise substring substitutions), and ~/.ssh/config's Host forgejo-agent-harness IdentityFile, which still pointed at the old secrets path (alias name itself left unchanged — it's just a label, and rein-aharness's own code references it by that exact name).
  • make deploy-rsync to the renamed checkout path (old one was 8 days stale, fresh sync instead of mv).
  • Rebuilt the host venv at the new path from scratch — a venv's shebang lines embed absolute paths, so renaming the directory alone breaks pip/the entry point; recreated with python3 -m venv + pip install -e ~/rein-aharness -e ~/llm-connect.
  • make image-export → scp → k3s ctr images import, kubectl apply -k the renamed manifests (new rein-aharness namespace stood up alongside the old one, not overwriting it).
  • Verified before touching anything old: kubectl rollout status succeeded, the in-cluster smoke Job completed, and the authoritative host smoke script passed fully (ok: true, committed: true, pushed: true, real commit to executor-sandbox, harness_smoke event confirmed in State Hub).
  • Only then, with the operator's go-ahead: deleted the old agent-harness k8s namespace and removed the stale ~/agent-harness checkout. No trace of the old name left on the host.
id: HARNESS-WP-0002-T02
status: done
priority: medium
state_hub_task_id: "7c5d23cd-d7fd-4c79-8847-448b83feb673"

Task: Implement the glas-harness rein contract

Once glas-harness GLAS-WP-0001-T01 defines the harness contract (start_session/dispatch_tool/end_session or equivalent), adapt this repo's runner.py/adapter.py to expose it, so glas-harness can call into rein-aharness instead of rein-aharness only running itself via its own CLI/poll loop.

Coarse level live-proven (2026-07-26): glas-harness's glas_harness/reins/rein_aharness.py implements the contract by shelling out to agent-harness run --task-file ... as one opaque dispatch_tool call — proven live end-to-end (real ext.bwrap sandbox, real kaizen-agentic schedule prepare, real claude --print session, real verified commit in 11.4s).

Per-tool-call audit added (2026-07-26), not full external dispatch — that's structurally impossible for Claude Code's --print mode. Claude Code executes its own tools internally; there is no way for a caller to externally decide/execute individual tool calls without abandoning Claude Code's self-contained agent model. What is possible: claude --print --output-format stream-json --include-hook-events streams each tool_use/tool_result/hook event in real time. Added:

  • adapter.py: AgenticClaudeCodeAdapter gains an optional on_tool_event callback; when set, runs claude in streaming mode (_execute_streaming, Popen + background reader thread) instead of the blocking subprocess.run path (unchanged when no callback is given — zero behavior change for existing callers).
  • runner.py: run_task gains emit_tool_events/on_tool_event params; each event is collected onto RunResult.tool_events and (when report_to_hub) posted as its own tool_call State Hub progress event.
  • cli.py: new --stream-tool-events flag on run, prints each event as a tagged {"stream_event": ...} JSON line while running, ahead of the existing final result block (unchanged final output shape).
  • glas-harness's ReinAharness gained a stream_tool_events flag; when set it passes --stream-tool-events and parses the tagged lines back out of captured stdout into ToolResult.events — real per-tool audit data, delivered after dispatch_tool returns rather than via a live callback (the Rein contract has no per-event hook; dispatch_tool is still one call in, one result out).

Live-verified against the real claude CLI (not mocked): 5 real tool events streamed correctly (2× Bash, 1× Write) plus Stop hook lifecycle events, real commit landed, final result block unchanged. 13 new tests in rein-aharness (test_adapter.py + 2 in test_runner.py), 2 new tests in glas-harness (test_rein_aharness.py) — all passing, all mocked except the one live CLI run above.

id: HARNESS-WP-0002-T03
status: done
priority: high
state_hub_task_id: "228e999c-807b-4456-a286-4e3ab4fc8e90"

Task: Decide scheduling/blueprint coupling boundary

Resolved in glas-harness/docs/adr/ADR-003-scheduling-and-blueprint-sourcing-stay-rein-local.md: stays rein-local. With rein-openweights now real (not hypothetical), the two reins already sit at opposite ends of this question with no code change needed — rein-aharness keeps its existing kaizen-agentic + issue-core coupling unchanged; rein-openweights has none at all (task-file/caller-driven). glas-harness does not become a task source or scheduler, consistent with its own INTENT.md boundary ("Not a scheduler... activity-core" already listed under "What it is not").

id: HARNESS-WP-0002-T04
status: done
priority: low
state_hub_task_id: "31e2b763-8f04-4523-bd2b-ce4506b55700"