Skip to content

Agentmemory Deployment Lessons

Komodo Periphery + Bind Mounts

Bind mounts in compose.yaml resolve on the host, not inside the periphery container.

  • /etc/komodo/repos/docker-compose/ only exists inside periphery — cannot use in compose volumes
  • /mnt/user/appdata/ is mounted from host into periphery — works in both contexts
  • Pre_deploy runs inside periphery → can access /etc/komodo/repos/ paths
  • Solution: pre_deploy copies files from repo path to /mnt/user/appdata/, then compose mounts from /mnt/user/appdata/

Missing compose.env Causes Silent Failure

If TOML declares additional_env_files = ["compose.env"] but file doesn't exist, deploy fails with no useful error.

Fix: Only declare env files that exist. Remove the line if not needed.

iii-engine UID is 65532

iii-engine image runs as UID 65532 (nonroot), not 99:100 (nobody/Unraid standard).

  • Wrong ownership → Permission denied on /data/state_store.db and /data/stream_store
  • Use init container (busybox) to chown, matching official docker-compose.yml pattern
  • Set user: "65532:65532" explicitly on iii-engine service

Storage is File-Based Only

iii-engine only has kv (SQLite file_based) and redis state adapters. No PostgreSQL adapter.

  • agentmemory uses iii-engine KV state for all storage
  • iii-database worker is for SQL queries, NOT a state store replacement
  • Embeddings use in-memory vector index (BM25 + vector), not pgvector

Viewer UI is Static HTML

Viewer HTML served at /agentmemory/viewer on iii-engine REST port 3111. The built-in viewer server binds to 127.0.0.1:3113 inside container — cannot be accessed externally via Docker port mapping. VIEWER_HOST=0.0.0.0 is not recognized.

  • Solution: nginx:alpine container proxying port 3113 → iii-engine:3111
  • nginx.conf: location //agentmemory/viewer, location /agentmemory/ → iii-engine:3111 (with WebSocket upgrade)
  • Pre_deploy must copy nginx.conf to /mnt/user/appdata/agentmemory/
  • Beware stale directories: if nginx.conf exists as a directory (from failed sync), cp silently fails. Remove directory first.

MCP Config

  • MCP servers go in project .mcp.json (not ~/.claude/settings.local.json)
  • Add .mcp.json to .gitignore (contains API keys)
  • Client-side env vars (GRAPH_EXTRACTION_ENABLED, EMBEDDING_PROVIDER, etc.) go in MCP env block, not server TOML
  • MUST set AGENTMEMORY_FORCE_PROXY=1 to use remote server — without it, MCP starts local iii-engine
  • MUST set AGENTMEMORY_SECRET in MCP env for auth with remote server

iii-engine REST API

All endpoints under /agentmemory/ prefix. Root returns 404.

  • Health: GET /agentmemory/livez (public), GET /agentmemory/health (auth)
  • Memory: POST /agentmemory/remember, /search, /forget
  • Auth: Authorization: Bearer <AGENTMEMORY_SECRET>

External Access: Bind 0.0.0.0

iii-config defaults to host: 127.0.0.1. Change to host: 0.0.0.0 for external access.

  • iptables DNAT in pre_deploy silently fails (Komodo periphery context)
  • socat on host network creates infinite loops
  • host: 0.0.0.0 + Tailscale is the correct solution

iii-engine Version Pin

Pinned to v0.11.2. v0.11.6+ introduces new sandbox worker model incompatible with agentmemory. Server binary auto-detects and refuses to start if version mismatch.

Semantic Search (BM25-Only)

Search works without vector embeddings. BM25-only mode returns conceptually-related results.

  • POST /agentmemory/search — finds related memories with different words
  • POST /agentmemory/smart-search — hybrid semantic+keyword
  • MCP memory_recall uses smart-search under the hood

CLI Demo Doesn't Work with Auth

agentmemory demo fails with 401 against authenticated remote servers. CLI doesn't pass AGENTMEMORY_SECRET as Bearer header.

  • Workaround: Seed via REST API with curl, or use MCP memory_save

Observe API Requires Hook Fields

POST /agentmemory/observe needs: hookType, sessionId, project, cwd, timestamp. Content goes in prompt/response, not content. Use POST /agentmemory/remember or MCP memory_save for direct memory operations.

Komodo Sync: file_paths Only Lists Compose Files

Komodo validates every file in file_paths as Docker Compose. Non-compose files (iii-config, etc.) cause validation errors.

  • file_paths = ["compose.yaml", "iii-config.docker.yaml"] → validation error: additional properties 'workers' not allowed
  • Fix: file_paths = ["compose.yaml"] only. Pre_deploy copies config from run_directory (all files synced regardless of file_paths)
  • file_paths tells Komodo WHICH files to validate as compose, not which to sync

agentmemory Server Requires AGENTMEMORY_URL + III_ENGINE_URL

The @agentmemory/agentmemory server needs BOTH env vars to connect to a separate iii-engine:

  • AGENTMEMORY_URL=http://iii-engine:3111 — REST API base URL (tells server where agentmemory API lives)
  • III_ENGINE_URL=ws://iii-engine:49134 — WebSocket bridge protocol (tells server to connect to existing engine instead of spawning local)
  • Without AGENTMEMORY_URL: server can't find REST endpoints
  • Without III_ENGINE_URL: server tries to download and spawn local iii-engine binary → fails in container
  • Both containers must be on same Docker network for inter-container DNS resolution

iii-engine Bridge Protocol Port (49134)

iii-engine listens on port 49134 for the internal bridge protocol (separate from REST 3111 and Stream 3112).

  • Port 49134 must be exposed if iii-engine runs in a separate container
  • agentmemory connects via WebSocket: ws://iii-engine:49134
  • This is the primary connection method, NOT the REST API

Pending Sync Blocks Stack Creation

Komodo Resource Sync with pending_alert = true requires manual UI approval before creating new resources.

  • Destroyed stacks are NOT recreated until pending changes are accepted in UI
  • Disable pending_alert (comment out) for automatic sync application
  • After disabling, run run-sync root-syncs first to update sync config, then run-sync <category>
  • State transitions: Ok → Pending (changes detected) → Ok (after accept or auto-apply)

Reverse-Proxy Network Pattern

All unraid stacks use reverse-proxy external network + bind mounts from /mnt/user/appdata/.

  • Bind mounts in compose resolve on HOST, not inside periphery container
  • Pre_deploy copies config files from repo path to /mnt/user/appdata/
  • iii-config.docker.yaml: host: 0.0.0.0 required for external access (not 127.0.0.1)
  • Pattern: compose mounts /mnt/user/appdata/<service>/config.yaml, pre_deploy copies from ./config.yaml

Central Server Architecture (Verified)

MCP Client (FORCE_PROXY=1) → HTTP REST → Unraid (0.0.0.0:3111)
  • Server: reverse-proxy external network + iii-config host: 0.0.0.0 on 3111/3112/49134
  • Three containers: iii-engine (iiidev/iii:0.11.2) + server (node:20 running npx @agentmemory/agentmemory) + viewer (nginx:alpine)
  • Server connects to iii-engine via III_ENGINE_URL=ws://iii-engine:49134 (bridge protocol)
  • Server also needs AGENTMEMORY_URL=http://iii-engine:3111 for REST API
  • Pre_deploy copies iii-config.docker.yaml + nginx.conf to /mnt/user/appdata/agentmemory/
  • Client: .mcp.json with AGENTMEMORY_URL, AGENTMEMORY_FORCE_PROXY=1, AGENTMEMORY_SECRET
  • No local iii-engine spawned with FORCE_PROXY=1
  • All MCP ops (save, recall, search, forget) verified end-to-end
  • Viewer at http://<server>:3113/ (nginx proxy to iii-engine:3111)
  • API also accessible at http://<server>:3113/agentmemory/livez