Skip to content

Nanobot Lessons

When to read: before debugging nanobot tool calls, image/vision issues, MCP failures, or workspace rule edits. Cross-cutting lessons live in [[homelab-deploy-debug-patterns]].

Meta-pattern: MCP tools run cross-container

The #1 source of "tool failed mysteriously": an MCP server (e.g. mcp_litellm_minimax-understand_image) runs on a different container than the nanobot caller. Tool description says "accepts local file path" but the file must be visible from where the MCP server runs, not from nanobot.

MCP tool Runs on Sees nanobot's /home/nanobot/...?
mcp_litellm_minimax-understand_image LiteLLM host container (litellm-litellm-1) ❌ No — separate filesystem
mcp_litellm_crawl4ai-* LiteLLM host container n/a (URL-based, no local files)
mcp_litellm_qmd-* LiteLLM host container n/a (server-side index)
mcp_litellm_todoist-* LiteLLM host → Todoist API n/a (SaaS API)

Symptom: MCP image tool returns Local image file does not exist: /home/nanobot/... even though the file exists in nanobot container.

Test matrix (verified 2026-06-16): | Input | Result | |-------|--------| | Local file path (/home/nanobot/...) | ❌ fail — "file does not exist" | | Public HTTP URL | ✅ work | | Data URL (base64 inline) | ❌ fail — JSON arg size limit (~18KB) | | Docker network HTTP URL (http://<container>:<port>/...) | ✅ work — no SSRF guard for private IPs |

Fix pattern — sidecar HTTP file server: nanobot's compose.yaml ships a nanobot-media busybox sidecar (httpd -f -p 18080 -h /media) on the reverse-proxy network. Local media path /home/nanobot/.nanobot/media/<channel>/<file> → URL http://nanobot-media:18080/<channel>/<file>.

Rule: when an MCP tool returns "file not found" for a local path, the MCP server is on a different container. Convert local paths to HTTP URLs via sidecar before calling.

Workspace rule lifecycle

unifiedSession: true means the bot reads RULES.md, AGENTS.md, MEMORY.md, SOUL.md, USER.md, PEOPLES.md once at session start. Edits to these files do not apply to the running session.

Implication: after editing any workspace file, you MUST restart the container (docker restart nanobot-gateway) for the bot to pick up the new rules. Dream cron will commit the edits independently.

Rule redundancy (3 places): when teaching the bot a new pattern, document it in:

  1. RULES.md — operational rule (loaded every session)
  2. AGENTS.md — tool routing reference (loaded every session)
  3. memory/MEMORY.md — long-term facts (Dream-consolidated)

A rule in only 1 place is insufficient if a stale/conflicting memory row exists (the LLM may trust the memory over the new rule). When the memory is wrong, fix the memory row — don't just add a counter-rule.

Bot failure spiral

When an approach fails, the LLM may pivot to worse fallbacks (verified):

  • MCP minimax-understand_image fail → read_file (binary, no-op)
  • apt-get install tesseract (pollutes container, slow)
  • pip install easyocr (large download)
  • → custom python3 urllib.request script calling LiteLLM API (often fails on DNS like litellm not resolving in nanobot container)
  • → give up with "không đọc được ảnh"

Detection: watch logs for apt-get, pip install, or custom Python scripts when a single MCP call should suffice. Stop the spiral by cancelling the task (docker restart nanobot-gateway).

Prevention: workspace rules that say "đừng fallback python urllib" + "don't try local paths with MCP". Make the failure cheap.

Log analysis — where to look

Source What it shows Limit
km-logs nanobot-gateway -n 200 -t Container stdout, tool call signatures (truncated) Tool args truncated at ~120 chars; full message text cut
workspace/sessions/unified_default.jsonl Full tool_call_id + full response + reasoning_content Long file, grep for tool name
workspace/.nanobot/tool-results/unified_default/call_<id>.txt Full tool response body (per call) File ID matches the call ID in JSONL
km-logs komodo-periphery Periphery actions (sync, deploy) Often empty — periphery doesn't log every action

Pattern for failed-tool investigation:

  1. Find the failure timestamp in container logs
  2. Grep session JSONL for the tool name + timestamp → get tool_call_id + full error response
  3. For successful calls, read tool-results/call_<id>.txt for full payload

Note: container timezone is +07 (Asia/Ho_Chi_Minh) for nanobot logger, but UTC (Z) for Docker log timestamps. Filter accordingly.

Komodo deploy stuck on "deploying: true"

km x deploy-stack nanobot (and likely other stacks) can hang indefinitely in deploying: true state even when:

  • Compose.yaml is valid (verified by direct docker compose up)
  • Periphery is connected to Core
  • Image is already pulled

Symptom: km x deploy-stack prints FINISHED in 1.4s: EXECUTION FAILED, then API shows status: InProgress forever; no docker compose process on periphery host.

Workaround — direct compose via periphery:

ssh root@100.68.251.84 "docker exec komodo-periphery sh -c 'cd /etc/komodo/repos/docker-compose/stacks/llm/nanobot && docker compose up -d'"

This is a Core↔Periphery comms issue (auth/network/queue), separate from compose validity. Treat Komodo deploy as best-effort; have direct-SSH fallback ready for time-sensitive deploys.

Quick reference

# Check both nanobot containers
ssh root@100.68.251.84 "docker ps --format '{{.Names}}\t{{.Status}}' | grep nanobot"

# Tail logs (UTC Docker + VN nanobot logger)
km-logs nanobot-gateway -n 50 -t

# Find tool calls in session JSONL (UTC timestamps)
ssh root@100.68.251.84 "docker exec nanobot-gateway grep 'understand_image' /home/nanobot/.nanobot/workspace/sessions/unified_default.jsonl | tail -5"

# Read full tool response
ssh root@100.68.251.84 "docker exec nanobot-gateway cat /home/nanobot/.nanobot/workspace/.nanobot/tool-results/unified_default/call_<ID>.txt"

# Test MCP minimax-understand_image directly (via my MCP, from dev container)
# Note: local path fails (cross-container); use HTTP URL

# Direct compose deploy (bypass stuck Komodo Core)
ssh root@100.68.251.84 "docker exec komodo-periphery sh -c 'cd /etc/komodo/repos/docker-compose/stacks/llm/nanobot && docker compose up -d'"

# Restart bot (picks up workspace rule edits + clears old session)
ssh root@100.68.251.84 "docker restart nanobot-gateway"

Related: [[homelab-deploy-debug-patterns]] meta-patterns (silent config divergence, service addressing), [[komodo]] deploy verification, [[custom-image-build-workflow]] Dockerfile patches.

Open questions

  • Komodo Core↔Periphery comms issue root cause (auth token expiry? websocket reconnect race?) — not investigated, workaround in place.
  • Whether nanobot will eventually support native multimodal (image content block to LLM instead of text reference + MCP tool). Upstream feature, tracked in nanobot/SKILL.md "Source Patches".