Skill: brasco05/ollama-memory-setup (version 1.2.3)

--- name: ollama-memory-setup description: Set up, diagnose, repair, and quality-test private local OpenClaw semantic memory search using Ollama embeddings. Use when memory_search is disabled, node-llama-cpp/local embedding errors appear, the user wants no API-key embeddings, or memory search quality/connectivity needs verification with nomic-embed-text or similar Ollama embedding models. --- # Ollama Memory Setup Use this skill to make OpenClaw `memory_search` work locally with Ollama embeddings instead of fragile native `node-llama-cpp` builds or paid hosted embedding APIs. ## What success looks like A correct setup has all of this: - Ollama installed and reachable at `http://localhost:11434` - an embedding model pulled, usually `nomic-embed-text` - OpenClaw config explicitly sets `agents.defaults.memorySearch.provider` to `ollama` - memory index rebuilt after config changes - optional `--quality-test` passes against known memory topics - `memory_search("...")` or `openclaw memory search "..."` returns results with provider `ollama` ## Side effects and consent Default script mode is read-only/diagnostic. Side effects require explicit flags: - `--install`: may install Ollama, start services, and pull a model. - `--apply-config`: writes OpenClaw `agents.defaults.memorySearch.*` config. - `--quality-test`: read-only search validation; temp files are deleted on exit, but query text/output may still appear in terminal logs. Before recommending `--install` or `--apply-config`, tell the user what will change. Do not run those flags silently. Prefer default localhost settings; review/patch the script before letting an agent provide arbitrary `--model` or `--base-url` values. ## Fast path Prefer the bundled diagnostic script first: ```bash bash scripts/check-ollama-memory.sh ``` To install/pull the model and print/apply OpenClaw config commands: ```bash # Diagnostic only first bash scripts/check-ollama-memory.sh # Then, with explicit user approval for side effects bash scripts/check-ollama-memory.sh --install --apply-config openclaw gateway restart openclaw memory index --force openclaw memory status --deep bash scripts/check-ollama-memory.sh --quality-test --query="known memory topic" ``` If running inside an agent with first-class config tools available, use those for config changes instead of hand-editing JSON. ## Workflow ### 1. Preflight before changing anything Check: ```bash command -v ollama curl -s http://localhost:11434/api/tags ollama list | grep -E 'nomic-embed-text|qwen.*embedding' openclaw memory status --deep ``` If Ollama is reachable and the model exists, skip installation and go to config validation. ### 2. Install or start Ollama macOS: ```bash brew install ollama brew services start ollama ``` Linux: ```bash curl -fsSL https://ollama.com/install.sh | sh ollama serve ``` Do not expose Ollama directly to the public internet. Keep it on localhost, VPN, or private LAN. ### 3. Pull an embedding model Default: ```bash ollama pull nomic-embed-text ``` Use `nomic-embed-text` for the lowest-friction setup. Use another embedding model only if OpenClaw/Ollama supports it and the user has a reason. ### 4. Configure OpenClaw memory search Set this under `agents.defaults.memorySearch`: ```json { "enabled": true, "provider": "ollama", "model": "nomic-embed-text", "remote": { "baseUrl": "http://localhost:11434" } } ``` CLI batch form: ```bash openclaw config set --batch-json '[ {"path":"agents.defaults.memorySearch.enabled","value":true}, {"path":"agents.defaults.memorySearch.provider","value":"ollama"}, {"path":"agents.defaults.memorySearch.model","value":"nomic-embed-text"}, {"path":"agents.defaults.memorySearch.remote.baseUrl","value":"http://localhost:11434"} ]' --strict-json ``` Then restart the gateway: ```bash openclaw gateway restart ``` ### 5. Reindex and validate ```bash openclaw memory index --force openclaw memory status --deep openclaw memory search "project decision" --max-results 5 ``` In-agent validation: ```text memory_search("a known topic from MEMORY.md") ``` Expected: provider is `ollama`, search is not disabled, and results are semantically relevant. For stronger proof, run: ```bash bash scripts/check-ollama-memory.sh --quality-test \ --query="known project decision" \ --query="known bug fix" \ --query="known todo" ``` ## When to read troubleshooting Read `references/troubleshooting.md` when: - `memory_search` still says disabled - Ollama is installed but not reachable - the model is pulled but OpenClaw still uses another provider - indexing is slow or returns no useful results - config commands fail or the installed OpenClaw CLI is older than the config file ## Safety rules - Never paste secrets into `openclaw.json` for this setup. Ollama local embeddings do not need real API keys. - Do not bind Ollama to `0.0.0.0` unless the user understands the network/security risk. - Do not delete existing memory files to “fix” search. Reindex instead. - Do not promise semantic quality until a real `memory_search`/`openclaw memory search` validation passes.

path: README.md
content: # 🧠 Ollama Memory Setup

**Local semantic memory for OpenClaw in ~5 minutes — no API key, no cloud embeddings, no `node-llama-cpp` pain.**

OpenClaw memory is much stronger when it can search by meaning instead of exact keywords. This skill sets up Ollama as the local embedding backend, usually with `nomic-embed-text`, and includes checks for setup quality.

## Use This When

- `memory_search` is disabled or returns no semantic results
- OpenClaw complains about `node-llama-cpp` or local embeddings
- You want private local embeddings instead of hosted APIs
- You need to diagnose whether memory search is connected, indexed, and useful

## What It Does

- Checks whether Ollama is installed and reachable
- Pulls the embedding model if missing
- Configures `agents.defaults.memorySearch.*` for OpenClaw
- Rebuilds/validates the memory index
- Runs optional quality tests against real memory topics
- Keeps defaults private: `localhost` only unless you intentionally override

## Quick Start

```bash
bash scripts/check-ollama-memory.sh --install --apply-config
openclaw gateway restart
openclaw memory index --force
openclaw memory status --deep
bash scripts/check-ollama-memory.sh --quality-test --query="known memory topic"
```

Expected result:

```text
provider: ollama
model: nomic-embed-text
semantic search: enabled
memory_search(...) returns relevant hits
```

## Side Effects Are Explicit

Default mode is diagnostic only. These flags change things:

| Flag | Side effect |
|---|---|
| `--install` | May install/start Ollama and pull the embedding model |
| `--apply-config` | Writes OpenClaw memory config |
| `--quality-test` | Runs read-only memory searches and prints sample result lines |

Avoid sensitive query terms if terminal logs are captured.

## Manual Config

```json
{
  "agents.defaults.memorySearch.enabled": true,
  "agents.defaults.memorySearch.provider": "ollama",
  "agents.defaults.memorySearch.model": "nomic-embed-text",
  "agents.defaults.memorySearch.remote.baseUrl": "http://localhost:11434"
}
```

## Security Notes

- Keep Ollama on `localhost` or a trusted private network
- Do not expose port `11434` publicly
- Do not paste API keys or private memory snippets into bug reports
- Review custom `--model` and `--base-url` values before letting an agent apply them

## Quality Test

Connectivity is not enough. Prove retrieval quality:

```bash
bash scripts/check-ollama-memory.sh --quality-test \
  --query="project decision" \
  --query="bug fix learning" \
  --query="open todo"
```

The script classifies searches as `OK`, `noisy`, or `broken`.

---

*by brasco05 · local/private semantic memory for OpenClaw*


path: assets/banner.svg
content: <svg width="800" height="200" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" style="stop-color:#0f0f1a;stop-opacity:1" />
      <stop offset="100%" style="stop-color:#1a1a2e;stop-opacity:1" />
    </linearGradient>
  </defs>
  <rect width="800" height="200" fill="url(#bg)" rx="12"/>
  <circle cx="80" cy="100" r="40" fill="#6366f1" opacity="0.2"/>
  <circle cx="80" cy="100" r="25" fill="#6366f1" opacity="0.4"/>
  <circle cx="80" cy="100" r="12" fill="#6366f1"/>
  <text x="140" y="85" font-family="monospace" font-size="28" font-weight="bold" fill="#ffffff">ollama-memory-setup</text>
  <text x="140" y="120" font-family="monospace" font-size="14" fill="#6366f1">Local semantic memory search for OpenClaw</text>
  <text x="140" y="148" font-family="monospace" font-size="12" fill="#64748b">Fixes node-llama-cpp · Uses nomic-embed-text · No API keys needed</text>
</svg>


path: package.json
content: {
  "name": "ollama-memory-setup",
  "version": "1.2.3",
  "description": "Set up, diagnose, repair, and quality-test private local OpenClaw semantic memory search using Ollama embeddings.",
  "author": "brasco05",
  "license": "MIT",
  "keywords": [
    "openclaw",
    "ollama",
    "memory",
    "semantic-search",
    "embeddings",
    "nomic-embed-text",
    "local-ai",
    "privacy",
    "node-llama-cpp",
    "quality-test",
    "private-embeddings"
  ]
}


path: references/troubleshooting.md
content: # Troubleshooting — Ollama Memory Setup

## 1. `memory_search` still says disabled

Check provider status:

```bash
openclaw memory status --deep
openclaw config get agents.defaults.memorySearch
```

Expected config:

```json
{
  "enabled": true,
  "provider": "ollama",
  "model": "nomic-embed-text",
  "remote": { "baseUrl": "http://localhost:11434" }
}
```

Then restart and reindex:

```bash
openclaw gateway restart
openclaw memory index --force
```

Also start a fresh chat/session if the current session cached old state.

## 2. Ollama is not reachable

```bash
curl -s http://localhost:11434/api/tags
```

macOS:

```bash
brew services restart ollama
```

Linux:

```bash
systemctl --user restart ollama 2>/dev/null || sudo systemctl restart ollama 2>/dev/null || ollama serve
```

If Ollama was installed as a desktop app, open it once and retry.

## 3. Model missing

```bash
ollama list
ollama pull nomic-embed-text
```

If `nomic-embed-text` fails, update Ollama and retry.

## 4. OpenClaw config command fails

First validate the CLI and config path:

```bash
openclaw config file
openclaw config validate
openclaw config set --help
```

If your installed CLI is older than your config file, update OpenClaw before writing config. Do not hand-edit config unless you have a backup.

## 5. Search works but results are bad

Reindex:

```bash
openclaw memory index --force
```

Then query with a specific concept that exists in memory. Bad query:

```text
test
```

Good query:

```text
Caresys DB auth Railway credentials issue
```

If results are still poor, check that the indexed files actually contain the information.

## 6. Search is slow

First query can be slow because Ollama loads the model. Subsequent queries should be faster.

If every query is slow:

- keep Ollama running as a service
- close heavy local chat models
- use `nomic-embed-text` instead of a large embedding model
- run `openclaw memory status --deep` to inspect provider latency

## 7. Security warning: exposed Ollama

Do not expose Ollama publicly.

Bad:

```bash
OLLAMA_HOST=0.0.0.0:11434 ollama serve
```

Acceptable only behind a trusted private VPN/firewall. For local memory search, prefer:

```text
http://localhost:11434
```


## 8. Quality test says noisy

Run the test with topics you know exist in your memory files:

```bash
bash scripts/check-ollama-memory.sh --quality-test \
  --query="exact project or decision name" \
  --query="specific bug you solved"
```

If generic queries are noisy but specific queries work, the system is healthy. Semantic search is not magic; it still needs meaningful queries and indexed source files.


## 9. Script refuses my base URL

The helper intentionally accepts only localhost, loopback, `.local`, or private LAN Ollama URLs. This prevents accidental use of a public Ollama endpoint.

Preferred:

```text
http://localhost:11434
```

If you need a remote host, put it behind a trusted VPN/private network and review the script before changing the allowlist.


## 10. Sensitive quality-test queries

The script deletes its temp result files on exit, but query strings and excerpts can still appear in terminal output, shell scrollback, CI logs, or agent transcripts. For sensitive memories, use abstract queries or skip `--quality-test` on shared machines.


path: scripts/check-ollama-memory.sh
content: #!/usr/bin/env bash
set -euo pipefail

INSTALL=false
APPLY_CONFIG=false
QUALITY_TEST=false
MODEL="${OLLAMA_MEMORY_MODEL:-nomic-embed-text}"
BASE_URL="${OLLAMA_BASE_URL:-http://localhost:11434}"
QUALITY_QUERIES=()
TEMP_PATHS=()
cleanup() {
  if [ ${#TEMP_PATHS[@]} -gt 0 ]; then
    rm -rf -- "${TEMP_PATHS[@]}" 2>/dev/null || true
  fi
}
trap cleanup EXIT


for arg in "$@"; do
  case "$arg" in
    --install) INSTALL=true ;;
    --apply-config) APPLY_CONFIG=true ;;
    --quality-test) QUALITY_TEST=true ;;
    --model=*) MODEL="${arg#*=}" ;;
    --base-url=*) BASE_URL="${arg#*=}" ;;
    --query=*) QUALITY_QUERIES+=("${arg#*=}") ;;
    -h|--help)
      cat <<HELP
Usage: bash scripts/check-ollama-memory.sh [options]

Options:
  --install                  Install/start Ollama when possible and pull the embedding model.
  --apply-config             Write OpenClaw memorySearch config using openclaw config set.
  --quality-test             Run real OpenClaw memory searches and classify result quality.
  --query="text"             Add a quality-test query. Repeatable. Defaults to generic agent-memory queries.
  --model=nomic-embed-text   Embedding model to use.
  --base-url=http://localhost:11434
                             Ollama base URL.

Default mode is diagnostic only. It does not install software, start services, or change config unless explicit flags are provided.
HELP
      exit 0
      ;;
    *) echo "Unknown arg: $arg" >&2; exit 2 ;;
  esac
done

step() { printf '\n\033[1m%s\033[0m\n' "$1"; }
ok() { printf '✅ %s\n' "$1"; }
warn() { printf '⚠️  %s\n' "$1"; }
fail() { printf '❌ %s\n' "$1"; }

validate_inputs() {
  case "$MODEL" in
    *[$'\n\r\t']*|"") fail "Invalid model name"; exit 2 ;;
  esac
  if ! [[ "$MODEL" =~ ^[A-Za-z0-9._:-]+$ ]]; then
    fail "Invalid model name. Allowed characters: letters, numbers, dot, underscore, colon, hyphen."
    exit 2
  fi

  case "$BASE_URL" in
    http://localhost:*|http://127.0.0.1:*|http://[::1]:*|http://localhost|http://127.0.0.1|http://[::1]) ;;
    http://10.*|http://172.16.*|http://172.17.*|http://172.18.*|http://172.19.*|http://172.20.*|http://172.21.*|http://172.22.*|http://172.23.*|http://172.24.*|http://172.25.*|http://172.26.*|http://172.27.*|http://172.28.*|http://172.29.*|http://172.30.*|http://172.31.*|http://192.168.*)
      warn "Using private-LAN Ollama base URL: $BASE_URL"
      ;;
    http://*.local:*|http://*.local)
      warn "Using .local Ollama base URL: $BASE_URL"
      ;;
    *)
      fail "Refusing non-local/private Ollama base URL: $BASE_URL"
      echo "Use localhost/private LAN only, or edit the script after reviewing the security risk." >&2
      exit 2
      ;;
  esac
}

validate_inputs

step "1. Checking commands"
if command -v ollama >/dev/null 2>&1; then
  ok "ollama found: $(ollama --version 2>/dev/null || echo unknown)"
elif $INSTALL; then
  warn "ollama missing — installing because --install was provided"
  if [[ "${OSTYPE:-}" == darwin* ]]; then
    command -v brew >/dev/null 2>&1 || { fail "Homebrew missing. Install Ollama manually: https://ollama.com"; exit 1; }
    brew install ollama
  else
    command -v curl >/dev/null 2>&1 || { fail "curl missing. Install curl or Ollama manually."; exit 1; }
    curl -fsSL https://ollama.com/install.sh | sh
  fi
else
  fail "ollama missing. Re-run with --install or install from https://ollama.com"
  exit 1
fi

if command -v openclaw >/dev/null 2>&1; then
  ok "openclaw found: $(openclaw --version 2>/dev/null || echo unknown)"
else
  warn "openclaw CLI not found in PATH — config/index validation will be skipped"
fi

step "2. Checking Ollama server at $BASE_URL"
if curl -fsS -- "$BASE_URL/api/tags" >/tmp/ollama-tags.json 2>/dev/null; then
  ok "Ollama API reachable"
elif $INSTALL; then
  warn "Ollama not reachable — trying to start it because --install was provided"
  if [[ "${OSTYPE:-}" == darwin* ]] && command -v brew >/dev/null 2>&1; then
    brew services start ollama >/dev/null 2>&1 || true
  else
    (ollama serve >/tmp/ollama-memory-setup.log 2>&1 &)
  fi
  sleep 3
  curl -fsS -- "$BASE_URL/api/tags" >/tmp/ollama-tags.json || { fail "Ollama still not reachable. Try: ollama serve"; exit 1; }
  ok "Ollama API reachable after start"
else
  fail "Ollama API not reachable. Re-run with --install or start Ollama manually."
  exit 1
fi

step "3. Checking embedding model: $MODEL"
if ollama list | awk '{print $1}' | grep -qx "$MODEL"; then
  ok "$MODEL already pulled"
elif $INSTALL; then
  warn "$MODEL missing — pulling now because --install was provided"
  ollama pull "$MODEL"
  ok "$MODEL pulled"
else
  fail "$MODEL missing. Re-run with --install or run: ollama pull $MODEL"
  exit 1
fi

step "4. Testing embedding endpoint"
OLLAMA_MEMORY_MODEL="$MODEL" OLLAMA_BASE_URL="$BASE_URL" python3 - <<'PY'
import json, os, urllib.request
base_url = os.environ["OLLAMA_BASE_URL"].rstrip("/")
model = os.environ["OLLAMA_MEMORY_MODEL"]
url = f"{base_url}/api/embeddings"
payload = json.dumps({"model": model, "prompt": "semantic memory test"}).encode()
req = urllib.request.Request(url, data=payload, headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=30) as r:
    data = json.load(r)
emb = data.get("embedding")
if not isinstance(emb, list) or len(emb) < 10:
    raise SystemExit("invalid embedding response")
print(f"✅ embedding ok: dimensions={len(emb)}")
PY

step "5. OpenClaw config"
if command -v openclaw >/dev/null 2>&1; then
  if $APPLY_CONFIG; then
    batch_file="$(mktemp)"
    TEMP_PATHS+=("$batch_file")
    OLLAMA_MEMORY_MODEL="$MODEL" OLLAMA_BASE_URL="$BASE_URL" python3 - "$batch_file" <<'PY'
import json, os, sys
model = os.environ["OLLAMA_MEMORY_MODEL"]
base_url = os.environ["OLLAMA_BASE_URL"]
ops = [
    {"path": "agents.defaults.memorySearch.enabled", "value": True},
    {"path": "agents.defaults.memorySearch.provider", "value": "ollama"},
    {"path": "agents.defaults.memorySearch.model", "value": model},
    {"path": "agents.defaults.memorySearch.remote.baseUrl", "value": base_url},
]
with open(sys.argv[1], "w", encoding="utf-8") as f:
    json.dump(ops, f)
PY
    openclaw config set --batch-file "$batch_file" --strict-json
    rm -f "$batch_file"
    ok "OpenClaw memorySearch config written"
  else
    warn "Not applying config. To apply, run with --apply-config. Current config:"
    openclaw config get agents.defaults.memorySearch || true
  fi

  step "6. Memory status"
  openclaw memory status --deep || true
else
  warn "Skipping OpenClaw checks because CLI is missing"
fi

if $QUALITY_TEST; then
  step "7. Quality test: real semantic searches"
  if ! command -v openclaw >/dev/null 2>&1; then
    fail "Cannot run quality test because openclaw CLI is missing"
    exit 1
  fi

  if [ ${#QUALITY_QUERIES[@]} -eq 0 ]; then
    QUALITY_QUERIES=(
      "important project decision"
      "bug fix learning"
      "open todo or next action"
    )
  fi

  tmpdir="$(mktemp -d)"
  TEMP_PATHS+=("$tmpdir")
  warn "Quality-test output is stored temporarily and will be deleted on exit. Avoid sensitive queries if your terminal/logs are captured."
  total=${#QUALITY_QUERIES[@]}
  passed=0
  noisy=0
  broken=0

  for i in "${!QUALITY_QUERIES[@]}"; do
    q="${QUALITY_QUERIES[$i]}"
    out="$tmpdir/search-$i.txt"
    printf '\nQuery: %s\n' "$q"
    if openclaw memory search "$q" --max-results 5 >"$out" 2>&1; then
      if grep -Eiq 'disabled|no results|0 results|error|failed' "$out"; then
        warn "Search ran but looks weak/noisy"
        noisy=$((noisy+1))
      elif grep -Eiq 'Source:|score|MEMORY|memory/' "$out"; then
        ok "Search returned memory-like results"
        passed=$((passed+1))
      else
        warn "Search returned output, but quality is unclear"
        noisy=$((noisy+1))
      fi
      sed -n '1,12p' "$out" | sed 's/^/  /'
    else
      fail "Search command failed"
      broken=$((broken+1))
      sed -n '1,12p' "$out" | sed 's/^/  /'
    fi
  done

  printf '\nQuality summary: %s OK / %s noisy / %s broken / %s total\n' "$passed" "$noisy" "$broken" "$total"
  if [ "$broken" -gt 0 ]; then
    fail "Memory search is broken. Check config, restart gateway, then reindex."
    exit 1
  elif [ "$passed" -eq 0 ]; then
    warn "Memory search runs, but quality is weak. Reindex and test with known memory topics."
  else
    ok "Memory search quality test passed enough to use."
  fi
fi

cat <<NEXT

✅ Done.

Next recommended commands:
  openclaw gateway restart
  openclaw memory index --force
  openclaw memory status --deep
  bash scripts/check-ollama-memory.sh --quality-test --query="known memory topic"
NEXT


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)