#!/bin/bash # # Claude Enforcer Installer (Linux / macOS) # Installs the skill-builder skill to your Claude Code project # # Usage: # bash -c "$(curl -fsSL https://raw.githubusercontent.com/odysseyalive/claude-enforcer/main/install)" # # Windows PowerShell users: use install.ps1 instead: # irm https://raw.githubusercontent.com/odysseyalive/claude-enforcer/main/install.ps1 | iex # # The list of shipped files lives in manifest.txt (shared with install.ps1). # set -e REPO_URL="https://raw.githubusercontent.com/odysseyalive/claude-enforcer/main" SKILL_DIR=".claude/skills/skill-builder" echo "Claude Enforcer Installer" echo "=========================" echo # Check for CLAUDE.md in current directory if [ ! -f "CLAUDE.md" ]; then echo "Error: CLAUDE.md not found in current directory." echo echo "This installer must be run from a Claude Code project root." echo "If you haven't initialized Claude Code yet, run:" echo echo " claude /init" echo echo "Then run this installer again." exit 1 fi echo "Found CLAUDE.md in $(pwd)" # Remove legacy files from prior installer versions # (older installs shipped these; they've since been removed from the skill) for legacy in \ "$SKILL_DIR/reference.md" \ "$SKILL_DIR/references/procedures.md" \ "$SKILL_DIR/references/self-heal-templates.md" \ "$SKILL_DIR/references/procedures/self-heal.md"; do if [ -f "$legacy" ]; then echo "Removing legacy $(basename "$legacy")..." rm -f "$legacy" fi done # Remove legacy standalone shell-safety skill (now absorbed into skill-builder) if [ -d ".claude/skills/shell-safety" ]; then echo "Removing legacy shell-safety skill (now a skill-builder subcommand)..." rm -rf ".claude/skills/shell-safety" fi # Hook distribution: per the 2026-05-11 sacred directive (extended 2026-06-06), # skill-builder ships its load-bearing hooks in two variants: bash # (protect-directives.sh, unique-persona.sh) and PowerShell companions for # Windows hosts (protect-directives.ps1, unique-persona.ps1). They guard two # other sacred user directives (no rewording of immutable blocks, and persona # uniqueness across agents) and without them every fresh install silently # loses load-bearing enforcement. The general no-distribute rule still applies # to all other hooks; users generate their own per-skill hooks via # `/skill-builder hooks [skill] --execute`. # # Remove legacy older-named hook scripts from prior installs. for legacy_hook in \ "$SKILL_DIR/hooks/verify-directive-integrity.sh" \ "$SKILL_DIR/hooks/check-persona-uniqueness.sh"; do if [ -f "$legacy_hook" ]; then echo "Removing legacy $(basename "$legacy_hook")..." rm -f "$legacy_hook" fi done # Download the shared manifest, then every file it lists. # Manifest format: optional flag ("keep" = fetch only if absent, # "hook" = chmod +x after fetch) followed by the repo-relative path. echo "Downloading skill-builder..." MANIFEST_TMP="$(mktemp)" trap 'rm -f "$MANIFEST_TMP"' EXIT curl -fsSL "$REPO_URL/manifest.txt" -o "$MANIFEST_TMP" while IFS= read -r line || [ -n "$line" ]; do # Skip blank lines and comments case "$line" in ''|\#*) continue ;; esac flag="" path="$line" case "$line" in "keep "*) flag="keep"; path="${line#keep }" ;; "hook "*) flag="hook"; path="${line#hook }" ;; esac dest="$SKILL_DIR/${path#skill-builder/}" if [ "$flag" = "keep" ] && [ -f "$dest" ]; then echo "Keeping existing $(basename "$dest") (preserving your edits)..." continue fi mkdir -p "$(dirname "$dest")" curl -fsSL "$REPO_URL/$path" -o "$dest" if [ "$flag" = "hook" ]; then chmod +x "$dest" fi done < "$MANIFEST_TMP" # Enable agent teams and auto-approve research tools SETTINGS_FILE=".claude/settings.local.json" echo "Configuring project settings..." if command -v python3 &>/dev/null; then python3 -c " import json, os p = '$SETTINGS_FILE' d = json.load(open(p)) if os.path.exists(p) else {} changed = False # Enable agent teams if d.get('env', {}).get('CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS') != '1': d.setdefault('env', {})['CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS'] = '1' changed = True print(' Agent teams enabled') else: print(' Agent teams already enabled') # Auto-approve web research tools (belt: permissions layer) # The suspenders (PreToolUse hook) are generated per-system by /skill-builder hooks research_tools = [ 'WebSearch', 'WebFetch', 'mcp__jina__read_url', 'mcp__jina__search_web', 'mcp__jina__parallel_read_url', 'mcp__jina__parallel_search_web', ] allow = d.setdefault('permissions', {}).setdefault('allow', []) for tool in research_tools: if tool not in allow: allow.append(tool) changed = True print(f' Added {tool} to permissions.allow') else: print(f' {tool} already in permissions.allow') if changed: json.dump(d, open(p, 'w'), indent=2) print(f' Settings saved to $SETTINGS_FILE') " else echo " Warning: python3 not found. Add these to $SETTINGS_FILE manually:" echo ' { "env": { "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" },' echo ' "permissions": { "allow": ["WebSearch", "WebFetch", "mcp__jina__read_url", "mcp__jina__search_web", "mcp__jina__parallel_read_url", "mcp__jina__parallel_search_web"] } }' fi echo echo "Installation complete." echo echo "Usage:" echo " /skill-builder Full audit (display mode)" echo " /skill-builder optimize [skill] Show optimization plan (--execute to apply)" echo " /skill-builder agents [skill] Show agent opportunities (--execute to create)" echo " /skill-builder hooks [skill] Show hooks inventory (--execute to create)" echo " /skill-builder shell-safety lint [file] Check shell or settings.json for pitfalls" echo " /skill-builder shell-safety audit [path] Scan and patch fragility (--execute to fix)" echo " /skill-builder route index Build /route skill index (auto-runs at audit end)" echo " /skill-builder route embed Plan route consultation gates (--execute to apply)" echo