activity-core/docs/llm-connect-host-access.md
tegwick 7711bf9c70
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 20s
feat(ops): run artefacts in API/UI + llm-connect host access design
ACTIVITY-WP-0027: document durable ClusterIP host access for llm-connect;
join activity_runs to ops_runs; surface Forgejo artefact links on
/ops/ui automation detail and new run detail pages.
2026-08-05 17:23:02 +02:00

73 lines
2.6 KiB
Markdown

# llm-connect host access (ACTIVITY-WP-0027)
**Audience:** operators on railiance01
**Status:** decision locked 2026-08-05
## Problem
rein-aharness runs on the **host** (user systemd claim loop) and must call:
| Service | In-cluster DNS | Used for |
| ------- | -------------- | -------- |
| `llm-connect` | `llm-connect.activity-core.svc.cluster.local:8080` | FI / Binky LLM |
| `actcore-api` | `actcore-api.activity-core.svc.cluster.local:8010` | claim / complete |
| `actcore-statehub-edge-relay` | `…:8000` | progress / completion events |
Historically the claim-loop env pointed at `http://127.0.0.1:8080` and
`http://127.0.0.1:8010` via ad-hoc **`kubectl port-forward`**. That dies on
reboot or PF process exit while k3s and the claim loop keep running.
## Decision (H2 — ClusterIP via kube-proxy)
On single-node k3s (railiance01), the **host can reach Service ClusterIPs**
directly through kube-proxy. No port-forward required.
```text
rein-aharness@host
→ http://<clusterIP>:8080 llm-connect
→ http://<clusterIP>:8010 actcore-api
→ http://<clusterIP>:8000 statehub edge relay
```
**Not chosen**
| Option | Why not |
| ------ | ------- |
| Long-lived kubectl port-forward | Not production; fails silently |
| Public Ingress / NodePort for llm-connect | Exposes LLM proxy surface |
| Move claim loop fully in-cluster | Domain checkouts live on host disk today (repos under `$HOME`) |
## How URLs are set
1. **Preferred:** claim-loop env uses `k8s://activity-core/<svc>:<port>` pseudo-URLs.
The `rein-aharness-claim` wrapper resolves them at process start via
`kubectl get svc` (requires `KUBECONFIG` readable by the user).
2. **Fallback:** concrete `http://10.43.x.x:port` ClusterIPs (stable until the
Service object is recreated).
3. **Refresh:** `deploy/scripts/refresh-claim-loop-k8s-urls.sh` on rein-aharness
rewrites concrete IPs from live Services.
## Health checks (host)
```bash
# After claim wrapper resolves k8s:// URLs into the process env:
curl -sS "$LLM_CONNECT_URL/health"
curl -sS "$ACTIVITY_CORE_URL/health"
curl -sS "${STATE_HUB_URL%/}/edge/health" # if using edge relay
```
## Security
- ClusterIP ranges are not published on the Internet; they are cluster-local.
- Do not change `llm-connect` Service type to `LoadBalancer` / public NodePort
without a separate security review.
- Worker token for actcore-api stays in `~/.config/rein-aharness/claim-loop.env`
(mode 600), never git.
## Ownership
| Piece | Owner |
| ----- | ----- |
| In-cluster llm-connect Deployment | activity-core / railiance k8s |
| Host claim loop + URL resolution | rein-aharness |
| This decision doc | activity-core (ACTIVITY-WP-0027-T01) |