$npx -y skills add Borda/AI-Rig --skill setupPost-install setup for foundry plugin. Run once after installing on a new machine, or after a plugin version upgrade to sync settings and symlinks. Merges statusLine, permissions.allow, enabledPlugins, and advisorModel into ~/.claude/settings.json; symlinks rules, TEAM_PROTOCOL.m
| 1 | <objective> |
| 2 | |
| 3 | Set up foundry on new machine: |
| 4 | |
| 5 | | Action | What happens | |
| 6 | | --- | --- | |
| 7 | | Detect Python 3.10+ (`python` / `py -3` / `python3`); install `~/.local/bin/python` shim if needed | ✓ | |
| 8 | | Merge `statusLine`, `permissions.allow`, `enabledPlugins`, `advisorModel` → `~/.claude/settings.json` | ✓ | |
| 9 | | `rules/*.md` → `~/.claude/rules/` | symlink | |
| 10 | | `TEAM_PROTOCOL.md` → `~/.claude/` | symlink | |
| 11 | | `skills/*` → `~/.claude/skills/` | symlink | |
| 12 | | `hooks/hooks.json` | auto — plugin system | |
| 13 | | Conflict review before overwriting existing user files | ✓ | |
| 14 | |
| 15 | **Why symlink rules and skills (not copy)?** Rules, TEAM_PROTOCOL.md, and skills load at session startup. Symlinks = every session gets plugin's current version — no stale copies, no re-run after upgrades. Broken symlink after upgrade = obvious error; stale copy silently serves old content. |
| 16 | |
| 17 | **Why symlink skills explicitly?** `claude plugin install` creates `~/.claude/skills/` symlinks on first install but does NOT update them on upgrade — old version directory stays in cache, symlinks go stale. Setup's stale-version detection (same pattern as rules) replaces them silently on every re-run. |
| 18 | |
| 19 | **Why not symlink agents?** Agents must use full plugin prefix (`foundry:sw-engineer`, not `sw-engineer`) for unambiguous dispatch. Plugin system exposes agents at `foundry:` namespace — no `~/.claude/agents/` symlinks needed. (Stale agent symlinks from prior installs removed by setup's Phase 1 cleanup.) |
| 20 | |
| 21 | **Why hooks need no action?** `hooks/hooks.json` inside plugin registers automatically when plugin enabled. Setup's only hook-adjacent step: write `statusLine.command` path (Step 4) — `statusLine` is top-level settings key, not part of `hooks.json`. |
| 22 | |
| 23 | NOT for: editing project `.claude/settings.json` (Step 8 READS it to propagate advisorModel, never writes it). |
| 24 | |
| 25 | </objective> |
| 26 | |
| 27 | <inputs> |
| 28 | |
| 29 | - **No arguments** — interactive mode; prompts on conflicts. |
| 30 | - **`--approve`** — non-interactive mode; auto-accepts all recommended answers. Use for scripted or CI setups. |
| 31 | |
| 32 | </inputs> |
| 33 | |
| 34 | <workflow> |
| 35 | |
| 36 | ## Flag detection |
| 37 | |
| 38 | Parse `$ARGUMENTS` for `--approve` (case-insensitive). If found, set `APPROVE_ALL=true`; else `APPROVE_ALL=false`. |
| 39 | |
| 40 | **Early git repository check** — Step 6 requires a git repository. In `--approve` mode there is no interactive fallback, so check immediately before Step 1: |
| 41 | |
| 42 | ```bash |
| 43 | if [ "$APPROVE_ALL" = "true" ] && [ ! -e ".git" ]; then |
| 44 | printf "! --approve requires git repository — run from project root\n" |
| 45 | exit 1 |
| 46 | fi |
| 47 | ``` |
| 48 | |
| 49 | When `APPROVE_ALL=true`, every `AskUserQuestion` below **skipped** — ★ recommended option applied automatically. Print `[--approve] auto-accepting recommended option` in place of question. |
| 50 | |
| 51 | **Unsupported flag check** — after all supported flags extracted, scan `$ARGUMENTS` for remaining `--<token>` tokens. If found: print `! Unknown flag(s): \`--<token>\`. Supported: \`--approve\`.` then invoke `AskUserQuestion` — (a) **Abort** (stop, re-invoke with correct flags) · (b) **Continue ignoring** (skip unknown flags, proceed). On Abort: stop. |
| 52 | |
| 53 | ## Python detection |
| 54 | |
| 55 | Probe Python 3.10+ — required before any `bin/*.py` calls. Windows Store stub returns exit 9009 when given args; caught by `2>/dev/null`: |
| 56 | |
| 57 | ```bash |
| 58 | PYTHON_CMD="" |
| 59 | SHIM_DIR="$HOME/.local/bin" |
| 60 | if command -v python >/dev/null 2>&1 && python --version 2>/dev/null | grep -qE "Python 3\.(1[0-9]|[2-9][0-9])"; then |
| 61 | PYTHON_CMD="python" |
| 62 | elif command -v py >/dev/null 2>&1 && py -3 --version 2>/dev/null | grep -qE "Python 3\.(1[0-9]|[2-9][0-9])"; then |
| 63 | PYTHON_CMD="py -3" |
| 64 | mkdir -p "$SHIM_DIR" |
| 65 | printf '#!/usr/bin/env bash\npy -3 "$@"\n' > "$SHIM_DIR/python" |
| 66 | chmod +x "$SHIM_DIR/python" |
| 67 | printf " Python shim installed: %s/python → py -3\n" "$SHIM_DIR" |
| 68 | elif command -v python3 >/dev/null 2>&1 && python3 --version 2>/dev/null | grep -qE "Python 3\.(1[0-9]|[2-9][0-9])"; then |
| 69 | PYTHON_CMD="python3" |
| 70 | mkdir -p "$SHIM_DIR" |
| 71 | printf '#!/usr/bin/env bash\npython3 "$@"\n' > "$SHIM_DIR/python" |
| 72 | chmod +x "$SHIM_DIR/python" |
| 73 | printf " Python shim installed: %s/python → python3\n" "$SHIM_DIR" |
| 74 | else |
| 75 | printf "! Python 3.10+ not found — install Python 3.10+ and re-run /foundry:setup\n" |
| 76 | exit 1 |
| 77 | fi |
| 78 | printf " Python: %s\n" "$PYTHON_CMD" |
| 79 | |
| 80 | # ~/.local/bin is XDG-standard but not always on PATH |
| 81 | if [ -f "$SHIM_DIR/python" ] && ! echo ":$PATH:" | grep -q ":$SHIM_DIR:"; then |
| 82 | printf " ⚠ %s not on PATH — add to shell rc:\n export PATH=\"\$HOME/.local/bin:\$PATH\"\n" "$SHIM_DIR" |
| 83 | fi |
| 84 | ``` |
| 85 | |
| 86 | `~/.local/bin` is XDG-standard user-bin directory on modern macOS/Linux. Shim |