# TASK: MOPAC self-host core — `harness loop` replaces the bash stack ## Context Charles (2026-08-28 ~21:30): "get to be self hosting asap — smallest core that can bootstrap itself (redmine/gitea interaction fine, discourse later)" and "moving away from the brittle _crossfeed setup and doorbell PMO<->work channel". The MVP bar is already met (`harness once --demo` live, REPORT in reports/). This turn makes the harness drive ITSELF: Redmine is the SoR, the conductor is the worker, no bash middle layer. ## What dies (list explicitly in REPORT, do not delete yet) - `/home/_crossfeed/tooling/agent-stack/semaphore.sh` + slot-file cap (replaced by in-process concurrency limit) - `~/.coordinate/scripts/queue-next.sh`, `queue-after.sh`, `pmo-heartbeat.sh` (replaced by the loop + its own wake discipline) - dispatch-turn.sh doorbell `screen -S reachableceo-PMO -X stuff` — note: this doorbell is ALREADY dead (screen is named RCEO-PMO, message silently dropped). Mention in REPORT; deletion happens after Charles signs off. ## Scope — smallest self-bootstrapping core 1. `harness loop` subcommand (Go, stdlib only, chainable with `once`): - Poll Redmine intake (existing `/issues.json` query) on interval (config, default 120s). `--once` flag = single scan (cron-able). - For each new/updated task issue not yet processed: run the bounded turn (existing conductor), then write REPORT back (existing Redmine note writeback — currently stubbed; implement the note POST) and update issue status per config map (e.g. In Progress -> Done). - State: append-only JSONL (one event per dispatch/report), dedup by issue id + updated_on. No _crossfeed paths, no slot files. - v0 = SEQUENTIAL turns (one at a time). Concurrency knob can come later. - Gitea: optional REPORT commit step behind config flag (off by default). Discourse: out of scope. 2. Credentials: harness.toml `key_ref` gains `mpk:` scheme → POST to keyproxy `/v1/resolve` (see ukrrs/mopac-keyproxy, built tonight). `env:` / `file:` refs keep working as fallback, so the loop runs with or without keyproxy up. Do not hardcode hosts — all in harness.toml. 3. `harness loop` supervises ITS OWN turns; PMO (me) verifies REPORTs and archives. The loop logs one line per action to stdout + JSONL. ## Build discipline - ALL DEV IN DOCKER: digest-pinned golang:1.26 builder, bind-mounted repo, Makefile build/vet/test through docker run. No host Go toolchain. - Docs standard applies (README status table + config reference update). - Tests: loop end-to-end against a fake Redmine HTTP server (pattern exists in internal/loop tests) — dispatch, dedup, writeback, status map. ## Deliverables - Commits + push to ukrrs/MOPAC main. - `REPORT-20260828-2131-selfhost-core.md` in `~/.coordinate/inbox-pmo/`: what runs, exact command to start the loop, what it replaces (the die list), how to roll back (just stop the loop, bash stack still present). ## Added by PMO (21:30, post docs-turn rot finding) - Rename Go module path `reachableceo/...` -> `ukrrs.com/mopac/...` or similar (go.mod module line + all internal imports). Mechanical, verify with build+vet+test in the Docker builder. Cited as doc rot in docs-standards REPORT; folding here since it is a source change.