BINKY-WP-0006: retarget Railiance rhythm to llm-connect/OpenRouter
Some checks failed
Work Records / validate (push) Has been cancelled
Some checks failed
Work Records / validate (push) Has been cancelled
Reject Claude Code (or any coding agent) on railiance01. Mail-scan stays deterministic; triage/briefs use llm-connect HTTP → structured JSON → deterministic apply. Document in integrations/railiance-llm-rhythm.md and rewrite WP-0006 tasks accordingly; timers no longer require_claude.
This commit is contained in:
parent
5011e53090
commit
88a4886ea7
9 changed files with 252 additions and 63 deletions
|
|
@ -58,11 +58,11 @@ all `enabled: true`). Execution on Railiance:
|
|||
`23 8 * * 1-5 /home/worsch/binky-control/scripts/rhythm-session.sh # binky rhythm bridge`
|
||||
and pause railiance timers. Script kept for one month as break-glass.
|
||||
|
||||
**Known residual (BINKY-WP-0006):** activity-core `ISSUE_SINK_TYPE=state-hub`
|
||||
emits progress events, not claimable issue-core tasks; agentic daily/review
|
||||
on Railiance need `claude` CLI on that host (mail-scan is deterministic and
|
||||
already runs there). Until Claude is installed on railiance01, agentic slots
|
||||
may still be run from a laptop harness session with the same task files.
|
||||
**Known residual (BINKY-WP-0006):** finish **llm-connect / OpenRouter** path
|
||||
for mail triage + briefs on Railiance (structured LLM output + deterministic
|
||||
apply). **Do not** install Claude Code or another coding agent on railiance01.
|
||||
Mail-scan is already deterministic and proven there; see
|
||||
`integrations/railiance-llm-rhythm.md`.
|
||||
|
||||
## Weekly review (founder, ~15 min)
|
||||
|
||||
|
|
|
|||
|
|
@ -42,9 +42,10 @@ cd ~/binky-control && git pull
|
|||
|
||||
| Gap | Follow-up |
|
||||
| --- | --- |
|
||||
| No continuous harness consumer of state-hub sink emissions | BINKY-WP-0006 / harness intake |
|
||||
| No `claude` CLI on railiance01 (agentic daily/review fail-closed until installed) | BINKY-WP-0006 |
|
||||
| Host timers are interim dual of activity-core cron (not pure sink-driven) | retire timers when poller live |
|
||||
| Post-scan **triage** still assumes coding-agent session (Claude) | BINKY-WP-0006: **llm-connect → OpenRouter** + JSON apply (see `railiance-llm-rhythm.md`) |
|
||||
| Daily/review unattended without host coding agent | Same pattern via llm-connect |
|
||||
| Host timers dual activity-core schedules | Simplify once llm path is the only executor |
|
||||
| **Out of scope / rejected:** install Claude Code on railiance01 | — |
|
||||
|
||||
## Rollback
|
||||
|
||||
|
|
|
|||
106
integrations/railiance-llm-rhythm.md
Normal file
106
integrations/railiance-llm-rhythm.md
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
# Railiance rhythm via llm-connect (not a host coding agent)
|
||||
|
||||
> Status: design note 2026-07-21 (BINKY-WP-0006).
|
||||
> Supersedes the residual “install Claude on railiance01” idea from the
|
||||
> BINKY-WP-0004 cutover notes.
|
||||
|
||||
## Principle
|
||||
|
||||
**Railiance executes infrastructure + hosted LLM inference. It does not host
|
||||
Claude Code, Codex, or another interactive coding harness.**
|
||||
|
||||
| Layer | On Railiance | Not on Railiance |
|
||||
| --- | --- | --- |
|
||||
| Secrets | OpenBao AppRole / in-cluster Secret | Paste into chat |
|
||||
| Deterministic I/O | email-connect scan, git commit/push with deploy key | — |
|
||||
| LLM | **llm-connect → OpenRouter** (open-weights / cheap models) | Claude CLI agentic session |
|
||||
| Policy | Allow-listed apply steps (Blue/Green) | Model free-form shell |
|
||||
|
||||
This matches agent-harness INTENT (session policy shell) and llm-connect
|
||||
INTENT (provider abstraction): the **server profile** uses llm-connect HTTP;
|
||||
laptop coding agents remain optional for interactive work only.
|
||||
|
||||
## Mail path (canonical)
|
||||
|
||||
```text
|
||||
timer / CronJob
|
||||
→ agent-harness mail-scan # deterministic, AppRole IMAP
|
||||
→ agent-harness mail-triage # NEW: llm-connect JSON + apply
|
||||
→ hub progress + local commit
|
||||
```
|
||||
|
||||
### Phase 1 — scan (exists, proven)
|
||||
|
||||
- Module: `agent_harness/mailscan.py`
|
||||
- Creds: `tenants/binky/company-email/imap` via AppRole
|
||||
- Output: `mailmeta/reports/email-channel-evidence-report-*.csv`
|
||||
- Hub: `binky_mail_intake` with counts only
|
||||
|
||||
### Phase 2 — triage (to build)
|
||||
|
||||
1. **Prompt** (metadata only): newest CSV rows + current mail-log tail +
|
||||
queue templates.
|
||||
2. **llm-connect** `POST` (same contract as activity-core `llm_client.py`):
|
||||
- URL: `http://llm-connect.activity-core.svc.cluster.local:8080`
|
||||
- Provider: OpenRouter (already configured on railiance)
|
||||
- Model: cost-efficient; **prefer open-weights** (pick at T03; examples to
|
||||
evaluate: Llama/Qwen/Mistral class on OpenRouter — measure quality on
|
||||
fixture CSV before locking).
|
||||
3. **Response**: strict JSON, e.g.
|
||||
|
||||
```json
|
||||
{
|
||||
"log_entries": [
|
||||
{"date": "2026-07-21", "from": "…", "subject": "…", "action": "ignore|queue|suspicious"}
|
||||
],
|
||||
"queue_items": [],
|
||||
"notes": "one-line summary"
|
||||
}
|
||||
```
|
||||
|
||||
4. **Apply** (deterministic Python): append mail-log; add queue YAML only if
|
||||
schema-valid; **suspicious** → log only; `git commit`; hub event.
|
||||
5. **Never** pass message bodies to the model if the scanner can omit them;
|
||||
never execute model-suggested shell.
|
||||
|
||||
## Daily / weekly (same shape)
|
||||
|
||||
| Slot | Deterministic inputs | LLM output | Apply |
|
||||
| --- | --- | --- | --- |
|
||||
| Daily brief | queues, open risks, yesterday brief | structured sections | write `briefs/YYYY-MM-DD-daily-brief.md` + commit |
|
||||
| Weekly review | briefs week, SuccessMilestones | structured prep | write weekly prep file + commit |
|
||||
|
||||
No tool-using coding agent required if apply is code-owned.
|
||||
|
||||
## What already runs on railiance01
|
||||
|
||||
| Component | Status (2026-07-21) |
|
||||
| --- | --- |
|
||||
| `llm-connect` Deployment in `activity-core` | Running; OpenRouter; ConfigMap model `google/gemini-2.5-flash` (may change) |
|
||||
| OpenRouter API key Secret | Present (operator custody) |
|
||||
| `agent-harness mail-scan` on host | Proven |
|
||||
| Host systemd timers | Interim cadence; must call llm path, not `require_claude` |
|
||||
| Claude CLI on host | **Must not** become a dependency |
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Installing Claude Code / npm agent stacks on railiance for rhythm.
|
||||
- Defaulting `runner.run_task` to `AgenticClaudeCodeAdapter` for server Jobs.
|
||||
- Sending full email bodies or secrets to OpenRouter.
|
||||
- Dual “coding agent policy” vs “server policy” that drifts (same JSON schema
|
||||
and apply code for all environments).
|
||||
|
||||
## Implementation homes
|
||||
|
||||
| Work | Repo |
|
||||
| --- | --- |
|
||||
| HTTP adapter + mail-triage command + tests | **agent-harness** |
|
||||
| Model/profile ConfigMap, smoke | **llm-connect** / activity-core overlay |
|
||||
| Timers, binky task prompts, dogfood | **binky-control** (this doc + BINKY-WP-0006) |
|
||||
|
||||
## See also
|
||||
|
||||
- `integrations/executor-cutover-runbook.md` — cutover status
|
||||
- `workplans/BINKY-WP-0006-…` — tasks
|
||||
- llm-connect `docs/activity-core-llm-endpoint.md`
|
||||
- agent-harness `mailscan.py` two-phase header comment
|
||||
|
|
@ -19,4 +19,5 @@ systemctl --user enable --now binky-rhythm-mail.timer
|
|||
systemctl --user enable --now binky-rhythm-review.timer
|
||||
systemctl --user list-timers --all | grep binky-rhythm || true
|
||||
echo "Installed. Logs: ~/.cache/binky-control/rhythm/"
|
||||
echo "Agentic daily/review require: claude CLI on PATH. mail-scan does not."
|
||||
echo "Execution model: llm-connect/OpenRouter on cluster — NOT Claude CLI on host."
|
||||
echo "See integrations/railiance-llm-rhythm.md (BINKY-WP-0006)."
|
||||
|
|
|
|||
|
|
@ -28,10 +28,18 @@ require_repo() {
|
|||
git -C "${BINKY_REPO}" pull --ff-only --quiet origin main || log "WARN: pull failed (continuing on local)"
|
||||
}
|
||||
|
||||
require_claude() {
|
||||
if ! command -v claude >/dev/null 2>&1; then
|
||||
log "ERROR: claude CLI not on PATH — agentic rhythm cannot run on this host"
|
||||
log " residual: install Claude Code (or swap in a hosted agentic adapter) on railiance01"
|
||||
exit 2
|
||||
require_llm_connect() {
|
||||
# Server-side rhythm uses llm-connect HTTP (OpenRouter), never Claude CLI.
|
||||
if [[ -z "${LLM_CONNECT_URL:-}" ]]; then
|
||||
# In-cluster default when running inside k8s; host timers may override.
|
||||
export LLM_CONNECT_URL="${LLM_CONNECT_URL:-http://llm-connect.activity-core.svc.cluster.local:8080}"
|
||||
fi
|
||||
log "LLM_CONNECT_URL=${LLM_CONNECT_URL}"
|
||||
}
|
||||
|
||||
require_claude() {
|
||||
# Deprecated for Railiance. Kept only so old docs fail loudly with the right message.
|
||||
log "ERROR: Claude CLI is not the Railiance execution path (BINKY-WP-0006)."
|
||||
log "Use llm-connect/OpenRouter via agent-harness hosted adapters — see integrations/railiance-llm-rhythm.md"
|
||||
exit 2
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,14 @@ set -euo pipefail
|
|||
# shellcheck disable=SC1091
|
||||
source "$(dirname "$0")/run-common.sh"
|
||||
require_repo
|
||||
require_claude
|
||||
log "START daily-rhythm"
|
||||
agent-harness run \
|
||||
--task-file "${BINKY_REPO}/integrations/harness-tasks/daily-rhythm.json" \
|
||||
2>&1 | tee -a "${LOG_DIR}/daily.log"
|
||||
require_llm_connect
|
||||
log "START daily-rhythm (llm-connect path when available; else fail until BINKY-WP-0006)"
|
||||
# Prefer dedicated command once implemented; fall back message if only Claude runner exists.
|
||||
if agent-harness brief-daily --help >/dev/null 2>&1; then
|
||||
agent-harness brief-daily --target-repo "${BINKY_REPO}" \
|
||||
2>&1 | tee -a "${LOG_DIR}/daily.log"
|
||||
else
|
||||
log "ERROR: brief-daily not implemented yet (needs llm-connect structured apply — BINKY-WP-0006-T05)"
|
||||
exit 3
|
||||
fi
|
||||
log "END daily-rhythm rc=${PIPESTATUS[0]}"
|
||||
|
|
|
|||
|
|
@ -15,13 +15,14 @@ log "mail-scan rc=${scan_rc}"
|
|||
if [[ "${scan_rc}" -ne 0 ]]; then
|
||||
exit "${scan_rc}"
|
||||
fi
|
||||
# Agentic triage if Claude present; otherwise scan+hub event is enough for intake idempotence.
|
||||
if command -v claude >/dev/null 2>&1; then
|
||||
log "START mail-triage session"
|
||||
agent-harness run \
|
||||
--task-file "${BINKY_REPO}/integrations/harness-tasks/mail-intake.json" \
|
||||
2>&1 | tee -a "${LOG_DIR}/mail.log" || log "WARN: mail-triage session failed"
|
||||
# Triage must use llm-connect (OpenRouter), not a host coding agent.
|
||||
# Until agent-harness mail-triage exists (BINKY-WP-0006), scan-only is OK.
|
||||
if agent-harness mail-triage --help >/dev/null 2>&1; then
|
||||
log "START mail-triage (llm-connect)"
|
||||
agent-harness mail-triage \
|
||||
--target-repo "${BINKY_REPO}" \
|
||||
2>&1 | tee -a "${LOG_DIR}/mail.log" || log "WARN: mail-triage failed"
|
||||
else
|
||||
log "SKIP mail-triage session (no claude CLI); mail-scan hub event stands"
|
||||
log "SKIP mail-triage: command not available yet (BINKY-WP-0006); scan-only"
|
||||
fi
|
||||
log "END mail-intake"
|
||||
|
|
|
|||
|
|
@ -4,9 +4,13 @@ set -euo pipefail
|
|||
# shellcheck disable=SC1091
|
||||
source "$(dirname "$0")/run-common.sh"
|
||||
require_repo
|
||||
require_claude
|
||||
log "START review-prep"
|
||||
agent-harness run \
|
||||
--task-file "${BINKY_REPO}/integrations/harness-tasks/review-prep.json" \
|
||||
2>&1 | tee -a "${LOG_DIR}/review.log"
|
||||
require_llm_connect
|
||||
log "START review-prep (llm-connect path)"
|
||||
if agent-harness brief-weekly --help >/dev/null 2>&1; then
|
||||
agent-harness brief-weekly --target-repo "${BINKY_REPO}" \
|
||||
2>&1 | tee -a "${LOG_DIR}/review.log"
|
||||
else
|
||||
log "ERROR: brief-weekly not implemented yet (BINKY-WP-0006-T05)"
|
||||
exit 3
|
||||
fi
|
||||
log "END review-prep rc=${PIPESTATUS[0]}"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
id: BINKY-WP-0006
|
||||
type: workplan
|
||||
title: "Railiance rhythm: continuous intake + agentic runtime on host"
|
||||
title: "Railiance rhythm: llm-connect execution (no host coding agent)"
|
||||
domain: infotech
|
||||
repo: binky-control
|
||||
status: ready
|
||||
|
|
@ -12,19 +12,44 @@ updated: "2026-07-21"
|
|||
state_hub_workstream_id: "1c068209-c3f7-4445-82ed-f762a095120c"
|
||||
---
|
||||
|
||||
Close the residual gaps after BINKY-WP-0004 cutover so rhythm is fully
|
||||
unattended on Railiance without host-timer dual scheduling.
|
||||
Close residual gaps after BINKY-WP-0004 cutover so Binky rhythm runs
|
||||
**unattended on Railiance without installing Claude Code or any coding
|
||||
agent/harness shell on the host.**
|
||||
|
||||
## Context
|
||||
## Architectural decision (founder direction 2026-07-21)
|
||||
|
||||
- activity-core `ISSUE_SINK_TYPE=state-hub` posts **progress** events on emit
|
||||
(not claimable issue-core issues). agent-harness intake still polls issue-core.
|
||||
- agent-harness k8s deploy is `sleep infinity` (placeholder).
|
||||
- railiance01 host timers call task files directly (interim).
|
||||
- Agentic daily/review need `claude` CLI on railiance01 (absent as of 2026-07-21);
|
||||
mail-scan works via AppRole without Claude.
|
||||
| Wrong | Right |
|
||||
| --- | --- |
|
||||
| Install Claude CLI / coding agent on railiance01 | Use **llm-connect** (already in `activity-core` ns on railiance) via **OpenRouter** |
|
||||
| AgenticClaudeCodeAdapter as default on server | **Hosted text adapter** + **deterministic apply** of structured results |
|
||||
| Re-implement policy in every client | Keep Green/Blue rules in harness apply layer; model only classifies/drafts |
|
||||
|
||||
## Task: Choose emission → execution contract
|
||||
### Two-phase mail path (already half-built)
|
||||
|
||||
1. **Deterministic scan** (`agent-harness mail-scan`) — IMAP via AppRole, CSV
|
||||
under `mailmeta/reports/`, hub `binky_mail_intake` counts. **No LLM.**
|
||||
Proven on railiance01 2026-07-21.
|
||||
2. **Triage** — today wrongly defaults to Claude Code agentic session.
|
||||
**Target:** call in-cluster
|
||||
`http://llm-connect.activity-core.svc.cluster.local:8080` (OpenRouter,
|
||||
cost-efficient open-weights or cheap hosted model) → **JSON triage plan** →
|
||||
deterministic applier commits metadata-only queue/log updates.
|
||||
|
||||
Daily brief / weekly review follow the same pattern (structured draft →
|
||||
apply → commit), not a full IDE agent on the node.
|
||||
|
||||
### Existing platform assets
|
||||
|
||||
- llm-connect Deployment live on railiance01 (`LLM_CONNECT_PROVIDER=openrouter`,
|
||||
model currently `google/gemini-2.5-flash` in ConfigMap — may retarget to
|
||||
open-weights for cost).
|
||||
- OpenBao lane for OpenRouter key already used by that service
|
||||
(`llm-connect-provider-secrets` / CCR path under activity-core).
|
||||
- activity-core `llm_client.py` is the HTTP client pattern to reuse.
|
||||
- agent-harness `runner.py` already accepts an injected `adapter=` (swap
|
||||
default off Claude Code for server profiles).
|
||||
|
||||
## Task: Spec llm-connect mail-triage contract
|
||||
|
||||
```task
|
||||
id: BINKY-WP-0006-T01
|
||||
|
|
@ -33,17 +58,21 @@ priority: high
|
|||
state_hub_task_id: "912a8802-e80f-4c04-aecd-9586c3b7a4b0"
|
||||
```
|
||||
|
||||
Decide with activity-core / harness owners:
|
||||
Write `integrations/railiance-llm-rhythm.md` (or extend cutover runbook):
|
||||
|
||||
A) Restore opt-in `ISSUE_SINK_TYPE=rest` for Binky labels only, or
|
||||
B) Teach agent-harness to claim work from a state-hub work-record / task queue, or
|
||||
C) Keep host timers as the durable executor and demote activity-core schedules
|
||||
to observability-only for Binky.
|
||||
- Input: newest `mailmeta/reports/*.csv` (metadata columns only; no bodies).
|
||||
- Output JSON schema: log entries, queue candidates, suspicious flags
|
||||
(sender/subject/date only).
|
||||
- Model profile: OpenRouter **cost-efficient** default (prefer open-weights;
|
||||
name candidates + fallback); max tokens; temperature low.
|
||||
- Apply rules: Blue lane, no push, no network from apply step; suspicious
|
||||
mail never acted on.
|
||||
- Where it runs: railiance Job/CronJob or host timer calling
|
||||
`agent-harness mail-triage` (new subcommand), **not** Claude.
|
||||
|
||||
Record decision (DEC if founder-relevant) and update
|
||||
`integrations/executor-cutover-runbook.md`.
|
||||
Done when: doc reviewed against AutonomyPolicy + mailscan two-phase design.
|
||||
|
||||
## Task: Continuous consumer on Railiance
|
||||
## Task: Implement hosted triage path in agent-harness
|
||||
|
||||
```task
|
||||
id: BINKY-WP-0006-T02
|
||||
|
|
@ -52,10 +81,18 @@ priority: high
|
|||
state_hub_task_id: "00439d4e-d6ee-4cbc-98e2-431eca4651fe"
|
||||
```
|
||||
|
||||
Implement the chosen path: systemd/k8s poller loop, not `sleep infinity`.
|
||||
Health metrics + logs under `~/.cache/binky-control/rhythm/`.
|
||||
In **agent-harness** (implementation repo; this WP tracks binky integration):
|
||||
|
||||
## Task: Agentic runtime on railiance01
|
||||
1. `LlmConnectHttpAdapter` (or client matching activity-core `llm_client.py`)
|
||||
using `LLM_CONNECT_URL`.
|
||||
2. `mail-triage` command: read report → prompt → parse JSON → apply to
|
||||
`mailmeta/mail-log.md` + queues → local commit → hub event.
|
||||
3. Server profile default: **never** require `claude` CLI.
|
||||
4. Tests with fixture CSV + mock HTTP llm-connect.
|
||||
|
||||
Done when: unit tests green; dry-run docs for railiance.
|
||||
|
||||
## Task: Wire OpenRouter model profile on railiance llm-connect
|
||||
|
||||
```task
|
||||
id: BINKY-WP-0006-T03
|
||||
|
|
@ -64,11 +101,21 @@ priority: high
|
|||
state_hub_task_id: "1f82c8e0-945e-44b6-a5dc-22dd055e751d"
|
||||
```
|
||||
|
||||
Install and auth Claude Code (or approved hosted agentic adapter) on
|
||||
railiance01 so `run-daily.sh` / `run-review.sh` exit 0 unattended. Document
|
||||
in `integrations/executor-worker-secrets.md` if new secret lanes appear.
|
||||
On railiance01 activity-core llm-connect ConfigMap (and optional dedicated
|
||||
profile env for rhythm):
|
||||
|
||||
## Task: Retire dual scheduling
|
||||
- Confirm OpenRouter secret still healthy (no values in git/chat).
|
||||
- Choose cost-efficient model (open-weights preferred; document choice and
|
||||
$/MTok rationale).
|
||||
- Smoke: in-cluster request from a Job to llm-connect with a tiny prompt.
|
||||
- Expose URL to host timers if host-run:
|
||||
`LLM_CONNECT_URL=http://…` via cluster DNS or port-forward service policy
|
||||
(prefer **in-cluster CronJob** over host if possible).
|
||||
|
||||
Done when: smoke OK; ConfigMap change committed in llm-connect/activity-core
|
||||
overlays as appropriate.
|
||||
|
||||
## Task: Railiance schedule uses llm path; drop Claude residual
|
||||
|
||||
```task
|
||||
id: BINKY-WP-0006-T04
|
||||
|
|
@ -77,17 +124,33 @@ priority: medium
|
|||
state_hub_task_id: "2093bf62-20ef-4d3e-9b91-be77a38603f7"
|
||||
```
|
||||
|
||||
Once T01–T03 proven for three business days: remove host timers **or**
|
||||
disable redundant activity-core schedules so only one cadence owner remains.
|
||||
Update OperatingRhythm.md.
|
||||
Update `scripts/railiance-rhythm/run-mail.sh` to call `mail-scan` then
|
||||
`mail-triage` (llm-connect), remove `require_claude` for mail. Prefer
|
||||
migrating daily/review similarly or keep them laptop-optional until T05.
|
||||
|
||||
## Task: Closure
|
||||
Update OperatingRhythm.md + executor-cutover-runbook residual section:
|
||||
**no coding agent on railiance**.
|
||||
|
||||
## Task: Daily/review via llm-connect (optional same WP if small)
|
||||
|
||||
```task
|
||||
id: BINKY-WP-0006-T05
|
||||
status: todo
|
||||
priority: low
|
||||
priority: medium
|
||||
state_hub_task_id: "503ff56b-ac38-44b0-911e-937e0c2fc089"
|
||||
```
|
||||
|
||||
Mark finished; log milestone; `statehub fix-consistency`.
|
||||
Extend the same pattern to daily brief + weekly review prep: structured
|
||||
generation via llm-connect + deterministic markdown apply + commit. If scope
|
||||
grows, spawn BINKY-WP-0007 and mark this task done with handoff.
|
||||
|
||||
## Task: Closure
|
||||
|
||||
```task
|
||||
id: BINKY-WP-0006-T06
|
||||
status: todo
|
||||
priority: low
|
||||
```
|
||||
|
||||
Three clean unattended mail cycles on railiance (scan+triage); milestone;
|
||||
`statehub fix-consistency`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue