Rename package, CLI, and deploy artifacts to rein-aharness (HARNESS-WP-0002-T02)

agent_harness -> rein_aharness (package + all imports), CLI command
agent-harness -> rein-aharness, Docker image tag, k8s namespace/labels/
names, Makefile targets, deploy script env var/paths. In-repo identity
strings (hub event source, metrics harness field, default assignee,
argparse prog name, commit author identity) updated to match.

Historical documents left untouched on purpose: docs/adr/ADR-001-agent-harness-architecture.md,
docs/architecture.md (dated v0.1 snapshot), workplans/HARNESS-WP-0001
(completed under the old name), and the SSH host alias
"forgejo-agent-harness" (external ~/.ssh/config entry, not owned here).

Verified: 47/47 tests pass, CLI runs correctly from a fresh venv,
`make image` builds and the resulting container runs correctly.

deploy/README.md gained an explicit rename cutover checklist for what
this session cannot safely do unattended -- moving the host-side
secrets dir and checkout on railiance01, and not deleting the old k8s
namespace until the new one is confirmed working. The actual live
cutover (running that checklist against the real Railiance deployment)
is not attempted here -- real production surgery on binky-control's
live automation, needs the operator present.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-07-26 14:22:18 +02:00
parent 08327a34a4
commit f6930ad115
41 changed files with 214 additions and 158 deletions

View file

@ -1,5 +1,5 @@
# agent-harness — shared unattended agent runtime (Railiance / local).
# Build: docker build -f Containerfile -t agent-harness:local .
# rein-aharness — shared unattended agent runtime (Railiance / local).
# Build: docker build -f Containerfile -t rein-aharness:local .
# Optional llm-connect sibling: docker build --build-arg WITH_LLM_CONNECT=1 ...
FROM python:3.12-slim
@ -17,7 +17,7 @@ RUN apt-get update \
&& useradd -u 10001 -g 10001 -m -s /usr/sbin/nologin harness
COPY pyproject.toml README.md ./
COPY agent_harness ./agent_harness
COPY rein_aharness ./rein_aharness
# Populated by `make image` from ../llm-connect when present.
COPY llm_connect_vendor ./llm_connect_vendor
@ -31,5 +31,5 @@ RUN pip install --no-cache-dir "httpx>=0.27" "PyYAML>=6.0" \
USER 10001:10001
# No long-running HTTP API yet — image is invoked as CLI (run / smoke / validate).
ENTRYPOINT ["agent-harness"]
ENTRYPOINT ["rein-aharness"]
CMD ["profiles"]

View file

@ -1,8 +1,8 @@
.PHONY: test image image-export deploy-rsync help
UV ?= $(shell command -v uv 2>/dev/null || echo uv)
IMAGE ?= agent-harness:railiance01
TAR ?= /tmp/agent-harness-railiance01.tar
IMAGE ?= rein-aharness:railiance01
TAR ?= /tmp/rein-aharness-railiance01.tar
help: ## Show targets
@grep -Eh '^[a-zA-Z_-]+:.*?##' $(MAKEFILE_LIST) | \
@ -26,8 +26,8 @@ image-export: image ## Save image tar for k3s import
docker save -o $(TAR) $(IMAGE)
@ls -lh $(TAR)
deploy-rsync: ## Rsync tree to railiance01:~/agent-harness
deploy-rsync: ## Rsync tree to railiance01:~/rein-aharness
rsync -az --delete \
--exclude '.git' --exclude '__pycache__' --exclude '.pytest_cache' \
--exclude 'llm_connect_vendor' --exclude '*.egg-info' \
./ railiance01:agent-harness/
./ railiance01:rein-aharness/

View file

@ -14,14 +14,17 @@ tenants that need governed cron-style agent runs. See
[glas-harness ADR-001](../glas-harness/docs/adr/ADR-001-rein-harness-family.md)
for how it relates to other reins (e.g. `rein-openweights`).
The CLI command (`agent-harness`), Python package (`agent_harness`), and
deploy artifacts (Docker image tag, k8s namespace, Railiance host paths)
still use the old name — that rename is tracked separately in
[workplans/REIN-A-WP-0002](workplans/REIN-A-WP-0002-rename-and-glas-harness-alignment.md)
because it touches a live Railiance deployment.
The CLI command (`rein-aharness`) and Python package (`rein_aharness`) are
renamed. Deploy artifacts (Docker image tag, k8s namespace, Railiance host
paths) are renamed in this repo too, but the live Railiance cutover itself
(moving the host-side checkout + secrets dir, redeploying) is a separate,
deliberate step — tracked in
[workplans/HARNESS-WP-0002](workplans/HARNESS-WP-0002-rename-and-glas-harness-alignment.md)
and [deploy/README.md](deploy/README.md)'s rename cutover checklist.
- Why and boundaries: [INTENT.md](INTENT.md)
- Decision + architecture: [docs/adr/ADR-001](docs/adr/ADR-001-agent-harness-architecture.md),
- Decision + architecture: [docs/adr/ADR-001](docs/adr/ADR-001-agent-harness-architecture.md)
(kept under its original filename — it documents the pre-rename decision),
[docs/architecture.md](docs/architecture.md)
- Current work: [workplans/](workplans/)
@ -29,33 +32,33 @@ because it touches a live Railiance deployment.
```
# Validate a consuming repo's instance manifest (.kaizen/schedule.yml)
agent-harness validate --target ~/binky-control
agent-harness validate --target ~/binky-control --strict # require harness fields
rein-aharness validate --target ~/binky-control
rein-aharness validate --target ~/binky-control --strict # require harness fields
# List named tool profiles
agent-harness profiles
rein-aharness profiles
# Run exactly one task (local JSON task-file path — dev)
agent-harness run --task-file examples/task-hello-sandbox.json [--no-hub] [--no-metrics]
rein-aharness run --task-file examples/task-hello-sandbox.json [--no-hub] [--no-metrics]
# Production intake: poll issue-core (activity-core emissions), claim, run, close
export ISSUE_CORE_URL=http://127.0.0.1:8765 ISSUE_CORE_API_KEY=…
agent-harness poll
agent-harness run --from-issue-core
rein-aharness poll
rein-aharness run --from-issue-core
# Deterministic mailbox scan (no LLM session)
agent-harness mail-scan --target-repo ~/binky-control
rein-aharness mail-scan --target-repo ~/binky-control
# Mail triage via llm-connect HTTP (OpenRouter behind the service; no Claude CLI)
export LLM_CONNECT_URL=http://llm-connect.activity-core.svc.cluster.local:8080
agent-harness mail-triage --target-repo ~/binky-control
rein-aharness mail-triage --target-repo ~/binky-control
# Daily brief via llm-connect (structured JSON → briefs/YYYY-MM-DD-daily-brief.md)
agent-harness brief-daily --target-repo ~/binky-control
rein-aharness brief-daily --target-repo ~/binky-control
# Railiance packaging smoke (commit + optional push + hub; no Claude required)
agent-harness smoke --work-dir ~/work/executor-sandbox
rein-aharness smoke --work-dir ~/work/executor-sandbox
```
Railiance deploy: [deploy/README.md](deploy/README.md).

View file

@ -20,7 +20,7 @@
| task | HARNESS-WP-0001-T07 | done | — | workplans/HARNESS-WP-0001-harness-foundation.md |
| task | HARNESS-WP-0002-T01 | done | — | workplans/HARNESS-WP-0002-rename-and-glas-harness-alignment.md |
| task | HARNESS-WP-0002-T02 | todo | — | workplans/HARNESS-WP-0002-rename-and-glas-harness-alignment.md |
| task | HARNESS-WP-0002-T03 | todo | — | workplans/HARNESS-WP-0002-rename-and-glas-harness-alignment.md |
| task | HARNESS-WP-0002-T03 | progress | — | workplans/HARNESS-WP-0002-rename-and-glas-harness-alignment.md |
| task | HARNESS-WP-0002-T04 | todo | — | workplans/HARNESS-WP-0002-rename-and-glas-harness-alignment.md |
| task | REIN-A-0001-T01 | todo | — | workplans/REIN-A-0001-statehub-bootstrap.md |
| task | REIN-A-0001-T02 | todo | — | workplans/REIN-A-0001-statehub-bootstrap.md |

View file

@ -3,6 +3,25 @@
Single shared harness instance on **railiance01**. Secrets stay on the host
(Lanes 23); the container image is the portable runtime package.
> **Renamed from agent-harness (HARNESS-WP-0002-T02).** Image tag, k8s
> namespace/labels, CLI command, and Python package are all renamed in
> this repo already. The commands below assume the **rename cutover
> checklist** just below has been done on railiance01 first — this is a
> live production deployment for `binky-control`, so the cutover itself
> is deliberately not automated from a workstation session.
## Rename cutover checklist (do this on railiance01 before redeploying)
1. Move the host-side secrets dir: `mv ~/.local/agent-harness ~/.local/rein-aharness`
(or symlink, if anything else still reads the old path).
2. Move/rename the checkout: `mv ~/agent-harness ~/rein-aharness` (or a fresh
`deploy-rsync` to the new path — see Makefile).
3. Verify no other host cron/systemd unit still references
`~/agent-harness` or the `agent-harness` command directly.
4. Once the above is done, `kubectl delete namespace agent-harness` **after**
confirming the new `rein-aharness` namespace deploys and smokes clean —
don't delete the old one first, in case cutover needs a rollback.
## Layout
| Path | Role |
@ -10,31 +29,31 @@ Single shared harness instance on **railiance01**. Secrets stay on the host
| `Containerfile` | Image: Python CLI + git + openssh; optional vendored llm-connect |
| `deploy/k8s/railiance/` | Namespace, ConfigMap, Deployment, smoke Job |
| `deploy/scripts/railiance-smoke.sh` | Host e2e: clone sandbox → commit → push → hub |
| `agent-harness smoke` | Deterministic smoke (no Claude Code required) |
| `rein-aharness smoke` | Deterministic smoke (no Claude Code required) |
## Prerequisites (done 2026-07-17)
## Prerequisites (done 2026-07-17, paths renamed per checklist above)
- Lane 2 deploy key on host + Forgejo write on `coulomb/executor-sandbox`
- Lane 3 AppRole under `~/.local/agent-harness/approle-binky-mail`
- `source ~/.local/agent-harness/env`
- Lane 3 AppRole under `~/.local/rein-aharness/approle-binky-mail`
- `source ~/.local/rein-aharness/env`
- Hub: `http://127.0.0.1:18000` (ops-bridge) or in-cluster `state-hub.state-hub.svc`
## Build & load image (workstation → railiance01)
```bash
# from agent-harness repo root
make image # tags agent-harness:railiance01
make image-export # /tmp/agent-harness-railiance01.tar
scp /tmp/agent-harness-railiance01.tar railiance01:/tmp/
ssh railiance01 sudo k3s ctr images import /tmp/agent-harness-railiance01.tar
# from rein-aharness repo root
make image # tags rein-aharness:railiance01
make image-export # /tmp/rein-aharness-railiance01.tar
scp /tmp/rein-aharness-railiance01.tar railiance01:/tmp/
ssh railiance01 sudo k3s ctr images import /tmp/rein-aharness-railiance01.tar
```
## Apply k8s
```bash
rsync -a deploy/k8s/railiance/ railiance01:agent-harness/deploy/k8s/railiance/
ssh railiance01 kubectl apply -k agent-harness/deploy/k8s/railiance/
ssh railiance01 kubectl -n agent-harness rollout status deploy/agent-harness
rsync -a deploy/k8s/railiance/ railiance01:rein-aharness/deploy/k8s/railiance/
ssh railiance01 kubectl apply -k rein-aharness/deploy/k8s/railiance/
ssh railiance01 kubectl -n rein-aharness rollout status deploy/rein-aharness
```
## Host smoke (authoritative e2e gate)
@ -42,7 +61,7 @@ ssh railiance01 kubectl -n agent-harness rollout status deploy/agent-harness
Full path uses the host deploy key and hub bridge:
```bash
ssh railiance01 'bash ~/agent-harness/deploy/scripts/railiance-smoke.sh'
ssh railiance01 'bash ~/rein-aharness/deploy/scripts/railiance-smoke.sh'
```
Expect: local commit + push to `executor-sandbox`, hub event `harness_smoke`,

View file

@ -1,7 +1,7 @@
apiVersion: v1
kind: Namespace
metadata:
name: agent-harness
name: rein-aharness
labels:
app.kubernetes.io/part-of: agent-harness
app.kubernetes.io/name: agent-harness
app.kubernetes.io/part-of: rein-aharness
app.kubernetes.io/name: rein-aharness

View file

@ -1,10 +1,10 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: agent-harness-config
namespace: agent-harness
name: rein-aharness-config
namespace: rein-aharness
labels:
app.kubernetes.io/name: agent-harness
app.kubernetes.io/name: rein-aharness
data:
# In-cluster State Hub (production). Host-level smoke may override to
# http://127.0.0.1:18000 (ops-bridge reverse tunnel to workstation hub).

View file

@ -3,32 +3,32 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: agent-harness
namespace: agent-harness
name: rein-aharness
namespace: rein-aharness
labels:
app.kubernetes.io/name: agent-harness
app.kubernetes.io/part-of: agent-harness
app.kubernetes.io/name: rein-aharness
app.kubernetes.io/part-of: rein-aharness
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: agent-harness
app.kubernetes.io/name: rein-aharness
template:
metadata:
labels:
app.kubernetes.io/name: agent-harness
app.kubernetes.io/part-of: agent-harness
app.kubernetes.io/name: rein-aharness
app.kubernetes.io/part-of: rein-aharness
spec:
securityContext:
fsGroup: 10001
containers:
- name: agent-harness
image: agent-harness:railiance01
- name: rein-aharness
image: rein-aharness:railiance01
imagePullPolicy: Never
command: ["sleep", "infinity"]
envFrom:
- configMapRef:
name: agent-harness-config
name: rein-aharness-config
resources:
requests:
cpu: 25m

View file

@ -4,10 +4,10 @@
apiVersion: batch/v1
kind: Job
metadata:
name: agent-harness-smoke
namespace: agent-harness
name: rein-aharness-smoke
namespace: rein-aharness
labels:
app.kubernetes.io/name: agent-harness
app.kubernetes.io/name: rein-aharness
app.kubernetes.io/component: smoke
spec:
ttlSecondsAfterFinished: 600
@ -15,7 +15,7 @@ spec:
template:
metadata:
labels:
app.kubernetes.io/name: agent-harness
app.kubernetes.io/name: rein-aharness
app.kubernetes.io/component: smoke
spec:
restartPolicy: Never
@ -23,13 +23,13 @@ spec:
fsGroup: 10001
containers:
- name: smoke
image: agent-harness:railiance01
image: rein-aharness:railiance01
imagePullPolicy: Never
args:
- "profiles"
envFrom:
- configMapRef:
name: agent-harness-config
name: rein-aharness-config
resources:
requests:
cpu: 50m

View file

@ -1,6 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: agent-harness
namespace: rein-aharness
resources:
- 00-namespace.yaml
- configmap.yaml

View file

@ -1,17 +1,22 @@
#!/usr/bin/env bash
# Host-level Railiance smoke for agent-harness (HARNESS-WP-0001-T06).
# Host-level Railiance smoke for rein-aharness (HARNESS-WP-0001-T06).
# Run on railiance01 after install. Uses deploy key + AppRole env + hub :18000.
#
# HARNESS-WP-0002-T02 rename: ROOT default and the AppRole env path below
# changed from agent-harness to rein-aharness. Both must exist under the
# NEW name on the host (checkout dir + ~/.local/rein-aharness/) before this
# script is deployed — see deploy/README.md "Rename cutover checklist".
set -euo pipefail
ROOT="${AGENT_HARNESS_ROOT:-$HOME/agent-harness}"
ROOT="${REIN_AHARNESS_ROOT:-$HOME/rein-aharness}"
# shellcheck disable=SC1090
source "${HOME}/.local/agent-harness/env"
source "${HOME}/.local/rein-aharness/env"
export STATE_HUB_URL="${STATE_HUB_URL:-http://127.0.0.1:18000}"
export PATH="${HOME}/.local/bin:${PATH}"
export PYTHONPATH="${ROOT}:${HOME}/llm-connect${PYTHONPATH:+:$PYTHONPATH}"
cd "$ROOT"
if ! command -v agent-harness >/dev/null 2>&1; then
if ! command -v rein-aharness >/dev/null 2>&1; then
python3 -m pip install --user -e . -q
fi
@ -19,6 +24,6 @@ echo "STATE_HUB_URL=$STATE_HUB_URL"
curl -sS -m 5 "$STATE_HUB_URL/state/health" || curl -sS -m 5 "${STATE_HUB_URL%/}/" || true
echo
agent-harness smoke \
rein-aharness smoke \
--work-dir "${HOME}/work/executor-sandbox" \
--remote "ssh://git@forgejo-agent-harness/coulomb/executor-sandbox.git"

View file

@ -10,7 +10,7 @@
```
**Same file as ADR-005.** kaizen-agentic owns the base schedule keys;
agent-harness owns the extension keys below. A sibling file is reserved
rein-aharness owns the extension keys below. A sibling file is reserved
only if kaizen owners later prefer hard separation — until then, one
manifest keeps cadence and runtime policy colocated.
@ -18,8 +18,8 @@ Validate:
```bash
kaizen-agentic schedule validate --target <repo> # base ADR-005 keys
agent-harness validate --target <repo> # base + harness extensions
agent-harness validate --target <repo> --strict # require harness fields on enabled agents
rein-aharness validate --target <repo> # base + harness extensions
rein-aharness validate --target <repo> --strict # require harness fields on enabled agents
```
## Schema
@ -39,12 +39,12 @@ agent-harness validate --target <repo> --strict # require harness fields on e
| `agents.<name>.budget` | harness | no | int | Token cap per run (positive) |
| `agents.<name>.harness` | harness | no | int | Per-agent major pin; overrides top-level |
\* Required for enabled agents under `agent-harness validate --strict`.
\* Required for enabled agents under `rein-aharness validate --strict`.
## Example (tenant-ready)
```yaml
# .kaizen/schedule.yml — ADR-005 + agent-harness extensions
# .kaizen/schedule.yml — ADR-005 + rein-aharness extensions
version: "1"
timezone: Europe/Berlin
harness: 0
@ -75,7 +75,7 @@ agents:
## Tool profiles
Defined **only** in agent-harness (see `agent_harness/profiles.py`).
Defined **only** in rein-aharness (see `rein_aharness/profiles.py`).
Manifests reference them by name; unknown names refuse to run.
| Name | Lane | Session tools |
@ -99,7 +99,7 @@ deliberate.
## Relationship to task files
Local development may still use JSON task files (`agent-harness run
Local development may still use JSON task files (`rein-aharness run
--task-file …`). When the target repo has a matching agent entry, the
runner resolves `tool_profile`, `budget`, and `lane` from the manifest;
otherwise it defaults to `green-commit-only` with no budget cap.

View file

@ -1,13 +1,13 @@
# Task intake (HARNESS-WP-0001-T03)
activity-core emits tasks via IssueSink → `POST /issues/` on **issue-core**.
agent-harness **consumes** them by polling the same service:
rein-aharness **consumes** them by polling the same service:
```
activity-core (cron/rule)
→ IssueCoreRestSink POST /issues/
→ issue-core backend (sqlite / gitea)
agent-harness poll/claim GET+PATCH /issues/
rein-aharness poll/claim GET+PATCH /issues/
→ run_task (profile + budget + persona + session)
→ PATCH close + hub progress + .kaizen/metrics
```
@ -17,8 +17,8 @@ activity-core (cron/rule)
## Mail path (server / Railiance)
```
agent-harness mail-scan # deterministic IMAP (AppRole)
agent-harness mail-triage # llm-connect HTTP → JSON → apply mail-log + commit
rein-aharness mail-scan # deterministic IMAP (AppRole)
rein-aharness mail-triage # llm-connect HTTP → JSON → apply mail-log + commit
```
Requires `LLM_CONNECT_URL` (e.g. in-cluster
@ -45,14 +45,14 @@ export ISSUE_CORE_API_KEY=…
export AGENT_HARNESS_REPO_MAP='{"binky-control":"/home/tegwick/binky-control"}'
# Peek / claim without executing
agent-harness poll
agent-harness poll --no-claim
rein-aharness poll
rein-aharness poll --no-claim
# Claim → run → close (or reopen on failure)
agent-harness run --from-issue-core
rein-aharness run --from-issue-core
# Local dev (unchanged)
agent-harness run --task-file examples/task-hello-sandbox.json --no-hub
rein-aharness run --task-file examples/task-hello-sandbox.json --no-hub
```
## Label filter

View file

@ -1,7 +1,7 @@
# Example instance manifest (ADR-005 + agent-harness extensions).
# Example instance manifest (ADR-005 + rein-aharness extensions).
# Copy keys into a consuming repo's .kaizen/schedule.yml.
# Validate with:
# agent-harness validate --target <repo> --strict
# rein-aharness validate --target <repo> --strict
version: "1"
timezone: Europe/Berlin
harness: 0

View file

@ -9,7 +9,7 @@ dependencies = [
]
[project.scripts]
agent-harness = "agent_harness.cli:main"
rein-aharness = "rein_aharness.cli:main"
[tool.uv.sources]
llm-connect = { path = "../llm-connect", editable = true }
@ -23,4 +23,4 @@ requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["agent_harness"]
packages = ["rein_aharness"]

View file

@ -20,7 +20,7 @@ from llm_connect.claude_code import ClaudeCodeAdapter
from llm_connect.exceptions import LLMSubprocessError, LLMTimeoutError
from llm_connect.models import LLMResponse, RunConfig
from agent_harness.profiles import ToolProfile, get_profile
from rein_aharness.profiles import ToolProfile, get_profile
# Backward-compatible alias for the seed profile allow-list string.
ALLOWED_TOOLS = get_profile("green-commit-only").allowed_tools

View file

@ -16,8 +16,8 @@ from pathlib import Path
from typing import Any, Callable
from zoneinfo import ZoneInfo
from agent_harness import hub
from agent_harness.llm_connect_client import (
from rein_aharness import hub
from rein_aharness.llm_connect_client import (
LLMConnectClient,
LLMConnectError,
get_llm_connect_client,

View file

@ -7,15 +7,15 @@ import json
import sys
from pathlib import Path
from agent_harness.manifest import (
from rein_aharness.manifest import (
ManifestError,
load_manifest_for_repo,
manifest_path,
validate_manifest,
)
from agent_harness.profiles import list_profiles
from agent_harness.runner import run_task
from agent_harness.taskspec import TaskSpec, TaskSpecError
from rein_aharness.profiles import list_profiles
from rein_aharness.runner import run_task
from rein_aharness.taskspec import TaskSpec, TaskSpecError
def _cmd_validate(args: argparse.Namespace) -> int:
@ -69,7 +69,7 @@ def _cmd_profiles(_args: argparse.Namespace) -> int:
def _cmd_poll(args: argparse.Namespace) -> int:
from agent_harness.intake import IntakeError, IssueCoreClient, poll_next
from rein_aharness.intake import IntakeError, IssueCoreClient, poll_next
try:
client = IssueCoreClient()
@ -100,7 +100,7 @@ def _cmd_poll(args: argparse.Namespace) -> int:
def _cmd_run(args: argparse.Namespace) -> int:
from agent_harness.intake import IntakeError, IssueCoreClient, poll_next
from rein_aharness.intake import IntakeError, IssueCoreClient, poll_next
issue_id: str | None = None
client: IssueCoreClient | None = None
@ -171,7 +171,7 @@ def _cmd_run(args: argparse.Namespace) -> int:
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(prog="agent-harness")
parser = argparse.ArgumentParser(prog="rein-aharness")
sub = parser.add_subparsers(dest="command", required=True)
run = sub.add_parser(
@ -305,7 +305,7 @@ def main(argv: list[str] | None = None) -> int:
return _cmd_run(args)
if args.command == "smoke":
from agent_harness.smoke import ensure_sandbox_clone, run_smoke
from rein_aharness.smoke import ensure_sandbox_clone, run_smoke
if args.target_repo:
repo = Path(args.target_repo).expanduser().resolve()
@ -348,7 +348,7 @@ def main(argv: list[str] | None = None) -> int:
return 0 if ok else 1
if args.command == "mail-triage":
from agent_harness.mail_triage import run_mail_triage
from rein_aharness.mail_triage import run_mail_triage
triage_result = run_mail_triage(
target_repo=Path(args.target_repo).expanduser(),
@ -377,7 +377,7 @@ def main(argv: list[str] | None = None) -> int:
if args.command == "brief-daily":
from datetime import date as date_cls
from agent_harness.brief_daily import run_brief_daily
from rein_aharness.brief_daily import run_brief_daily
day = None
if args.date:
@ -408,7 +408,7 @@ def main(argv: list[str] | None = None) -> int:
return 0 if brief_result.ok else 1
if args.command == "mail-scan":
from agent_harness.mailscan import run_mail_scan
from rein_aharness.mailscan import run_mail_scan
result = run_mail_scan(
target_repo=Path(args.target_repo).expanduser(),

View file

@ -71,7 +71,7 @@ def post_token_event(
payload: dict[str, Any] = {
"repo": repo,
"tokens": tokens,
"source": "agent-harness",
"source": "rein-aharness",
"ok": ok,
}
if budget is not None:

View file

@ -8,11 +8,11 @@ Environment:
ISSUE_CORE_URL default http://127.0.0.1:8765
ISSUE_CORE_API_KEY required for live poll
AGENT_HARNESS_INTAKE_LABELS comma list; issue must have ALL (default: automated)
AGENT_HARNESS_ASSIGNEE claim assignee (default: agent-harness)
AGENT_HARNESS_ASSIGNEE claim assignee (default: rein-aharness)
AGENT_HARNESS_REPO_MAP JSON object namepath, e.g. {"binky-control":"~/binky-control"}
AGENT_HARNESS_REPO_ROOTS colon-separated search roots (default: ~:~/work)
Local development still uses `agent-harness run --task-file `.
Local development still uses `rein-aharness run --task-file `.
"""
from __future__ import annotations
@ -25,11 +25,11 @@ from typing import Any
import httpx
from agent_harness.taskspec import TaskSpec, TaskSpecError
from rein_aharness.taskspec import TaskSpec, TaskSpecError
DEFAULT_ISSUE_CORE_URL = "http://127.0.0.1:8765"
DEFAULT_INTAKE_LABELS = ("automated",)
DEFAULT_ASSIGNEE = "agent-harness"
DEFAULT_ASSIGNEE = "rein-aharness"
DEFAULT_REPO_ROOTS = ("~", "~/work")
# activity-definition / label → (agent instance, completion_event_type)

View file

@ -1,7 +1,7 @@
"""HTTP client for in-cluster / remote llm-connect (server mode).
Mirrors activity-core's llm_client pattern: provider keys and model routing
stay behind llm-connect; agent-harness only sends prompts over HTTP.
stay behind llm-connect; rein-aharness only sends prompts over HTTP.
"""
from __future__ import annotations

View file

@ -22,8 +22,8 @@ from datetime import date
from pathlib import Path
from typing import Any, Callable
from agent_harness import hub
from agent_harness.llm_connect_client import (
from rein_aharness import hub
from rein_aharness.llm_connect_client import (
LLMConnectClient,
LLMConnectError,
get_llm_connect_client,

View file

@ -9,7 +9,7 @@ agentic session's tool allow-list:
metadata-only counts. Credential values live exclusively in the child
process environment never in argv, logs, hub events, or files.
2. **Triage** (``agent-harness mail-triage``): llm-connect HTTP (OpenRouter
2. **Triage** (``rein-aharness mail-triage``): llm-connect HTTP (OpenRouter
behind the service) returns structured JSON; deterministic apply updates
mailmeta/mail-log.md and commits. No Claude Code / host coding agent.
Suspicious-mail rule: log only, never act on content.
@ -29,7 +29,7 @@ import subprocess
from dataclasses import dataclass
from pathlib import Path
from agent_harness import hub
from rein_aharness import hub
_KV_PATH = "tenants/binky/company-email/imap"
_BAO_TIMEOUT = 30

View file

@ -2,7 +2,7 @@
Extends ADR-005 `.kaizen/schedule.yml` with harness fields. kaizen-agentic
owns the base keys (version, timezone, agents.<name>.{cadence,cron,enabled});
agent-harness owns the extension keys (lane, tool_profile, budget, harness,
rein-aharness owns the extension keys (lane, tool_profile, budget, harness,
optional blueprint). Same file no sibling manifest unless kaizen owners
later prefer separation.
@ -17,7 +17,7 @@ from typing import Any
import yaml
from agent_harness.profiles import PROFILES, UnknownToolProfileError, get_profile
from rein_aharness.profiles import PROFILES, UnknownToolProfileError, get_profile
MANIFEST_RELATIVE_PATH = Path(".kaizen") / "schedule.yml"
MANIFEST_VERSION = "1"

View file

@ -33,7 +33,7 @@ class ExecutionRecord:
committed: bool | None = None
head_after: str | None = None
reason: str | None = None
harness: str = "agent-harness"
harness: str = "rein-aharness"
def to_json_line(self) -> str:
data = asdict(self)

View file

@ -15,11 +15,11 @@ import time
from dataclasses import dataclass
from pathlib import Path
from agent_harness import hub, metrics
from agent_harness.manifest import resolve_run_policy
from agent_harness.persona import load_persona_bundle
from agent_harness.profiles import UnknownToolProfileError, get_profile
from agent_harness.taskspec import TaskSpec
from rein_aharness import hub, metrics
from rein_aharness.manifest import resolve_run_policy
from rein_aharness.persona import load_persona_bundle
from rein_aharness.profiles import UnknownToolProfileError, get_profile
from rein_aharness.taskspec import TaskSpec
PROMPT_TEMPLATE = """\
You are an unattended executor session (agent persona below, if any).
@ -104,7 +104,7 @@ def run_task(
)
if adapter is None:
from agent_harness.adapter import AgenticClaudeCodeAdapter
from rein_aharness.adapter import AgenticClaudeCodeAdapter
adapter = AgenticClaudeCodeAdapter(
workdir=spec.target_repo,

View file

@ -12,8 +12,8 @@ from dataclasses import dataclass
from datetime import datetime, timezone
from pathlib import Path
from agent_harness.runner import RunResult, run_task
from agent_harness.taskspec import TaskSpec
from rein_aharness.runner import RunResult, run_task
from rein_aharness.taskspec import TaskSpec
@dataclass
@ -35,7 +35,7 @@ class _CommittingSmokeAdapter:
self.prompts.append(prompt)
path = self.repo / "SMOKE.md"
path.write_text(
f"# agent-harness smoke\n\nstamp: {self.stamp}\n",
f"# rein-aharness smoke\n\nstamp: {self.stamp}\n",
encoding="utf-8",
)
subprocess.run(["git", "add", "SMOKE.md"], cwd=self.repo, check=True)
@ -43,9 +43,9 @@ class _CommittingSmokeAdapter:
[
"git",
"-c",
"user.email=agent-harness@railiance.local",
"user.email=rein-aharness@railiance.local",
"-c",
"user.name=agent-harness",
"user.name=rein-aharness",
"commit",
"-qm",
f"harness smoke: {self.stamp}",

View file

@ -19,8 +19,8 @@ _ROOT = Path(__file__).resolve().parents[1]
if str(_ROOT) not in sys.path:
sys.path.insert(0, str(_ROOT))
from agent_harness.runner import run_task
from agent_harness.taskspec import TaskSpec
from rein_aharness.runner import run_task
from rein_aharness.taskspec import TaskSpec
class EvidenceAdapter:
@ -47,9 +47,9 @@ class EvidenceAdapter:
[
"git",
"-c",
"user.email=agent-harness@local",
"user.email=rein-aharness@local",
"-c",
"user.name=agent-harness",
"user.name=rein-aharness",
"commit",
"-qm",
f"harness onboard: {self.slug}",

View file

@ -5,7 +5,7 @@ import subprocess
from datetime import date
from pathlib import Path
from agent_harness import brief_daily
from rein_aharness import brief_daily
def _git_repo(tmp_path: Path) -> Path:

View file

@ -7,7 +7,7 @@ from unittest.mock import MagicMock, patch
import pytest
from agent_harness.intake import (
from rein_aharness.intake import (
EmittedIssue,
IntakeConfig,
IssueCoreClient,
@ -16,7 +16,7 @@ from agent_harness.intake import (
poll_next,
resolve_target_repo,
)
from agent_harness.taskspec import TaskSpecError
from rein_aharness.taskspec import TaskSpecError
def _make_repo(tmp_path: Path, name: str = "binky-control") -> Path:
@ -110,7 +110,7 @@ def test_client_list_claim_close() -> None:
base_url="http://issue-core.test",
api_key="k",
require_labels=("automated",),
assignee="agent-harness",
assignee="rein-aharness",
)
client = IssueCoreClient(cfg)
@ -126,11 +126,11 @@ def test_client_list_claim_close() -> None:
"activity_definition_id": "binky-daily-rhythm",
}
]
claim_body = {**list_body[0], "state": "in_progress", "assignee": "agent-harness"}
claim_body = {**list_body[0], "state": "in_progress", "assignee": "rein-aharness"}
close_body = {**claim_body, "state": "closed"}
with patch("agent_harness.intake.httpx.get") as get_mock, patch(
"agent_harness.intake.httpx.patch"
with patch("rein_aharness.intake.httpx.get") as get_mock, patch(
"rein_aharness.intake.httpx.patch"
) as patch_mock:
get_resp = MagicMock()
get_resp.raise_for_status = MagicMock()

View file

@ -6,8 +6,8 @@ from pathlib import Path
import pytest
from agent_harness import mail_triage
from agent_harness.llm_connect_client import LLMConnectClient, LLMConnectError
from rein_aharness import mail_triage
from rein_aharness.llm_connect_client import LLMConnectClient, LLMConnectError
def _git_repo(tmp_path: Path) -> Path:
@ -166,7 +166,7 @@ def test_run_mail_triage_no_report(tmp_path: Path, monkeypatch) -> None:
def test_llm_connect_client_complete(monkeypatch) -> None:
import agent_harness.llm_connect_client as mod
import rein_aharness.llm_connect_client as mod
class FakeResp:
def raise_for_status(self) -> None:
@ -190,6 +190,6 @@ def test_llm_connect_client_complete(monkeypatch) -> None:
def test_get_client_requires_env(monkeypatch) -> None:
monkeypatch.delenv("LLM_CONNECT_URL", raising=False)
with pytest.raises(LLMConnectError, match="LLM_CONNECT_URL"):
from agent_harness.llm_connect_client import get_llm_connect_client
from rein_aharness.llm_connect_client import get_llm_connect_client
get_llm_connect_client()

View file

@ -5,7 +5,7 @@ from pathlib import Path
import pytest
from agent_harness import mailscan
from rein_aharness import mailscan
class FakeCompleted:

View file

@ -5,8 +5,8 @@ from pathlib import Path
import pytest
import yaml
from agent_harness.cli import main
from agent_harness.manifest import (
from rein_aharness.cli import main
from rein_aharness.manifest import (
HARNESS_MAJOR,
ManifestError,
load_manifest,
@ -14,7 +14,7 @@ from agent_harness.manifest import (
resolve_run_policy,
validate_manifest,
)
from agent_harness.profiles import UnknownToolProfileError, get_profile, list_profiles
from rein_aharness.profiles import UnknownToolProfileError, get_profile, list_profiles
def _write_manifest(tmp_path: Path, data: dict) -> Path:

View file

@ -3,7 +3,7 @@ from __future__ import annotations
import json
from pathlib import Path
from agent_harness.metrics import record_execution, regenerate_summary
from rein_aharness.metrics import record_execution, regenerate_summary
def test_record_execution_writes_jsonl_and_summary(tmp_path: Path) -> None:
@ -25,7 +25,7 @@ def test_record_execution_writes_jsonl_and_summary(tmp_path: Path) -> None:
assert rec["agent"] == "coach"
assert rec["success"] is True
assert rec["tokens"] == 100
assert rec["harness"] == "agent-harness"
assert rec["harness"] == "rein-aharness"
assert rec["metadata"]["task_title"] == "hello"
summary = json.loads(

View file

@ -7,9 +7,9 @@ from pathlib import Path
import pytest
import yaml
from agent_harness.manifest import HARNESS_MAJOR
from agent_harness.runner import RunResult, run_task
from agent_harness.taskspec import TaskSpec, TaskSpecError
from rein_aharness.manifest import HARNESS_MAJOR
from rein_aharness.runner import RunResult, run_task
from rein_aharness.taskspec import TaskSpec, TaskSpecError
def _make_repo(tmp_path: Path) -> Path:

View file

@ -3,7 +3,7 @@ from __future__ import annotations
import subprocess
from pathlib import Path
from agent_harness.smoke import run_smoke
from rein_aharness.smoke import run_smoke
def _make_repo(tmp_path: Path) -> Path:

View file

@ -33,19 +33,48 @@ state_hub_task_id: "bf04ed50-cbe2-4f8f-9876-d06c579d19e6"
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 (`pyproject.toml
[project.scripts]`, `agent_harness/cli.py` entry point), the
`agent_harness` Python package directory, the Docker image tag
(`agent-harness:railiance01`), the k8s namespace/labels/ConfigMap names
(`deploy/k8s/railiance/*.yaml`), the Railiance host directory
(`~/agent-harness/deploy/...`), and `deploy/scripts/railiance-smoke.sh`'s
`AGENT_HARNESS_ROOT` env var and SSH remote alias. Do this as one
reviewed change with a Railiance re-deploy and smoke-test run
immediately after, not as incidental cleanup.
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`/`TAR``rein-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_ROOT`
`REIN_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
**Still open — the actual live cutover:** running the checklist on
railiance01, rebuilding+importing the image there, applying the renamed
k8s manifests, and running the host smoke script against the live
deployment. Not attempted from this session — real production surgery
on `binky-control`'s live automation, needs the operator present for
the actual host-side moves and a confirmed rollback point.
```task
id: HARNESS-WP-0002-T02
status: todo
status: progress
priority: medium
state_hub_task_id: "7c5d23cd-d7fd-4c79-8847-448b83feb673"
```