diff --git a/.github/workflows/pub-release.yml b/.github/workflows/pub-release.yml
index 7cdb853..193bfd5 100644
--- a/.github/workflows/pub-release.yml
+++ b/.github/workflows/pub-release.yml
@@ -27,15 +27,45 @@ jobs:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact: zeroclaw
- - os: macos-latest
+ archive_ext: tar.gz
+ cross_compiler: ""
+ linker_env: ""
+ linker: ""
+ - os: ubuntu-latest
+ target: aarch64-unknown-linux-gnu
+ artifact: zeroclaw
+ archive_ext: tar.gz
+ cross_compiler: gcc-aarch64-linux-gnu
+ linker_env: CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER
+ linker: aarch64-linux-gnu-gcc
+ - os: ubuntu-latest
+ target: armv7-unknown-linux-gnueabihf
+ artifact: zeroclaw
+ archive_ext: tar.gz
+ cross_compiler: gcc-arm-linux-gnueabihf
+ linker_env: CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER
+ linker: arm-linux-gnueabihf-gcc
+ - os: macos-15-intel
target: x86_64-apple-darwin
artifact: zeroclaw
- - os: macos-latest
+ archive_ext: tar.gz
+ cross_compiler: ""
+ linker_env: ""
+ linker: ""
+ - os: macos-14
target: aarch64-apple-darwin
artifact: zeroclaw
+ archive_ext: tar.gz
+ cross_compiler: ""
+ linker_env: ""
+ linker: ""
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact: zeroclaw.exe
+ archive_ext: zip
+ cross_compiler: ""
+ linker_env: ""
+ linker: ""
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
@@ -46,20 +76,41 @@ jobs:
- uses: useblacksmith/rust-cache@f53e7f127245d2a269b3d90879ccf259876842d5 # v3
+ - name: Install cross-compilation toolchain (Linux)
+ if: runner.os == 'Linux' && matrix.cross_compiler != ''
+ run: |
+ sudo apt-get update -qq
+ sudo apt-get install -y ${{ matrix.cross_compiler }}
+
- name: Build release
- run: cargo build --release --locked --target ${{ matrix.target }}
+ env:
+ LINKER_ENV: ${{ matrix.linker_env }}
+ LINKER: ${{ matrix.linker }}
+ run: |
+ if [ -n "$LINKER_ENV" ] && [ -n "$LINKER" ]; then
+ echo "Using linker override: $LINKER_ENV=$LINKER"
+ export "$LINKER_ENV=$LINKER"
+ fi
+ cargo build --release --locked --target ${{ matrix.target }}
- name: Check binary size (Unix)
if: runner.os != 'Windows'
run: |
- SIZE=$(stat -f%z target/${{ matrix.target }}/release/${{ matrix.artifact }} 2>/dev/null || stat -c%s target/${{ matrix.target }}/release/${{ matrix.artifact }})
+ BIN="target/${{ matrix.target }}/release/${{ matrix.artifact }}"
+ if [ ! -f "$BIN" ]; then
+ echo "::error::Expected binary not found: $BIN"
+ exit 1
+ fi
+ SIZE=$(stat -f%z "$BIN" 2>/dev/null || stat -c%s "$BIN")
SIZE_MB=$((SIZE / 1024 / 1024))
echo "Binary size: ${SIZE_MB}MB ($SIZE bytes)"
echo "### Binary Size: ${{ matrix.target }}" >> "$GITHUB_STEP_SUMMARY"
echo "- Size: ${SIZE_MB}MB ($SIZE bytes)" >> "$GITHUB_STEP_SUMMARY"
- if [ "$SIZE" -gt 15728640 ]; then
- echo "::error::Binary exceeds 15MB hard limit (${SIZE_MB}MB)"
+ if [ "$SIZE" -gt 41943040 ]; then
+ echo "::error::Binary exceeds 40MB safeguard (${SIZE_MB}MB)"
exit 1
+ elif [ "$SIZE" -gt 15728640 ]; then
+ echo "::warning::Binary exceeds 15MB advisory target (${SIZE_MB}MB)"
elif [ "$SIZE" -gt 5242880 ]; then
echo "::warning::Binary exceeds 5MB target (${SIZE_MB}MB)"
else
@@ -70,19 +121,19 @@ jobs:
if: runner.os != 'Windows'
run: |
cd target/${{ matrix.target }}/release
- tar czf ../../../zeroclaw-${{ matrix.target }}.tar.gz ${{ matrix.artifact }}
+ tar czf ../../../zeroclaw-${{ matrix.target }}.${{ matrix.archive_ext }} ${{ matrix.artifact }}
- name: Package (Windows)
if: runner.os == 'Windows'
run: |
cd target/${{ matrix.target }}/release
- 7z a ../../../zeroclaw-${{ matrix.target }}.zip ${{ matrix.artifact }}
+ 7z a ../../../zeroclaw-${{ matrix.target }}.${{ matrix.archive_ext }} ${{ matrix.artifact }}
- name: Upload artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: zeroclaw-${{ matrix.target }}
- path: zeroclaw-${{ matrix.target }}.*
+ path: zeroclaw-${{ matrix.target }}.${{ matrix.archive_ext }}
retention-days: 7
publish:
diff --git a/README.md b/README.md
index 53fbc30..629842a 100644
--- a/README.md
+++ b/README.md
@@ -88,7 +88,7 @@ Local machine quick benchmark (macOS arm64, Feb 2026) normalized for 0.8GHz edge
| **Binary Size** | ~28MB (dist) | N/A (Scripts) | ~8MB | **3.4 MB** |
| **Cost** | Mac Mini $599 | Linux SBC ~$50 | Linux Board $10 | **Any hardware $10** |
-> Notes: ZeroClaw results are measured on release builds using `/usr/bin/time -l`. OpenClaw requires Node.js runtime (typically ~390MB additional memory overhead), while NanoBot requires Python runtime. PicoClaw and ZeroClaw are static binaries.
+> Notes: ZeroClaw results are measured on release builds using `/usr/bin/time -l`. OpenClaw requires Node.js runtime (typically ~390MB additional memory overhead), while NanoBot requires Python runtime. PicoClaw and ZeroClaw are static binaries. The RAM figures above are runtime memory; build-time compilation requirements are higher.
@@ -173,11 +173,32 @@ Or skip the steps above and install everything (system deps, Rust, ZeroClaw) in
curl -LsSf https://raw.githubusercontent.com/zeroclaw-labs/zeroclaw/main/scripts/install.sh | bash
```
+#### Compilation resource requirements
+
+Building from source needs more resources than running the resulting binary:
+
+| Resource | Minimum | Recommended |
+|---|---|---|
+| **RAM + swap** | 2 GB | 4 GB+ |
+| **Free disk** | 6 GB | 10 GB+ |
+
+If your host is below the minimum, use pre-built binaries:
+
+```bash
+./bootstrap.sh --prefer-prebuilt
+```
+
+To require binary-only install with no source fallback:
+
+```bash
+./bootstrap.sh --prebuilt-only
+```
+
#### Optional
- **Docker** — required only if using the [Docker sandboxed runtime](#runtime-support-current) (`runtime.kind = "docker"`). Install via your package manager or [docker.com](https://docs.docker.com/engine/install/).
-> **Note:** The default `cargo build --release` uses `codegen-units=1` for compatibility with low-memory devices (e.g., Raspberry Pi 3 with 1GB RAM). For faster builds on powerful machines, use `cargo build --profile release-fast`.
+> **Note:** The default `cargo build --release` uses `codegen-units=1` to lower peak compile pressure. For faster builds on powerful machines, use `cargo build --profile release-fast`.
@@ -201,6 +222,12 @@ cd zeroclaw
# Optional: bootstrap dependencies + Rust on fresh machines
./bootstrap.sh --install-system-deps --install-rust
+# Optional: pre-built binary first (recommended on low-RAM/low-disk hosts)
+./bootstrap.sh --prefer-prebuilt
+
+# Optional: binary-only install (no source build fallback)
+./bootstrap.sh --prebuilt-only
+
# Optional: run onboarding in the same flow
./bootstrap.sh --onboard --api-key "sk-..." --provider openrouter [--model "openrouter/auto"]
@@ -216,6 +243,25 @@ curl -fsSL https://raw.githubusercontent.com/zeroclaw-labs/zeroclaw/main/scripts
Details: [`docs/one-click-bootstrap.md`](docs/one-click-bootstrap.md) (toolchain mode may request `sudo` for system packages).
+### Pre-built binaries
+
+Release assets are published for:
+
+- Linux: `x86_64`, `aarch64`, `armv7`
+- macOS: `x86_64`, `aarch64`
+- Windows: `x86_64`
+
+Download the latest assets from:
+
+
+Example (ARM64 Linux):
+
+```bash
+curl -fsSLO https://github.com/zeroclaw-labs/zeroclaw/releases/latest/download/zeroclaw-aarch64-unknown-linux-gnu.tar.gz
+tar xzf zeroclaw-aarch64-unknown-linux-gnu.tar.gz
+install -m 0755 zeroclaw "$HOME/.cargo/bin/zeroclaw"
+```
+
```bash
git clone https://github.com/zeroclaw-labs/zeroclaw.git
cd zeroclaw
diff --git a/docs/one-click-bootstrap.md b/docs/one-click-bootstrap.md
index 25cd108..c9001f7 100644
--- a/docs/one-click-bootstrap.md
+++ b/docs/one-click-bootstrap.md
@@ -2,7 +2,7 @@
This page defines the fastest supported path to install and initialize ZeroClaw.
-Last verified: **February 18, 2026**.
+Last verified: **February 20, 2026**.
## Option 0: Homebrew (macOS/Linuxbrew)
@@ -23,6 +23,31 @@ What it does by default:
1. `cargo build --release --locked`
2. `cargo install --path . --force --locked`
+### Resource preflight and pre-built flow
+
+Source builds typically require at least:
+
+- **2 GB RAM + swap**
+- **6 GB free disk**
+
+When resources are constrained, bootstrap now attempts a pre-built binary first.
+
+```bash
+./bootstrap.sh --prefer-prebuilt
+```
+
+To require binary-only installation and fail if no compatible release asset exists:
+
+```bash
+./bootstrap.sh --prebuilt-only
+```
+
+To bypass pre-built flow and force source compilation:
+
+```bash
+./bootstrap.sh --force-source-build
+```
+
## Dual-mode bootstrap
Default behavior is **app-only** (build/install ZeroClaw) and expects existing Rust toolchain.
@@ -37,6 +62,9 @@ Notes:
- `--install-system-deps` installs compiler/build prerequisites (may require `sudo`).
- `--install-rust` installs Rust via `rustup` when missing.
+- `--prefer-prebuilt` tries release binary download first, then falls back to source build.
+- `--prebuilt-only` disables source fallback.
+- `--force-source-build` disables pre-built flow entirely.
## Option B: Remote one-liner
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index ab7cfbf..7fd02aa 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -2,7 +2,7 @@
This guide focuses on common setup/runtime failures and fast resolution paths.
-Last verified: **February 19, 2026**.
+Last verified: **February 20, 2026**.
## Installation / Bootstrap
@@ -32,6 +32,48 @@ Fix:
./bootstrap.sh --install-system-deps
```
+### Build fails on low-RAM / low-disk hosts
+
+Symptoms:
+
+- `cargo build --release` is killed (`signal: 9`, OOM killer, or `cannot allocate memory`)
+- Build crashes after adding swap because disk space runs out
+
+Why this happens:
+
+- Runtime memory (<5MB for common operations) is not the same as compile-time memory.
+- Full source build can require **2 GB RAM + swap** and **6+ GB free disk**.
+- Enabling swap on a tiny disk can avoid RAM OOM but still fail due to disk exhaustion.
+
+Preferred path for constrained machines:
+
+```bash
+./bootstrap.sh --prefer-prebuilt
+```
+
+Binary-only mode (no source fallback):
+
+```bash
+./bootstrap.sh --prebuilt-only
+```
+
+If you must compile from source on constrained hosts:
+
+1. Add swap only if you also have enough free disk for both swap + build output.
+1. Limit cargo parallelism:
+
+```bash
+CARGO_BUILD_JOBS=1 cargo build --release --locked
+```
+
+1. Reduce heavy features when Matrix is not required:
+
+```bash
+cargo build --release --locked --no-default-features --features hardware
+```
+
+1. Cross-compile on a stronger machine and copy the binary to the target host.
+
### Build is very slow or appears stuck
Symptoms:
diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh
index f256fa6..a081a61 100755
--- a/scripts/bootstrap.sh
+++ b/scripts/bootstrap.sh
@@ -28,6 +28,9 @@ Options:
--docker Run bootstrap in Docker and launch onboarding inside the container
--install-system-deps Install build dependencies (Linux/macOS)
--install-rust Install Rust via rustup if missing
+ --prefer-prebuilt Try latest release binary first; fallback to source build on miss
+ --prebuilt-only Install only from latest release binary (no source build fallback)
+ --force-source-build Disable prebuilt flow and always build from source
--onboard Run onboarding after install
--interactive-onboard Run interactive onboarding (implies --onboard)
--api-key API key for non-interactive onboarding
@@ -41,6 +44,8 @@ Examples:
./bootstrap.sh
./bootstrap.sh --docker
./bootstrap.sh --install-system-deps --install-rust
+ ./bootstrap.sh --prefer-prebuilt
+ ./bootstrap.sh --prebuilt-only
./bootstrap.sh --onboard --api-key "sk-..." --provider openrouter [--model "openrouter/auto"]
./bootstrap.sh --interactive-onboard
@@ -53,6 +58,8 @@ Environment:
ZEROCLAW_API_KEY Used when --api-key is not provided
ZEROCLAW_PROVIDER Used when --provider is not provided (default: openrouter)
ZEROCLAW_MODEL Used when --model is not provided
+ ZEROCLAW_BOOTSTRAP_MIN_RAM_MB Minimum RAM threshold for source build preflight (default: 2048)
+ ZEROCLAW_BOOTSTRAP_MIN_DISK_MB Minimum free disk threshold for source build preflight (default: 6144)
USAGE
}
@@ -60,6 +67,155 @@ have_cmd() {
command -v "$1" >/dev/null 2>&1
}
+get_total_memory_mb() {
+ case "$(uname -s)" in
+ Linux)
+ if [[ -r /proc/meminfo ]]; then
+ awk '/MemTotal:/ {printf "%d\n", $2 / 1024}' /proc/meminfo
+ fi
+ ;;
+ Darwin)
+ if have_cmd sysctl; then
+ local bytes
+ bytes="$(sysctl -n hw.memsize 2>/dev/null || true)"
+ if [[ "$bytes" =~ ^[0-9]+$ ]]; then
+ echo $((bytes / 1024 / 1024))
+ fi
+ fi
+ ;;
+ esac
+}
+
+get_available_disk_mb() {
+ local path="${1:-.}"
+ local free_kb
+ free_kb="$(df -Pk "$path" 2>/dev/null | awk 'NR==2 {print $4}')"
+ if [[ "$free_kb" =~ ^[0-9]+$ ]]; then
+ echo $((free_kb / 1024))
+ fi
+}
+
+detect_release_target() {
+ local os arch
+ os="$(uname -s)"
+ arch="$(uname -m)"
+
+ case "$os:$arch" in
+ Linux:x86_64)
+ echo "x86_64-unknown-linux-gnu"
+ ;;
+ Linux:aarch64|Linux:arm64)
+ echo "aarch64-unknown-linux-gnu"
+ ;;
+ Linux:armv7l|Linux:armv6l)
+ echo "armv7-unknown-linux-gnueabihf"
+ ;;
+ Darwin:x86_64)
+ echo "x86_64-apple-darwin"
+ ;;
+ Darwin:arm64|Darwin:aarch64)
+ echo "aarch64-apple-darwin"
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+}
+
+should_attempt_prebuilt_for_resources() {
+ local workspace="${1:-.}"
+ local min_ram_mb min_disk_mb total_ram_mb free_disk_mb low_resource
+
+ min_ram_mb="${ZEROCLAW_BOOTSTRAP_MIN_RAM_MB:-2048}"
+ min_disk_mb="${ZEROCLAW_BOOTSTRAP_MIN_DISK_MB:-6144}"
+ total_ram_mb="$(get_total_memory_mb || true)"
+ free_disk_mb="$(get_available_disk_mb "$workspace" || true)"
+ low_resource=false
+
+ if [[ "$total_ram_mb" =~ ^[0-9]+$ && "$total_ram_mb" -lt "$min_ram_mb" ]]; then
+ low_resource=true
+ fi
+ if [[ "$free_disk_mb" =~ ^[0-9]+$ && "$free_disk_mb" -lt "$min_disk_mb" ]]; then
+ low_resource=true
+ fi
+
+ if [[ "$low_resource" == true ]]; then
+ warn "Source build preflight indicates constrained resources."
+ if [[ "$total_ram_mb" =~ ^[0-9]+$ ]]; then
+ warn "Detected RAM: ${total_ram_mb}MB (recommended >= ${min_ram_mb}MB for local source builds)."
+ else
+ warn "Unable to detect total RAM automatically."
+ fi
+ if [[ "$free_disk_mb" =~ ^[0-9]+$ ]]; then
+ warn "Detected free disk: ${free_disk_mb}MB (recommended >= ${min_disk_mb}MB)."
+ else
+ warn "Unable to detect free disk space automatically."
+ fi
+ return 0
+ fi
+
+ return 1
+}
+
+install_prebuilt_binary() {
+ local target archive_url temp_dir archive_path extracted_bin install_dir
+
+ if ! have_cmd curl; then
+ warn "curl is required for pre-built binary installation."
+ return 1
+ fi
+ if ! have_cmd tar; then
+ warn "tar is required for pre-built binary installation."
+ return 1
+ fi
+
+ target="$(detect_release_target || true)"
+ if [[ -z "$target" ]]; then
+ warn "No pre-built binary target mapping for $(uname -s)/$(uname -m)."
+ return 1
+ fi
+
+ archive_url="https://github.com/zeroclaw-labs/zeroclaw/releases/latest/download/zeroclaw-${target}.tar.gz"
+ temp_dir="$(mktemp -d -t zeroclaw-prebuilt-XXXXXX)"
+ archive_path="$temp_dir/zeroclaw-${target}.tar.gz"
+
+ info "Attempting pre-built binary install for target: $target"
+ if ! curl -fsSL "$archive_url" -o "$archive_path"; then
+ warn "Could not download release asset: $archive_url"
+ rm -rf "$temp_dir"
+ return 1
+ fi
+
+ if ! tar -xzf "$archive_path" -C "$temp_dir"; then
+ warn "Failed to extract pre-built archive."
+ rm -rf "$temp_dir"
+ return 1
+ fi
+
+ extracted_bin="$temp_dir/zeroclaw"
+ if [[ ! -x "$extracted_bin" ]]; then
+ extracted_bin="$(find "$temp_dir" -maxdepth 2 -type f -name zeroclaw -perm -u+x | head -n 1 || true)"
+ fi
+ if [[ -z "$extracted_bin" || ! -x "$extracted_bin" ]]; then
+ warn "Archive did not contain an executable zeroclaw binary."
+ rm -rf "$temp_dir"
+ return 1
+ fi
+
+ install_dir="$HOME/.cargo/bin"
+ mkdir -p "$install_dir"
+ install -m 0755 "$extracted_bin" "$install_dir/zeroclaw"
+ rm -rf "$temp_dir"
+
+ info "Installed pre-built binary to $install_dir/zeroclaw"
+ if [[ ":$PATH:" != *":$install_dir:"* ]]; then
+ warn "$install_dir is not in PATH for this shell."
+ warn "Run: export PATH=\"$install_dir:\$PATH\""
+ fi
+
+ return 0
+}
+
run_privileged() {
if [[ "$(id -u)" -eq 0 ]]; then
"$@"
@@ -221,10 +377,14 @@ REPO_URL="https://github.com/zeroclaw-labs/zeroclaw.git"
DOCKER_MODE=false
INSTALL_SYSTEM_DEPS=false
INSTALL_RUST=false
+PREFER_PREBUILT=false
+PREBUILT_ONLY=false
+FORCE_SOURCE_BUILD=false
RUN_ONBOARD=false
INTERACTIVE_ONBOARD=false
SKIP_BUILD=false
SKIP_INSTALL=false
+PREBUILT_INSTALLED=false
API_KEY="${ZEROCLAW_API_KEY:-}"
PROVIDER="${ZEROCLAW_PROVIDER:-openrouter}"
MODEL="${ZEROCLAW_MODEL:-}"
@@ -243,6 +403,18 @@ while [[ $# -gt 0 ]]; do
INSTALL_RUST=true
shift
;;
+ --prefer-prebuilt)
+ PREFER_PREBUILT=true
+ shift
+ ;;
+ --prebuilt-only)
+ PREBUILT_ONLY=true
+ shift
+ ;;
+ --force-source-build)
+ FORCE_SOURCE_BUILD=true
+ shift
+ ;;
--onboard)
RUN_ONBOARD=true
shift
@@ -314,16 +486,6 @@ else
fi
fi
-if [[ "$DOCKER_MODE" == false ]] && ! have_cmd cargo; then
- error "cargo is not installed."
- cat <<'MSG' >&2
-Install Rust first: https://rustup.rs/
-or re-run with:
- ./bootstrap.sh --install-rust
-MSG
- exit 1
-fi
-
WORK_DIR="$ROOT_DIR"
TEMP_CLONE=false
TEMP_DIR=""
@@ -364,6 +526,15 @@ echo " workspace: $WORK_DIR"
cd "$WORK_DIR"
+if [[ "$FORCE_SOURCE_BUILD" == true ]]; then
+ PREFER_PREBUILT=false
+ PREBUILT_ONLY=false
+fi
+
+if [[ "$PREBUILT_ONLY" == true ]]; then
+ PREFER_PREBUILT=true
+fi
+
if [[ "$DOCKER_MODE" == true ]]; then
ensure_docker_ready
if [[ "$RUN_ONBOARD" == false ]]; then
@@ -389,6 +560,39 @@ DONE
exit 0
fi
+if [[ "$FORCE_SOURCE_BUILD" == false ]]; then
+ if [[ "$PREFER_PREBUILT" == false && "$PREBUILT_ONLY" == false ]]; then
+ if should_attempt_prebuilt_for_resources "$WORK_DIR"; then
+ info "Attempting pre-built binary first due to resource preflight."
+ PREFER_PREBUILT=true
+ fi
+ fi
+
+ if [[ "$PREFER_PREBUILT" == true ]]; then
+ if install_prebuilt_binary; then
+ PREBUILT_INSTALLED=true
+ SKIP_BUILD=true
+ SKIP_INSTALL=true
+ elif [[ "$PREBUILT_ONLY" == true ]]; then
+ error "Pre-built-only mode requested, but no compatible release asset is available."
+ error "Try again later, or run with --force-source-build on a machine with enough RAM/disk."
+ exit 1
+ else
+ warn "Pre-built install unavailable; falling back to source build."
+ fi
+ fi
+fi
+
+if [[ "$PREBUILT_INSTALLED" == false && ( "$SKIP_BUILD" == false || "$SKIP_INSTALL" == false ) ]] && ! have_cmd cargo; then
+ error "cargo is not installed."
+ cat <<'MSG' >&2
+Install Rust first: https://rustup.rs/
+or re-run with:
+ ./bootstrap.sh --install-rust
+MSG
+ exit 1
+fi
+
if [[ "$SKIP_BUILD" == false ]]; then
info "Building release binary"
cargo build --release --locked
@@ -406,6 +610,8 @@ fi
ZEROCLAW_BIN=""
if have_cmd zeroclaw; then
ZEROCLAW_BIN="zeroclaw"
+elif [[ -x "$HOME/.cargo/bin/zeroclaw" ]]; then
+ ZEROCLAW_BIN="$HOME/.cargo/bin/zeroclaw"
elif [[ -x "$WORK_DIR/target/release/zeroclaw" ]]; then
ZEROCLAW_BIN="$WORK_DIR/target/release/zeroclaw"
fi