1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
services:
leankg:
build:
context: .
dockerfile: Dockerfile.rocksdb
env_file:
# Local-only configuration that overrides the defaults below. This file
# is .gitignored so user-specific host paths and project locations never
# leak into the committed compose file. Copy `.dockerfile.example` to
# `.dockerfile` and edit for your environment.
- path: ./.dockerfile
required: false
environment:
LEANKG_DB_ENGINE: rocksdb
LEANKG_ROCKSDB_ROOT: /data/leankg-rocksdb
MCP_HTTP_PORT: "9699"
LEANKG_AUTO_INDEX: "1"
# Plan §"Part B" defaults: never block MCP on embed. The MCP server
# owns the in-process background embed; LEANKG_EMBED_BACKGROUND_* knobs
# let operators tune workers/batch/full-rebuild at runtime. Set
# LEANKG_EMBED_BACKGROUND=0 to opt out and rely on the legacy
# foreground `leankg embed --wait` (off by default).
# Offline cold embed via docker-compose.embed.yml. Keep BACKGROUND off
# so MCP does not drop HNSW mid-query (override .dockerfile if needed).
LEANKG_EMBED_ON_BOOT: "0"
LEANKG_EMBED_BACKGROUND: "0"
LEANKG_EMBED_FAST: "1"
LEANKG_EMBED_MODEL: "bge-q"
LEANKG_EMBED_MAX_SEQ: "128"
LEANKG_EMBED_MAX_BLOB_CHARS: "500"
# Soft pause budget must fit under mem_limit 2g (Local survival).
# Offline full rebuild uses docker-compose.embed.yml (higher mem_limit).
LEANKG_EMBED_MAX_MB: "512"
LEANKG_EMBED_BACKGROUND_WORKERS: "1"
LEANKG_EMBED_BACKGROUND_BATCH: "32"
# `LEANKG_MCP_PROJECT` and `LEANKG_PROJECT_DIRS` are intentionally
# NOT set here. With both `env_file` (`.dockerfile`) and `environment:`
# declaring the same key, Compose lets `environment:` win, which silently
# ignored user overrides. The defaults live in `entrypoint.sh`:
# LEANKG_MCP_PROJECT -> /workspace if unset
# LEANKG_PROJECT_DIRS -> unset (entrypoint falls back to /workspace* glob)
# Override both by setting them in `.dockerfile` (comma-separated for
# LEANKG_PROJECT_DIRS, matching `entrypoint.sh`'s `IFS=','`).
# Lower mmap default to keep RSS bounded; the previous 256 MiB blew
# containers past the macOS Docker Desktop limit and triggered OOM kills.
LEANKG_MMAP_SIZE: "67108864"
# Slower, larger debounce window absorbs git-pull / build storms.
LEANKG_WATCHER_DEBOUNCE_MS: "2000"
LEANKG_WATCHER_BURST_LIMIT: "256"
RUST_LOG: "leankg=info"
# Option A: REST API for UI v2 alongside MCP (entrypoint starts `leankg serve`).
# Set LEANKG_SERVE_HTTP=0 in .dockerfile to disable and keep MCP-only.
LEANKG_SERVE_HTTP: "1"
LEANKG_SERVE_PORT: "8080"
ports:
- "9699:9699"
- "8080:8080"
volumes:
# Primary project mount (the LeanKG source tree itself, used by the
# auto-init fallback path). The host side is taken from HOST_PROJECT_PATH
# (default: the current dir). Override via .dockerfile.
- ${HOST_PROJECT_PATH:-./}:${CONTAINER_PROJECT_PATH:-/workspace}
- leankg-rocksdb:/data/leankg-rocksdb
# Persist ONNX / tokenizer cache across restarts (Embedder + DirectEmbedder).
- leankg_models:/root/.cache/leankg
working_dir: ${CONTAINER_PROJECT_PATH:-/workspace}
# Resource limits — multi-project / mega-graph MCP envelope (embed report
# 2026-07-17/18): ~147k vectors OOMed under 2g during semantic_search.
# Defaults: mem_limit 6g, mem_reservation 3g, cpus 6. Single-project
# LocalEngine survival KPI remains 2g (PRD §5.14) — lower via override
# when not serving large side mounts.
mem_limit: 6g
mem_reservation: 3g
cpus: "6"
pids_limit: 4096
restart: unless-stopped
volumes:
leankg-rocksdb:
leankg_models: