Receber por email
← Voltar para o catálogo

setup

Post-install setup for foundry plugin. Merges statusLine, permissions.allow, and enabledPlugins into ~/.claude/settings.json; symlinks rules, TEAM_PROTOCOL.md, and skills into ~/.claude/.

20estrelas
Atualizado há 4 meses

Ver no GitHub ↗

Como adicionar

/plugin marketplace add Borda/AI-Rig

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/setup-borda/svg)](https://www.skillteca.com.br/skills/setup-borda)

Skills relacionadas

Ver todas de DevOps e Infra →

Alerta por categoria

Receba novas skills de DevOps e Infra toda segunda

1 email curto, só com as skills novas de DevOps e Infra. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

<objective>

Set up foundry on new machine:

| Action | What happens | | --- | --- | | Detect Python 3.10+ (python / py -3 / python3); install ~/.local/bin/python shim if needed | ✓ | | Merge statusLine, permissions.allow, enabledPlugins → ~/.claude/settings.json | ✓ | | rules/.md → ~/.claude/rules/ | symlink | | TEAM_PROTOCOL.md → ~/.claude/ | symlink | | skills/ → ~/.claude/skills/ | symlink | | hooks/hooks.json | auto — plugin system | | Conflict review before overwriting existing user files | ✓ |

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.

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.

Why not symlink agents? Agents must always 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 are removed by setup's Phase 1 cleanup.)

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.

NOT for: editing project .claude/settings.json.

</objective>

<inputs>

  • No arguments — interactive mode; prompts on conflicts.
  • --approve — non-interactive mode; auto-accepts all recommended answers. Use for scripted or CI setups.

</inputs>

<workflow>

Flag detection

Parse $ARGUMENTS for --approve (case-insensitive). If found, set APPROVE_ALL=true; else APPROVE_ALL=false.

Early git repository check — Step 6 requires a git repository. In --approve mode there is no interactive fallback, so check immediately before Step 1:

if [ "$APPROVE_ALL" = "true" ] && [ ! -e ".git" ]; then
    printf "! --approve requires git repository — run from project root\n"
    exit 1
fi

When APPROVE_ALL=true, every AskUserQuestion below skipped — ★ recommended option applied automatically. Print [--approve] auto-accepting recommended option in place of question.

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.

Python detection

Probe Python 3.10+ — required before any bin/*.py calls. Windows Store stub returns exit 9009 when given args; caught by 2>/dev/null:

PYTHON_CMD=""
SHIM_DIR="$HOME/.local/bin"
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
    PYTHON_CMD="python"
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
    PYTHON_CMD="py -3"
    mkdir -p "$SHIM_DIR"
    printf '#!/usr/bin/env bash\npy -3 "$@"\n' > "$SHIM_DIR/python"
    chmod +x "$SHIM_DIR/python"
    printf "  Python shim installed: %s/python → py -3\n" "$SHIM_DIR"
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
    PYTHON_CMD="python3"
    mkdir -p "$SHIM_DIR"
    printf '#!/usr/bin/env bash\npython3 "$@"\n' > "$SHIM_DIR/python"
    chmod +x "$SHIM_DIR/python"
    printf "  Python shim installed: %s/python → python3\n" "$SHIM_DIR"
else
    printf "! Python 3.10+ not found — install Python 3.10+ and re-run /foundry:setup\n"
    exit 1
fi
printf "  Python: %s\n" "$PYTHON_CMD"

# PATH guidance — ~/.local/bin standard on modern macOS/Linux (XDG Base Directory spec) but not always on PATH by default
if [ -f "$SHIM_DIR/python" ] && ! echo ":$PATH:" | grep -q ":$SHIM_DIR:"; then
    printf "  ⚠ %s not on PATH — add to shell rc:\n      export PATH=\"\$HOME/.local/bin:\$PATH\"\n" "$SHIM_DIR"
fi

~/.local/bin is the XDG-standard user-bin directory on modern macOS/Linux. Shim created only when python absent or resolves to Store stub. Idempotent — re-running setup overwrites shim with same content. If ~/.local/bin is not yet on $PATH, setup prints the export PATH="$HOME/.local/bin:$PATH" line for the user's shell rc.

Step 1: Locate the installed plugin

Execute this exact jq command — do not parse the JSON manually:

# Primary: registry lookup — sort by installedAt desc, pick latest install path
PLUGIN_ROOT=$(jq -r '
    .plugins
    | to_entries[]
    | select(.key | ascii_downcase | contains("foundry"))
    | .value[]
    | select(.installPath != null)
    | [.installedAt, .installPath]
    | @tsv
' "$HOME/.claude/plugins/installed_plugins.json" 2>/dev/null \
    | sort -rk1 | head -1 | cut -f2)  # timeout: 5000

# Fallback: filesystem scan — skip orphaned dirs, semver-sort descending, pick latest
if [ -z "$PLUGIN_ROOT" ]; then
    PLUGIN_ROOT=$(find ~/.claude/plugins/cache -maxdepth 5 -name "plugin.json" 2>/dev/null \
            | xargs grep -l '"name"[[:space:]]*:[[:space:]]*"foundry"' 2>/dev/null \
            | while IFS= read -r f; do
                dir=$(dirname "$(dirname "$f")")
                [ -f "$dir/.orphaned_at" ] && continue
                echo "$dir"
              done \
            | sort -Vr | head -1)  # timeout: 10000
    [ -n "$PLUGIN_ROOT" ] && printf "  Note: foundry not in installed_plugins.json — using cache scan result; consider reinstalling\n"
fi
echo "$PLUGIN_ROOT" > "${TMPDIR:-/tmp}/setup-plugin-root"  # persist for later blocks (Check 41)

If $PLUGIN_ROOT empty after both attempts, stop and report: "foundry plugin not found — install it first with: claude plugin marketplace add /path/to/Borda-AI-Rig && claude plugin install foundry@borda-ai-rig"

Confirm $PLUGIN_ROOT/hooks/statusline.js exists. If not, stop and report.

Step 2: Back up settings.json

If ~/.claude/settings.json does not exist, create it using the Write tool with content {}.

SETUP_BAK_TS=$(date -u +%Y%m%dT%H%M%SZ)
cp ~/.claude/settings.json "$HOME/.claude/settings.json.bak-${SETUP_BAK_TS}"  # timeout: 5000
echo "$SETUP_BAK_TS" > "${TMPDIR:-/tmp}/foundry-setup-bak-ts"

Report: "Backed up ~/.claude/settings.json → ~/.claude/settings.json.bak-<timestamp>"

Step 3: Check for stale hooks block

jq -e 'has("hooks")' ~/.claude/settings.json >/dev/null 2>&1  # timeout: 5000

If hooks key exists, user has pre-plugin-migration settings block — hooks fire twice.

If APPROVE_ALL=true: print [--approve] auto-accepting: remove stale hooks block and proceed to remove (apply option a below).

Otherwise, use AskUserQuestion:

  • a) Remove stale hooks block now ★ recommended (backup in place from Step 2)
  • b) Skip — I'll handle manually

On (a): use jq to strip hooks key, write back with Write tool, continue. On (b): warn "Double-firing risk: existing hooks block will fire alongside plugin-registered hooks." Continue.

Step 4: Merge statusLine

Check if statusLine already points to the current plugin's statusline.js (filename match alone is insufficient — a stale entry from an older plugin version survives upgrades and silently runs the previous hook). Verify both that the command contains statusline.js AND that the $PLUGIN_ROOT path (with its version segment) appears in the command string:

PLUGIN_ROOT=$(cat "${TMPDIR:-/tmp}/setup-plugin-root" 2>/dev/null)  # reload (Che
Compartilhar X LinkedIn