diff --git a/handoffs/HANDOFF_TO_CODEX_BLENDER_MCP_AUDIT.md b/handoffs/HANDOFF_TO_CODEX_BLENDER_MCP_AUDIT.md new file mode 100644 index 00000000..c2894df2 --- /dev/null +++ b/handoffs/HANDOFF_TO_CODEX_BLENDER_MCP_AUDIT.md @@ -0,0 +1,200 @@ +# HANDOFF_TO_CODEX — Blender-MCP-Native audit (research only) + +> **Status:** READY for Codex pickup. Smallest scope of the overnight queue. No code changes — output is an ADR. +> +> **Sequence position:** Task 2 in overnight queue (after B5). +> +> **Owner:** `codex-impl-05`. +> +> **Estimated time:** 30-60 minutes. + +--- + +## 1. Mission + +Audit `https://github.com/rakaarwaky/blender-mcp-native` to determine whether it should be adopted as the canonical Blender integration path for Hermes3D. + +The current Hermes3D Blender integration is `03_implementation/src/hermes3d/adapters/blender_mcp.py` (the existing adapter). The proposed alternative — `rakaarwaky/blender-mcp-native` — claims to be "MCP-native" but its README on first inspection looked like a pasted Blender upstream README, which is suspicious. + +Output a decision ADR with one of FOUR verdicts: + +- **ADOPT** — adopt as primary Blender path, deprecate or wrap the existing adapter +- **FORK** — fork it, sandbox what's useful, harden licensing/security, expose only safe tools +- **REJECT** — don't adopt; stay with the existing adapter (use ONLY for content-based rejection: licensing-incompatible, security-unsafe, abandoned, or unrelated to its claims) +- **NEEDS-DEEPER-AUDIT** — couldn't reach a confident verdict in the time budget; recommend specific follow-up work (use for: repo unreachable, low-confidence after 60 min, novel security pattern that needs domain expert review) + +The architect (Claude) does NOT have a recommendation. You decide based on the audit. + +--- + +## 2. Claim + +```text +hermes_pick_task + owner=codex-impl-05 + prefer_task_id=H3D-BLENDER-AUDIT +``` + +Or fallback claim with `taskId=H3D-BLENDER-AUDIT`, `title=Audit blender-mcp-native for adoption`, `reason=Decide whether rakaarwaky/blender-mcp-native is safe to adopt or fork; output an ADR.` + +--- + +## 3. Branch + +`docs/blender-mcp-native-audit` from `develop`. + +--- + +## 4. Lock these exact 2 files + +```text +hermes_lock_files + owner=codex-impl-05 + taskId=H3D-BLENDER-AUDIT + ttlMinutes=90 + files=[ + "02_architecture/adr/ADR-014-blender-mcp-native-audit.md", + "00_overview/contract/ROADMAP.md" + ] +``` + +Both NEW files (ADR-014 doesn't exist yet; ROADMAP gets a new row referencing the decision). + +--- + +## 5. Audit checklist + +Spend 30-60 minutes investigating. Use online research agents if needed for narrow questions (e.g., "what does the Blender 4.2 GPL exception say about wrapping the Python API in an MCP server?"). + +### 5.1 What is it actually? + +- Clone `https://github.com/rakaarwaky/blender-mcp-native` to `./tmp/audit-blender-mcp-native` (workspace-relative; ensure `tmp/` is in `.gitignore` so the clone doesn't accidentally get staged — read-only — DO NOT add as a remote or submodule) +- Run `git log --oneline | head -20` to see recent activity +- Run `find . -type f -name "*.py" | head -20` and `find . -type f -name "*.md" | head -20` to see what's actually there +- Look for: addon code (`__init__.py` with `bl_info`), MCP server code (`mcp_server.py` or similar), tool definitions, Blender Python API usage +- Is it a fork of Blender (~50 GB of source) or a small addon/plugin (~hundreds of KB)? + +### 5.2 License + +- Top-level LICENSE file: GPL? MIT? Apache? +- If GPL-2 or GPL-3 (Blender's default), this would contaminate Hermes3D's MIT license if we statically link or vendor any GPL code into the Hermes3D package +- If it's a separate-process MCP server that Hermes3D talks to over stdio, GPL is fine (the server is its own program; calling it from MIT code over a process boundary is not derivative work) +- Document which interaction model applies + +### 5.3 Tool surface + +- What MCP tools does it expose? List every tool name + signature +- Does it expose `execute_blender_python` or any "run arbitrary Python in Blender" tool? +- If yes: this is a critical security concern. Blender has full filesystem + network access via Python. An LLM with a `python_eval` tool inside Blender = compromise of the entire host machine. +- Are tools allowlisted to specific operations (mesh repair, render, export) or open-ended? + +### 5.4 Authentication / sandbox + +- Does the MCP server require auth tokens, or is stdio open? +- Is there sandboxing of Blender Python (e.g., restricted builtins, no `os`, no `subprocess`)? +- Is there a process-isolation layer (Blender runs in a container or jail)? + +### 5.5 Activity / maintenance + +- Last commit date — actively maintained or abandoned? +- Open issues / closed PRs — does the maintainer respond? +- Stars / forks — what's the community signal? +- Release tags — semver? changelog? + +### 5.6 Comparison to existing `blender_mcp.py` + +- The existing Hermes3D adapter at `03_implementation/src/hermes3d/adapters/blender_mcp.py` already provides Blender integration via MCP +- What does the existing adapter cover? Read its 200-or-so lines and list its capabilities +- Does the new `blender-mcp-native` cover the same ground? Different ground? Subset? Superset? +- Would adoption mean ripping out the existing adapter, or running both? + +### 5.7 Specific safety questions to answer in the ADR + +- Can a malicious prompt cause filesystem writes outside `/tmp` or `~/.blender`? +- Can it open network sockets? +- Can it import arbitrary Python modules (pickle, marshal, ctypes, etc.)? +- Does it honor Blender's `--factory-startup` flag to avoid loading user addons? +- Is there any analytics / telemetry / phone-home behavior? + +--- + +## 6. Output: ADR-014 + +Mirror the shape of `02_architecture/adr/ADR-013-kit-hardening-v5_1.md`. + +**`02_architecture/adr/ADR-014-blender-mcp-native-audit.md`** — sections: + +8 sections (in order): + +1. **Title** — ADR-014: Audit of `rakaarwaky/blender-mcp-native` for adoption as Hermes3D's Blender integration path +2. **Status** — Proposed | Accepted | Rejected (you decide) +3. **Date** — 2026-05-03 +4. **Context** — Why this audit is happening: existing `blender_mcp.py` adapter, proposal to use `blender-mcp-native` instead, security concerns about arbitrary Python execution in Blender +5. **Decision** — `ADOPT` / `FORK` / `REJECT` / `NEEDS-DEEPER-AUDIT` (one of the four) with verdict statement +6. **Rationale & Consequences** — 5-15 bullet points walking through the §5 audit findings. Reference specific commits, file paths, license fragments. Cover both positive + negative consequences of the chosen verdict. +7. **Alternatives considered:** + - Keep `blender_mcp.py` as-is (status quo) + - Adopt `blender-mcp-native` as primary + - Fork and harden `blender-mcp-native` + - Build a minimal new Blender adapter from scratch +8. **References** — GitHub repo URL, last commit SHA at audit time, license file path within the repo, any external blog posts / discussions found via online research + +**`00_overview/contract/ROADMAP.md`** — add a row under the `Future / Pending Audits` section (create the section if it doesn't exist): +- `Blender MCP integration path (ADR-014)` | Status: `` | Decision date: 2026-05-03 + +--- + +## 7. Tests + gates + +```text +hermes_run_gate gateId=git-status cwd=. +hermes_run_gate gateId=git-diff-check cwd=. +``` + +Local: +- ADR-014 has the 8 standard sections (Title, Status, Date, Context, Decision, Rationale & Consequences, Alternatives, References) +- ROADMAP.md still parses (no markdown breakage) + +This is a docs-only PR. **Do NOT run `pytest -q`** — it's not necessary and adds 30+ minutes to a 30-60min task. Layer F (honesty gates) on the PR will validate the contract / manifest if needed. + +--- + +## 8. PR + close-out + +```bash +git push -u origin docs/blender-mcp-native-audit +gh pr create --base develop \ + --title "docs(adr): ADR-014 — audit of blender-mcp-native (verdict: )" \ + --body "[mirror prior PR body shape; Hermes evidence chain: PASS; Task: H3D-BLENDER-AUDIT; Gate run: git-status PASS, git-diff-check PASS]" +``` + +Close-out: + +```text +hermes_append_evidence + owner=codex-impl-05 + taskId=H3D-BLENDER-AUDIT + kind=checkpoint + summary=ADR-014 written; verdict ; PR #N opened at SHA + +hermes_release_files owner=codex-impl-05 files=[the 2 above] +hermes_release_task owner=codex-impl-05 taskId=H3D-BLENDER-AUDIT +``` + +--- + +## 9. Hard rules + +- DO NOT add `rakaarwaky/blender-mcp-native` as a git submodule, remote, or runtime dependency without an ADOPT verdict that explicitly authorizes it +- DO NOT execute any code from the cloned repo on your machine. Inspection only — read files, don't `python anything.py` +- DO NOT touch `03_implementation/src/hermes3d/adapters/blender_mcp.py` — that's a code change for a follow-up checkpoint if the verdict is FORK or REPLACE +- DO NOT touch any file outside the 2 locked above +- DO NOT install Blender on the host machine for testing — audit is documentation-only + +## 10. Failure protocol + +If you can't reach the GitHub repo (network, takedown, etc.), write the verdict as **REJECT** with rationale "repo unreachable at audit time". That's a valid output. + +If the repo turns out to be empty or unrelated to its README claims, write the verdict as **REJECT** with rationale "repo content does not match stated purpose". + +If you have low confidence after 60 minutes of audit, write the verdict as **NEEDS-DEEPER-AUDIT** (a 4th valid option) and recommend specific follow-up work. diff --git a/handoffs/HANDOFF_TO_CODEX_HERMES3D_LOCAL_INTELLIGENCE.md b/handoffs/HANDOFF_TO_CODEX_HERMES3D_LOCAL_INTELLIGENCE.md new file mode 100644 index 00000000..bf1a3fce --- /dev/null +++ b/handoffs/HANDOFF_TO_CODEX_HERMES3D_LOCAL_INTELLIGENCE.md @@ -0,0 +1,13 @@ +# HANDOFF_TO_CODEX — LOCAL-INTELLIGENCE (SUPERSEDED — see splits below) + +> **Status:** SUPERSEDED. The original mega-brief was split per the audit's M2 recommendation after the LOCAL-INTELLIGENCE audit returned VERDICT: FAIL on six critical issues (paths wrong, Settings tab nonexistent, mnemosyne PyPI name wrong, port-monitor not a library, llm_policy rewrite destructive). +> +> **Replaced by three independently-completable briefs:** +> +> 1. `HANDOFF_TO_CODEX_HERMES3D_LOCAL_LM_STUDIO.md` — Task 4a (LM Studio default + Ollama fallback + Hipfire optional) +> 2. `HANDOFF_TO_CODEX_HERMES3D_MNEMOSYNE_RECALL.md` — Task 4b (Mnemosyne recall layer) +> 3. `HANDOFF_TO_CODEX_HERMES3D_SERVICE_HEALTH.md` — Task 4c (in-house port probe + new top-level /health route) +> +> Each split is scope-tighter, has an audit-clean lock list, and can ship independently. If the Mnemosyne PyPI install hits a quirk, the LM Studio and Service Health work still ships. +> +> **Do NOT pick up this file.** Pick up the splits in order: 4a → 4b → 4c. diff --git a/handoffs/HANDOFF_TO_CODEX_HERMES3D_LOCAL_LM_STUDIO.md b/handoffs/HANDOFF_TO_CODEX_HERMES3D_LOCAL_LM_STUDIO.md new file mode 100644 index 00000000..2fd6fc88 --- /dev/null +++ b/handoffs/HANDOFF_TO_CODEX_HERMES3D_LOCAL_LM_STUDIO.md @@ -0,0 +1,223 @@ +# HANDOFF_TO_CODEX — LM Studio default + Ollama fallback + Hipfire optional (Task 4a) + +> **Status:** READY for Codex pickup. +> +> **Sequence position:** Task 4a in overnight queue (split from former CP-HERMES3D-LOCAL-INTELLIGENCE which failed audit). +> +> **Owner:** `codex-impl-06`. +> +> **Estimated time:** 2-3 hours. +> +> **Audit history:** parent brief failed audit on path mismatches; this split has been reality-checked against `origin/develop`. + +--- + +## 1. Mission + +Make LM Studio the default local LLM provider. The user has 80 local models / 652 GB at `C:\Users\Admin\.lmstudio\models` — Ollama is the wrong default for them. + +Three additions: + +1. **`lm_studio_provider.py`** (NEW) — talks to LM Studio at `http://localhost:1234/v1` (OpenAI-compatible REST). Streaming + tool-calling. +2. **Ollama fallback** — modify the existing `core/llm/ollama_client.py` (CONFIRMED EXISTS) to register as the second-priority provider in the chain. +3. **Hipfire optional** — `hipfire_provider.py` (NEW), default disabled, opt-in via `HERMES3D_AMD_NODE=1` env var. + +NO UI changes. NO Mnemosyne. NO port monitor. Those are 4b and 4c. + +--- + +## 2. Claim + +```text +hermes_pick_task + owner=codex-impl-06 + prefer_task_id=CP-HERMES3D-LOCAL-LM-STUDIO +``` + +Or fallback: `taskId=CP-HERMES3D-LOCAL-LM-STUDIO`, `title=LM Studio default + Ollama fallback + Hipfire optional`, `reason=User has 80 LM Studio models locally; Ollama is the wrong default. This is split 1/3 of the former mega-task LOCAL-INTELLIGENCE which failed audit.` + +--- + +## 3. Branch + +`feat/cp-hermes3d-local-lm-studio` from `develop`. + +--- + +## 4. Lock these files (audit-verified against origin/develop) + +```text +hermes_lock_files + owner=codex-impl-06 + taskId=CP-HERMES3D-LOCAL-LM-STUDIO + ttlMinutes=180 + files=[ + "03_implementation/config/llm_policy.yaml", + "03_implementation/config/llm_policy.schema.json", + "03_implementation/src/hermes3d/core/llm/lm_studio_provider.py", + "03_implementation/src/hermes3d/core/llm/ollama_client.py", + "03_implementation/src/hermes3d/core/llm/hipfire_provider.py", + "03_implementation/src/hermes3d/core/llm/providers.py", + "04_testing/pytest/integration/test_lm_studio_provider.py", + "04_testing/pytest/integration/test_ollama_client.py", + "04_testing/pytest/integration/test_hipfire_provider.py" + ] +``` + +**Confirmed existing on develop:** `llm_policy.yaml`, `llm_policy.schema.json`, `core/llm/ollama_client.py`, `core/llm/providers.py` (or equivalent — verify before locking; if not exactly named `providers.py`, check `core/llm/__init__.py`). + +**Confirmed NEW:** `lm_studio_provider.py`, `hipfire_provider.py`, the 3 test files. + +**If `core/llm/providers.py` does not exist** but the chain logic lives in `core/llm/__init__.py`, swap the lock list entry to match reality. Verify before locking. + +--- + +## 5. Implementation contract + +### 5.1 `llm_policy.yaml` — MERGE not REPLACE + +The audit flagged the parent brief for proposing a destructive rewrite. Instead: + +- **Read the existing YAML, validate against `llm_policy.schema.json`** +- **Merge** the new provider chain entries into the existing structure +- **Preserve** all existing user-set values (cost_caps, model preferences, anything custom) +- **Only add or modify** the `default_chain` ordering and the new `hipfire` provider entry + +If the existing YAML doesn't have `local_first_mode` / `cloud_fallback_mode` sections, ADD them with these defaults (keeping `cloud_fallback_mode.enabled: false` opt-in): + +```yaml +local_first_mode: + default_chain: + - lm_studio # primary — user has 80 models locally + - ollama # fallback — used when LM Studio is offline + - hipfire # optional AMD path; activated only if HERMES3D_AMD_NODE=1 + cost_caps: + daily_usd: 0 # local mode: zero spend + per_request_max_tokens: 16000 + +cloud_fallback_mode: + enabled: false # explicit opt-in only + enable_via_env: HERMES3D_CLOUD_FALLBACK # set to "1" to enable + default_chain: + - anthropic + - minimax + - deepseek + - siliconflow +``` + +Document the cloud-enable path in the ADR (§5.5). + +### 5.2 `lm_studio_provider.py` (NEW) + +Implements the `LLMProvider` protocol (find the contract in `core/llm/__init__.py` or wherever it's defined — verify before assuming). Key responsibilities: + +- Talk to LM Studio at `http://localhost:1234/v1/chat/completions` (OpenAI-compatible) +- Support streaming (SSE) AND non-streaming +- Support tool-calling per OpenAI's `tools` array +- Health probe via `GET /v1/models` + +Failure modes (each returns `outcome="provider-unavailable"` and falls through to next in chain): +- LM Studio not running (connection refused) +- LM Studio running but no model loaded +- Streaming connection drop (retry once, then fall through) +- Request takes longer than `httpx` timeout (default 30s) + +Port override: `HERMES3D_LM_STUDIO_BASE_URL` env var (e.g., `http://10.0.0.42:1234/v1` for LAN-hosted LM Studio). + +**Recommended default model for tool-calling workloads:** `NousResearch/Hermes-4-14B-FP8` — Hermes 4 (May 2026), runs on a single 24 GB GPU, supports tool-calling + `` hybrid reasoning, MIT-aligned with Llama 3.1 Community License (commercial OK under 700M MAU cap). Document this in the ADR's References section but DO NOT bundle the weights — user pulls them via LM Studio's UI. Rationale: Hermes Agent (Nous Research) is the spiritual ancestor of "Hermes3D" — circling back to their 4.x model family closes the loop. + +### 5.3 Ollama fallback (modify existing `ollama_client.py`) + +The audit confirmed `core/llm/ollama_client.py` exists. Don't create a new `ollama_provider.py`. Either: +- Rename `ollama_client.py` → `ollama_provider.py` (cleaner naming) AND update all imports — but this is more risk +- OR keep `ollama_client.py` and have it conform to the same `LLMProvider` protocol — minimal-change path + +Pick the minimal-change path. Just ensure `ollama_client.py` exposes the same protocol shape as `lm_studio_provider.py`. + +### 5.4 `hipfire_provider.py` (NEW, default disabled) + +Same shape as `lm_studio_provider.py`. Talks to Hipfire at `http://localhost:11435/v1/chat/completions`. + +Init guard: +```python +def __init__(self) -> None: + if os.environ.get("HERMES3D_AMD_NODE") != "1": + raise ProviderDisabled("Hipfire is opt-in; set HERMES3D_AMD_NODE=1 to enable") + super().__init__() +``` + +The chain orchestrator in `providers.py` should catch `ProviderDisabled` and skip to the next provider silently (not log an error — disabled is the expected state). + +### 5.5 ADR + +**`02_architecture/adr/ADR-015-local-llm-providers.md`** (NEW) — 8 sections per the BLENDER-AUDIT-corrected ADR template: + +1. Title — ADR-015: Local LLM provider chain — LM Studio default + Ollama fallback + Hipfire optional +2. Status — Proposed +3. Date — 2026-05-03 +4. Context — Why LM Studio default (user has 80 models / 652 GB), why Ollama as fallback (already integrated), why Hipfire is opt-in (AMD-only, only meaningful for users with AMD inference nodes) +5. Decision — chain order: lm_studio → ollama → hipfire (when enabled). Cloud fallback is opt-in via `HERMES3D_CLOUD_FALLBACK=1` +6. Rationale & Consequences — privacy posture, cost ($0 daily cap), capability (LM Studio's catalog is large), user agency (cloud always one env-var-flip away) +7. Alternatives considered — Ollama as primary (rejected: user has more LM Studio capacity); cloud-first (rejected: privacy posture); chain-only with no Hipfire (rejected: lose opt-in path for AMD users) +8. References — LM Studio docs, Ollama docs, Hipfire repo + +### 5.6 Tests + +3 new integration tests, all using mocks (no real LM Studio / Ollama / Hipfire required in CI): + +- `test_lm_studio_provider.py` — happy path (mock at :1234), provider-unavailable path (no listener), streaming path +- `test_ollama_client.py` — protocol conformance after refactor (covers existing logic + new chain integration) +- `test_hipfire_provider.py` — `ProviderDisabled` raised when `HERMES3D_AMD_NODE` not set; happy path when env is set + +--- + +## 6. Tests + gates + +```text +hermes_run_gate gateId=git-status cwd=. +hermes_run_gate gateId=git-diff-check cwd=. +``` + +Local: +- `pip install -e ".[all]"` (no new deps required — uses existing `httpx`) +- `pytest -q 04_testing/pytest/` — 670+ existing + 3 new pass +- `ruff check 03_implementation/src 04_testing/pytest` +- `ruff format --check 03_implementation/src 04_testing/pytest` +- LM Studio policy validates against schema: `python -c "import yaml,jsonschema; ..."` (use the existing schema) + +CI: Layer A/B/C/D/D3/F/M/T/W must all pass. + +--- + +## 7. PR + close-out + +```bash +git push -u origin feat/cp-hermes3d-local-lm-studio +gh pr create --base develop \ + --title "feat: LM Studio default + Ollama fallback + Hipfire optional (Task 4a)" \ + --body "[Hermes evidence chain: PASS; Task: CP-HERMES3D-LOCAL-LM-STUDIO; Gate run via hermes_run_gate]" +``` + +Close-out: +```text +hermes_append_evidence owner=codex-impl-06 taskId=CP-HERMES3D-LOCAL-LM-STUDIO kind=checkpoint summary=LM Studio default chain shipped; PR #N at SHA +hermes_release_files owner=codex-impl-06 files=[the lock list] +hermes_release_task owner=codex-impl-06 taskId=CP-HERMES3D-LOCAL-LM-STUDIO +``` + +--- + +## 8. Hard rules + +- DO NOT default-enable Hipfire (must require `HERMES3D_AMD_NODE=1`) +- DO NOT REPLACE `llm_policy.yaml` — MERGE only, preserve user values +- DO NOT add cloud providers as defaults — `cloud_fallback_mode.enabled: false` is the contract; user opts in via `HERMES3D_CLOUD_FALLBACK=1` +- DO NOT touch the React UI in this brief — that's split 4c +- DO NOT touch any file outside the §4 lock list +- DO NOT install LM Studio on the test machine; CI uses mocks only + +## 9. Failure protocol + +If `core/llm/providers.py` doesn't exist as a separate file (chain logic might live in `__init__.py` instead), update the lock list to include `__init__.py` and proceed. This is a known reality-check item the parent brief got wrong. + +If the LM Studio API surface has shifted between your training cutoff and now, do a quick WebFetch of `https://lmstudio.ai/docs/local-server` to confirm the OpenAI-compat endpoint shape before implementing. diff --git a/handoffs/HANDOFF_TO_CODEX_HERMES3D_MNEMOSYNE_RECALL.md b/handoffs/HANDOFF_TO_CODEX_HERMES3D_MNEMOSYNE_RECALL.md new file mode 100644 index 00000000..456ec242 --- /dev/null +++ b/handoffs/HANDOFF_TO_CODEX_HERMES3D_MNEMOSYNE_RECALL.md @@ -0,0 +1,280 @@ +# HANDOFF_TO_CODEX — Mnemosyne recall layer (Task 4b) + +> **Status:** READY for Codex pickup. +> +> **Sequence position:** Task 4b in overnight queue (after Task 4a). +> +> **Owner:** `codex-impl-07`. +> +> **Estimated time:** 1.5-3 hours. +> +> **Audit history:** parent brief failed audit on PyPI name mismatch; this split corrects it (`mnemosyne-memory`, NOT `mnemosyne`) and confirms the package IS pip-installable. The §9 BEAM/Erlang fallback branch from the parent brief is dead code and removed. + +--- + +## 1. Mission + +Add `mnemosyne-memory` (the user's local-first SQLite + FTS5 + vector-search memory library at `rakaarwaky/mnemosyne`) as a **recall layer** for Hermes3D's agents. Recall hints feed the dispatcher's scoring + the auto-orient agent's decisions. + +**Critical contract:** Mnemosyne is a recall layer. The evidence ledger (`var/proofs/...`) remains the canonical source of truth. Mnemosyne stores NON-canonical hints — printer quirks observed, agent failure patterns, "this material × this printer needs flow=92%" reinforcement signals. + +NO LLM provider work. NO UI work. NO port monitor. Those are 4a and 4c. + +--- + +## 2. Claim + +```text +hermes_pick_task + owner=codex-impl-07 + prefer_task_id=CP-HERMES3D-MNEMOSYNE-RECALL +``` + +Or fallback: `taskId=CP-HERMES3D-MNEMOSYNE-RECALL`, `title=Mnemosyne local-first memory recall layer`, `reason=Agent recall hints; not source of truth. Split 2/3 of LOCAL-INTELLIGENCE.` + +--- + +## 3. Branch + +`feat/cp-hermes3d-mnemosyne-recall` from `develop`. + +--- + +## 4. Lock these files + +```text +hermes_lock_files + owner=codex-impl-07 + taskId=CP-HERMES3D-MNEMOSYNE-RECALL + ttlMinutes=180 + files=[ + "03_implementation/src/hermes3d/core/memory/__init__.py", + "03_implementation/src/hermes3d/core/memory/mnemosyne_recall.py", + "03_implementation/src/hermes3d/core/agents/orchestrator.py", + "03_implementation/src/hermes3d/core/agents/dispatcher.py", + "04_testing/pytest/integration/test_mnemosyne_recall.py", + "00_overview/contract/HONESTY_LEDGER.md", + "02_architecture/adr/ADR-016-mnemosyne-recall-layer.md", + "pyproject.toml", + "requirements.txt" + ] +``` + +**Confirmed existing on develop:** `core/memory/__init__.py` (yes), `core/agents/orchestrator.py` (yes), `core/agents/dispatcher.py` (yes — it's the existing dispatch agent), `pyproject.toml`, `requirements.txt`, `HONESTY_LEDGER.md`. + +**Confirmed NEW:** `core/memory/mnemosyne_recall.py`, the test file, ADR-016 (skipping ADR-015 which is reserved for Task 4a's LLM-providers ADR — confirm in Task 4a's PR before claiming -016). + +If ADR-016 conflicts because Task 4a hasn't merged yet, use ADR-017 instead. Verify ADR availability via `git ls-tree origin/develop -- 02_architecture/adr/` before locking. + +--- + +## 5. Implementation contract + +### 5.1 PyPI dependency + +**`pyproject.toml`** + **`requirements.txt`** — add: + +```toml +mnemosyne-memory>=0.1,<2.0 +``` + +The package name is `mnemosyne-memory` (NOT `mnemosyne` — the audit confirmed this is the actual PyPI name; the bare name `mnemosyne` doesn't resolve). If your install fails, double-check the user's repo at `https://github.com/rakaarwaky/mnemosyne` for the canonical pip-installable name in their README. + +**Failure protocol:** if `pip install mnemosyne-memory` fails (package renamed, taken down, or never published), write a blocked-handoff and skip. Don't `git clone` the repo into `node_modules` / `site-packages`. + +### 5.2 `core/memory/mnemosyne_recall.py` (NEW) + +```python +"""Mnemosyne-backed recall layer for Hermes3D agents. + +CRITICAL: This is a RECALL layer, NOT a source of truth. + +The evidence ledger at var/proofs/...ndjson remains canonical. Mnemosyne +stores NON-canonical hints — printer quirks observed, agent failure +patterns, reinforcement signals. Decisions cite recall hints; they don't +authoritatively rely on them. + +If Mnemosyne is unavailable (offline DB, package import error), the +agents continue with deterministic logic — degraded but functional. +""" +from __future__ import annotations + +import logging +from dataclasses import dataclass, field +from pathlib import Path +from typing import Optional + +LOG = logging.getLogger(__name__) + + +@dataclass +class RecallHint: + hint_id: str + kind: str + text: str + relevance: float + metadata: dict = field(default_factory=dict) + + +class MnemosyneRecall: + """Soft-import wrapper. Methods no-op if Mnemosyne is unavailable.""" + + KINDS = frozenset({ + "printer_quirk", + "material_quirk", + "scheduling_pref", + "user_preference", + "failure_pattern", + "parameter_override", + }) + + def __init__(self, db_path: Optional[Path] = None) -> None: + self._db = None + try: + import mnemosyne_memory # type: ignore[import-not-found] + except ImportError: + LOG.info("mnemosyne-memory not installed; recall layer disabled") + return + try: + self._db = mnemosyne_memory.open( + str(db_path or Path.home() / ".hermes3d" / "mnemosyne.db") + ) + except Exception as exc: + LOG.warning("Mnemosyne open failed: %s; recall layer disabled", exc) + + def remember(self, kind: str, text: str, **metadata) -> Optional[str]: + if self._db is None or kind not in self.KINDS: + return None + try: + return self._db.remember(kind=kind, text=text, **metadata) + except Exception as exc: + LOG.warning("Mnemosyne remember failed: %s", exc) + return None + + def search( + self, query: str, kind: Optional[str] = None, limit: int = 5 + ) -> list[RecallHint]: + if self._db is None: + return [] + try: + raw = self._db.search(query=query, kind=kind, limit=limit) + return [ + RecallHint( + hint_id=r["id"], + kind=r["kind"], + text=r["text"], + relevance=r.get("score", 0.0), + metadata=r.get("metadata", {}), + ) + for r in raw + ] + except Exception as exc: + LOG.warning("Mnemosyne search failed: %s", exc) + return [] + + def forget(self, hint_id: str) -> None: + if self._db is None: + return + try: + self._db.forget(hint_id) + except Exception as exc: + LOG.warning("Mnemosyne forget failed: %s", exc) + + +def default_recall() -> MnemosyneRecall: + """Singleton-ish factory; agents call this rather than constructing directly.""" + return MnemosyneRecall() +``` + +### 5.3 Wire into orchestrator + dispatcher + +**`core/agents/orchestrator.py`** — at orchestrator init, store a `MnemosyneRecall` instance. Pass it to dispatcher / mesh-repair / preflight as an optional kwarg (`recall: MnemosyneRecall | None = None`). Default behavior unchanged when recall is `None`. + +**`core/agents/dispatcher.py`** — in the scoring function, after the deterministic score, call `recall.search(query=...)` with a query like `"printer={printer_id} material={material} quality={quality}"`. If hints exist, blend their reinforcement into the score (small weight — e.g., +0.05 for confirmed-good, -0.10 for confirmed-failure). DO NOT let recall hints alone flip the verdict; the deterministic score must dominate. + +After a successful print, the post-print agent should `recall.remember(kind="parameter_override", text="prusa-mk4-02 + PLA + normal-quality + flow=98% → success", ...)`. + +### 5.4 Tests (`test_mnemosyne_recall.py`) + +```python +def test_remember_search_round_trip(tmp_path): + recall = MnemosyneRecall(db_path=tmp_path / "test.db") + if recall._db is None: + pytest.skip("mnemosyne-memory not installed") + hint_id = recall.remember( + kind="printer_quirk", + text="prusa-mk4-02 needs Z-offset -0.05 with PEI", + ) + hits = recall.search("prusa-mk4-02", kind="printer_quirk") + assert any(h.text.startswith("prusa-mk4-02") for h in hits) + + +def test_recall_unavailable_silent_degradation(monkeypatch): + monkeypatch.setattr( + "hermes3d.core.memory.mnemosyne_recall.MnemosyneRecall._db", None + ) + recall = MnemosyneRecall() + assert recall.remember("printer_quirk", "test") is None + assert recall.search("anything") == [] + + +def test_recall_hints_do_not_appear_in_evidence_ledger(tmp_path): + """Recall is NOT canonical. The ledger must be untouched.""" + # This test should grep var/proofs/*.ndjson before + after a recall.remember() + # call and confirm zero new ledger entries. + ... +``` + +### 5.5 ADR + +**`02_architecture/adr/ADR-016-mnemosyne-recall-layer.md`** — 8 sections per the corrected ADR template (or ADR-017 if -016 collides). Decision: Mnemosyne is a recall layer, NOT a source of truth. Evidence ledger remains canonical. Falls back to deterministic logic when unavailable. + +### 5.6 Honesty ledger + +**`HONESTY_LEDGER.md`** — append rows: + +- `core.memory.mnemosyne_recall` — REAL when `mnemosyne-memory` installed; DEGRADED-OK when not. Recall layer, not source of truth. + +--- + +## 6. Tests + gates + +```text +hermes_run_gate gateId=git-status cwd=. +hermes_run_gate gateId=git-diff-check cwd=. +``` + +Local: +- `pip install -e ".[all]"` succeeds (with `mnemosyne-memory` added) +- `pytest -q 04_testing/pytest/` — 670+ existing + 3 new, all pass +- `pytest -q 04_testing/pytest/ -k mnemosyne` — 3 new tests +- Soft-import smoke: temporarily uninstall `mnemosyne-memory`; `pytest -k mnemosyne` should pass via skip; orchestrator should still init. + +--- + +## 7. PR + close-out + +```bash +git push -u origin feat/cp-hermes3d-mnemosyne-recall +gh pr create --base develop \ + --title "feat(memory): Mnemosyne recall layer (Task 4b)" \ + --body "[Hermes evidence chain: PASS; Task: CP-HERMES3D-MNEMOSYNE-RECALL; Gate run via hermes_run_gate]" +``` + +Close-out per standard pattern. + +--- + +## 8. Hard rules + +- DO NOT make Mnemosyne the source of truth for ANY decision — recall layer ONLY +- DO NOT commit the SQLite DB file (it's user-data, gitignored at `var/`) +- DO NOT swallow exceptions from Mnemosyne silently — LOG.warning with context +- DO NOT add the package as a runtime dependency without `try/except ImportError` guard +- DO NOT touch any file outside the §4 lock list + +## 9. Failure protocol + +If `mnemosyne-memory` fails to install (renamed package, BEAM-only, taken down), the soft-import pattern in §5.2 already handles it gracefully — the recall layer is disabled, agents continue with deterministic logic. Skip the dependency add in §5.1, but ship the wrapper module + tests anyway. The architect can wire in a real implementation later. + +If integration with the dispatcher introduces a regression in existing tests, prefer keeping the dispatcher behavior identical when `recall is None` — that's the safe path. diff --git a/handoffs/HANDOFF_TO_CODEX_HERMES3D_SERVICE_HEALTH.md b/handoffs/HANDOFF_TO_CODEX_HERMES3D_SERVICE_HEALTH.md new file mode 100644 index 00000000..5c611c71 --- /dev/null +++ b/handoffs/HANDOFF_TO_CODEX_HERMES3D_SERVICE_HEALTH.md @@ -0,0 +1,272 @@ +# HANDOFF_TO_CODEX — Service Health (Task 4c) + +> **Status:** READY for Codex pickup. +> +> **Sequence position:** Task 4c in overnight queue (after Task 4b). +> +> **Owner:** `codex-impl-08`. +> +> **Estimated time:** 2-3 hours. +> +> **Audit history:** parent brief assumed `SettingsTab.tsx` exists — IT DOES NOT (audit confirmed `ui/src/components/` has only badges/cards/charts/dock/layout/pipeline/tables, no SettingsTab). Parent also assumed `port-monitor` is a Python library — it's a C++/Qt6 desktop GUI. This split commits up-front to in-house port probing (stdlib socket) and a NEW top-level `/health` route (NOT a Settings subtab). + +--- + +## 1. Mission + +Make Hermes3D's service topology VISIBLE in the React UI. Operators need to see at a glance whether: HermesProof MCP is reachable, LM Studio is up, Ollama is up, Blender MCP is up, ComfyUI is up, Moonraker is reachable per printer, FastAPI server is up, Gradio launcher is up, VPS tunnel is up. + +Three pieces: + +1. **`port_probe.py`** (NEW) — stdlib `socket.connect_ex` probe across a known service list. NO `port-monitor` library dependency (it's a desktop GUI, not callable). +2. **FastAPI endpoint** `/api/health/services` — returns probe results as JSON. +3. **React `/health` route** (NEW) — top-level route in the React UI sidebar. Cards per service with status pills. + +NO LLM provider work. NO Mnemosyne. Those are 4a and 4b. + +--- + +## 2. Claim + +```text +hermes_pick_task + owner=codex-impl-08 + prefer_task_id=CP-HERMES3D-SERVICE-HEALTH +``` + +Or fallback: `taskId=CP-HERMES3D-SERVICE-HEALTH`, `title=Service Health UI + in-house port probe`, `reason=Operators need topology visibility. Split 3/3 of LOCAL-INTELLIGENCE which failed audit.` + +--- + +## 3. Branch + +`feat/cp-hermes3d-service-health` from `develop`. + +--- + +## 4. Lock these files (audit-verified) + +```text +hermes_lock_files + owner=codex-impl-08 + taskId=CP-HERMES3D-SERVICE-HEALTH + ttlMinutes=180 + files=[ + "03_implementation/src/hermes3d/core/integrations/port_probe.py", + "03_implementation/src/hermes3d/api/server.py", + "03_implementation/src/hermes3d/api/routes/health.py", + "03_implementation/ui/src/app/routes.tsx", + "03_implementation/ui/src/app/AppShell.tsx", + "03_implementation/ui/src/components/health/ServiceHealthPage.tsx", + "03_implementation/ui/src/components/health/ServiceCard.tsx", + "03_implementation/ui/src/components/health/StatusPill.tsx", + "04_testing/pytest/integration/test_port_probe.py", + "04_testing/pytest/integration/test_health_route.py", + "04_testing/playwright/health_page.spec.ts" + ] +``` + +**Confirmed existing on develop:** +- `03_implementation/src/hermes3d/api/server.py` (NOTE the `src/hermes3d/` subpath — the parent brief got this wrong) +- `03_implementation/ui/src/app/routes.tsx` +- `03_implementation/ui/src/app/AppShell.tsx` +- `03_implementation/ui/src/components/` (no `health/` subdir yet — NEW) +- `04_testing/playwright/` (existing test directory) + +**Confirmed NEW:** `port_probe.py`, `routes/health.py`, all 3 React `health/*.tsx` files, the 3 test files. + +**If `api/routes/` directory doesn't exist** on develop (FastAPI app may have routes inline in `server.py`), update the lock list: drop `routes/health.py` and add the new endpoint inline in `server.py` instead. Verify before locking. + +--- + +## 5. Implementation contract + +### 5.1 `port_probe.py` — in-house stdlib probe + +```python +"""Service-health port probe. NO external library — stdlib socket only. + +`port-monitor` (rakaarwaky/port-monitor) is a C++/Qt6 desktop GUI, not a +Python library. We probe ports ourselves with `socket.connect_ex` for +fast TCP-reachability checks plus optional HTTP probes for richer status. +""" +from __future__ import annotations + +import socket +from dataclasses import dataclass, field +from datetime import datetime, timezone +from enum import Enum +from typing import Callable, Optional + + +class Status(str, Enum): + ONLINE = "online" + OFFLINE = "offline" + UNREACHABLE = "unreachable" + AUTH_REQUIRED = "auth-required" + DISABLED = "disabled" + UNKNOWN = "unknown" + + +@dataclass(frozen=True) +class ServiceSpec: + name: str + host: str + port: int + category: str # "mcp" | "llm" | "modeling" | "printer" | "api" | "tunnel" + enabled: bool = True + http_health_path: Optional[str] = None # e.g. "/v1/models" for LM Studio + + +@dataclass +class ProbeResult: + spec: ServiceSpec + status: Status + detail: str + latency_ms: float + probed_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat()) + + +KNOWN_SERVICES: tuple[ServiceSpec, ...] = ( + ServiceSpec("HermesProof MCP", "127.0.0.1", 0, "mcp", enabled=False), # stdio, special-cased + ServiceSpec("LM Studio", "127.0.0.1", 1234, "llm", http_health_path="/v1/models"), + ServiceSpec("Ollama", "127.0.0.1", 11434, "llm", http_health_path="/api/tags"), + ServiceSpec("Hipfire (AMD)", "127.0.0.1", 11435, "llm", enabled=False), # only if HERMES3D_AMD_NODE=1 + ServiceSpec("Blender MCP", "127.0.0.1", 9876, "modeling"), + ServiceSpec("ComfyUI", "127.0.0.1", 8188, "modeling"), + ServiceSpec("FastAPI server", "127.0.0.1", 8000, "api"), + ServiceSpec("Gradio launcher", "127.0.0.1", 7860, "api"), +) + + +def probe_one(spec: ServiceSpec, timeout_s: float = 0.5) -> ProbeResult: + if not spec.enabled: + return ProbeResult(spec, Status.DISABLED, "service disabled by config", 0.0) + if spec.port == 0: + return ProbeResult(spec, Status.UNKNOWN, "stdio service; probe via MCP handshake separately", 0.0) + start = datetime.now(timezone.utc) + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.settimeout(timeout_s) + rc = s.connect_ex((spec.host, spec.port)) + elapsed_ms = (datetime.now(timezone.utc) - start).total_seconds() * 1000 + if rc == 0: + return ProbeResult(spec, Status.ONLINE, f"TCP {spec.host}:{spec.port} accepted", elapsed_ms) + return ProbeResult(spec, Status.OFFLINE, f"TCP {spec.host}:{spec.port} refused (errno={rc})", elapsed_ms) + except socket.gaierror as exc: + return ProbeResult(spec, Status.UNREACHABLE, f"DNS/host error: {exc}", 0.0) + except OSError as exc: + return ProbeResult(spec, Status.UNREACHABLE, f"socket error: {exc}", 0.0) + + +def probe_all(extra: tuple[ServiceSpec, ...] = ()) -> list[ProbeResult]: + """Probe KNOWN_SERVICES plus any extra (e.g., per-printer Moonraker entries + loaded from printers.user.toml). + """ + return [probe_one(s) for s in (*KNOWN_SERVICES, *extra)] +``` + +Per-printer Moonraker entries: read `03_implementation/config/printers.toml` (stock template) and the gitignored `printers.user.toml` if present. For each printer, build a `ServiceSpec("Moonraker — {printer_id}", host=printer.ip, port=7125, ...)`. Don't fail if `printers.user.toml` doesn't exist — fall back to stock-template hosts. + +### 5.2 `/api/health/services` endpoint + +In `api/server.py` (or `api/routes/health.py` if the FastAPI app uses APIRouter modules): + +```python +from hermes3d.core.integrations.port_probe import probe_all + +@router.get("/api/health/services") +def health_services(): + results = probe_all() + return {"results": [ + { + "name": r.spec.name, + "category": r.spec.category, + "status": r.status.value, + "detail": r.detail, + "latency_ms": round(r.latency_ms, 1), + "probed_at": r.probed_at, + } + for r in results + ]} +``` + +Same auth as the rest of the API (session token via `Depends(get_session)` or whatever the existing pattern is — read existing route examples in `server.py` first). + +### 5.3 React `/health` route — NEW top-level route + +The audit confirmed there's NO Settings tab in the React UI. So this is NOT a subtab — it's a new top-level route in the existing sidebar. + +**`ui/src/app/routes.tsx`** — add a new route `{ path: "/health", element: }`. + +**`ui/src/app/AppShell.tsx`** — add a sidebar nav entry for `/health` with an icon (use `Heart` or `Activity` from lucide-react). Place it between the existing Logs and any future Settings items, or at the end if Settings doesn't exist. + +**`ui/src/components/health/ServiceHealthPage.tsx`** (NEW): +- Calls `GET /api/health/services` on mount +- Auto-refreshes every 30s (configurable; expose a "Pause auto-refresh" toggle) +- Renders a grid of `ServiceCard`s grouped by category (MCP / LLM / Modeling / Printer / API / Tunnel) +- "Re-probe now" button calls the API immediately + +**`ui/src/components/health/ServiceCard.tsx`** (NEW): +- Service name + category badge +- Status pill (online green / offline red / unreachable amber / auth-required purple / disabled gray) +- Last-probed timestamp (relative, "12s ago") +- Latency in ms + +**`ui/src/components/health/StatusPill.tsx`** (NEW): +- Reusable pill component with status → color mapping +- Used by ServiceCard, may be used by other tabs later + +### 5.4 Tests + +- `test_port_probe.py` — probe a localhost port that's open (use `socketserver` fixture); probe a closed port; timeout handling; per-result schema correctness +- `test_health_route.py` — mock `probe_all`, verify endpoint shape; auth required; latency reported +- `health_page.spec.ts` (Playwright) — page loads at `/health`, cards render, "Re-probe now" button triggers a request + +--- + +## 6. Tests + gates + +```text +hermes_run_gate gateId=git-status cwd=. +hermes_run_gate gateId=git-diff-check cwd=. +``` + +Local: +- `pip install -e ".[all]"` (no new deps — uses stdlib socket) +- `pytest -q` — 670+ existing + 2 new pytest tests pass +- `npm --prefix 03_implementation/ui run build` — UI builds clean +- `npm --prefix 03_implementation/ui test` (if Vitest configured) — passes +- `npx playwright test 04_testing/playwright/health_page.spec.ts` — passes (via `scripts/run-e2e.sh` if needed) + +CI: Layer A/B/C/D/D3/F/M/T/W must all pass. Layer D3 should not regress (Codex fixed it cleanly — keep that pattern). + +--- + +## 7. PR + close-out + +```bash +git push -u origin feat/cp-hermes3d-service-health +gh pr create --base develop \ + --title "feat(ui): Service Health page + in-house port probe (Task 4c)" \ + --body "[Hermes evidence chain: PASS; Task: CP-HERMES3D-SERVICE-HEALTH; Gate run via hermes_run_gate]" +``` + +Close-out per standard pattern. + +--- + +## 8. Hard rules + +- DO NOT add `port-monitor` (rakaarwaky/port-monitor) as a dependency — it's a C++/Qt6 desktop GUI, not a library. Use stdlib `socket` only. +- DO NOT auto-discover printer IPs from network scan — read from existing `printers.toml` + gitignored `printers.user.toml`. +- DO NOT make the health endpoint unauthenticated — same auth as the rest of the API. +- DO NOT touch the LLM provider chain (that's Task 4a) or Mnemosyne (that's Task 4b). +- DO NOT touch any file outside the §4 lock list. +- DO NOT introduce a Settings tab if you discover a half-written one — that's its own checkpoint, not this brief's scope. + +## 9. Failure protocol + +If the FastAPI app's structure is `routes/` (separate route modules) — fine, follow that pattern. If it's a single-file `server.py` — fine, add the endpoint inline. Don't refactor existing route organization just for this PR. + +If Playwright is broken on the develop branch (e.g., the launcher's tab names changed again), update the smoke test to match reality and fix it as part of this PR — same pattern Codex used for the Layer D3 flake fix during B4. That's a known-acceptable cross-cutting fix. diff --git a/handoffs/HANDOFF_TO_CODEX_HERMESPROOF_0.6_GATE_PACK.md b/handoffs/HANDOFF_TO_CODEX_HERMESPROOF_0.6_GATE_PACK.md new file mode 100644 index 00000000..b48587f0 --- /dev/null +++ b/handoffs/HANDOFF_TO_CODEX_HERMESPROOF_0.6_GATE_PACK.md @@ -0,0 +1,363 @@ +# HANDOFF_TO_CODEX — HermesProof v0.6: Secret + Quality + Test gate pack + +> **Status:** READY for Codex pickup. **Different repo:** `G:\Github\hermes3d-mcp-lock-orchestrator` (HermesProof), not Hermes3D. +> +> **Sequence position:** Task 3 in overnight queue (after BLENDER-AUDIT). +> +> **Owner:** `codex-impl-05`. +> +> **Estimated time:** 2-4 hours. + +--- + +## 1. Mission + +Ship HermesProof v0.6 — a foundational gate pack that closes the secret-leak vector (the `.env.txt` incident on 2026-05-03), integrates two of the user's own tools (`Ghenghis/auto_linter`, `Ghenghis/agentic-testing`), and adds first-class env-var path resolution. + +Five concrete additions: + +1. **`secret.scan` truth gate** — gitleaks integration with custom regex pack for non-GitHub-scanned providers (Anthropic, MiniMax, DeepSeek, SiliconFlow, HuggingFace, CodeRabbit) +2. **`auto-lint-*` truth gates** — 4 gates wrapping `Ghenghis/auto_linter`: check, security, architecture, report +3. **`agentic-test-*` truth gates** — 2 gates wrapping `Ghenghis/agentic-testing`: coverage-audit, test-self-heal +4. **`HERMES3D_ENV_FILE` resolution** — first-class env-var path resolution in HermesProof's launcher, plus `HERMES3D_VPS_ENV_FILE` for the deploy bundle +5. **Hardened `.gitignore`** — catches `.env.txt`, `.env.bak`, `.env~`, `.env.swp`, `.env.deploy`, `.env2`, `*.env`, while preserving `!.env.example` and `!.env.vps.example` exceptions +6. **Pre-commit hook** — `gitleaks protect --staged --redact` so secrets can't reach a push attempt at all + +--- + +## 2. Claim + +```text +hermes_pick_task + owner=codex-impl-hp + prefer_task_id=CP-HERMESPROOF-0.6 +``` + +Or fallback claim with `taskId=CP-HERMESPROOF-0.6`, `title=v0.6 — Secret + Quality + Test gate pack`, `reason=Foundational gates closing secret-leak vector + auto_linter + agentic-testing integration. Builds on v0.5.0 task queue.` + +--- + +## 3. Branch + +`feat/cp-hermesproof-0.6-gate-pack` from HermesProof's `main` (HermesProof uses `main` directly, not `develop`). + +--- + +## 4. Lock these exact files + +```text +hermes_lock_files + owner=codex-impl-hp + taskId=CP-HERMESPROOF-0.6 + ttlMinutes=180 + files=[ + "package.json", + "src/server.mjs", + "src/core/lock-manager.mjs", + "src/core/event-manager.mjs", + "src/core/queue-manager.mjs", + "src/core/gate-runner.mjs", + "scripts/truth-gates.mjs", + "scripts/coordination-smoke-test.mjs", + "scripts/hardening-smoke-test.mjs", + "scripts/install-clients.mjs", + "scripts/wizard.mjs", + ".gitignore", + ".gitleaks.toml", + ".githooks/pre-commit", + "docs/SECURITY_POLICY.md", + "docs/TOOL_REFERENCE.md", + "docs/MAINTENANCE.md", + "README.md" + ] +``` + +`.gitleaks.toml` and `.githooks/pre-commit` are NEW. Others are MODIFIED. + +Lock list includes `event-manager.mjs` and `queue-manager.mjs` because §5.3 sets coverage thresholds against them — if Codex needs to add type hints / docstrings / minor cleanup to lift coverage, the locked-list rule must permit it. Same for `hardening-smoke-test.mjs` which is part of the test script (`package.json` test runner reads it) so new tests for secret/lint gates may belong there. + +If your audit of HermesProof finds any of the listed files don't exist on `main`, file a blocked-handoff (lock-list-vs-reality contradiction) and skip to the next task. Same discipline as B1/B2. + +--- + +## 5. Implementation contract + +### 5.1 `secret.scan` gate (gitleaks integration) + +**`.gitleaks.toml`** — NEW. Custom config layered on top of gitleaks default rules: + +```toml +title = "HermesProof secret-scan rules" +extend.useDefault = true + +[[rules]] +id = "anthropic-api-key" +description = "Anthropic API key (sk-ant-...)" +regex = '''sk-ant-[a-zA-Z0-9_-]{20,}''' +keywords = ["sk-ant-"] + +[[rules]] +id = "minimax-api-key" +description = "MiniMax API key" +regex = '''(?i)minimax[_-]?(api[_-]?)?key['"\s:=]+([a-zA-Z0-9_.-]{30,})''' +keywords = ["minimax"] + +[[rules]] +id = "deepseek-api-key" +description = "DeepSeek API key (requires deepseek keyword co-located within 100 chars)" +regex = '''(?i)deepseek[\s\S]{0,120}sk-[a-zA-Z0-9]{32,48}''' +keywords = ["deepseek"] + +[[rules]] +id = "siliconflow-api-key" +description = "SiliconFlow API key" +regex = '''sk-[a-zA-Z0-9_-]{40,}''' +keywords = ["siliconflow"] + +[[rules]] +id = "huggingface-token" +description = "Hugging Face token (hf_...)" +regex = '''hf_[a-zA-Z0-9]{30,}''' +keywords = ["hf_"] + +[[rules]] +id = "coderabbit-api-key" +description = "CodeRabbit API key" +regex = '''(?i)coderabbit[_-]?(api[_-]?)?key['"\s:=]+([a-zA-Z0-9_-]{30,})''' +keywords = ["coderabbit"] + +[allowlist] +description = "Permitted patterns — synthetic test keys, examples" +regexes = [ + '''sk-ant-test-[a-zA-Z0-9-]+''', # synthetic test keys used in unit tests + '''sk-ant-example-key''', # README placeholders +] +paths = [ + '''.*\.example$''', # .env.example, .env.vps.example + '''node_modules/.*''', # vendored deps, not our code + '''PROOF/.*''', # auto-generated proof artifacts +] +``` + +**`scripts/truth-gates.mjs`** — add a new gate `secret.scan`: + +- Calls `gitleaks detect --config .gitleaks.toml --no-git --redact --report-format json --report-path /tmp/gitleaks-report.json --exit-code 1` +- If `gitleaks` binary not on PATH, emit a clear "gitleaks not installed; install via `brew install gitleaks` or `choco install gitleaks` or `go install github.com/gitleaks/gitleaks/v8@latest`" — and treat as `skip` only on local runs, `fail` in CI +- In CI: install gitleaks via `gitleaks/gitleaks-action@v2` (SHA-pin the action). The action runs against the PR diff +- Gate evidence: `findings_count`, `redacted_findings`, `gitleaks_version` +- Required gate (not advisory) + +**`docs/SECURITY_POLICY.md`** — add a "Secret-leak prevention" section explaining: +- The 2026-05-03 `.env.txt` incident (one paragraph, no specifics) +- The two-store convention (`G:\private\` and `C:\Users\Admin\Downloads\VPS\`) — generic-language version, no actual paths committed +- The `secret.scan` gate +- The pre-commit hook +- The hardened `.gitignore` + +### 5.2 `auto-lint-*` gates (Ghenghis/auto_linter integration) + +**`scripts/truth-gates.mjs`** — add 4 gates: + +- `auto-lint.check` — runs `auto_linter check --output sarif --output-path /tmp/auto-lint.sarif`. Required gate. +- `auto-lint.security` — runs `auto_linter security --output sarif --output-path /tmp/auto-lint-security.sarif`. Required gate. +- `auto-lint.architecture` — runs `auto_linter architecture --rules .auto-lint-rules.json`. Advisory (not gating until rules are tuned for HermesProof). +- `auto-lint.report` — runs `auto_linter report --inputs /tmp/auto-lint*.sarif --output PROOF/auto-lint-report.json`. Required gate (just publishes the aggregated report; never fails on findings; finding-count published as evidence). + +**`auto_linter`** is the user's own tool at `https://github.com/Ghenghis/auto_linter`. Add it as a dev dependency. If it's published to npm/pypi, install via package.json/requirements. If not, document a `git clone + npm link` setup in `docs/MAINTENANCE.md`. + +If `auto_linter` is not yet published (likely), this is a brief contradiction — write a blocked-handoff requesting clarification. The architect (Claude) will respond with a path-fix. + +### 5.3 `agentic-test-*` gates (Ghenghis/agentic-testing integration) + +**`scripts/truth-gates.mjs`** — add 2 gates: + +- `agentic-test.coverage-audit` — runs `agentic_testing coverage --target src/ --output json`. Required gate. Fails if coverage < 80% for `src/server.mjs`, `src/core/lock-manager.mjs`, `src/core/gate-runner.mjs`, `src/core/event-manager.mjs`, `src/core/queue-manager.mjs`. Other files advisory. +- `agentic-test.self-heal` — runs `agentic_testing self-heal --dry-run --target test/`. Advisory gate. Reports tests that flake / break with a known-good fix recommendation. Never fails CI; reports findings in PROOF. + +Same dependency-availability concern as 5.2. + +### 5.4 `HERMES3D_ENV_FILE` resolution + +**`src/server.mjs`** — at the top of `main()`, before any `process.env.X` reads, add: + +```javascript +import { config as loadDotenv } from "dotenv"; +import fs from "node:fs"; +import path from "node:path"; + +// HERMES3D_ENV_FILE (general dev) takes precedence. +// HERMES3D_PROFILE=vps switches to HERMES3D_VPS_ENV_FILE. +// Falls back to ./.env if it exists (legacy in-tree pattern). +// +// Note: HermesProof's server.mjs is launched by MCP clients via stdio JSON-RPC. +// It does NOT parse process.argv for command flags. Profile selection therefore +// uses the HERMES3D_PROFILE env var (NOT a `--vps-mode` argv flag). +function resolveEnvFile() { + const profile = (process.env.HERMES3D_PROFILE || "").toLowerCase(); + if (profile === "vps" && process.env.HERMES3D_VPS_ENV_FILE) { + return process.env.HERMES3D_VPS_ENV_FILE; + } + if (process.env.HERMES3D_ENV_FILE) { + return process.env.HERMES3D_ENV_FILE; + } + const localEnv = path.resolve(process.cwd(), ".env"); + return fs.existsSync(localEnv) ? localEnv : null; +} + +const envFile = resolveEnvFile(); +if (envFile && fs.existsSync(envFile)) { + loadDotenv({ path: envFile }); +} +``` + +Add `dotenv` to `package.json` dependencies (currently 2 deps — adding a 3rd is acceptable for this use case). Pin to `^16.4` or current stable. + +`docs/MAINTENANCE.md` — document the resolution order: +1. `HERMES3D_PROFILE=vps` + `HERMES3D_VPS_ENV_FILE` env vars (deploy mode) +2. `HERMES3D_ENV_FILE` env var (explicit override) — recommended for users with secrets at `G:\private\.env` +3. `./.env` in current working directory (legacy fallback; ignored if `.env` doesn't exist) + +DO NOT log the resolved env file path at info level. Debug-level only, redacted. + +### 5.5 Hardened `.gitignore` + +**`.gitignore`** — append (at the bottom of the existing file): + +```gitignore +# 2026-05-03 hardening: catch secret-bearing variants the standard .env pattern misses +.env.txt +.env.bak +.env.old +.env.swp +.env~ +.env.deploy +.env2 +.env.production +.env.staging +.env.vps +.env.local +.env.*.local + +# Catch-all for any *.env file +*.env + +# But preserve documented templates +!.env.example +!.env.vps.example +!.env.deploy.example +``` + +`.env` itself is already there from earlier hardening. Don't duplicate. + +### 5.6 Pre-commit hook (`gitleaks protect`) + +**`.githooks/pre-commit`** — NEW: + +```bash +#!/usr/bin/env bash +# HermesProof pre-commit: block commits that introduce secrets + +set -e + +if ! command -v gitleaks &>/dev/null; then + echo "[pre-commit] gitleaks not installed; skipping secret-scan (install via go install or brew)" >&2 + exit 0 +fi + +gitleaks protect --staged --redact --no-banner --config .gitleaks.toml +``` + +Make executable: `chmod +x .githooks/pre-commit` and document in `docs/MAINTENANCE.md` how users install it: `git config core.hooksPath .githooks`. + +`scripts/wizard.mjs` — add a wizard step that asks "Install pre-commit hook for secret scanning? [Y/n]" and runs the `git config` line if yes. + +### 5.7 README + tool reference + +**`README.md`** — bump truth-gates count from 17 to 24 (17 existing + 7 new = 24 truth gates). + +**Important — gates ≠ tools:** the existing README shows two separate counts that get confused easily: +- "Truth gates" — the CI verification suite (currently 17, becoming 24 after this PR) +- "MCP tools" — the server's tool surface (currently 24; UNCHANGED by this PR) + +After v0.6 lands, both counts coincidentally equal 24. They are NOT the same metric — keep them in separate badges and separate prose. Don't write "24 gates and 24 tools = 24" or any equality claim. The truth-gates table needs the 7 new rows; the MCP-tools section is untouched. + +**`docs/TOOL_REFERENCE.md`** — add a "Truth gate inventory" section listing all 24 gates with one-line descriptions. + +**`package.json`** — bump version `0.5.0` → `0.6.0`. + +--- + +## 6. Tests + +Add to `scripts/coordination-smoke-test.mjs`: + +- `secret.scan rejects a synthetic Anthropic key in a tracked file` +- `secret.scan allowlist passes the .env.example synthetic placeholders` +- `auto-lint.check runs and emits SARIF` +- `agentic-test.coverage-audit fails when coverage drops below threshold` +- `HERMES3D_ENV_FILE resolution prefers env var over local .env` +- `HERMES3D_VPS_ENV_FILE only resolves when --vps-mode arg present` +- `pre-commit hook blocks staging of a synthetic secret` + +All tests must pass on Windows + Linux (HermesProof's existing matrix). If `gitleaks` / `auto_linter` / `agentic-testing` aren't installed in CI, gate the tests on `command -v` checks and skip with a clear "tool not installed" message; don't fail. + +--- + +## 7. Gates + +```text +hermes_run_gate gateId=git-status cwd=. +hermes_run_gate gateId=git-diff-check cwd=. +``` + +Local validation: +- `npm install` (with the new `dotenv` dep added) +- `npm test` — all existing 47+ tests + new ones pass +- `npm run truth-gates` — now reports 17→24 gates passing (or whatever the count actually is). All required gates green. +- `npm run truth-gates -- --ci` — CI subset green (some advisory gates may skip) +- `gitleaks detect --config .gitleaks.toml --no-git --redact` — scans clean against the working tree (allowlist must cover existing fixtures) +- `git diff --check` — no whitespace errors + +--- + +## 8. PR + close-out + +```bash +git push -u origin feat/cp-hermesproof-0.6-gate-pack +gh pr create --base main \ + --title "feat(0.6): Secret + Quality + Test gate pack — gitleaks + auto_linter + agentic-testing + HERMES3D_ENV_FILE" \ + --body "[mirror v0.5 PR body shape; Hermes evidence chain: PASS; Task: CP-HERMESPROOF-0.6; Gate run via hermes_run_gate]" +``` + +Close-out: + +```text +hermes_append_evidence + owner=codex-impl-05 + taskId=CP-HERMESPROOF-0.6 + kind=checkpoint + summary=v0.6 gate pack opened in PR #N at SHA ; gates total; secret.scan + auto-lint + agentic-test integrated. + +hermes_release_files owner=codex-impl-05 files=[the lock list] +hermes_release_task owner=codex-impl-05 taskId=CP-HERMESPROOF-0.6 +``` + +--- + +## 9. Hard rules + +- DO NOT add any actual API keys, real or test, to any file. Synthetic keys for tests must match the `sk-ant-test-...` prefix that the gitleaks allowlist exempts. +- DO NOT skip the secret.scan gate if `gitleaks` isn't installed in CI — install it via the official action. +- DO NOT commit any file from `G:\private\` or `C:\Users\Admin\Downloads\VPS\` even if a script or test seems to require it. +- DO NOT add `auto_linter` or `agentic-testing` as runtime dependencies (they're dev/test tools only). +- DO NOT touch any file outside the §4 lock list. +- If `Ghenghis/auto_linter` or `Ghenghis/agentic-testing` isn't installable (no published package), write a blocked-handoff and skip — DO NOT manually `git clone` the repo into `node_modules`. + +## 10. Failure protocol + +If `auto_linter` or `agentic-testing` aren't installable as packages, write `handoffs/HANDOFF_TO_CLAUDE_CP-HERMESPROOF-0.6_BLOCKED.md` quoting the exact failure mode. The architect can either: + +- Provide a path-fix (e.g., "use a stub for now, real integration in v0.6.1") +- Authorize partial scope (e.g., "ship just the secret.scan gate + .gitignore + pre-commit hook; defer auto_linter / agentic-testing to v0.6.1") + +If gitleaks itself is missing from CI runners' default image, install it via `gitleaks/gitleaks-action@`. Don't fail the PR over tool installation. diff --git a/handoffs/HANDOFF_TO_CODEX_OVERNIGHT_AUTOPILOT.md b/handoffs/HANDOFF_TO_CODEX_OVERNIGHT_AUTOPILOT.md new file mode 100644 index 00000000..0515c860 --- /dev/null +++ b/handoffs/HANDOFF_TO_CODEX_OVERNIGHT_AUTOPILOT.md @@ -0,0 +1,204 @@ +# HANDOFF_TO_CODEX — Overnight Autopilot Master Prompt + +> **Status:** ACTIVE once user authorizes "go". The user is going to sleep. You have explicit authorization to run unattended for the rest of the night, picking up tasks from the HermesProof queue (or the handoffs/ folder fallback), shipping PRs, and looping until the queue is empty. +> +> **Auto-merge is NOT authorized.** Open PRs and leave them OPEN with green CI for morning review by the architect. The architect (Claude) merges in the morning. +> +> **Architect contact:** Claude reviews everything in the morning. Do NOT block on architect questions overnight — write a `HANDOFF_TO_CLAUDE__BLOCKED.md`, release locks + task, and skip to the next task. Loop continues. + +--- + +## 1. Loop protocol + +Every iteration of the overnight loop: + +```text +1. hermes_doctor → confirm ok=true +2. hermes_get_state → confirm 0 codex-impl-* locks held +3. Determine the next task and its owner string from §3 (each brief specifies its + owner — they are NOT all `codex-impl-04`). For the first iteration use the + highest-priority unclaimed brief in §3. Then: + hermes_pick_task owner= prefer_task_id= + | + | If queue empty for that owner: ls handoffs/HANDOFF_TO_CODEX_*.md, find the + | highest-priority unclaimed brief (priority order in §3 below), claim it via + | hermes_claim_task using the Task ID and owner listed in the brief. + | + | If no unclaimed briefs: STOP. Write the morning report (see §4) and stop. + +4. Read the claimed brief end-to-end. +5. Verify lock list against actual files on develop (catch architect-side + contradictions BEFORE editing — same discipline you've used on B1/B2). + | + | If contradiction: write HANDOFF_TO_CLAUDE__BLOCKED.md with the + | exact ambiguity, release locks + task, append evidence kind=block, + | GO TO STEP 1 (try next task). + +6. hermes_lock_files (matches brief) +7. Implement per brief +8. Run local validation: npm test (if applicable), pytest -q, ruff, + git-status, git-diff-check, plus any brief-specific gates +9. git push -u origin ; gh pr create +10. Wait up to 12 minutes for CI: poll `gh pr view --json statusCheckRollup` + every 60 seconds. Required gates that must go green: mechanical-review, + Layer A, Layer B (all 4 cells), Layer C, Layer D, Layer D3, Layer F, + Layer M, Layer T, Layer W. Layer E correctly SKIPPED on non-release branches. +11. **DO NOT MERGE.** Leave the PR open with green CI. The architect reviews + and merges in the morning. +12. Close out HermesProof state: hermes_append_evidence (kind=checkpoint, + summary=PR #N opened at SHA , all gates green, awaiting architect + review), hermes_release_files, hermes_release_task. +13. GO TO STEP 1. +``` + +**Circuit breaker:** if you hit 3 consecutive blocked-handoffs OR 3 consecutive CI +failures that don't self-resolve, STOP and write `HANDOFF_TO_CLAUDE_OVERNIGHT_COMPLETE.md` +(same filename as the normal-completion report — distinguished by content). Set the +report's "Halt reason" field to `circuit-breaker-3-strikes`. Don't keep churning. + +**Verified-contradiction handling (§1 step 5):** a contradiction in a brief's +lock list vs. reality is a "blocked-handoff" and DOES count toward the 3-strike +circuit-breaker. This prevents getting stuck on consecutively-broken briefs. + +**12-min CI timeout:** if `gh pr view --json statusCheckRollup` doesn't show +all required gates as `SUCCESS` or `FAILURE` after 12 polls (12 minutes), treat +the iteration as a CI failure for circuit-breaker purposes. Update the PR body +with `[ci-timeout-pending-review]` and proceed to next task. + +**Heartbeat:** if a task takes longer than 90 minutes, call `hermes_heartbeat` +to extend the lock TTL. Don't let locks expire mid-work. + +**CI red but not blocker:** if CI fails on something you can fix (lint, test +flake, missing import), push a fix commit and re-poll. If CI fails on something +you cannot fix in <2 attempts, treat as blocked and skip. + +--- + +## 2. Boundaries — what you CAN and CANNOT do unattended + +### ✅ CAN do without user input + +- Pick + claim + lock + implement + open PR per §1 +- **Open PRs and leave them open** for morning architect review +- Self-correct: revert your own commits, fix linting, retry pre-push hooks, + rebase your own feature branch on top of fresh `develop` if there's been + a merge while you were working +- Spawn online research agents for narrowly-scoped questions (e.g., "what's + the gitleaks 2026 custom-pattern syntax for Anthropic API keys") +- Add advisory CI jobs (continue-on-error) that don't gate merges +- Update your own PR body / commit messages on PRs you own + +### 🚫 CANNOT do — these require user awake + +- **Auto-merge any PR**, including your own. Architect merges in the morning. +- **Cut `release/v5.3.0` or any `release/*` branch** +- **Push, merge, or modify `main` in any way** (branch protection blocks anyway) +- **Tag any `v*` version** or run `gh release create` +- **Connect to the user's VPS / SSH / Tailscale tailnet** +- **Run actual deployment commands** (`docker compose up`, `caddy reload`, etc. on real infra) +- **Read or write any of these paths:** + - `G:\private\` (anything) + - `C:\Users\Admin\Downloads\VPS\` (anything) + - Any `.env*` file in any repo working tree (only `.env.example` / + `.env.vps.example` templates) + - Any file containing API key values +- **Modify branch protection rules, GH secrets, repo settings** +- **Force-push to any branch you don't own** (your own feature branches OK + with `--force-with-lease`) +- **Hard-reset shared branches** (develop, main, release/*) +- **Delete any branch on origin** +- **Modify CI workflows that gate merges** (Layer A/B/C/D/D3/F/M/T/W) — adding + new advisory layers OK; modifying required layers is NOT +- **Open PRs that include any file under `04_testing/playwright/`'s recorded + baselines** without a clear test-update justification + +### ⚠️ ASK YOURSELF before any non-listed action + +"Would the user want to be woken up to approve this?" If yes, write the blocked +handoff and skip. If no, proceed. **Default is conservative — when in doubt, skip.** + +--- + +## 3. Tonight's queue (priority order) + +**Task 1 — H3D-SOTA-MARKETING-V2 (B5)** ⭐ TOP PRIORITY +- Brief: `handoffs/HANDOFF_TO_CODEX_SOTA_MARKETING_V2.md` (already on develop) +- Marketing site + README v2 with R3F hero + gcode-preview + VHS demo +- User explicitly excited about your design instincts on this — give it your best +- Owner string: `codex-impl-04` +- Lock list and full spec in the existing brief + +**Task 2 — H3D-BLENDER-AUDIT** (research only — smallest scope, lowest risk) +- Brief: `handoffs/HANDOFF_TO_CODEX_BLENDER_MCP_AUDIT.md` (this PR) +- Audit `https://github.com/rakaarwaky/blender-mcp-native` — output is an ADR, + no code changes +- Owner string: `codex-impl-05` + +**Task 3 — CP-HERMESPROOF-0.6** (gate pack — foundational) +- Brief: `handoffs/HANDOFF_TO_CODEX_HERMESPROOF_0.6_GATE_PACK.md` (this PR) +- gitleaks + auto_linter + agentic-testing + HERMES3D_ENV_FILE + + hardened .gitignore +- This goes in the **HermesProof repo** (`G:\Github\hermes3d-mcp-lock-orchestrator`), + NOT Hermes3D. Different working tree. +- Owner string: `codex-impl-hp` (HermesProof-specific owner to avoid collision + with `codex-impl-05` used in Hermes3D Task 2; the HermesProof state is a + separate workspace, but explicit prefix prevents confusion in cross-repo logs) + +**Task 4a — CP-HERMES3D-LOCAL-LM-STUDIO** (split from former mega-task) +- Brief: `handoffs/HANDOFF_TO_CODEX_HERMES3D_LOCAL_LM_STUDIO.md` (this PR) +- LM Studio default provider, Ollama fallback (modify existing `ollama_client.py`), + Hipfire optional. NO UI changes, NO Mnemosyne, NO port monitor. +- Owner string: `codex-impl-06` + +**Task 4b — CP-HERMES3D-MNEMOSYNE-RECALL** (split from former mega-task) +- Brief: `handoffs/HANDOFF_TO_CODEX_HERMES3D_MNEMOSYNE_RECALL.md` (this PR) +- `mnemosyne-memory` (correct PyPI name) integration as recall layer +- Owner string: `codex-impl-07` + +**Task 4c — CP-HERMES3D-SERVICE-HEALTH** (split from former mega-task) +- Brief: `handoffs/HANDOFF_TO_CODEX_HERMES3D_SERVICE_HEALTH.md` (this PR) +- In-house port probe + new top-level `/health` React route + `/api/health/services` + FastAPI endpoint. NO Settings tab assumption (the audit confirmed it doesn't exist). +- Owner string: `codex-impl-08` + +**Order matters:** B5 first (most user-visible), then BLENDER-AUDIT (smallest, validates +the loop works), then HermesProof v0.6 (foundational), then 4a → 4b → 4c (split from +the former mega-task; each independently completable so a Mnemosyne package quirk +doesn't block LM Studio or Service Health). + +If you finish all six, claim a v0.5.1 perf-companion PR for HermesProof addressing +Gemini's 4 deferred items (init-once guard, O(1) heartbeat-by-id, parallel readTasks, +per-task error handling in recoverStaleTasks). Owner: `codex-impl-hp-perf`. Stop after that. + +--- + +## 4. The morning report + +When the loop finally stops (queue empty OR circuit breaker tripped), write: + +`handoffs/HANDOFF_TO_CLAUDE_OVERNIGHT_COMPLETE.md` + +Containing: + +- **Summary table:** task id, status (PR opened / blocked / skipped), PR #, commit SHA, test counts +- **What's open for review:** list of PRs awaiting architect merge, with one-line descriptions +- **What blocked:** list of each blocked-handoff with link to the file and a one-line reason +- **What was skipped:** any task that was claimed but couldn't proceed for a non-blocker reason +- **Surprises / observations:** anything unusual you noticed (test infra issues, develop drift, + unexpected file states, agent research results worth flagging, etc.) +- **Recommended next steps:** what the architect should look at first when they wake up + +Then commit + push to `docs/overnight-results-` branch and open a PR for visibility. +DO NOT auto-merge this morning report PR — it's the hand-back to the architect. + +--- + +## 5. Hard rules summary (one-liner version) + +1. Pick → lock → implement → PR → leave OPEN with green CI → release locks + task → loop +2. Skip on blocker, never block on the architect overnight +3. No auto-merge, no release cut, no main push, no tags, no VPS, no secrets +4. Heartbeat long tasks; circuit-breaker after 3 consecutive failures +5. Write the morning report when done; that PR does NOT auto-merge either + +The discipline you've shown across CP5.1-A through B4 has earned this trust. Sleep is the user's; the work is yours. diff --git a/handoffs/PROJECT_COMPLETION_ROADMAP.md b/handoffs/PROJECT_COMPLETION_ROADMAP.md new file mode 100644 index 00000000..3c05922a --- /dev/null +++ b/handoffs/PROJECT_COMPLETION_ROADMAP.md @@ -0,0 +1,117 @@ +# Project Completion Roadmap — pre-written briefs queue + +> **Purpose:** Forward-look at the next 8-15 checkpoints across both Hermes3D and HermesProof. The 4 overnight-priority briefs have full specs (linked below). The rest are one-paragraph stubs marked `[NEEDS-FULL-BRIEF]` — they can't be picked up until expanded. +> +> **For Codex's overnight loop:** ONLY pick tasks marked `READY` in the table below. Skip anything `[NEEDS-FULL-BRIEF]`. + +--- + +## Status legend + +- ✅ **MERGED** — landed on develop or main, closed +- 🟢 **READY** — full brief exists, Codex can claim and ship +- 🟡 **STUB** — paragraph-level description; needs architect expansion before claim +- 🔵 **DEFERRED** — explicitly post-v6 or post-v5.3 release; don't touch + +--- + +## Hermes3D-OS + +| ID | Title | Status | Brief | +|---|---|---|---| +| H3D-CP5.1-A | Phase 5.1 plan + ADR-013 | ✅ | merged | +| H3D-CP5.1-B | failure_predictor + backup scheduler | ✅ | merged | +| H3D-CP5.1-C | profile_generator + skill_store + doctor JSON | ✅ | merged | +| H3D-CP5.1-D | Gradio smoke + matrix coverage gate | ✅ | merged | +| H3D-CP5.1-E | Phase 5.1 completion report + proof bundle | ✅ | merged | +| H3D-WINREL-MVP | Windows release MVP (PyInstaller + Velopack) | ✅ | merged | +| H3D-VPS-DEPLOY | Hostinger VPS deploy bundle | ✅ | merged | +| H3D-LOCAL-BACKUP | Syncthing + Restic-B2 scripts | ✅ | merged | +| H3D-MARKETING-V1 | Marketing site v1 (4 SVGs + landing) | ✅ | merged | +| H3D-SOTA-MARKETING-V2 | Codex's design-led SOTA marketing upgrade | 🟢 | `HANDOFF_TO_CODEX_SOTA_MARKETING_V2.md` | +| H3D-BLENDER-AUDIT | Audit `rakaarwaky/blender-mcp-native` (research only ADR) | 🟢 | `HANDOFF_TO_CODEX_BLENDER_MCP_AUDIT.md` | +| CP-HERMESPROOF-0.6 | Secret + Quality + Test gate pack (HermesProof repo) | 🟢 | `HANDOFF_TO_CODEX_HERMESPROOF_0.6_GATE_PACK.md` | +| ~~H3D-LOCAL-INTELLIGENCE~~ | ~~mega-task superseded after audit FAIL~~ | 🚫 | SUPERSEDED — see splits below | +| H3D-LOCAL-LM-STUDIO | Task 4a — LM Studio default + Ollama fallback + Hipfire optional | 🟢 | `HANDOFF_TO_CODEX_HERMES3D_LOCAL_LM_STUDIO.md` | +| H3D-MNEMOSYNE-RECALL | Task 4b — `mnemosyne-memory` recall layer (NOT canonical) | 🟢 | `HANDOFF_TO_CODEX_HERMES3D_MNEMOSYNE_RECALL.md` | +| H3D-SERVICE-HEALTH | Task 4c — in-house port probe + new top-level `/health` route | 🟢 | `HANDOFF_TO_CODEX_HERMES3D_SERVICE_HEALTH.md` | +| H3D-HERMES-AGENT-PORT-PATTERNS | Port 3 patterns from `NousResearch/hermes-agent` v0.12.0: registry, injection-defense scanner, delegate isolation | 🟡 | [NEEDS-FULL-BRIEF — research agent flagged: Hermes Agent is ACTIVE not stale; 130k stars, last push 2026-05-03; MIT licensed; ADOPT-SELECTIVELY verdict] | +| H3D-SETTINGS-TAB-FULL | Implement React Settings tab fully (provider config form, env-var management UI, validation) | 🟡 | [NEEDS-FULL-BRIEF — architect to write] | +| H3D-SCREENSHOT-CAPTURE | Playwright-driven 22-shot capture pass + commit to `site/screenshots/` | 🟡 | [NEEDS-FULL-BRIEF — depends on launcher running locally] | +| H3D-VHS-DEMO | Author + render `site/demos/quickstart.tape` to GIF + MP4 | 🟡 | [NEEDS-FULL-BRIEF — depends on CLI being demoable] | +| H3D-RELEASE-V5.3.0 | Cut release/v5.3.0 → main → tag → gh release create | 🔵 | DEFERRED — user must authorize release cut | +| H3D-WINREL-SIGN | Phase 5B — Azure Artifact Signing + winget manifest | 🟡 | [NEEDS-FULL-BRIEF — pending user signing up for Azure Artifact Signing $9.99/mo] | +| H3D-DOCS-CONSOLIDATION | Move dev-internal README content to CONTRIBUTING.md + tighten AGENTS.md | 🟡 | [NEEDS-FULL-BRIEF] | +| H3D-HIPFIRE-OPTIONAL | Wire `rakaarwaky/hipfire` AMD provider (gated on env var) | 🟡 | [NEEDS-FULL-BRIEF — only meaningful if user spins up an AMD inference node] | +| H3D-ANYTYPE-OPTIONAL | Anytype docs / knowledge graph integration | 🔵 | DEFERRED — post-v6 | + +--- + +## HermesProof + +| ID | Title | Status | Brief | +|---|---|---|---| +| HP-0.4 | Trigger bridge (4 event tools, hash-chained ledger) | ✅ | merged | +| HP-0.4.1 | Perf + robustness (streaming evidence, lazy events, webhook timeout) | ✅ | merged (PR #14) | +| HP-0.5.0 | Task queue (4 new tools, 14 → 17 truth gates) | ✅ | merged (PR #15) | +| HP-WIZARD | Universal setup wizard (6-client interactive CLI) | ✅ | merged (PR #16) | +| HP-SITE-V1 | Marketing site (HermesProof's own GH Pages) | ✅ | merged (PRs #12, #17) | +| HP-V0.5.0-RELEASE | GitHub release v0.5.0 published | ✅ | https://github.com/Ghenghis/HermesProof/releases/tag/v0.5.0 | +| HP-0.5.1-PERF | Gemini's 4 deferred items (init-once guard, O(1) heartbeat-by-id, parallel readTasks, per-task error handling in recoverStaleTasks) | 🟡 | [NEEDS-FULL-BRIEF — small, can be written quickly] | +| CP-HERMESPROOF-0.6 | Secret + Quality + Test gate pack (cross-listed; lives in HermesProof repo) | 🟢 | `HANDOFF_TO_CODEX_HERMESPROOF_0.6_GATE_PACK.md` | +| HP-0.7-MNEMOSYNE-RECALL | Use Mnemosyne for HermesProof's own conflict-pattern recall (optional, debatable) | 🔵 | DEFERRED — not strictly needed; HermesProof has its own evidence ledger | +| HP-DOCS-V05-AUDIT | Audit existing v0.5.0 release notes for accuracy after a few weeks of usage | 🟡 | [NEEDS-FULL-BRIEF — wait until users have hit any v0.5 quirks first] | + +--- + +## Tonight's overnight queue (priority order) + +Codex picks these in order: + +1. **🟢 H3D-SOTA-MARKETING-V2** — `HANDOFF_TO_CODEX_SOTA_MARKETING_V2.md` (already on develop pre-overnight) +2. **🟢 H3D-BLENDER-AUDIT** — `HANDOFF_TO_CODEX_BLENDER_MCP_AUDIT.md` +3. **🟢 CP-HERMESPROOF-0.6** — `HANDOFF_TO_CODEX_HERMESPROOF_0.6_GATE_PACK.md` (in HermesProof repo) +4. **🟢 H3D-LOCAL-LM-STUDIO** (4a) — `HANDOFF_TO_CODEX_HERMES3D_LOCAL_LM_STUDIO.md` +5. **🟢 H3D-MNEMOSYNE-RECALL** (4b) — `HANDOFF_TO_CODEX_HERMES3D_MNEMOSYNE_RECALL.md` +6. **🟢 H3D-SERVICE-HEALTH** (4c) — `HANDOFF_TO_CODEX_HERMES3D_SERVICE_HEALTH.md` + +If all 6 ship cleanly + circuit breaker is happy, claim **HP-0.5.1-PERF** as a stretch goal. The brief is a stub (no full spec) but the 4 perf items are well-documented in PR #15's review comments — Codex can write the implementation directly from there if they're confident, otherwise treat as `[NEEDS-FULL-BRIEF]` and skip. + +**Audit posture (overnight):** +- Round 1 (Claude's audit agents): COMPLETE — caught 16 critical issues across 4 briefs (master, BLENDER, v0.6, LOCAL-INTELLIGENCE). All fixed in this PR; LOCAL-INTELLIGENCE split into 4a/4b/4c. +- Round 2 (Claude's audit agents on the FIXED briefs + 3 NEW splits): pending. +- Round 3 (Codex's own audit pass): pending — Codex must verify each brief before claiming. +- Round 4 (overnight execution): only after rounds 1-3 PASS. + +--- + +## Where the markdowns live + +All overnight-queue briefs are at: + +``` +G:\Github\Hermes3D\handoffs\ + HANDOFF_TO_CODEX_OVERNIGHT_AUTOPILOT.md ← master loop protocol (start here) + HANDOFF_TO_CODEX_SOTA_MARKETING_V2.md ← B5 / Task 1 (already on develop pre-overnight) + HANDOFF_TO_CODEX_BLENDER_MCP_AUDIT.md ← Task 2 + HANDOFF_TO_CODEX_HERMESPROOF_0.6_GATE_PACK.md ← Task 3 (HermesProof repo, not Hermes3D) + HANDOFF_TO_CODEX_HERMES3D_LOCAL_INTELLIGENCE.md ← Task 4 + PROJECT_COMPLETION_ROADMAP.md ← this file (forward-look) +``` + +The HermesProof v0.6 task is implemented in a different repo +(`G:\Github\hermes3d-mcp-lock-orchestrator`), but the BRIEF lives here +(in Hermes3D's handoffs/) for queue discoverability. Codex needs to `cd` to +the HermesProof repo to actually do the work for that one task. + +--- + +## Morning report convention + +When the loop stops, Codex writes: + +``` +G:\Github\Hermes3D\handoffs\HANDOFF_TO_CLAUDE_OVERNIGHT_COMPLETE.md +``` + +Including: summary table, what's open for review, what blocked, surprises, recommended next steps. Then commits to `docs/overnight-results-` and opens a PR (which itself does NOT auto-merge).