hemlock stack¶
Local Docker-compose orchestration of the canonical four-framework RAG evaluation battery (ChromaDB + LangChain + LlamaIndex + Unstructured + Haystack pipes). The stack tree is embedded into the hemlock binary via go:embed and unpacked into ~/.hemlock/stack-<version>/ on first stack up. Subsequent invocations reuse the unpacked tree.
The four pipes are intentionally identical at the API layer (same /extract, /ingest, /query, /health endpoints) so attacks can be measured under matched-comparison discipline.
Synopsis¶
hemlock stack up [--detach] [--build] [--path DIR]
hemlock stack down [--volumes] [--path DIR]
hemlock stack status
hemlock stack path [--path DIR]
Subcommands¶
| Subcommand | Purpose |
|---|---|
up |
docker compose up -d (builds images on first run) |
down |
docker compose down (preserves the chromadb volume by default) |
status |
Ping each pipe's /health endpoint and print one row per service |
path |
Print the unpacked stack directory and exit |
Ports¶
| Service | Port | Notes |
|---|---|---|
chromadb |
8000 | Persistent volume chromadb-data (preserved across down unless --volumes) |
pipe-langchain |
8100 | LangChain RetrievalQA |
pipe-llamaindex |
8101 | LlamaIndex VectorStoreIndex query engine |
pipe-unstructured |
8102 | Unstructured partition() loader chain |
pipe-haystack |
8103 | Haystack BM25 + dense hybrid retriever |
LLM and embedder configuration¶
The pipes default to a host-side ollama instance at host.docker.internal:11434 serving qwen2.5:7b for the LLM and bge-large for embeddings. Override any of these by creating .env next to the unpacked docker-compose.yml:
LLM_BASE_URL=http://host.docker.internal:11434/v1
LLM_MODEL=qwen2.5:7b
LLM_API_KEY=ollama
EMBED_BASE_URL=http://host.docker.internal:11434/v1
EMBED_MODEL=bge-large
EMBED_API_KEY=ollama
Any OpenAI-compatible endpoint works for LLM_BASE_URL and EMBED_BASE_URL — including a remote vLLM server. Find the unpacked stack with hemlock stack path.
Examples¶
Bring everything up and confirm health:
hemlock stack up
hemlock stack status
# chromadb :8000 ok status=200
# langchain :8100 ok langchain v0.3.35
# llamaindex :8101 ok llamaindex v0.12.5
# unstructured :8102 ok unstructured v0.16.11
# haystack :8103 ok haystack v2.9.0
Stop everything but keep the indexed corpus:
Wipe the corpus too:
Use a custom unpack location:
Requirements¶
- Docker installed and running on
PATH - Around 6 GB of free space for the four pipe images (first build only)
- Network access on first
up(to pullchromadb/chroma:0.6.3and resolve Python wheels for the pipe images)
Related¶
hemlock run— fire crafted documents at one of the pipes the stack brings uphemlock defend monitor— front a pipe with the strict-canary detector