⚠️ V1 removed 2026-07-24 (commit 62540bf); the repo was then flattened 2026-07-24 (commit 2d4bd9c) — there is no v2; there is only Ordo. The stack keeps a single data root atC:\dev\ordo-ai-stack\data;site.DATA_PATHinordo.yamlrenders it into the compose bind mounts. The per-directory schemas / bind-mount / backup guidance below still broadly describes what lives underdata/, but config and bring-up flow through the render substrate: edit the declarative sourceordo.yaml(tracked templateordo.example.yaml), runordo render(python -m ordo.cli render --out out), then bring up the rendered compose fromout/(docker compose -p ordo … up). Never hand-edit rendered output. Authoritative guide:operator-guide.md.
Reference for where data lives, how it moves, and what survives a restart / rebuild.
| Source | Description | Consumer |
|---|---|---|
out/.env (rendered from ordo.yaml) |
Environment configuration | All services at startup |
data/mcp/servers.txt |
Enabled MCP server list (comma-separated or one-per-line) | mcp-gateway |
data/mcp/servers.txt + registry-custom.yaml |
enabled MCP servers + custom-server metadata | mcp-gateway, dashboard |
data/mcp/registry-custom.yaml |
Custom catalog fragment (e.g. ComfyUI MCP) | mcp-gateway |
data/rag-input/ |
Drop zone for RAG documents | rag-ingestion watch directory |
models/gguf/ |
llama.cpp GGUF download/staging dir (ordo fetch target) |
Seeds the models-gguf named volume (not mounted by any service) |
models-gguf named volume |
llama.cpp GGUF files at runtime (ext4 inside the Docker VM) | llamacpp / llamacpp-cpu / llamacpp-embed (/models:ro), dashboard (/gguf-models rw), ops-api (/gguf-models:ro) |
comfyui-models named volume |
ComfyUI checkpoints, LoRAs, VAEs, encoders | comfyui (RO), dashboard (RW — pull UI), ops-api (RO) |
| Sink | Description | Format |
|---|---|---|
data/ops-controller/audit.log |
Privileged-action audit log | JSONL (append-only) |
qdrant-data named volume |
Vector DB storage (RAG profile) | Qdrant native |
data/dashboard/ |
Throughput samples, benchmarks, job tracking | JSON |
hermes-home named volume |
Hermes agent brain (sessions, config, skills, cron) | JSON / SQLite / YAML |
data/comfyui-output/ |
Generated media (renders) | mixed |
comfyui-app named volume |
ComfyUI app tree + custom nodes — app version pinned by COMFYUI_APP_REF, reconciled on boot (configuration.md) |
mixed |
n8n-data named volume |
n8n workflows and credentials | n8n native |
couchdb-data named volume |
CouchDB (Obsidian LiveSync) | CouchDB native |
open-webui-data named volume |
Open WebUI accounts + uploads | SQLite / files |
Location: data/ops-controller/audit.log. Append-only JSONL.
{"timestamp":"2026-03-22T10:00:00Z","action":"model_pulled","model":"qwen3:8b","status":"success"}
{"timestamp":"2026-03-22T10:01:00Z","action":"service_started","service":"llamacpp","status":"success"}| Field | Type | Description |
|---|---|---|
timestamp |
ISO 8601 | Event timestamp |
action |
string | model_pulled, service_started, env_set, etc. |
status |
string | success, failed, ... |
model / service / component |
string (optional) | Action-specific target |
Size-bounded: ops-controller rotates to audit.log.1 when AUDIT_LOG_MAX_BYTES (default 10 MB) is exceeded.
Location: data/mcp/servers.txt (one enabled server per line) plus data/mcp/registry-custom.yaml (custom-server metadata). There is no registry.json — that was the V1 layout.
{
"version": 1,
"servers": {
"duckduckgo": {
"image": "mcp/duckduckgo",
"scopes": ["search"],
"allow_clients": ["*"],
"rate_limit_rpm": 60,
"timeout_sec": 30,
"env_schema": {}
}
}
}| Field | Type | Description |
|---|---|---|
allow_clients |
string[] | ["*"] = all clients; [] = disabled by policy |
rate_limit_rpm |
int | Per-client rate limit (informational today) |
env_schema |
object | Required secrets (surfaced in dashboard as "needs key") |
Stored in Qdrant on the qdrant-data named volume. Collection name defaults to documents (RAG_COLLECTION).
{
"id": "unique-chunk-id",
"vector": [0.1, 0.2, "..."],
"payload": {
"document_name": "example.md",
"chunk_index": 0,
"content": "The actual chunk text",
"chunk_size": 400,
"chunk_overlap": 50
}
}Configuration: EMBED_MODEL, RAG_CHUNK_SIZE, RAG_CHUNK_OVERLAP in out/.env (rendered from ordo.yaml).
Triggered by ordo render + first docker compose -p ordo … up from out/.
- Creates
data/andmodels/subdirectories. - Copies the MCP registry template into
data/mcp/if missing. - Hardware detection (
hardware: auto/ordo detect) and GPU pinning happen at render time, not via a separate script —ordo renderinspects the host and writes the resolved config directly intoout/(.env,docker-compose.yml); there is nooverrides/compute.ymlstep to run.
All directories created this way persist across restarts and rebuilds.
llama.cpp GGUF: runtime models live in the models-gguf named volume (ext4 inside the Docker VM — Windows bind mounts ride the 9p bridge, which wedges under a 20GB+ sequential model load). Adding a model is a two-step:
ordo fetch --models-dir models/gguf(checksum-mandatory) downloads catalog models to the host staging dir. The default--models-diris./models— passmodels/ggufexplicitly.- Copy into the volume:
docker run --rm -v ordo_models-gguf:/dst -v "$(pwd)/models/gguf:/src:ro" alpine cp /src/<file>.gguf /dst/(ordocker cpvia any container mounting the volume).
On a fresh install the volume starts empty and llamacpp crash-loops with failed to load model until seeded. The host models/gguf/ dir doubles as the recovery copy. The dashboard's GGUF-pull UI was not ported (its backing endpoint returns 501); use the two-step above.
ComfyUI: the dashboard's ComfyUI model-pack UI (backed by scripts/comfyui/pull_comfyui_models.py) downloads packs into the comfyui-models named volume (the dashboard's RW /models mount is the same volume ComfyUI reads RO), so downloads land where ComfyUI looks with no copy step. First run can be tens of GB. (The V1 comfyui-model-puller compose service was not ported — its old endpoints return 501.)
rag-ingestionwatchesdata/rag-input/for new files.- Each file is chunked per
RAG_CHUNK_SIZE/RAG_CHUNK_OVERLAP. - Chunks are embedded via
EMBED_MODELthrough the model gateway. - Points are written to Qdrant (
qdrant-datanamed volume).
Status: GET /api/rag/status on the dashboard returns current collection point count.
Every privileged call through ops-controller appends one JSONL line to data/ops-controller/audit.log, with X-Request-ID propagated from the dashboard. Rotation by size; export by scp data/ops-controller/audit.log*.
Hermes maintains its own state under data/hermes/ — session records, Discord per-user allowlists, scheduled tasks. The compose entrypoint re-seeds Docker-network endpoints on each start, so switching Docker networks doesn't require wiping state. See hermes-agent.md for upgrade notes.
| Store | Purpose | Survives restart | Survives rebuild |
|---|---|---|---|
hermes-home volume |
Hermes brain (sessions, config, skills, cron) | yes | yes |
qdrant-data volume |
Vector DB | yes | yes |
couchdb-data volume |
CouchDB (LiveSync) | yes | yes |
n8n-data volume |
n8n workflows | yes | yes |
open-webui-data volume |
Open WebUI accounts | yes | yes |
models-gguf volume |
llama.cpp GGUF weights | yes | yes |
comfyui-models volume |
ComfyUI weights | yes | yes |
comfyui-app volume |
ComfyUI app + custom nodes | yes | yes |
data/rag-input/ |
RAG drop zone | yes | yes |
data/n8n-files/ |
n8n file exchange | yes | yes |
data/ops-controller/ |
Audit log | yes | yes |
data/mcp/ |
MCP config | yes | yes |
data/dashboard/ |
Throughput / benchmarks | yes | yes |
data/comfyui-output/ |
Render outputs | yes | yes |
| Location | Purpose | Survives restart |
|---|---|---|
/tmp (tmpfs) |
Scratch | no |
| Container layer writes | Read-only rootfs on most custom services | no |
hermes-homevolume — agent brain (state, config, skills, cron)qdrant-data,couchdb-data,n8n-data,open-webui-datavolumes — service statedata/ops-controller/audit.log*— audit historyordo.yamlandout/secrets.env— declarative source + operator secrets (do not commit)- Model volumes (
models-gguf,comfyui-models) are usually skipped — weights are re-downloadable (ordo fetch/ the model-pack UI), just expensive.
tar -czf ordo-ai-stack-host-$(date +%Y%m%d).tar.gz \
data/ops-controller/ data/mcp/ data/dashboard/ ordo.yaml out/secrets.envfor v in hermes-home qdrant-data couchdb-data n8n-data open-webui-data; do
docker run --rm -v ordo_$v:/src:ro -v "$(pwd)/backups:/backup" alpine \
tar -czf /backup/$v-$(date +%Y%m%d).tar.gz -C /src .
donecd out && docker compose -p ordo down
tar -xzf ordo-ai-stack-backup-<date>.tar.gz
cd out && docker compose -p ordo up -d# ordo.yaml
site:
DATA_PATH: /new/path/to/datamkdir -p /new/path/to/data
cp -a data/. /new/path/to/data/
python -m ordo.cli render --out out
cd out && docker compose -p ordo down
cd out && docker compose -p ordo up -d| Data | Action | Frequency |
|---|---|---|
data/ops-controller/audit.log |
Archive rotated files (audit.log.1 etc.) |
Monthly |
data/rag-input/ |
Remove processed files | As needed |
data/comfyui-storage/output/ |
Prune old outputs | As needed |
models-gguf volume |
Remove unused models | Quarterly |
# Archive current audit log
mv data/ops-controller/audit.log data/ops-controller/audit.log.$(date +%Y%m%d)
# Prune GGUF models (list, then delete unused files inside the volume)
docker run --rm -v ordo_models-gguf:/models alpine ls -la /models
docker run --rm -v ordo_models-gguf:/models alpine rm /models/<model-file>.gguf