Skip to content

Instantly share code, notes, and snippets.

@zazk
Created May 24, 2026 01:31
Show Gist options
  • Select an option

  • Save zazk/c323a958959d65d09000ed04a7194ae8 to your computer and use it in GitHub Desktop.

Select an option

Save zazk/c323a958959d65d09000ed04a7194ae8 to your computer and use it in GitHub Desktop.
Bonsai 1-bit LLM — Installer & Runner

Copy/Download the script and run it like this:

bashchmod +x bonsai-install.sh
./bonsai-install.sh

What you'll get: What would you like to do?

  1. Install + run interactive chat (CLI)
  2. Install + run as local server with WebUI
  3. Run interactive chat (already installed)
  4. Run local server with WebUI (already installed)
  5. Change model size (current: 8B)
  6. Uninstall q) Quit Key features:

Auto-detects your platform (macOS Apple Silicon/Intel, Linux CUDA/CPU) and builds with the right flags Downloads the correct GGUF from Hugging Face with a progress bar Skips re-downloading/rebuilding if already done Option 2 auto-opens your browser to http://localhost:8080 when the server is ready The server exposes a full OpenAI-compatible API at /v1/chat/completions Supports all three model sizes (1.7B / 4B / 8B) Everything installs to ~/bonsai (clean uninstall via option 6)

Note: On first run, building llama.cpp takes 1–3 minutes. The 8B model download is ~1.15 GB. After that, options 3/4 skip straight to running.

#!/usr/bin/env bash
# =============================================================================
# Bonsai 1-bit LLM — Installer & Runner
# Supports: macOS (Apple Silicon + Intel), Linux (CUDA / CPU)
# =============================================================================
set -euo pipefail
# ── Colours ──────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
info() { echo -e "${CYAN}${BOLD}[INFO]${RESET} $*"; }
success() { echo -e "${GREEN}${BOLD}[OK]${RESET} $*"; }
warn() { echo -e "${YELLOW}${BOLD}[WARN]${RESET} $*"; }
error() { echo -e "${RED}${BOLD}[ERROR]${RESET} $*" >&2; exit 1; }
step() { echo -e "\n${BOLD}━━━ $* ━━━${RESET}"; }
# ── Defaults ─────────────────────────────────────────────────────────────────
INSTALL_DIR="$HOME/bonsai"
REPO_URL="https://github.com/PrismML-Eng/llama.cpp.git"
MODEL_SIZE="${BONSAI_MODEL:-8B}" # 1.7B | 4B | 8B
SERVER_PORT="${BONSAI_PORT:-8080}"
CTX_SIZE=65536
GPU_LAYERS=99
# ── Banner ────────────────────────────────────────────────────────────────────
echo -e "
${CYAN}${BOLD}
██████╗ ██████╗ ███╗ ██╗███████╗ █████╗ ██╗
██╔══██╗██╔═══██╗████╗ ██║██╔════╝██╔══██╗██║
██████╔╝██║ ██║██╔██╗ ██║███████╗███████║██║
██╔══██╗██║ ██║██║╚██╗██║╚════██║██╔══██║██║
██████╔╝╚██████╔╝██║ ╚████║███████║██║ ██║██║
╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚═╝
${RESET}${BOLD} 1-bit LLM Installer & Runner${RESET}
PrismML • Apache 2.0 • ~1 GB for 8B params
"
# ── Menu ──────────────────────────────────────────────────────────────────────
echo -e "${BOLD}What would you like to do?${RESET}"
echo " 1) Install + run interactive chat (CLI)"
echo " 2) Install + run as local server with WebUI"
echo " 3) Run interactive chat (already installed)"
echo " 4) Run local server with WebUI (already installed)"
echo " 5) Change model size (current: ${MODEL_SIZE})"
echo " 6) Uninstall"
echo " q) Quit"
echo ""
read -rp "Choice [1]: " CHOICE
CHOICE="${CHOICE:-1}"
# ── Model size picker ─────────────────────────────────────────────────────────
pick_model_size() {
echo -e "\n${BOLD}Choose model size:${RESET}"
echo " 1) 8B — 1.15 GB (best quality, recommended)"
echo " 2) 4B — 0.5 GB (balanced)"
echo " 3) 1.7B — 0.24 GB (smallest, Raspberry Pi / edge)"
read -rp "Choice [1]: " SZ
case "${SZ:-1}" in
1) MODEL_SIZE="8B" ;;
2) MODEL_SIZE="4B" ;;
3) MODEL_SIZE="1.7B" ;;
*) MODEL_SIZE="8B" ;;
esac
success "Model size set to ${MODEL_SIZE}"
}
if [[ "$CHOICE" == "5" ]]; then
pick_model_size
# Re-show menu after picking
exec "$0"
fi
if [[ "$CHOICE" == "6" ]]; then
step "Uninstall"
if [[ -d "$INSTALL_DIR" ]]; then
read -rp "Remove $INSTALL_DIR? [y/N] " CONFIRM
[[ "${CONFIRM,,}" == "y" ]] && rm -rf "$INSTALL_DIR" && success "Removed $INSTALL_DIR" || info "Aborted."
else
warn "Nothing to remove at $INSTALL_DIR"
fi
exit 0
fi
if [[ "$CHOICE" == "q" ]]; then exit 0; fi
# ── Detect platform ───────────────────────────────────────────────────────────
detect_platform() {
OS="$(uname -s)"
ARCH="$(uname -m)"
case "$OS" in
Darwin)
PLATFORM="macos"
if [[ "$ARCH" == "arm64" ]]; then
BUILD_FLAGS="" # Metal on by default for Apple Silicon
HW_DESC="macOS Apple Silicon (Metal)"
else
BUILD_FLAGS="-DGGML_METAL=OFF"
HW_DESC="macOS Intel (CPU)"
fi
;;
Linux)
PLATFORM="linux"
if command -v nvcc &>/dev/null || [[ -d /usr/local/cuda ]]; then
BUILD_FLAGS="-DGGML_CUDA=ON"
HW_DESC="Linux + NVIDIA CUDA"
else
BUILD_FLAGS=""
HW_DESC="Linux CPU"
warn "No CUDA detected — building CPU-only (slower). Install CUDA toolkit for GPU acceleration."
fi
;;
*)
error "Unsupported OS: $OS. Use macOS or Linux (for Windows, use WSL2)."
;;
esac
info "Platform: ${HW_DESC}"
}
# ── Dependency checks ─────────────────────────────────────────────────────────
check_deps() {
step "Checking dependencies"
local missing=()
for cmd in git cmake make; do
if ! command -v "$cmd" &>/dev/null; then
missing+=("$cmd")
fi
done
if [[ "$PLATFORM" == "macos" ]] && ! xcode-select -p &>/dev/null; then
warn "Xcode Command Line Tools not found. Installing..."
xcode-select --install
read -rp "Press Enter once Xcode CLT installation completes..."
fi
if [[ ${#missing[@]} -gt 0 ]]; then
error "Missing required tools: ${missing[*]}\n\n macOS: brew install ${missing[*]}\n Ubuntu: sudo apt install ${missing[*]}"
fi
success "All dependencies found"
}
# ── HuggingFace model URLs ────────────────────────────────────────────────────
get_model_url() {
case "$MODEL_SIZE" in
8B) echo "https://huggingface.co/prism-ml/Bonsai-8B-gguf/resolve/main/Bonsai-8B-Q1_0.gguf" ;;
4B) echo "https://huggingface.co/prism-ml/Bonsai-4B-gguf/resolve/main/Bonsai-4B-Q1_0.gguf" ;;
1.7B) echo "https://huggingface.co/prism-ml/Bonsai-1.7B-gguf/resolve/main/Bonsai-1.7B-Q1_0.gguf" ;;
*) error "Unknown model size: $MODEL_SIZE" ;;
esac
}
get_model_filename() {
case "$MODEL_SIZE" in
8B) echo "Bonsai-8B-Q1_0.gguf" ;;
4B) echo "Bonsai-4B-Q1_0.gguf" ;;
1.7B) echo "Bonsai-1.7B-Q1_0.gguf" ;;
esac
}
# ── Install ───────────────────────────────────────────────────────────────────
install_bonsai() {
step "Installing Bonsai to $INSTALL_DIR"
mkdir -p "$INSTALL_DIR/models"
# ── Clone PrismML llama.cpp fork ──────────────────────────────────────────
if [[ -d "$INSTALL_DIR/llama.cpp/.git" ]]; then
info "llama.cpp fork already cloned — pulling latest..."
git -C "$INSTALL_DIR/llama.cpp" pull --ff-only || warn "Could not pull updates (offline?)"
else
info "Cloning PrismML llama.cpp fork (includes Q1_0 1-bit kernels)..."
git clone --depth=1 "$REPO_URL" "$INSTALL_DIR/llama.cpp"
fi
# ── Build ──────────────────────────────────────────────────────────────────
BINARY="$INSTALL_DIR/llama.cpp/build/bin/llama-cli"
if [[ -f "$BINARY" ]]; then
info "Binaries already built — skipping build step"
else
info "Building llama.cpp (this takes 1–3 minutes)..."
cmake -S "$INSTALL_DIR/llama.cpp" \
-B "$INSTALL_DIR/llama.cpp/build" \
-DCMAKE_BUILD_TYPE=Release \
$BUILD_FLAGS
cmake --build "$INSTALL_DIR/llama.cpp/build" \
--config Release \
-j "$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 4)"
success "Build complete"
fi
# ── Download model ─────────────────────────────────────────────────────────
MODEL_FILE="$(get_model_filename)"
MODEL_PATH="$INSTALL_DIR/models/$MODEL_FILE"
if [[ -f "$MODEL_PATH" ]]; then
success "Model already downloaded: $MODEL_FILE"
else
MODEL_URL="$(get_model_url)"
info "Downloading $MODEL_FILE from Hugging Face..."
info "URL: $MODEL_URL"
echo ""
if command -v wget &>/dev/null; then
wget --show-progress -O "$MODEL_PATH" "$MODEL_URL"
elif command -v curl &>/dev/null; then
curl -L --progress-bar -o "$MODEL_PATH" "$MODEL_URL"
else
error "Neither wget nor curl found. Please install one and retry."
fi
success "Model downloaded: $MODEL_PATH"
fi
}
# ── Run: interactive CLI ──────────────────────────────────────────────────────
run_chat() {
MODEL_PATH="$INSTALL_DIR/models/$(get_model_filename)"
BINARY="$INSTALL_DIR/llama.cpp/build/bin/llama-cli"
[[ -f "$BINARY" ]] || error "Binary not found. Run install first (option 1 or 2)."
[[ -f "$MODEL_PATH" ]] || error "Model not found at $MODEL_PATH. Run install first."
step "Starting Bonsai ${MODEL_SIZE} — Interactive Chat"
echo -e " ${YELLOW}Type your message and press Enter. Ctrl+C to exit.${RESET}\n"
"$BINARY" \
-m "$MODEL_PATH" \
--interactive-first \
--color \
-n -1 \
--temp 0.5 \
--top-p 0.85 \
--top-k 20 \
--repeat-penalty 1.1 \
-ngl "$GPU_LAYERS" \
--ctx-size 4096 \
-p "You are a helpful assistant."
}
# ── Run: local server + WebUI ─────────────────────────────────────────────────
run_server() {
MODEL_PATH="$INSTALL_DIR/models/$(get_model_filename)"
BINARY="$INSTALL_DIR/llama.cpp/build/bin/llama-server"
[[ -f "$BINARY" ]] || error "Server binary not found. Run install first (option 1 or 2)."
[[ -f "$MODEL_PATH" ]] || error "Model not found at $MODEL_PATH. Run install first."
step "Starting Bonsai ${MODEL_SIZE} — Local Server"
echo ""
echo -e " ${GREEN}${BOLD}WebUI:${RESET} http://localhost:${SERVER_PORT}"
echo -e " ${GREEN}${BOLD}API:${RESET} http://localhost:${SERVER_PORT}/v1/chat/completions"
echo -e " ${YELLOW}Ctrl+C to stop the server${RESET}"
echo ""
# Open browser after a short delay (best-effort)
(
sleep 3
if command -v open &>/dev/null; then
open "http://localhost:${SERVER_PORT}"
elif command -v xdg-open &>/dev/null; then
xdg-open "http://localhost:${SERVER_PORT}" &>/dev/null
fi
) &
"$BINARY" \
-m "$MODEL_PATH" \
--host 0.0.0.0 \
--port "$SERVER_PORT" \
-ngl "$GPU_LAYERS" \
--ctx-size "$CTX_SIZE" \
--temp 0.5 \
--top-p 0.85 \
--top-k 20
}
# ── Main dispatcher ───────────────────────────────────────────────────────────
detect_platform
check_deps
case "$CHOICE" in
1)
install_bonsai
echo ""
run_chat
;;
2)
install_bonsai
echo ""
run_server
;;
3)
run_chat
;;
4)
run_server
;;
*)
error "Invalid choice: $CHOICE"
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment