fix(hooks): check venv cache path before marketplace path

Startup hooks in data-platform and pr-review were checking for venvs
at the marketplace path (~/.claude/plugins/marketplaces/.../mcp-servers/)
which gets wiped on updates. The actual venvs live in the cache directory
(~/.cache/claude-mcp-venvs/) which survives updates.

This caused false "MCP venv missing" errors even when venvs existed,
wasting hours of debugging time.

Fixed hooks now check cache path first, matching the pattern used
by run.sh scripts.

Also updated docs/CANONICAL-PATHS.md with the correct venv path pattern
to prevent future occurrences.

Lesson learned: lessons/patterns/startup-hooks-must-check-venv-cache-path-first

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-02 22:13:40 -05:00
parent db8fec42f2
commit c9e054e013
3 changed files with 51 additions and 9 deletions

View File

@@ -182,10 +182,42 @@ MCP servers are **shared at repository root** and configured in `.mcp.json`.
| MCP configuration | `.mcp.json` | `.mcp.json` (at repo root) | | MCP configuration | `.mcp.json` | `.mcp.json` (at repo root) |
| Shared MCP server | `mcp-servers/{server}/` | `mcp-servers/gitea/` | | Shared MCP server | `mcp-servers/{server}/` | `mcp-servers/gitea/` |
| MCP server code | `mcp-servers/{server}/mcp_server/` | `mcp-servers/gitea/mcp_server/` | | MCP server code | `mcp-servers/{server}/mcp_server/` | `mcp-servers/gitea/mcp_server/` |
| MCP venv | `mcp-servers/{server}/.venv/` | `mcp-servers/gitea/.venv/` | | MCP venv (local) | `mcp-servers/{server}/.venv/` | `mcp-servers/gitea/.venv/` |
**Note:** Plugins do NOT have their own `mcp-servers/` directories. All MCP servers are shared at root and configured via `.mcp.json`. **Note:** Plugins do NOT have their own `mcp-servers/` directories. All MCP servers are shared at root and configured via `.mcp.json`.
### MCP Venv Paths - CRITICAL
**Venvs live in a CACHE directory that SURVIVES marketplace updates.**
When checking for venvs, ALWAYS check in this order:
| Priority | Path | Survives Updates? |
|----------|------|-------------------|
| 1 (CHECK FIRST) | `~/.cache/claude-mcp-venvs/leo-claude-mktplace/{server}/.venv/` | YES |
| 2 (fallback) | `{marketplace}/mcp-servers/{server}/.venv/` | NO |
**Why cache first?**
- Marketplace directory gets WIPED on every update/reinstall
- Cache directory SURVIVES updates
- False "venv missing" errors waste hours of debugging
**Pattern for hooks checking venvs:**
```bash
CACHE_VENV="$HOME/.cache/claude-mcp-venvs/leo-claude-mktplace/{server}/.venv/bin/python"
LOCAL_VENV="$MARKETPLACE_ROOT/mcp-servers/{server}/.venv/bin/python"
if [[ -f "$CACHE_VENV" ]]; then
VENV_PATH="$CACHE_VENV"
elif [[ -f "$LOCAL_VENV" ]]; then
VENV_PATH="$LOCAL_VENV"
else
echo "venv missing"
fi
```
**See lesson learned:** [Startup Hooks Must Check Venv Cache Path First](https://gitea.hotserv.cloud/personal-projects/leo-claude-mktplace/wiki/lessons/patterns/startup-hooks-must-check-venv-cache-path-first)
### Documentation Paths ### Documentation Paths
| Type | Location | | Type | Location |

View File

@@ -5,13 +5,18 @@
PREFIX="[data-platform]" PREFIX="[data-platform]"
# Check if MCP venv exists # Check if MCP venv exists - check cache first, then local
CACHE_VENV="$HOME/.cache/claude-mcp-venvs/leo-claude-mktplace/data-platform/.venv/bin/python"
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "$(realpath "$0")")")}" PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "$(realpath "$0")")")}"
# MCP servers are at marketplace root, not inside plugin
MARKETPLACE_ROOT="$(dirname "$(dirname "$PLUGIN_ROOT")")" MARKETPLACE_ROOT="$(dirname "$(dirname "$PLUGIN_ROOT")")"
VENV_PATH="$MARKETPLACE_ROOT/mcp-servers/data-platform/.venv/bin/python" LOCAL_VENV="$MARKETPLACE_ROOT/mcp-servers/data-platform/.venv/bin/python"
if [[ ! -f "$VENV_PATH" ]]; then # Check cache first (preferred), then local
if [[ -f "$CACHE_VENV" ]]; then
VENV_PATH="$CACHE_VENV"
elif [[ -f "$LOCAL_VENV" ]]; then
VENV_PATH="$LOCAL_VENV"
else
echo "$PREFIX MCP venv missing - run /initial-setup or setup.sh" echo "$PREFIX MCP venv missing - run /initial-setup or setup.sh"
exit 0 exit 0
fi fi

View File

@@ -5,13 +5,18 @@
PREFIX="[pr-review]" PREFIX="[pr-review]"
# Check if MCP venv exists # Check if MCP venv exists - check cache first, then local
CACHE_VENV="$HOME/.cache/claude-mcp-venvs/leo-claude-mktplace/gitea/.venv/bin/python"
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "$(realpath "$0")")")}" PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "$(realpath "$0")")")}"
# MCP servers are at marketplace root, not inside plugin
MARKETPLACE_ROOT="$(dirname "$(dirname "$PLUGIN_ROOT")")" MARKETPLACE_ROOT="$(dirname "$(dirname "$PLUGIN_ROOT")")"
VENV_PATH="$MARKETPLACE_ROOT/mcp-servers/gitea/.venv/bin/python" LOCAL_VENV="$MARKETPLACE_ROOT/mcp-servers/gitea/.venv/bin/python"
if [[ ! -f "$VENV_PATH" ]]; then # Check cache first (preferred), then local
if [[ -f "$CACHE_VENV" ]]; then
VENV_PATH="$CACHE_VENV"
elif [[ -f "$LOCAL_VENV" ]]; then
VENV_PATH="$LOCAL_VENV"
else
echo "$PREFIX MCP venvs missing - run setup.sh from installed marketplace" echo "$PREFIX MCP venvs missing - run setup.sh from installed marketplace"
exit 0 exit 0
fi fi