diff --git a/AGENTS.md b/AGENTS.md index 1926f56..47c1048 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,8 +31,9 @@ gh project item-list 2 --owner traverse-framework --format json --limit 300 \ | `llm-mcp-traverse-starter-catalog` | **Blocked** | Traverse #865 (registry #99 closed) | | `loop-wf1-registry-deps` | **Done** (#263) | Digest inventory in `docs/loop-registry-deps.md` | | `loop-wf1-multi-os` | **Done** (#265) | `apps/loop/` WF1 × 7 OS; compose via `registry_ref` | -| `retire-registry-ref-materialize` | **In Progress** | Phase A gate/docs; full delete blocked on Traverse BundleEmbedder + Spec 107 | -| `llm-mcp-embedded-host` | **Ready** | Mode B host on Spec 520 cache (#860 closed) | +| `retire-registry-ref-materialize` | **Done** (#267) | Phase A gate; host cutover → Future `retire-registry-ref-materialize-hosts` | +| `retire-registry-ref-materialize-hosts` | **Future** | Full materialize delete after BundleEmbedder + Spec 107 | +| `llm-mcp-embedded-host` | **In Progress** | Mode B scaffold on Spec 520 cache; live host → Traverse #865 | Full gap table + wave notes: [`docs/production-reference-plan.md`](docs/production-reference-plan.md). diff --git a/apps/llm-mcp-reference/README.md b/apps/llm-mcp-reference/README.md index 5ca979e..ce4497b 100644 --- a/apps/llm-mcp-reference/README.md +++ b/apps/llm-mcp-reference/README.md @@ -11,6 +11,7 @@ Plan: [`docs/llm-reference-apps-plan.md`](../../docs/llm-reference-apps-plan.md) ```text apps/llm-mcp-reference/ README.md ← this file + mode-b/ ← Spec 520 prepare/cache scaffold (fail-closed serve) shared/ prompts/system-boundary.md workflows/traverse-starter.md @@ -38,6 +39,14 @@ cargo run -p traverse-mcp -- stdio 4. Follow `shared/workflows/traverse-starter.md` — submit a note via tools; **only display runtime fields**. 5. For transcripts, follow `shared/workflows/meeting-notes.md` — concrete `describe_server` → `execute_entrypoint` → `render_execution_report` sequence for `meeting-notes.process`. +## Mode B (scaffold — Spec 520 prepare / verified cache) + +Stronger isolation path: prepare registry deps into a **host-owned verified cache**, then serve MCP from that cache — **no App-Refs materialize rewrite**. + +See [`mode-b/README.md`](mode-b/README.md), [`mode-b/mcp.json.example`](mode-b/mcp.json.example), and fail-closed [`mode-b/serve.sh`](mode-b/serve.sh). + +**Honest status:** Spec 520 library APIs shipped in Traverse (#860). The Mode B MCP host process is **not** upstream yet (Traverse #865). Mode A remains the only runnable LLM path; Mode B launcher exits non-zero until that host exists. + Optional bearer token (execution commands): ```bash diff --git a/apps/llm-mcp-reference/mode-b/README.md b/apps/llm-mcp-reference/mode-b/README.md new file mode 100644 index 0000000..8ec1dab --- /dev/null +++ b/apps/llm-mcp-reference/mode-b/README.md @@ -0,0 +1,77 @@ +# Mode B — MCP → Spec 520 prepare / verified cache (scaffold) + +Secondary façade for LLM clients that want **stronger isolation** than Mode A expedition stdio: prepare registry dependencies into a **host-owned verified cache**, then serve MCP from that cache (no App-Refs `materialize` rewrite). + +| Layer | Status | +|---|---| +| Spec 520 library (`HostRegistryCache`, prepare / offline resolve) | Shipped in Traverse (#860) | +| Mode B MCP host process (`traverse-mcp` embedded / cache-root serve) | **Not shipped upstream** — see Traverse #865 | +| This tree | **Scaffold** — docs + fail-closed launcher + example MCP config | + +Mode A (`cargo run -p traverse-mcp -- stdio`) remains the only **runnable** LLM path today. + +## Contract (prepare → cache → serve) + +```text +LLM client --MCP stdio--> mode-b/serve.sh --> Traverse Mode B host (when shipped) + ^ + | + TRAVERSE_MCP_CACHE_ROOT (host-owned verified cache) + ^ + | + mode-b/prepare-cache.sh (index sync + Spec 520 prepare docs) +``` + +Rules: + +1. **No business fields** in this façade — same as Mode A / OS shells. +2. **No App-Refs materialize** — leave `registry_ref` intact; do not rewrite destination manifests to local `wasm_*` paths here. +3. **Fail closed** — `serve.sh` must not silently fall back to Mode A expedition stdio (that would mislabel Mode B). + +## Env + +| Variable | Meaning | +|---|---| +| `TRAVERSE_REPO` | Absolute path to Traverse checkout | +| `TRAVERSE_MCP_CACHE_ROOT` | Host-owned cache directory (you create/own it) | +| `TRAVERSE_WORKSPACE` | Registry workspace id (default `local-default`) | +| `TRAVERSE_REGISTRY_TOKEN` | Optional token for private registry sync | + +## Prepare (documented) + +```bash +export TRAVERSE_REPO="$(cd ../../../../Traverse && pwd)" # adjust +export TRAVERSE_MCP_CACHE_ROOT="${HOME}/.cache/traverse-mcp-mode-b" +export TRAVERSE_WORKSPACE=local-default +bash prepare-cache.sh +``` + +`prepare-cache.sh` runs public index sync via `traverse-cli` and prints the Spec 520 **library** prepare steps. There is no public one-liner CLI for artifact prepare yet — hosts call: + +- Rust: `traverse_embedder::{HostRegistryCache, prepare_registry_dependency, resolve_registry_dependency_offline}` +- Web (reference): `prepareRegistryDependency` / `resolveRegistryDependencyOffline` from TraverseEmbedder + +## Serve (fail-closed until upstream Mode B host) + +```bash +bash serve.sh +``` + +Intended upstream shape (not available yet): + +```bash +cargo run -p traverse-mcp -- embedded --cache-root "$TRAVERSE_MCP_CACHE_ROOT" +# or env-driven offline serve once Traverse ships it +``` + +Today `serve.sh` exits non-zero with a clear message. Point LLM clients at Mode A until Traverse lands the Mode B host (umbrella #865). + +## MCP client example + +See [`mcp.json.example`](mcp.json.example). Absolute paths required. + +## Upstream + +- Spec 520 / `080-embedded-registry-cache` +- Traverse issue [#865](https://github.com/traverse-framework/Traverse/issues/865) (Mode B host child) +- App-Refs Mode A: [`../README.md`](../README.md) diff --git a/apps/llm-mcp-reference/mode-b/mcp.json.example b/apps/llm-mcp-reference/mode-b/mcp.json.example new file mode 100644 index 0000000..52c0eee --- /dev/null +++ b/apps/llm-mcp-reference/mode-b/mcp.json.example @@ -0,0 +1,15 @@ +{ + "mcpServers": { + "traverse-mode-b": { + "command": "bash", + "args": [ + "/ABS/PATH/TO/App-References/apps/llm-mcp-reference/mode-b/serve.sh" + ], + "env": { + "TRAVERSE_REPO": "/ABS/PATH/TO/Traverse", + "TRAVERSE_MCP_CACHE_ROOT": "/ABS/PATH/TO/host-owned-cache", + "TRAVERSE_WORKSPACE": "local-default" + } + } + } +} diff --git a/apps/llm-mcp-reference/mode-b/prepare-cache.sh b/apps/llm-mcp-reference/mode-b/prepare-cache.sh new file mode 100755 index 0000000..f53c2c3 --- /dev/null +++ b/apps/llm-mcp-reference/mode-b/prepare-cache.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# Mode B prepare helper — Spec 520 verified cache supply chain (scaffold). +# Syncs the public registry index; documents library prepare (no App-Refs materialize). +set -euo pipefail + +if [ -z "${TRAVERSE_REPO:-}" ]; then + echo "FAIL: set TRAVERSE_REPO to your Traverse checkout" >&2 + exit 1 +fi +if [ -z "${TRAVERSE_MCP_CACHE_ROOT:-}" ]; then + echo "FAIL: set TRAVERSE_MCP_CACHE_ROOT to a host-owned cache directory" >&2 + exit 1 +fi + +WORKSPACE="${TRAVERSE_WORKSPACE:-local-default}" +mkdir -p "$TRAVERSE_MCP_CACHE_ROOT" + +echo "OK: TRAVERSE_REPO=$TRAVERSE_REPO" +echo "OK: TRAVERSE_MCP_CACHE_ROOT=$TRAVERSE_MCP_CACHE_ROOT" +echo "OK: TRAVERSE_WORKSPACE=$WORKSPACE" +echo "OK: Mode B does not use App-Refs sync materialize rewrite (registry_ref stays as-is)" + +cd "$TRAVERSE_REPO" +echo "→ registry index sync (network-capable prepare phase)…" +cargo run -p traverse-cli -- registry sync --workspace "$WORKSPACE" --json + +cat <<'EOF' + +Next (Spec 520 library — no public CLI yet): + Rust: traverse_embedder::HostRegistryCache + prepare_registry_dependency + then resolve_registry_dependency_offline / EmbedderConfig::with_registry_cache + Web: prepareRegistryDependency / resolveRegistryDependencyOffline + +Cache bytes stay under TRAVERSE_MCP_CACHE_ROOT (host-owned). +Then run: bash serve.sh # fail-closed until Traverse Mode B host ships (#865) +EOF diff --git a/apps/llm-mcp-reference/mode-b/serve.sh b/apps/llm-mcp-reference/mode-b/serve.sh new file mode 100755 index 0000000..257192c --- /dev/null +++ b/apps/llm-mcp-reference/mode-b/serve.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# Mode B MCP launcher — fail closed until Traverse ships an embedded/cache host. +# Do NOT silently fall back to Mode A expedition stdio (would mislabel Mode B). +set -euo pipefail + +if [ -z "${TRAVERSE_REPO:-}" ]; then + echo "FAIL: set TRAVERSE_REPO" >&2 + exit 1 +fi +if [ -z "${TRAVERSE_MCP_CACHE_ROOT:-}" ]; then + echo "FAIL: set TRAVERSE_MCP_CACHE_ROOT (Spec 520 host-owned verified cache)" >&2 + exit 1 +fi + +cd "$TRAVERSE_REPO" + +# Probe for a future Mode B entrypoint without inventing one. +if cargo run -p traverse-mcp -- --help 2>/dev/null | grep -Eqi 'embedded|cache-root|mode-b'; then + echo "OK: Mode B-looking traverse-mcp help found — wire serve.sh to the shipped flags and re-run." + echo "HINT: intended shape: cargo run -p traverse-mcp -- embedded --cache-root \"\$TRAVERSE_MCP_CACHE_ROOT\"" + exit 2 +fi + +cat <&2 +FAIL: Mode B host not yet shipped in Traverse. + Spec 520 prepare/cache libraries exist (#860); MCP embedded/cache serve does not. + Track: https://github.com/traverse-framework/Traverse/issues/865 + Use Mode A for a runnable path: cargo run -p traverse-mcp -- stdio + Cache root configured: $TRAVERSE_MCP_CACHE_ROOT +EOF +exit 2 diff --git a/docs/llm-reference-apps-plan.md b/docs/llm-reference-apps-plan.md index fb6486e..3426c10 100644 --- a/docs/llm-reference-apps-plan.md +++ b/docs/llm-reference-apps-plan.md @@ -76,7 +76,7 @@ Shared: | Mode | When | Notes | |---|---|---| | **A. MCP stdio → local Traverse** (v1 default) | Developer laptop / agent IDE | `cargo run -p traverse-mcp -- stdio` with `TRAVERSE_REPO` | -| **B. MCP → embedded host in a sidecar process** | Stronger product isolation | Future; align with Spec 520 prepare/cache | +| **B. MCP → embedded host in a sidecar process** | Stronger product isolation | **Scaffolded** under `apps/llm-mcp-reference/mode-b/` (Spec 520 prepare/cache docs + fail-closed launcher). Live host still blocked on Traverse #865 | | **C. Remote MCP gateway** | Multi-tenant SaaS | Future; needs auth/tenancy — not this slice | v1 documents **Mode A** only. Do not revive HTTP `traverse-cli serve` as the production architecture for primary OS shells; MCP stdio is a **separate agent façade**, not a replacement for embedded Web/iOS/Android clients. @@ -92,7 +92,7 @@ v1 documents **Mode A** only. Do not revive HTTP `traverse-cli serve` as the pro | `llm-mcp-chatgpt-adapter` | ChatGPT Actions/GPT mapping (or MCP when shipped) | Future / Ready when API stable | | `llm-mcp-grok-adapter` | Grok tool-calling mapping | Future / Ready when API stable | | `llm-mcp-traverse-starter-catalog` | Expose kit (`traverse-starter.*` / meeting-notes) on MCP stdio catalog | Blocked — Traverse [#865](https://github.com/traverse-framework/Traverse/issues/865) / registry [#99](https://github.com/traverse-framework/registry/issues/99) | -| `llm-mcp-embedded-host` | Mode B embedded prepare/cache for MCP host | Blocked on Traverse Spec 520 implement | +| `llm-mcp-embedded-host` | Mode B embedded prepare/cache for MCP host | Scaffold Done (this slice); live Mode B host waits on Traverse #865 | ## Success criteria (plan slice) diff --git a/scripts/ci/llm_mcp_reference_smoke.sh b/scripts/ci/llm_mcp_reference_smoke.sh index 8c5cd00..b9aaec6 100755 --- a/scripts/ci/llm_mcp_reference_smoke.sh +++ b/scripts/ci/llm_mcp_reference_smoke.sh @@ -33,6 +33,27 @@ need apps/llm-mcp-reference/clients/cursor/evidence/cursor-mcp-stdio-transcript. need apps/llm-mcp-reference/clients/cursor/evidence/cursor-mcp-execute-transcript.jsonl need apps/llm-mcp-reference/clients/chatgpt/README.md need apps/llm-mcp-reference/clients/grok/README.md +# Mode B scaffold (Spec 520 prepare/cache — fail-closed until Traverse host ships) +need apps/llm-mcp-reference/mode-b/README.md +need apps/llm-mcp-reference/mode-b/mcp.json.example +need apps/llm-mcp-reference/mode-b/prepare-cache.sh +need apps/llm-mcp-reference/mode-b/serve.sh +if ! rg -q 'TRAVERSE_MCP_CACHE_ROOT' "$ROOT/apps/llm-mcp-reference/mode-b/mcp.json.example"; then + echo "FAIL: mode-b mcp example must set TRAVERSE_MCP_CACHE_ROOT" + fail=1 +fi +if ! rg -q 'HostRegistryCache|prepare_registry_dependency|Spec 520' "$ROOT/apps/llm-mcp-reference/mode-b/README.md"; then + echo "FAIL: mode-b README must document Spec 520 prepare/cache APIs" + fail=1 +fi +if ! rg -qi 'not yet shipped|Mode B host not yet|fail' "$ROOT/apps/llm-mcp-reference/mode-b/serve.sh"; then + echo "FAIL: mode-b serve.sh must fail closed until Traverse Mode B host ships" + fail=1 +fi +if rg -q 'APP_REFS_MATERIALIZE_REGISTRY_REFS|sync_bundle_materialize_registry_refs' "$ROOT/apps/llm-mcp-reference/mode-b"; then + echo "FAIL: mode-b must not depend on App-Refs materialize rewrite" + fail=1 +fi # Configs must mention traverse-mcp, not invent business fields if ! rg -q 'traverse-mcp' "$ROOT/apps/llm-mcp-reference/clients/claude-desktop/mcp.json.example"; then echo "FAIL: claude-desktop mcp example must reference traverse-mcp"