Development
Hook
Hooks
What repobrain runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.
Install
> /plugin marketplace add study8677/repobrain > /plugin install repobrain@repobrain
Ships with repobrain. Installing the plugin gets these hooks.
What fires, and when
SessionStart
Fires once when a session begins, and again after a context compaction. It is where a plugin sets up its environment, or restores state the compaction dropped.
python3 "${CLAUDE_PLUGIN_ROOT}/hooks/install_engine.py" || python "${CLAUDE_PLUGIN_ROOT}/hooks/install_engine.py"
Where it lives
- hooks/install_engine.pyRunsGitHub
Read the script
#!/usr/bin/env python3 """SessionStart hook: ensure the RepoBrain CLI and engine are on PATH. Single cross-platform installer for Claude Code's plugin SessionStart hook. Idempotent and silent on the happy path. All output goes to stderr (stdout on a hook is interpreted as injected context). Strategy: 1. If all RepoBrain commands are on PATH at the bundled versions, exit 0. 2. Ensure pipx exists: - macOS with Homebrew → `brew install pipx` - Otherwise → `python -m pip install --user pipx` Both paths require no sudo. 3. `pipx ensurepath` and prepend the pipx bin dir to PATH for the current process so the next `pipx install` finds the freshly placed shim. 4. `pipx install --force <plugin_root>/engine`, then inject the bundled CLI into the same environment with `--include-apps`. 5. If pipx remains unavailable, fall back to `pip install --user --upgrade`. 6. On total failure, print a clear manual-install message and exit 1. """ from __future__ import annotations import os import re import shutil import subprocess import sys from pathlib import Path ENGINE_PACKAGE = "repobrain-engine" REQUIRED_COMMANDS = ("rb", "rb-ask", "rb-refresh", "rb-mcp") def log(msg: str) -> None: print(msg, file=sys.stderr, flush=True) def has(cmd: str) -> bool: return shutil.which(cmd) is not None def user_scripts_bin() -> Path | None: """Resolve site.USER_BASE bin/Scripts dir from the current Python.""" try: import site base = Path(site.USER_BASE) except Exception: return None candidate = base / ("Scripts" if os.name == "nt" else "bin") return candidate if candidate.is_dir() else None def prepend_path(p: Path) -> None: if not p.is_dir(): return cur = os.environ.get("PATH", "") parts = cur.split(os.pathsep) if str(p) in parts: return os.environ["PATH"] = str(p) + os.pathsep + cur def run(cmd: list[str]) -> int: try: return subprocess.run(cmd, stderr=sys.stderr, stdout=sys.stderr).returncode except FileNotFoundError: return 127 def ensure_pipx() -> bool: """Install pipx if missing. Returns True if pipx is available afterwards.""" if has("pipx"): return True # macOS with Homebrew: cleanest path, no sudo. if sys.platform == "darwin" and has("brew"): log("[repobrain] Installing pipx via Homebrew...") run(["brew", "install", "pipx"]) # Cross-platform fallback: pip install --user pipx. if not has("pipx"): py = sys.executable or ("python" if has("python") else "python3") log(f"[repobrain] Installing pipx via pip --user ({py})...") run([py, "-m", "pip", "install", "--user", "--quiet", "pipx"]) # User-base scripts/bin needs to be on PATH for `pipx` to be findable. ub = user_scripts_bin() if ub: prepend_path(ub) return has("pipx") or _has_pipx_module() def _has_pipx_module() -> bool: """Some installs put pipx on PATH only after `ensurepath`. Check for the module so we can invoke it via `python -m pipx` as a fallback.""" try: subprocess.run( [sys.executable or "python", "-m", "pipx", "--version"], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) return True except Exception: return False def pipx(args: list[str]) -> int: if has("pipx"): return run(["pipx", *args]) return run([sys.executable or "python", "-m", "pipx", *args]) def read_project_version(package_dir: Path) -> str | None: """Read a bundled package version from its ``pyproject.toml``.""" try: text = (package_dir / "pyproject.toml").read_text(encoding="utf-8") except OSError: return None match = re.search(r'^version\s*=\s*"([^"]+)"', text, flags=re.MULTILINE) return match.group(1) if match else None def get_installed_engine_version() -> str | None: """Return the installed rb-mcp engine version, if it can be queried.""" rb_mcp = shutil.which("rb-mcp") if rb_mcp is None: return None try: completed = subprocess.run( [rb_mcp, "--version"], check=False, capture_output=True, text=True, timeout=15, ) except Exception: return None if completed.returncode != 0: return None output = (completed.stdout or completed.stderr).strip() match = re.search(r"(\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.]+)?)", output) return match.group(1) if match else None def get_installed_cli_version() -> str | None: """Return the installed ``rb`` CLI version, if it can be queried.""" rb = shutil.which("rb") if rb is None: return None try: completed = subprocess.run( [rb, "version"], check=False, capture_output=True, text=True, timeout=15, ) except Exception: return None if completed.returncode != 0: return None output = (completed.stdout or completed.stderr).strip() match = re.search(r"(\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.]+)?)", output) return match.group(1) if match else None def required_commands_available() -> bool: """Return whether every command promised by the plugin is on PATH.""" return all(has(command) for command in REQUIRED_COMMANDS) def installation_is_current( installed_engine: str | None, expected_engine: str | None, installed_cli: str | None, expected_cli: str | None, ) -> bool: """Return whether versions and all public commands match the bundle.""" return ( installed_engine == expected_engine and installed_cli == expected_cli and None not in (installed_engine, expected_engine, installed_cli, expected_cli) and required_commands_available() ) def installed_bundle_is_current( expected_engine: str | None, expected_cli: str | None - hooks/install_engine.shGitHub
Read the script
#!/usr/bin/env bash # Thin wrapper for manual invocation. The real install logic lives in # `install_engine.py` so it can be reused by the Windows .bat wrapper and # the cross-platform hook command in `hooks.json`. set -u DIR="$(cd "$(dirname "$0")" && pwd)" exec python3 "${DIR}/install_engine.py" 2>/dev/null \ || exec python "${DIR}/install_engine.py"
Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.
Ships withrepobrain
🧠 RepoBrain (formerly Antigravity) — Give your repo a brain. ChatGPT for your codebase: works in Claude Code, Cursor, Codex, Windsurf & more.
Get the whole plugin

