Setup script + Ansible playbook that gets a fresh Apple Silicon MacBook Pro from out-of-the-box to running local LLM inference on LLMKube. One command, then the secrets you wire in yourself.
Target: Apple Silicon MacBook Pro on macOS Sequoia (15) or later.
The default memory budget is tuned for a 128 GB machine; on smaller
hardware, lower metal_agent_memory_fraction in group_vars/all.yml
before running bootstrap. Earlier macOS versions and Intel Macs are
intentionally out of scope for v0.1.
After a clean bootstrap you have:
- Homebrew + the LLMKube-supporting package set (
kubectl,helm,kind,jq,yq,gh,k9s,tmux,ripgrep,fzf). colimastarted with a user-space Lima VM (4 CPU, 6 GiB, 60 GiB disk by default; override via--extra-vars). Provides the Docker socketkinduses.docker/docker-compose/docker-buildxCLIs installed via Homebrew, no Docker Desktop required. To use Docker Desktop instead, see the "Docker Desktop on Apple Silicon" callout near the end of this README.- A
kindcluster namedllmkube-localrunning the LLMKube operator from the published Helm chart. - A clone of
defilantech/LLMKubeat~/src/LLMKube, and themetal-agentdaemon installed + running underlaunchd. - A starter model (
phi-4-mini-instruct, Q4_K_M) deployed viaModel+InferenceServiceCRs and verified via a real chat completion againstlocalhost:<port>. opencodeinstalled with a sanitized config pointing at your local llama-server. MCP servers (brave-search,github,context7,playwright) are configured but inert until you supply API keys.
Optional add-ons via flags:
--with-carnice— pullsCarnice-Qwen3.6-MoE-35B-A3B-APEX-MTP-I-Balanced.gguf(~36 GB) and deploys it as a second InferenceService. A larger MoE coder model serving up to 256 K context via YaRN; expect 10–40 min to download depending on connection.--with-foreman— installs the Foreman agentic-workload add-on (operator + node agent) onto the local kind cluster. See the LLMKube Foreman M3 runbook.
git clone https://github.com/defilantech/llmkube-bootstrap
cd llmkube-bootstrap
./bootstrap.sh # base install (phi-4-mini)
./bootstrap.sh --with-carnice # base + Carnice 35B
./bootstrap.sh --with-foreman # base + Foreman opt-in
./bootstrap.sh --with-foreman --with-carnice # the worksOn a fresh Mac, the very first git clone will trigger macOS to
prompt "git requires Command Line Tools, install?" — click Install,
wait ~3 min, re-run the clone. That is the only pre-prerequisite this
repo cannot pave around.
Bootstrap is idempotent. Run it again after an OS update or a chart release to bring the install current.
The playbook intentionally never touches secrets. After it finishes:
| What | Where | Used by |
|---|---|---|
| GitHub PAT | ~/.config/foreman/github-token (or $GITHUB_TOKEN env) |
Foreman (push branches to your fork), gh CLI |
| Brave Search API key | $BRAVE_API_KEY env (e.g. in ~/.zshrc) |
opencode's brave-search MCP server |
| Anthropic API key | $ANTHROPIC_API_KEY env |
opencode's Anthropic provider, Foreman M6 planner |
| Hugging Face token | $HF_TOKEN env |
opencode's huggingface MCP server, gated model downloads |
| Jira creds | $JIRA_URL / $JIRA_USERNAME / $JIRA_API_TOKEN env |
opencode's atlassian MCP server |
Restart your shell (or source ~/.zshrc) after setting envs.
If you need to start from a clean slate to test a change to the playbook:
./teardown.sh # removes kind cluster, launchd unit, model storeteardown.sh deliberately does NOT uninstall Homebrew, Docker
Desktop, or your shell config. It removes only what the bootstrap
created in the LLMKube layer.
bootstrap.sh # ensures brew + ansible, then runs the playbook
teardown.sh # nuke the LLMKube layer for re-testing
playbook.yml # Ansible entrypoint
inventory/localhost.yml # always local
group_vars/all.yml # tunables (memory_fraction, src_dir, model_repo, etc.)
roles/
system/ # macOS sanity asserts, Xcode CLT
homebrew/ # brew + per-package installs
kubernetes/ # colima, kind, kubectl, helm, k9s
llmkube_core/ # clone LLMKube, helm install, install metal-agent
model_starter/ # download phi-4-mini, apply Model + InferenceService
opencode/ # opencode binary + sanitized config template
developer_tools/ # gh, jq, yq, tmux, etc.
carnice/ # opt-in via --tags carnice
foreman/ # opt-in via --tags foreman
files/
opencode.json.template # the opencode config we drop into ~/.config/opencode/
.github/workflows/
ci.yml # ansible-lint + yamllint + shellcheck
Every PR runs three linters:
ansible-lint— Ansible best practices, role correctnessyamllint— YAML formattingshellcheck—bootstrap.shandteardown.sh
These run on an Ubuntu runner in seconds. They do not exercise the playbook end-to-end — macOS-bound bugs in homebrew / launchd / colima will only surface when a human runs the bootstrap on a real Mac. A future change may add a nightly macOS runner that does the full install; that's not in v0.1.
The default Docker runtime is colima. If you specifically want
Docker Desktop instead (for the GUI, for parity with an existing
team setup, or to test something Docker Desktop-only), opt in via
your group_vars:
# group_vars/all.yml or a per-host override
homebrew_casks:
- docker # the cask is named `docker`; brew resolves to docker-desktopTwo caveats specific to Apple Silicon:
-
Docker Desktop's cask postinstall hook writes CLI plugin symlinks into
/usr/local/cli-plugins. The pre-task inroles/homebrew/tasks/main.ymlhandles that automatically whenhomebrew_caskscontainsdocker/docker-desktop. -
Docker Desktop also writes the
docker,docker-compose, anddocker-buildxbinaries into/usr/local/bin. On a fresh Apple Silicon Mac that directory may not exist (Homebrew lives at/opt/homebrew/bin), and/usr/local/is root-owned. If bootstrap fails here, run once:sudo mkdir -p /usr/local/bin sudo chown -R "$(whoami)":staff /usr/local/bin ./bootstrap.shSubsequent runs no-op; Docker Desktop will not try to recreate the directory once it has user-write perms.
If neither caveat sounds appealing, the default colima path is strictly easier.
This repo is small but opinionated. Two rules:
- Roles must be idempotent. Re-running
./bootstrap.shon a fully set-up machine must converge cleanly to "ok=N changed=0" — no destructive operations, no half-applied state. - Roles must not require secrets at apply time. The secret inventory in this README is the contract; if a role needs a new secret, add it to the table.
DCO sign-off on every commit (git commit -s).
Apache 2.0 — matches LLMKube's license.