Release v2.1.1 portable sync

This commit is contained in:
Sam Valladares 2026-05-01 05:24:03 -05:00
parent 738e4f7dce
commit f3d63af12e
35 changed files with 3257 additions and 421 deletions

View file

@ -5,21 +5,53 @@ set -u
ok() { printf ' \033[1;32m[ OK ]\033[0m %s\n' "$*"; }
warn() { printf ' \033[1;33m[WARN]\033[0m %s\n' "$*"; FAIL=1; }
miss() { printf ' \033[1;31m[MISS]\033[0m %s\n' "$*"; FAIL=1; }
info() { printf ' \033[1;36m[INFO]\033[0m %s\n' "$*"; }
FAIL=0
CHECK_PREFLIGHT=0
CHECK_SANHEDRIN=0
DASHBOARD_PORT="${VESTIGE_DASHBOARD_PORT:-3927}"
MLX_ENDPOINT="${MLX_ENDPOINT:-http://127.0.0.1:8080/v1/chat/completions}"
MLX_ENDPOINT="${MLX_ENDPOINT%/}"
MLX_MODELS_URL="${MLX_ENDPOINT%/chat/completions}/models"
SANHEDRIN_ENV="${VESTIGE_SANHEDRIN_ENV:-$HOME/.claude/hooks/vestige-sanhedrin.env}"
for arg in "$@"; do
case "$arg" in
--preflight|--enable-preflight) CHECK_PREFLIGHT=1 ;;
--sanhedrin|--enable-sanhedrin) CHECK_SANHEDRIN=1 ;;
-h|--help)
cat <<'EOF'
Usage: scripts/check-sandwich-prereqs.sh [--preflight] [--sanhedrin]
Without flags, verifies that the default install has no Vestige hooks wired.
With --preflight, checks the optional UserPromptSubmit hook layer.
With --sanhedrin, checks the optional OpenAI-compatible verifier endpoint.
EOF
exit 0
;;
esac
done
if [ -f "$SANHEDRIN_ENV" ]; then
set +u
set -a
# shellcheck disable=SC1090
. "$SANHEDRIN_ENV" 2>/dev/null || true
set +a
set -u
fi
SANHEDRIN_ENDPOINT="${VESTIGE_SANHEDRIN_ENDPOINT:-${MLX_ENDPOINT:-http://127.0.0.1:8080/v1/chat/completions}}"
SANHEDRIN_ENDPOINT="${SANHEDRIN_ENDPOINT%/}"
SANHEDRIN_MODELS_URL="${SANHEDRIN_ENDPOINT%/chat/completions}/models"
echo "Vestige Cognitive Sandwich — Prereq Check"
echo
# Platform
if [ "$(uname -s)" = "Darwin" ] && [ "$(uname -m)" = "arm64" ]; then
ok "Apple Silicon macOS ($(sw_vers -productVersion 2>/dev/null || echo darwin))"
else
miss "Apple Silicon Mac required (M1+). Detected $(uname -s) $(uname -m)."
OS_NAME="$(uname -s)"
ARCH_NAME="$(uname -m)"
ok "Platform: $OS_NAME $ARCH_NAME"
if [ "$OS_NAME" != "Darwin" ] || [ "$ARCH_NAME" != "arm64" ]; then
info "Local MLX launchd is Apple Silicon-only; base hooks and endpoint-backed Sanhedrin can run on x86."
fi
# Python
@ -35,56 +67,95 @@ fi
# CLI tools
command -v jq >/dev/null && ok "jq" || miss "jq missing — brew install jq"
command -v uv >/dev/null && ok "uv" || miss "uv missing — brew install uv"
command -v mlx_lm.server >/dev/null && ok "mlx-lm" || miss "mlx-lm — uv tool install mlx-lm"
command -v hf >/dev/null && ok "huggingface_hub CLI" || miss "hf — uv tool install 'huggingface_hub[cli]'"
command -v claude >/dev/null && ok "claude CLI" || miss "claude CLI — install Claude Code"
command -v vestige-mcp >/dev/null && ok "vestige-mcp" || miss "vestige-mcp — cargo install vestige-mcp"
if [ "$CHECK_PREFLIGHT" -eq 1 ]; then
command -v claude >/dev/null && ok "claude CLI" || miss "claude CLI — install Claude Code"
command -v vestige-mcp >/dev/null && ok "vestige-mcp" || miss "vestige-mcp — cargo install vestige-mcp"
# Model on disk — HF cache uses `models--<org>--<name>` (double-dash separators).
MODEL="${VESTIGE_SANDWICH_MODEL:-mlx-community/Qwen3.6-35B-A3B-4bit}"
HF_HOME_DEFAULT="${HF_HOME:-$HOME/.cache/huggingface}"
ENC_MODEL="models--$(printf '%s' "$MODEL" | sed 's|/|--|g')"
if [ -d "$HF_HOME_DEFAULT/hub/$ENC_MODEL" ]; then
ok "Model cached: $MODEL"
else
printf ' \033[1;33m[INFO]\033[0m Model not yet downloaded — first run will fetch ~19GB\n'
printf ' hf download %s\n' "$MODEL"
# NOT a failure — first-run download is expected.
fi
# Vestige MCP HTTP API
if curl -fsS -m 2 "http://127.0.0.1:${DASHBOARD_PORT}/api/health" >/dev/null 2>&1; then
ok "vestige-mcp dashboard responding on :$DASHBOARD_PORT"
else
warn "vestige-mcp dashboard not responding on :$DASHBOARD_PORT"
fi
# OpenAI-compatible local/remote model endpoint
if curl -fsS -m 2 "$MLX_MODELS_URL" >/dev/null 2>&1; then
ok "model endpoint responding at $MLX_MODELS_URL"
else
warn "model endpoint not responding at $MLX_MODELS_URL — install + load launchd plist or set MLX_ENDPOINT"
fi
# launchd plist
if [ -f "$HOME/Library/LaunchAgents/com.vestige.mlx-server.plist" ]; then
ok "launchd plist installed"
else
warn "launchd plist missing — run: install-sandwich.sh"
# Vestige MCP HTTP API
if curl -fsS -m 2 "http://127.0.0.1:${DASHBOARD_PORT}/api/health" >/dev/null 2>&1; then
ok "vestige-mcp dashboard responding on :$DASHBOARD_PORT"
else
warn "vestige-mcp dashboard not responding on :$DASHBOARD_PORT"
fi
fi
# Settings hook wiring
if [ -f "$HOME/.claude/settings.json" ] && \
jq -e '.hooks.UserPromptSubmit and .hooks.Stop' "$HOME/.claude/settings.json" >/dev/null 2>&1; then
ok "settings.json hooks block present"
if [ "$CHECK_PREFLIGHT" -eq 0 ] && [ "$CHECK_SANHEDRIN" -eq 0 ]; then
if [ -f "$HOME/.claude/settings.json" ] && \
jq -e 'any((.hooks.UserPromptSubmit[]?.hooks[]?, .hooks.Stop[]?.hooks[]?); ((.command? // "") | test("synthesis-preflight\\.sh|cwd-state-injector\\.sh|vestige-pulse-daemon\\.sh|preflight-swarm\\.sh|load-all-memory\\.sh|veto-detector\\.sh|sanhedrin\\.sh|synthesis-stop-validator\\.sh|synthesis-gate\\.sh")))' "$HOME/.claude/settings.json" >/dev/null 2>&1; then
warn "Vestige hooks are still wired; run: install-sandwich.sh --force"
else
ok "no Vestige Claude Code hooks wired by default"
fi
fi
if [ "$CHECK_PREFLIGHT" -eq 1 ]; then
echo
echo "Optional Preflight"
if [ -f "$HOME/.claude/settings.json" ] && \
jq -e 'any(.hooks.UserPromptSubmit[]?.hooks[]?; ((.command? // "") | contains("synthesis-preflight.sh"))) and any(.hooks.UserPromptSubmit[]?.hooks[]?; ((.command? // "") | contains("preflight-swarm.sh")))' "$HOME/.claude/settings.json" >/dev/null 2>&1; then
ok "preflight UserPromptSubmit hooks wired"
else
warn "preflight hooks not wired — run: install-sandwich.sh --enable-preflight"
fi
info "preflight-swarm.sh uses claude -p with Haiku when enabled; default installs do not wire it."
fi
if [ "$CHECK_SANHEDRIN" -eq 1 ]; then
echo
echo "Optional Sanhedrin"
if [ -f "$SANHEDRIN_ENV" ]; then
ok "Sanhedrin env file present"
else
warn "Sanhedrin env file missing — run: install-sandwich.sh --enable-sanhedrin"
fi
if [ "$OS_NAME" = "Darwin" ] && [ "$ARCH_NAME" = "arm64" ]; then
command -v uv >/dev/null && ok "uv" || warn "uv missing — brew install uv"
command -v mlx_lm.server >/dev/null && ok "mlx-lm" || warn "mlx-lm — uv tool install mlx-lm"
command -v hf >/dev/null && ok "huggingface_hub CLI" || warn "hf — uv tool install 'huggingface_hub[cli]'"
MODEL="${VESTIGE_SANHEDRIN_MODEL:-${VESTIGE_SANDWICH_MODEL:-mlx-community/Qwen3.6-35B-A3B-4bit}}"
HF_HOME_DEFAULT="${HF_HOME:-$HOME/.cache/huggingface}"
ENC_MODEL="models--$(printf '%s' "$MODEL" | sed 's|/|--|g')"
if [ -d "$HF_HOME_DEFAULT/hub/$ENC_MODEL" ]; then
ok "Model cached: $MODEL"
else
info "Model not cached: $MODEL (local MLX path downloads ~19GB)"
fi
if [ -f "$HOME/Library/LaunchAgents/com.vestige.mlx-server.plist" ]; then
ok "launchd plist installed"
else
info "launchd plist not installed; endpoint-backed Sanhedrin can still run"
fi
else
info "Skipping MLX/launchd checks on $OS_NAME $ARCH_NAME"
fi
if curl -fsS -m 2 "$SANHEDRIN_MODELS_URL" >/dev/null 2>&1; then
ok "Sanhedrin model endpoint responding at $SANHEDRIN_MODELS_URL"
else
warn "Sanhedrin endpoint not responding at $SANHEDRIN_MODELS_URL"
fi
if [ -f "$HOME/.claude/settings.json" ] && \
jq -e '.hooks.Stop[]?.hooks[]?.command | contains("sanhedrin.sh")' "$HOME/.claude/settings.json" >/dev/null 2>&1; then
ok "Sanhedrin Stop hook wired"
else
warn "Sanhedrin Stop hook not wired — run: install-sandwich.sh --enable-sanhedrin"
fi
else
warn "settings.json missing hooks block — run: install-sandwich.sh"
echo
info "Sanhedrin is optional and not checked. Use --sanhedrin to verify an enabled endpoint."
fi
echo
if [ $FAIL -eq 0 ]; then
echo " Ready. Cognitive Sandwich will fire on next Claude Code prompt."
echo " Ready. Default install has no Vestige Claude Code hooks wired and makes no automatic model calls."
exit 0
else
echo " Fix the items above, then re-run."

View file

@ -2,28 +2,28 @@
# install-sandwich.sh — One-command installer for the Vestige Cognitive Sandwich.
#
# Usage:
# curl -fsSL https://raw.githubusercontent.com/samvallad33/vestige/v2.1.0/scripts/install-sandwich.sh | sh
# curl -fsSL https://raw.githubusercontent.com/samvallad33/vestige/v2.1.1/scripts/install-sandwich.sh | sh
# # or, from a checkout:
# ./scripts/install-sandwich.sh [--force] [--no-launchd] [--include-memory-loader]
# ./scripts/install-sandwich.sh [--force] [--enable-preflight] [--enable-sanhedrin] [--with-launchd] [--include-memory-loader]
# ./scripts/install-sandwich.sh --enable-sanhedrin --sanhedrin-endpoint=http://127.0.0.1:11434/v1/chat/completions --sanhedrin-model=qwen2.5:14b
#
# What it does:
# 1. Verifies required local tools
# 2. Stages ~/.claude/hooks/, ~/.claude/agents/, ~/Library/LaunchAgents/
# 2. Stages ~/.claude/hooks/ and ~/.claude/agents/
# 3. Copies sanitized hooks + agents
# 4. Renders launchd plist template with $HOME and chosen MODEL
# 5. Merges hooks block into ~/.claude/settings.json (preserves existing keys)
# 6. launchctl load com.vestige.mlx-server (auto-starts mlx_lm.server with Qwen3.6-35B-A3B)
# 7. Prints next-steps for model download
# 4. Removes old Vestige hook wiring from ~/.claude/settings.json by default
# 5. Optionally enables preflight hooks and/or Sanhedrin. Only with --with-launchd on Apple Silicon,
# auto-starts mlx_lm.server with Qwen3.6-35B-A3B
set -euo pipefail
VERSION="${VESTIGE_SANDWICH_VERSION:-v2.1.0}"
VERSION="${VESTIGE_SANDWICH_VERSION:-v2.1.1}"
REPO="samvallad33/vestige"
MODEL_ID="${VESTIGE_SANDWICH_MODEL:-mlx-community/Qwen3.6-35B-A3B-4bit}"
MODEL_ID="${VESTIGE_SANHEDRIN_MODEL:-${VESTIGE_SANDWICH_MODEL:-mlx-community/Qwen3.6-35B-A3B-4bit}}"
DASHBOARD_PORT="${VESTIGE_DASHBOARD_PORT:-3927}"
MLX_ENDPOINT="${MLX_ENDPOINT:-http://127.0.0.1:8080/v1/chat/completions}"
MLX_ENDPOINT="${MLX_ENDPOINT%/}"
MLX_MODELS_URL="${MLX_ENDPOINT%/chat/completions}/models"
SANHEDRIN_ENDPOINT="${VESTIGE_SANHEDRIN_ENDPOINT:-${MLX_ENDPOINT:-http://127.0.0.1:8080/v1/chat/completions}}"
SANHEDRIN_ENDPOINT="${SANHEDRIN_ENDPOINT%/}"
SANHEDRIN_MODELS_URL="${SANHEDRIN_ENDPOINT%/chat/completions}/models"
HOOKS_DIR="$HOME/.claude/hooks"
AGENTS_DIR="$HOME/.claude/agents"
@ -31,45 +31,70 @@ LAUNCHD_DIR="$HOME/Library/LaunchAgents"
SETTINGS="$HOME/.claude/settings.json"
FORCE=0
NO_LAUNCHD=0
ENABLE_PREFLIGHT=0
ENABLE_SANHEDRIN=0
WITH_LAUNCHD=0
INCLUDE_MEMORY_LOADER=0
SRC=""
for arg in "$@"; do
case "$arg" in
--force) FORCE=1 ;;
--no-launchd) NO_LAUNCHD=1 ;;
--enable-preflight) ENABLE_PREFLIGHT=1 ;;
--enable-sandwich) ENABLE_PREFLIGHT=1; ENABLE_SANHEDRIN=1 ;;
--enable-sanhedrin) ENABLE_SANHEDRIN=1 ;;
--with-launchd) WITH_LAUNCHD=1 ;;
--no-launchd) WITH_LAUNCHD=0 ;;
--include-memory-loader) INCLUDE_MEMORY_LOADER=1 ;;
--sanhedrin-endpoint=*|--endpoint=*)
SANHEDRIN_ENDPOINT="${arg#*=}"
SANHEDRIN_ENDPOINT="${SANHEDRIN_ENDPOINT%/}"
SANHEDRIN_MODELS_URL="${SANHEDRIN_ENDPOINT%/chat/completions}/models"
;;
--sanhedrin-model=*|--model=*)
MODEL_ID="${arg#*=}"
;;
--src=*) SRC="${arg#--src=}" ;;
-h|--help)
sed -n '2,20p' "$0"
sed -n '2,24p' "$0"
exit 0
;;
esac
done
if [ "$WITH_LAUNCHD" -eq 1 ] && [ "$ENABLE_SANHEDRIN" -eq 0 ]; then
ENABLE_SANHEDRIN=1
fi
say() { printf '\033[1;36m[sandwich]\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[sandwich]\033[0m %s\n' "$*" >&2; }
die() { printf '\033[1;31m[sandwich]\033[0m %s\n' "$*" >&2; exit 1; }
# --- Platform check (honors --no-launchd for Linux/Intel users) ---
if [ "$(uname -s)" != "Darwin" ]; then
if [ "$NO_LAUNCHD" -eq 0 ]; then
die "macOS required for the launchd auto-start of mlx_lm.server. Re-run with --no-launchd to install hooks only and run mlx_lm.server manually."
fi
warn "Non-Darwin platform — installing hooks/agents only (no launchd). Run an OpenAI-compatible model endpoint and set MLX_ENDPOINT if it is not $MLX_ENDPOINT."
elif [ "$(uname -m)" != "arm64" ]; then
warn "Apple Silicon recommended (M1+). Detected $(uname -m). The local Qwen3.6 model requires arm64 + Metal."
# --- Platform check ---
OS_NAME="$(uname -s)"
ARCH_NAME="$(uname -m)"
say "platform: $OS_NAME $ARCH_NAME"
if [ "$ENABLE_SANHEDRIN" -eq 1 ] && [ "$WITH_LAUNCHD" -eq 0 ]; then
say "Sanhedrin enabled without launchd; using OpenAI-compatible endpoint: $SANHEDRIN_ENDPOINT"
fi
if [ "$WITH_LAUNCHD" -eq 1 ] && { [ "$OS_NAME" != "Darwin" ] || [ "$ARCH_NAME" != "arm64" ]; }; then
warn "--with-launchd is Apple Silicon only; skipping local MLX autostart on $OS_NAME $ARCH_NAME"
warn "Sanhedrin can still run on x86 via --sanhedrin-endpoint or VESTIGE_SANHEDRIN_ENDPOINT."
WITH_LAUNCHD=0
fi
# --- Prereqs (warnings only, install proceeds) ---
command -v jq >/dev/null || die "jq required: brew install jq"
command -v python3 >/dev/null || die "python3 required (3.10+)"
command -v claude >/dev/null || warn "'claude' CLI not found — install Claude Code first."
command -v vestige-mcp >/dev/null || warn "'vestige-mcp' not found — install with: cargo install vestige-mcp"
command -v uv >/dev/null || warn "'uv' not found — install with: brew install uv"
command -v mlx_lm.server >/dev/null || warn "mlx-lm not installed — run: uv tool install mlx-lm"
command -v hf >/dev/null || warn "'hf' not found — run: uv tool install 'huggingface_hub[cli]'"
if [ "$ENABLE_PREFLIGHT" -eq 1 ]; then
command -v claude >/dev/null || warn "'claude' CLI not found — preflight-swarm.sh will fail open."
command -v vestige-mcp >/dev/null || warn "'vestige-mcp' not found — Vestige preflight hooks will fail open."
fi
if [ "$WITH_LAUNCHD" -eq 1 ]; then
command -v uv >/dev/null || warn "'uv' not found — install with: brew install uv"
command -v mlx_lm.server >/dev/null || warn "mlx-lm not installed — run: uv tool install mlx-lm"
command -v hf >/dev/null || warn "'hf' not found — run: uv tool install 'huggingface_hub[cli]'"
fi
# --- Resolve source: local checkout or release tarball ---
if [ -n "$SRC" ]; then
@ -89,7 +114,21 @@ fi
[ -d "$SCRIPT_DIR/hooks" ] || die "hooks/ not found in $SCRIPT_DIR — wrong source?"
# --- Stage directories ---
mkdir -p "$HOOKS_DIR" "$AGENTS_DIR" "$LAUNCHD_DIR"
mkdir -p "$HOOKS_DIR" "$AGENTS_DIR"
if [ "$WITH_LAUNCHD" -eq 1 ]; then
mkdir -p "$LAUNCHD_DIR"
fi
# v2.1.0 originally installed the MLX server as part of the default path.
# Default reinstalls now retire that job; users can restore it with --with-launchd.
if [ "$WITH_LAUNCHD" -eq 0 ] && [ "$OS_NAME" = "Darwin" ]; then
LEGACY_PLIST="$LAUNCHD_DIR/com.vestige.mlx-server.plist"
if [ -f "$LEGACY_PLIST" ]; then
launchctl unload "$LEGACY_PLIST" 2>/dev/null || true
rm -f "$LEGACY_PLIST"
say "removed old Sanhedrin launchd job (use --with-launchd to opt back in)"
fi
fi
# --- Copy hooks ---
copied=0; skipped=0
@ -121,8 +160,25 @@ for f in "$SCRIPT_DIR/agents"/*.md; do
done
say "agents installed to $AGENTS_DIR"
# --- Render launchd plist (macOS only) ---
if [ "$NO_LAUNCHD" -eq 0 ]; then
# --- Persist optional Sanhedrin env ---
quote_env() {
printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\\\\''/g")"
}
if [ "$ENABLE_SANHEDRIN" -eq 1 ]; then
SANHEDRIN_ENV="$HOOKS_DIR/vestige-sanhedrin.env"
{
printf 'VESTIGE_SANHEDRIN_ENABLED=1\n'
printf 'VESTIGE_SANHEDRIN_ENDPOINT=%s\n' "$(quote_env "$SANHEDRIN_ENDPOINT")"
printf 'VESTIGE_SANHEDRIN_MODEL=%s\n' "$(quote_env "$MODEL_ID")"
printf 'VESTIGE_DASHBOARD_PORT=%s\n' "$(quote_env "$DASHBOARD_PORT")"
} > "$SANHEDRIN_ENV"
chmod 0600 "$SANHEDRIN_ENV"
say "Sanhedrin opt-in config written to $SANHEDRIN_ENV"
fi
# --- Render launchd plist (Apple Silicon opt-in only) ---
if [ "$WITH_LAUNCHD" -eq 1 ]; then
PLIST="$LAUNCHD_DIR/com.vestige.mlx-server.plist"
TEMPLATE="$SCRIPT_DIR/launchd/com.vestige.mlx-server.plist.template"
[ -f "$TEMPLATE" ] || die "launchd template missing: $TEMPLATE"
@ -140,31 +196,80 @@ else
cp "$SETTINGS" "$HOME/.claude/settings.json.bak.pre-sandwich"
fi
TMP_MERGE="$(mktemp)"
jq -s '.[0] * .[1]' "$SETTINGS" "$SCRIPT_DIR/hooks/settings.fragment.json" > "$TMP_MERGE"
PREFLIGHT_FRAGMENT="$SCRIPT_DIR/hooks/settings.fragment.json"
SANHEDRIN_FRAGMENT="$SCRIPT_DIR/hooks/settings.fragment.json"
if [ "$ENABLE_PREFLIGHT" -eq 1 ]; then
PREFLIGHT_FRAGMENT="$SCRIPT_DIR/hooks/settings.preflight.fragment.json"
fi
if [ "$ENABLE_SANHEDRIN" -eq 1 ]; then
SANHEDRIN_FRAGMENT="$SCRIPT_DIR/hooks/settings.sanhedrin.fragment.json"
fi
jq -s '
def is_vestige_hook:
(.command? // "") as $cmd
| [
"synthesis-preflight.sh",
"cwd-state-injector.sh",
"vestige-pulse-daemon.sh",
"preflight-swarm.sh",
"load-all-memory.sh",
"veto-detector.sh",
"sanhedrin.sh",
"synthesis-stop-validator.sh",
"synthesis-gate.sh"
] | any(. as $needle | $cmd | contains($needle));
def scrub_vestige_hooks:
.hooks.UserPromptSubmit = (
(.hooks.UserPromptSubmit // [])
| map(.hooks = ((.hooks // []) | map(select((is_vestige_hook | not)))))
| map(select(((.hooks // []) | length) > 0))
)
| if ((.hooks.UserPromptSubmit // []) | length) == 0 then del(.hooks.UserPromptSubmit) else . end
| .hooks.Stop = (
(.hooks.Stop // [])
| map(.hooks = ((.hooks // []) | map(select((is_vestige_hook | not)))))
| map(select(((.hooks // []) | length) > 0))
)
| if ((.hooks.Stop // []) | length) == 0 then del(.hooks.Stop) else . end
| if ((.hooks // {}) | length) == 0 then del(.hooks) else . end;
(.[0] | scrub_vestige_hooks) * .[1] * .[2]
' "$SETTINGS" "$PREFLIGHT_FRAGMENT" "$SANHEDRIN_FRAGMENT" > "$TMP_MERGE"
mv "$TMP_MERGE" "$SETTINGS"
say "merged hooks block into $SETTINGS (backup at .bak.pre-sandwich)"
if [ "$ENABLE_PREFLIGHT" -eq 1 ] || [ "$ENABLE_SANHEDRIN" -eq 1 ]; then
enabled_layers=""
[ "$ENABLE_PREFLIGHT" -eq 1 ] && enabled_layers="${enabled_layers} preflight"
[ "$ENABLE_SANHEDRIN" -eq 1 ] && enabled_layers="${enabled_layers} sanhedrin"
say "merged optional hook layer(s) into $SETTINGS:${enabled_layers} (backup at .bak.pre-sandwich)"
else
say "removed Vestige hook wiring from $SETTINGS; default install activates no Claude Code hooks (backup at .bak.pre-sandwich)"
fi
# --- Next steps ---
cat <<EOF
┌──────────────────────────────────────────────────────────────┐
│ Cognitive Sandwich installed. │
│ Cognitive Sandwich files installed. No hooks enabled by default.
└──────────────────────────────────────────────────────────────┘
Next steps:
1. Download the local model (~19 GB, one-time):
hf download $MODEL_ID
2. Restart Claude Code so it picks up the new hooks.
3. Verify the install:
1. Restart Claude Code if you enabled optional hooks.
Default installs activate no Vestige Claude Code hooks and make no model calls.
2. Verify the install:
vestige health # if vestige CLI installed
curl http://127.0.0.1:$DASHBOARD_PORT/api/health
curl $MLX_MODELS_URL
4. Try a prompt — the Sanhedrin Stop hook will fire and judge
Claude's draft against your Vestige memory before delivery.
scripts/check-sandwich-prereqs.sh # from a checkout
3. Optional hook layers:
./scripts/install-sandwich.sh --enable-preflight
./scripts/install-sandwich.sh --enable-sanhedrin --sanhedrin-endpoint=$SANHEDRIN_ENDPOINT --sanhedrin-model=$MODEL_ID
On Apple Silicon with >20 GB free RAM, add --with-launchd to auto-start
the local MLX Qwen server. On x86, point --sanhedrin-endpoint at vLLM,
Ollama, llama.cpp, or another OpenAI-compatible /v1/chat/completions URL.
To uninstall:
launchctl unload $LAUNCHD_DIR/com.vestige.mlx-server.plist
rm $LAUNCHD_DIR/com.vestige.mlx-server.plist
launchctl unload $LAUNCHD_DIR/com.vestige.mlx-server.plist 2>/dev/null || true
rm -f $LAUNCHD_DIR/com.vestige.mlx-server.plist
cp $HOME/.claude/settings.json.bak.pre-sandwich $HOME/.claude/settings.json
EOF