Runs Gemma 4 26B MoE (Q4_K_M, ~18 GB) via Ollama on a CPU-only machine. The agentic harness is oh-my-pi (omp), running in a separate Bun container.
| Requirement | Minimum | Notes |
|---|---|---|
| RAM | 32 GB | ~18 GB model weights + 6–7 GB KV cache + OS |
| Disk | 20 GB free | ~18 GB model, ~1 GB images |
| CPU | x86-64 or ARM64 | Physical core count → set OLLAMA_NUM_THREADS |
| Docker / Podman | Docker Engine 24+ or Podman 4+ | Compose v2 required (docker compose, not docker-compose) |
| Internet | Required once | For model pull and image builds during setup |
If you are unsure, use Docker Compose with bash scripts/setup.sh. It is the default path and the shortest route to a working local setup.
| Your Setup | Recommended Method | Command |
|---|---|---|
| Docker Desktop / Docker Engine | Compose (default) | bash scripts/setup.sh |
| Podman + systemd auto-start | Quadlets | bash podman/quadlets/install.sh |
| Podman + manual control | Bind-mount script | bash podman/bind-mount/podman.sh setup |
| Kubernetes / OpenShift | Kube manifest | kubectl apply -f podman/kube/ollama.yaml |
All methods run the same model (Gemma 4 26B Q4) with the same configuration.
- Ollama: the local model server that loads the model and serves responses over an API
- omp: the agentic harness that talks to Ollama and provides the interactive coding/chat interface
- Modelfile: the Ollama-specific configuration file that sets model parameters like context window and stop tokens
Run from the deployments/ directory:
bash scripts/setup.sh # one-time: build images, pull model (~18 GB)
bash omp/scripts/start-omp.sh # launch the interactive agentic harnessSubsequent runs only need start-omp.sh. Ollama persists the model between restarts.
Windows: Use scripts/setup.ps1 and omp/scripts/start-omp.ps1 instead.
After setup finishes, you should be able to confirm the stack with these checks:
docker compose ps
docker compose exec ollama ollama list
bash omp/scripts/start-omp.shExpected outcome:
docker compose psshows theollamaservice as running and healthyollama listincludesgemma4-localomp/scripts/start-omp.shopens the harness and can send requests to Ollama- the first response may still take several minutes on CPU, especially with a large context
deployments/
├── compose.yaml # Ollama + omp service definitions
├── scripts/
│ └── setup.sh / .ps1 # One-time setup (Compose-based, default)
├── podman/ # Podman-specific deployment methods
│ ├── bind-mount/
│ │ └── podman.sh # Manual Podman commands (advanced/debugging)
│ ├── quadlets/ # Systemd service (recommended for Podman)
│ │ ├── install.sh # Install Ollama as systemd user service
│ │ ├── podman-ollama.kube
│ │ ├── podman-ollama.container
│ │ ├── podman-ollama-data.volume
│ │ └── podman-local-ai.network
│ └── kube/
│ └── ollama.yaml # Kubernetes/OpenShift pod manifest
├── ollama/
│ ├── modelfiles/ # Modelfiles (sampling params, num_ctx, stop sequences)
│ │ ├── gemma4.Modelfile
│ │ └── qwen3-14b.Modelfile
│ └── scripts/
│ └── pull-model.sh # Model management (works with all deployment methods)
├── omp/
│ ├── Dockerfile.omp # Builds the oh-my-pi container image
│ ├── config/
│ │ ├── models.yml # Ollama provider + model definition for omp
│ │ ├── config.yml # omp agent roles, compaction, retry settings
│ │ └── extensions/ # omp safety/permission extensions
│ └── scripts/
│ ├── start-omp.sh / .ps1 # Launch the interactive omp session
│ └── install-omp.sh # Install omp natively (no container)
└── workspace/ # Created by setup.sh — mounted into omp container
Controls how Ollama serves the model. Key parameters:
| Parameter | Value | Why |
|---|---|---|
FROM |
gemma4:26b |
Q4_K_M variant (~18 GB) |
temperature |
1.0 | Google's recommended baseline for Gemma 4 |
top_p / top_k |
0.95 / 64 | Recommended sampling for Gemma 4 |
num_ctx |
65536 | Calibrated sweet spot — see KV cache notes |
num_thread |
8 | Override with OLLAMA_NUM_THREADS env var |
stop |
<end_of_turn>, <eos> |
Gemma 4 stop sequences |
Tells oh-my-pi where to find the model:
baseUrl: http://ollama:11434/v1— uses the Docker service nameollama(internal DNS). If running omp outside Docker, change tohttp://localhost:11434/v1.auth: none— required; an emptyOLLAMA_API_KEYenv var is not equivalent. Without this, omp silently filters out the provider.reasoning: false— Gemma 4 thinking is prompt-controlled (prepend<|think|>to the system prompt), not via API extension flags that Ollama doesn't support.
Controls omp's behavior:
- All model roles (
default,smol,slow,plan,commit) are mapped toollama/gemma4-local— there is only one local model. - Compaction is enabled: omp summarizes old turns when the context fills up. With
num_ctx: 65536and~16Ktokens of fixed tool overhead, this keeps sessions functional over long conversations. retry.maxRetries: 3withbaseDelayMs: 3000— CPU inference is slow; retries help recover from timeouts.
The KV cache is allocated upfront based on num_ctx, not actual usage. It lives in RAM alongside the model weights.
num_ctx |
KV cache size | Usable on 32 GB |
|---|---|---|
| 32 K | ~3–4 GB | Yes (leaves ~10 GB headroom) |
| 65 K | ~6–7 GB | Yes — recommended |
| 128 K | ~12–16 GB | Tight; may OOM depending on OS overhead |
At 65K, tool definitions (~16K tokens) consume ~25% of the window, leaving ~49K for conversation.
| Phase | Typical rate |
|---|---|
| Prefill (processing input) | 50–150 tok/s |
| Decode (generating output) | 3–8 tok/s |
Expect up to 20 minutes with a typical AMD Ryzen 5 PRO 4650U Laptop CPU before the first output token on a fresh request with a full context window loaded. This is normal — see prefill.md for a full explanation.
- Never add GPU device config to
compose.yaml. This is a CPU-only deployment; addingdevicesordeploy.resources.reservations.devicesbreaks it. - Q8 variant OOMs on 32 GB:
gemma4:26b-q8_0requires ~32 GB for weights alone, leaving no room for the KV cache. Only viable on ≥48 GB hosts. - Do not use
docker-compose(v1). The scripts require Compose v2 (docker compose).
- verify Docker or Podman is installed and running
- run
docker compose logs ollamato inspect startup failures - confirm port
11434is not already in use by another Ollama instance
- rerun
bash ollama/scripts/pull-model.sh - confirm the base model pull completed successfully before the registration step
- check that
ollama/modelfiles/gemma4.Modelfilestill exists and matches the selected alias
- verify
omp/config/models.ymlstill points tohttp://ollama:11434/v1for the container-based setup - keep
auth: noneinomp/config/models.yml; an empty API key is not equivalent - confirm Ollama is healthy before starting
omp
- this is expected on CPU, especially on the first request with a large context window
- see prefill.md for why the delay happens before the first token appears
- reduce context size only if you are deliberately changing the deployment tradeoff
Three Podman deployment options are available in the podman/ directory:
1. Systemd Quadlets (Recommended)
Best for production use. Pick this if you want Ollama to start automatically on login.
bash podman/quadlets/install.sh # choose kube or container method
systemctl --user status podman-ollama
bash podman/bind-mount/podman.sh start # launch omp2. Bind-mount script
For development and debugging. Pick this if you want direct manual control over the Podman containers.
bash podman/bind-mount/podman.sh setup # one-time
bash podman/bind-mount/podman.sh start # launch omp3. Kubernetes/OpenShift
For cluster deployments. Ignore this unless you already know you want a Kubernetes-style deployment.
kubectl apply -f podman/kube/ollama.yaml| Topic | File |
|---|---|
| Why prefill is slow on CPU; KV cache sizing | prefill.md |
| Inference engines, web UIs, quantization | software-stack.md |
| System prompts, tools, agentic harness concepts | README.md |
| All deployments | deployments/README.md |