Technical Documentation: memovai/mimiclaw
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Overview (`README.md`)
MimiClaw: Pocket AI Assistant on a $5 Chip
The world's first AI assistant(OpenClaw) on a $5 chip. No Linux. No Node.js. Just pure C
MimiClaw turns a tiny ESP32-S3 board into a personal AI assistant. Plug it into USB power, connect to WiFi, and talk to it through Telegram โ it handles any task you throw at it and evolves over time with local memory โ all on a chip the size of a thumb.
Meet MimiClaw
- Tiny โ No Linux, no Node.js, no bloat โ just pure C
- Handy โ Message it from Telegram, it handles the rest
- Loyal โ Learns from memory, remembers across reboots
- Energetic โ USB power, 0.5 W, runs 24/7
- Lovable โ One ESP32-S3 board, $5, nothing else
How It Works
You send a message on Telegram. The ESP32-S3 picks it up over WiFi, feeds it into an agent loop โ the LLM thinks, calls tools, reads memory โ and sends the reply back. Supports both Anthropic (Claude) and OpenAI (GPT) as providers, switchable at runtime. Everything runs on a single $5 chip with all your data stored locally on flash.
Quick Start
What You Need
- An ESP32-S3 dev board with 16 MB flash and 8 MB PSRAM (e.g. Xiaozhi AI board, ~$10)
- A USB Type-C cable
- A Telegram bot token โ talk to @BotFather on Telegram to create one
- An Anthropic API key โ from console.anthropic.com, or an OpenAI API key โ from platform.openai.com
Install
# You need ESP-IDF v5.5+ installed first:
# https://docs.espressif.com/projects/esp-idf/en/v5.5.2/esp32s3/get-started/
git clone https://github.com/memovai/mimiclaw.git
cd mimiclaw
idf.py set-target esp32s3Ubuntu Install
Recommended baseline:
- Ubuntu 22.04/24.04
- Python >= 3.10
- CMake >= 3.16
- Ninja >= 1.10
- Git >= 2.34
- flex >= 2.6
- bison >= 3.8
- gperf >= 3.1
- dfu-util >= 0.11
libusb-1.0-0,libffi-dev,libssl-dev
Install and build on Ubuntu:
sudo apt-get update
sudo apt-get install -y git wget flex bison gperf python3 python3-pip python3-venv \
cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0
./scripts/setup_idf_ubuntu.sh
./scripts/build_ubuntu.shmacOS Install
Recommended baseline:
- macOS 12/13/14
- Xcode Command Line Tools
- Homebrew
- Python >= 3.10
- CMake >= 3.16
- Ninja >= 1.10
- Git >= 2.34
- flex >= 2.6
- bison >= 3.8
- gperf >= 3.1
- dfu-util >= 0.11
libusb,libffi,openssl
Install and build on macOS:
xcode-select --install
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
./scripts/setup_idf_macos.sh
./scripts/build_macos.shConfigure
MimiClaw uses a two-layer config system: build-time defaults in mimi_secrets.h, with runtime overrides via the serial CLI. CLI values are stored in NVS flash and take priority over build-time values.
cp main/mimi_secrets.h.example main/mimi_secrets.hEdit main/mimi_secrets.h:
#define MIMI_SECRET_WIFI_SSID "YourWiFiName"
#define MIMI_SECRET_WIFI_PASS "YourWiFiPassword"
#define MIMI_SECRET_TG_TOKEN "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
#define MIMI_SECRET_API_KEY "sk-ant-api03-xxxxx"
#define MIMI_SECRET_MODEL_PROVIDER "anthropic" // "anthropic" or "openai"
#define MIMI_SECRET_SEARCH_KEY "" // optional: Brave Search API key
#define MIMI_SECRET_TAVILY_KEY "" // optional: Tavily API key (preferred)
#define MIMI_SECRET_PROXY_HOST "" // optional: e.g. "10.0.0.1"
#define MIMI_SECRET_PROXY_PORT "" // optional: e.g. "7897"Then build and flash:
# Clean build (required after any mimi_secrets.h change)
idf.py fullclean && idf.py build
# Find your serial port
ls /dev/cu.usb* # macOS
ls /dev/ttyACM* # Linux
# Flash and monitor (replace PORT with your port)
# USB adapter: likely /dev/cu.usbmodem11401 (macOS) or /dev/ttyACM0 (Linux)
idf.py -p PORT flash monitorImportant: Plug into the correct USB port! Most ESP32-S3 boards have two USB-C ports. You must use the one labeled USB (native USB Serial/JTAG), not the one labeled COM (external UART bridge). Plugging into the wrong port will cause flash/monitor failures.
Show reference photo
CLI Commands (via UART/COM port)
Connect via serial to configure or debug. Config commands let you change settings without recompiling โ just plug in a USB cable anywhere.
Runtime config (saved to NVS, overrides build-time defaults):
mimi> wifi_set MySSID MyPassword # change WiFi network
mimi> set_tg_token 123456:ABC... # change Telegram bot token
mimi> set_api_key sk-ant-api03-... # change API key (Anthropic or OpenAI)
mimi> set_model_provider openai # switch provider (anthropic|openai)
mimi> set_model gpt-4o # change LLM model
mimi> set_proxy 127.0.0.1 7897 # set HTTP proxy
mimi> clear_proxy # remove proxy
mimi> set_search_key BSA... # set Brave Search API key
mimi> set_tavily_key tvly-... # set Tavily API key (preferred)
mimi> config_show # show all config (masked)
mimi> config_reset # clear NVS, revert to build-time defaultsDebug & maintenance:
mimi> wifi_status # am I connected?
mimi> memory_read # see what the bot remembers
mimi> memory_write "content" # write to MEMORY.md
mimi> heap_info # how much RAM is free?
mimi> session_list # list all chat sessions
mimi> session_clear 12345 # wipe a conversation
mimi> heartbeat_trigger # manually trigger a heartbeat check
mimi> cron_start # start cron scheduler now
mimi> restart # rebootUSB (JTAG) vs UART: Which Port for What
Most ESP32-S3 dev boards expose two USB-C ports:
| Port | Use for |
|---|---|
| USB (JTAG) | idf.py flash, JTAG debugging |
| COM (UART) | REPL CLI, serial console |
REPL requires the UART (COM) port. The USB (JTAG) port does not support interactive REPL input.
Port details & recommended workflow
| Port | Label | Protocol |
|---|---|---|
| USB | USB / JTAG | Native USB Serial/JTAG |
| COM | UART / COM | External UART bridge (CP2102/CH340) |
The ESP-IDF console/REPL is configured to use UART by default (CONFIG_ESP_CONSOLE_UART_DEFAULT=y).
If you have both ports connected simultaneously:
- USB (JTAG) handles flash/download and provides secondary serial output
- UART (COM) provides the primary interactive console for the REPL
- macOS: both appear as
/dev/cu.usbmodem*or/dev/cu.usbserial-*โ runls /dev/cu.usb*to identify - Linux: USB (JTAG) โ
/dev/ttyACM0, UART โ/dev/ttyUSB0
Recommended workflow:
# Flash via USB (JTAG) port
idf.py -p /dev/cu.usbmodem11401 flash
# Open REPL via UART (COM) port
idf.py -p /dev/cu.usbserial-110 monitor
# or use any serial terminal: screen, minicom, PuTTY at 115200 baudMemory
MimiClaw stores everything as plain text files you can read and edit:
| File | What it is |
|---|---|
SOUL.md |
The bot's personality โ edit this to change how it behaves |
USER.md |
Info about you โ name, preferences, language |
MEMORY.md |
Long-term memory โ things the bot should always remember |
HEARTBEAT.md |
Task list the bot checks periodically and acts on autonomously |
cron.json |
Scheduled jobs โ recurring or one-shot tasks created by the AI |
2026-02-05.md |
Daily notes โ what happened today |
tg_12345.jsonl |
Chat history โ your conversation with the bot |
Tools
MimiClaw supports tool calling for both Anthropic and OpenAI โ the LLM can call tools during a conversation and loop until the task is done (ReAct pattern).
| Tool | Description |
|---|---|
web_search |
Search the web via Tavily (preferred) or Brave for current information |
get_current_time |
Fetch current date/time via HTTP and set the system clock |
cron_add |
Schedule a recurring or one-shot task (the LLM creates cron jobs on its own) |
cron_list |
List all scheduled cron jobs |
cron_remove |
Remove a cron job by ID |
To enable web search, set a Tavily API key via MIMI_SECRET_TAVILY_KEY (preferred), or a Brave Search API key via MIMI_SECRET_SEARCH_KEY in mimi_secrets.h.
Cron Tasks
MimiClaw has a built-in cron scheduler that lets the AI schedule its own tasks. The LLM can create recurring jobs ("every N seconds") or one-shot jobs ("at unix timestamp") via the cron_add tool. When a job fires, its message is injected into the agent loop โ so the AI wakes up, processes the task, and responds.
Jobs are persisted to SPIFFS (cron.json) and survive reboots. Example use cases: daily summaries, periodic reminders, scheduled check-ins.
Heartbeat
The heartbeat service periodically reads HEARTBEAT.md from SPIFFS and checks for actionable tasks. If uncompleted items are found (anything that isn't an empty line, a header, or a checked - [x] box), it sends a prompt to the agent loop so the AI can act on them autonomously.
This turns MimiClaw into a proactive assistant โ write tasks to HEARTBEAT.md and the bot will pick them up on the next heartbeat cycle (default: every 30 minutes).
Also Included
- WebSocket gateway on port 18789 โ connect from your LAN with any WebSocket client
- OTA updates โ flash new firmware over WiFi, no USB needed
- Dual-core โ network I/O and AI processing run on separate CPU cores
- HTTP proxy โ CONNECT tunnel support for restricted networks
- Multi-provider โ supports both Anthropic (Claude) and OpenAI (GPT), switchable at runtime
- Cron scheduler โ the AI can schedule its own recurring and one-shot tasks, persisted across reboots
- Heartbeat โ periodically checks a task file and prompts the AI to act autonomously
- Tool use โ ReAct agent loop with tool calling for both providers
For Developers
Technical details live in the docs/ folder:
- docs/ARCHITECTURE.md โ system design, module map, task layout, memory budget, protocols, flash partitions
- docs/TODO.md โ feature gap tracker and roadmap
- docs/WIFI_ONBOARDING_AP.md โ how the local
MimiClaw-XXXXonboarding/admin AP flow works - docs/tool-setup/ โ configuration guides for external service integrations (Tavily, etc.)
Contributing
Please read CONTRIBUTING.md before opening issues or pull requests.
Contributors
Thanks to everyone who has contributed to MimiClaw.
License
MIT
Acknowledgments
Inspired by OpenClaw and Nanobot. MimiClaw reimplements the core AI agent architecture for embedded hardware โ no Linux, no server, just a $5 chip.
Star History
Overview (`docs/im-integration/README.md`)
IM Integration Guides
Configuration guides for MimiClaw's instant messaging channel integrations.
Guides
| Guide | Service | Description |
|---|---|---|
| Feishu Setup | Feishu / Lark | Feishu bot channel โ receive and send messages via Feishu |
Overview
MimiClaw supports multiple IM channels for interacting with the AI agent. Each guide below walks through obtaining API credentials, configuring MimiClaw (build-time or runtime), and verifying the integration.
All credentials can be set in two ways:
- Build-time โ define in
main/mimi_secrets.hand rebuild - Runtime โ use serial CLI commands (saved to NVS flash, no rebuild needed)
See mimi_secrets.h.example for the full list of configurable secrets.
Overview (`docs/tool-setup/README.md`)
Tool Setup Guides
Configuration guides for MimiClaw's external service integrations.
Related local setup guide:
- Wi-Fi AP Onboarding Guide โ configure firmware builds that expose the local
MimiClaw-XXXXonboarding/admin access point
Guides
| Guide | Service | Description |
|---|---|---|
| Tavily Setup | Tavily | Web search API โ preferred search provider for the web_search tool |
Overview
MimiClaw integrates with external services to extend its capabilities. Each guide below walks through obtaining API credentials, configuring MimiClaw (build-time or runtime), and verifying the integration.
All credentials can be set in two ways:
- Build-time โ define in
main/mimi_secrets.hand rebuild - Runtime โ use serial CLI commands (saved to NVS flash, no rebuild needed)
See mimi_secrets.h.example for the full list of configurable secrets.
Overview (`main/channels/feishu/README.md`)
Feishu/Lark Bot Integration
This directory contains the Feishu bot integration for MimiClaw.
Features
- Send text messages to Feishu chats
- Receive messages via WebSocket persistent connection (long-connection mode)
- Automatic message chunking (4096 chars per message)
- Tenant access token management with auto-refresh
- Message deduplication
- Reply to specific messages
- Support for both DM (p2p) and group chats
Configuration
Option 1: Build-time Configuration
- Copy the secrets template:
cp main/mimi_secrets.h.example main/mimi_secrets.h- Edit
main/mimi_secrets.h:
#define MIMI_SECRET_FEISHU_APP_ID "cli_xxxxxxxxxxxxxx"
#define MIMI_SECRET_FEISHU_APP_SECRET "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"- Rebuild:
idf.py fullclean && idf.py buildOption 2: Runtime Configuration (CLI)
mimi> set_feishu_creds cli_xxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFeishu App Setup
- Go to Feishu Open Platform
- Create an app and get App ID / App Secret
- Enable permissions:
im:message- Send and receive messagesim:message:send_as_bot- Send messages as bot
- Configure Event Subscription:
- Set subscription mode to Persistent connection (้ฟ่ฟๆฅ)
- Subscribe to:
im.message.receive_v1
- The ESP32 will connect to Feishu automatically on boot
Architecture
Feishu Server (wss://open.feishu.cn)
^
| (WebSocket persistent connection, ESP32 initiates)
[feishu_ws_task]
|
v (message_bus_push_inbound)
[Message Bus] --> [Agent Loop] --> [Message Bus]
| |
v (outbound dispatch) |
[feishu_send_message] <-----------------+
|
v (POST /im/v1/messages)
Feishu APIAPI Reference
| Function | Description |
|---|---|
feishu_bot_init() |
Load credentials from NVS/build-time |
feishu_bot_start() |
Start WebSocket persistent connection task |
feishu_send_message(chat_id, text) |
Send text message |
feishu_reply_message(message_id, text) |
Reply to a specific message |
feishu_set_credentials(app_id, secret) |
Save credentials to NVS |
References
ARCHITECTURE (`docs/ARCHITECTURE.md`)
MimiClaw Architecture
ESP32-S3 AI Agent firmware โ C/FreeRTOS implementation running on bare metal (no Linux).
System Overview
/* Detailed source-code truncated for AI context efficiency. */Data Flow
1. User sends message on Telegram (or WebSocket)
2. Channel poller receives message, wraps in mimi_msg_t
3. Message pushed to Inbound Queue (FreeRTOS xQueue)
4. Agent Loop (Core 1) pops message:
a. Load session history from SPIFFS (JSONL)
b. Build system prompt (SOUL.md + USER.md + MEMORY.md + recent notes + tool guidance)
c. Build cJSON messages array (history + current message)
d. ReAct loop (max 10 iterations):
i. Call Claude API via HTTPS (non-streaming, with tools array)
ii. Parse JSON response โ text blocks + tool_use blocks
iii. If stop_reason == "tool_use":
- Execute each tool (e.g. web_search โ Brave Search API)
- Append assistant content + tool_result to messages
- Continue loop
iv. If stop_reason == "end_turn": break with final text
e. Save user message + final assistant text to session file
f. Push response to Outbound Queue
5. Outbound Dispatch (Core 0) pops response:
a. Route by channel field ("telegram" โ sendMessage, "websocket" โ WS frame)
6. User receives replyModule Map
/* Detailed source-code truncated for AI context efficiency. */FreeRTOS Task Layout
| Task | Core | Priority | Stack | Description |
|---|---|---|---|---|
tg_poll |
0 | 5 | 12 KB | Telegram long polling (30s timeout) |
agent_loop |
1 | 6 | 12 KB | Message processing + Claude API call |
outbound |
0 | 5 | 8 KB | Route responses to Telegram / WS |
serial_cli |
0 | 3 | 4 KB | USB serial console REPL |
| httpd (internal) | 0 | 5 | โ | WebSocket server (esp_http_server) |
| wifi_event (IDF) | 0 | 8 | โ | WiFi event handling (ESP-IDF) |
Core allocation strategy: Core 0 handles I/O (network, serial, WiFi). Core 1 is dedicated to the agent loop (CPU-bound JSON building + waiting on HTTPS).
Memory Budget
| Purpose | Location | Size |
|---|---|---|
| FreeRTOS task stacks | Internal SRAM | ~40 KB |
| WiFi buffers | Internal SRAM | ~30 KB |
| TLS connections x2 (Telegram + Claude) | PSRAM | ~120 KB |
| JSON parse buffers | PSRAM | ~32 KB |
| Session history cache | PSRAM | ~32 KB |
| System prompt buffer | PSRAM | ~16 KB |
| LLM response stream buffer | PSRAM | ~32 KB |
| Remaining available | PSRAM | ~7.7 MB |
Large buffers (32 KB+) are allocated from PSRAM via heap_caps_calloc(1, size, MALLOC_CAP_SPIRAM).
Flash Partition Layout
Offset Size Name Purpose
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
0x009000 24 KB nvs ESP-IDF internal use (WiFi calibration etc.)
0x00F000 8 KB otadata OTA boot state
0x011000 4 KB phy_init WiFi PHY calibration
0x020000 2 MB ota_0 Firmware slot A
0x220000 2 MB ota_1 Firmware slot B
0x420000 12 MB spiffs Markdown memory, sessions, config
0xFF0000 64 KB coredump Crash dump storageTotal: 16 MB flash.
Storage Layout (SPIFFS)
SPIFFS is a flat filesystem โ no real directories. Files use path-like names.
/spiffs/config/SOUL.md AI personality definition
/spiffs/config/USER.md User profile
/spiffs/memory/MEMORY.md Long-term persistent memory
/spiffs/memory/2026-02-05.md Daily notes (one file per day)
/spiffs/sessions/tg_12345.jsonl Session history (one file per Telegram chat)Session files are JSONL (one JSON object per line):
{"role":"user","content":"Hello","ts":1738764800}
{"role":"assistant","content":"Hi there!","ts":1738764802}Configuration
All configuration is done exclusively through mimi_secrets.h at build time. There is no runtime configuration โ changing any setting requires idf.py fullclean && idf.py build.
| Define | Description |
|---|---|
MIMI_SECRET_WIFI_SSID |
WiFi SSID |
MIMI_SECRET_WIFI_PASS |
WiFi password |
MIMI_SECRET_TG_TOKEN |
Telegram Bot API token |
MIMI_SECRET_API_KEY |
Anthropic API key |
MIMI_SECRET_MODEL |
Model ID (default: claude-opus-4-6) |
MIMI_SECRET_PROXY_HOST |
HTTP proxy hostname/IP (optional) |
MIMI_SECRET_PROXY_PORT |
HTTP proxy port (optional) |
MIMI_SECRET_SEARCH_KEY |
Brave Search API key (optional) |
NVS is still initialized (required by ESP-IDF WiFi internals) but is not used for application configuration.
Message Bus Protocol
The internal message bus uses two FreeRTOS queues carrying mimi_msg_t:
typedef struct {
char channel[16]; // "telegram", "websocket", "cli"
char chat_id[32]; // Telegram chat ID or WS client ID
char *content; // Heap-allocated text (ownership transferred)
} mimi_msg_t;- Inbound queue: channels โ agent loop (depth: 8)
- Outbound queue: agent loop โ dispatch โ channels (depth: 8)
- Content string ownership is transferred on push; receiver must
free().
WebSocket Protocol
Port: 18789. Max clients: 4.
Client โ Server:
{"type": "message", "content": "Hello", "chat_id": "ws_client1"}Server โ Client:
{"type": "response", "content": "Hi there!", "chat_id": "ws_client1"}Client chat_id is auto-assigned on connection (ws_<fd>) but can be overridden in the first message.
Claude API Integration
Endpoint: POST https://api.anthropic.com/v1/messages
Request format (Anthropic-native, non-streaming, with tools):
{
"model": "claude-opus-4-6",
"max_tokens": 4096,
"system": "<system prompt>",
"tools": [
{
"name": "web_search",
"description": "Search the web for current information.",
"input_schema": {"type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"]}
}
],
"messages": [
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": "Hi!"},
{"role": "user", "content": "What's the weather today?"}
]
}Key difference from OpenAI: system is a top-level field, not inside the messages array.
Non-streaming JSON response:
{
"id": "msg_xxx",
"type": "message",
"role": "assistant",
"content": [
{"type": "text", "text": "Let me search for that."},
{"type": "tool_use", "id": "toolu_xxx", "name": "web_search", "input": {"query": "weather today"}}
],
"stop_reason": "tool_use"
}When stop_reason is "tool_use", the agent loop executes each tool and sends results back:
{"role": "assistant", "content": [<text + tool_use blocks>]}
{"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_xxx", "content": "..."}]}The loop repeats until stop_reason is "end_turn" (max 10 iterations).
Startup Sequence
app_main()
โโโ init_nvs() NVS flash init (erase if corrupted)
โโโ esp_event_loop_create_default()
โโโ init_spiffs() Mount SPIFFS at /spiffs
โโโ message_bus_init() Create inbound + outbound queues
โโโ memory_store_init() Verify SPIFFS paths
โโโ session_mgr_init()
โโโ wifi_manager_init() Init WiFi STA mode + event handlers
โโโ http_proxy_init() Load proxy config from build-time secrets
โโโ telegram_bot_init() Load bot token from build-time secrets
โโโ llm_proxy_init() Load API key + model from build-time secrets
โโโ tool_registry_init() Register tools, build tools JSON
โโโ agent_loop_init()
โโโ serial_cli_init() Start REPL (works without WiFi)
โ
โโโ wifi_manager_start() Connect using build-time credentials
โ โโโ wifi_manager_wait_connected(30s)
โ
โโโ [if WiFi connected]
โโโ telegram_bot_start() Launch tg_poll task (Core 0)
โโโ agent_loop_start() Launch agent_loop task (Core 1)
โโโ ws_server_start() Start httpd on port 18789
โโโ outbound_dispatch task Launch outbound task (Core 0)If WiFi credentials are missing or connection times out, the CLI remains available for diagnostics.
Serial CLI Commands
The CLI provides debug and maintenance commands only. All configuration is done via mimi_secrets.h.
| Command | Description |
|---|---|
wifi_status |
Show connection status and IP |
memory_read |
Print MEMORY.md contents |
memory_write <CONTENT> |
Overwrite MEMORY.md |
session_list |
List all session files |
session_clear <CHAT_ID> |
Delete a session file |
heap_info |
Show internal + PSRAM free bytes |
restart |
Reboot the device |
help |
List all available commands |
Nanobot Reference Mapping
| Nanobot Module | MimiClaw Equivalent | Notes |
|---|---|---|
agent/loop.py |
agent/agent_loop.c |
ReAct loop with tool use |
agent/context.py |
agent/context_builder.c |
Loads SOUL.md + USER.md + memory + tool guidance |
agent/memory.py |
memory/memory_store.c |
MEMORY.md + daily notes |
session/manager.py |
memory/session_mgr.c |
JSONL per chat, ring buffer |
channels/telegram.py |
telegram/telegram_bot.c |
Raw HTTP, no python-telegram-bot |
bus/events.py + queue.py |
bus/message_bus.c |
FreeRTOS queues vs asyncio |
providers/litellm_provider.py |
llm/llm_proxy.c |
Direct Anthropic API only |
config/schema.py |
mimi_config.h + mimi_secrets.h |
Build-time secrets only |
cli/commands.py |
cli/serial_cli.c |
esp_console REPL |
agent/tools/* |
tools/tool_registry.c + tool_web_search.c |
web_search via Brave API |
agent/subagent.py |
(not yet implemented) | See TODO.md |
agent/skills.py |
(not yet implemented) | See TODO.md |
cron/service.py |
(not yet implemented) | See TODO.md |
heartbeat/service.py |
(not yet implemented) | See TODO.md |
TODO (`docs/TODO.md`)
MimiClaw vs Nanobot โ Feature Gap Tracker
Comparing against
nanobot/reference implementation. Tracks features MimiClaw has not yet aligned with.
Priority: P0 = Core missing, P1 = Important enhancement, P2 = Nice to have
P0 โ Core Agent Capabilities
[x] ~~Tool Use Loop (multi-turn agent iteration)~~
- Implemented:
agent_loop.cReAct loop withllm_chat_tools(), max 10 iterations, non-streaming JSON parsing
[ ] Memory Write via Tool Use (agent-driven memory persistence)
- openclaw: Agent uses standard
write/edittools to writeMEMORY.mdandmemory/YYYY-MM-DD.md; system prompt instructs agent to persist important information; pre-compaction memory flush triggers a silent agent turn to save durable memories before context window limit - MimiClaw:
memory_write_long_termandmemory_append_todayexist but are only called from CLI; agent loop never writes memory - Scope: Expose
memory_writeandmemory_append_todayas tool_use tools for Claude; add system prompt guidance on when to persist memory; optionally add pre-compaction flush (trigger memory save when session history nearsMIMI_SESSION_MAX_MSGS) - Depends on: Tool Use Loop
[x] ~~Tool Registry + web_search Tool~~
- Implemented:
tools/tool_registry.cโ tool registration, JSON schema builder, dispatch by name - Implemented:
tools/tool_web_search.cโ Brave Search API via HTTPS (direct + proxy support)
[ ] More Built-in Tools
- nanobot built-in tools not yet ported:
read_file,write_file,edit_file,list_dir,message - Recommendation: Reasonable tool subset for ESP32:
read_file,write_file,list_dir(SPIFFS),message,memory_write
[ ] Subagent / Spawn Background Tasks
- nanobot:
subagent.pyโ SubagentManager spawns independent agent instances with isolated tool sets and system prompts, announces results back to main agent via system channel - MimiClaw: Not implemented
- Recommendation: ESP32 memory is limited; simplify to a single background FreeRTOS task for long-running work, inject result into inbound queue on completion
P1 โ Important Features
[ ] Telegram User Allowlist (allow_from)
- nanobot:
channels/base.pyL59-82 โis_allowed()checks sender_id against allow_list - MimiClaw: No authentication; anyone can message the bot and consume API credits
- Recommendation: Store allow_from list in
mimi_secrets.has a build-time define, filter inprocess_updates()
[ ] Telegram Markdown to HTML Conversion
- nanobot:
channels/telegram.pyL16-76 โ_markdown_to_telegram_html()full converter: code blocks, inline code, bold, italic, links, strikethrough, lists - MimiClaw: Uses
parse_mode: Markdowndirectly; special characters can cause send failures (has fallback to plain text) - Recommendation: Implement simplified Markdown-to-HTML converter, or switch to
parse_mode: HTML
[ ] Telegram /start Command
- nanobot:
telegram.pyL183-192 โ handles/startcommand, replies with welcome message - MimiClaw: Not handled; /start is sent to Claude as a regular message
[ ] Telegram Media Handling (photos/voice/files)
- nanobot:
telegram.pyL194-289 โ handles photo, voice, audio, document; downloads files; transcribes voice - MimiClaw: Only processes
message.text, ignores all media messages - Recommendation: Images can be base64-encoded for Claude Vision; voice requires Whisper API (extra HTTPS request)
[ ] Skills System (pluggable capabilities)
- nanobot:
agent/skills.pyโ loads skills from SKILL.md files, supports always-loaded and on-demand, frontmatter metadata, requirements checking - MimiClaw: Not implemented
- Recommendation: Simplified version: store SKILL.md files on SPIFFS, load into system prompt via context_builder
[ ] Full Bootstrap File Alignment
- nanobot: Loads
AGENTS.md,SOUL.md,USER.md,TOOLS.md,IDENTITY.md(5 files) - MimiClaw: Only loads
SOUL.mdandUSER.md - Recommendation: Add AGENTS.md (behavior guidelines) and TOOLS.md (tool documentation)
[ ] Longer Memory Lookback
- nanobot:
memory.pyL56-80 โget_recent_memories(days=7)defaults to 7 days - MimiClaw:
context_builder.conly reads last 3 days - Recommendation: Make configurable, but mind token budget
[x] ~~System Prompt Tool Guidance~~
- Implemented:
context_builder.cincludes tool usage guidance in system prompt
[ ] Message Metadata (media, reply_to, metadata)
- nanobot:
bus/events.pyโ InboundMessage has media, metadata fields; OutboundMessage has reply_to - MimiClaw:
mimi_msg_tonly has channel + chat_id + content - Recommendation: Extend msg struct, add media_path and metadata fields
[ ] Outbound Subscription Pattern
- nanobot:
bus/queue.pyL41-49 โ supportssubscribe_outbound(channel, callback)subscription model - MimiClaw: Hardcoded if-else dispatch
- Recommendation: Current approach is simple and reliable; not worth changing with few channels
P2 โ Advanced Features
[ ] Cron Scheduled Task Service
- nanobot:
cron/service.pyโ full cron scheduler supporting at/every/cron expressions, persistent storage, timed agent triggers - MimiClaw: Not implemented
- Recommendation: Use FreeRTOS timer for simplified version, support "every N minutes" only
[ ] Heartbeat Service
- nanobot:
heartbeat/service.pyโ reads HEARTBEAT.md every 30 minutes, triggers agent if tasks are found - MimiClaw: Not implemented
- Recommendation: Simple FreeRTOS timer that periodically checks HEARTBEAT.md
[ ] Multi-LLM Provider Support
- nanobot:
providers/litellm_provider.pyโ supports OpenRouter, Anthropic, OpenAI, Gemini, DeepSeek, Groq, Zhipu, vLLM via LiteLLM - MimiClaw: Hardcoded to Anthropic Messages API
- Recommendation: Abstract LLM interface, support OpenAI-compatible API (most providers are compatible)
[ ] Voice Transcription
- nanobot:
providers/transcription.pyโ Groq Whisper API - MimiClaw: Not implemented
- Recommendation: Requires extra HTTPS request to Whisper API: download Telegram voice -> forward -> get text
[x] ~~Build-time Config File + Runtime NVS Override~~
- Implemented:
mimi_secrets.has build-time defaults, NVS as runtime override via CLI - Two-layer config: build-time secrets โ NVS fallback, CLI commands to set/show/reset
[ ] WebSocket Gateway Protocol Enhancement
- nanobot: Gateway port 18790 + richer protocol
- MimiClaw: Basic JSON protocol, lacks streaming token push
- Recommendation: Add
{"type":"token","content":"..."}streaming push
[ ] Multi-Channel Manager
- nanobot:
channels/manager.pyโ unified lifecycle management for multiple channels - MimiClaw: Hardcoded in app_main()
- Recommendation: Not worth abstracting with few channels
[ ] WhatsApp / Feishu Channels
- nanobot:
channels/whatsapp.py,channels/feishu.py - MimiClaw: Only Telegram + WebSocket
- Recommendation: Low priority, Telegram is sufficient
[x] ~~Telegram Proxy Support (HTTP CONNECT)~~
- Implemented: HTTP CONNECT tunnel via
proxy/http_proxy.c, configurable viamimi_secrets.h(MIMI_SECRET_PROXY_HOST/MIMI_SECRET_PROXY_PORT)
[ ] Session Metadata Persistence
- nanobot:
session/manager.pyL136-153 โ session file includes metadata line (created_at, updated_at) - MimiClaw: JSONL only stores role/content/ts, no metadata header
- Recommendation: Low priority
Completed Alignment
- Telegram Bot long polling (getUpdates)
- Message Bus (inbound/outbound queues)
- Agent Loop with ReAct tool use (multi-turn, max 10 iterations)
- Claude API (Anthropic Messages API, non-streaming, tool_use protocol)
- Tool Registry + web_search tool (Brave Search API)
- Context Builder (system prompt + bootstrap files + memory + tool guidance)
- Memory Store (MEMORY.md + daily notes)
- Session Manager (JSONL per chat_id, ring buffer history)
- WebSocket Gateway (port 18789, JSON protocol)
- Serial CLI (esp_console, debug/maintenance commands)
- HTTP CONNECT Proxy (Telegram + Claude API + Brave Search via proxy tunnel)
- OTA Update
- WiFi Manager (build-time credentials, exponential backoff)
- SPIFFS storage
- Build-time config (
mimi_secrets.h) + runtime NVS override via CLI
Suggested Implementation Order
1. [done] Tool Use Loop + Tool Registry + web_search
2. Memory Write via Tool Use <- makes the agent actually remember
3. Built-in Tools (read_file, write_file, message)
4. Telegram Allowlist (allow_from) <- security essential
5. Bootstrap File Completion (AGENTS.md, TOOLS.md)
6. Subagent (simplified)
7. Telegram Markdown -> HTML
8. Media Handling
9. Cron / Heartbeat
10. Other enhancementsWIFI ONBOARDING AP (`docs/WIFI_ONBOARDING_AP.md`)
Wi-Fi AP Onboarding Guide
This guide documents the Wi-Fi onboarding flow for firmware builds that include the MimiClaw onboarding portal.
What It Does
When onboarding is enabled, MimiClaw can expose a local Wi-Fi access point such as MimiClaw-XXXX and serve a configuration page at http://192.168.4.1.
Typical uses:
- first-time Wi-Fi setup without editing firmware
- updating saved Wi-Fi, model, proxy, or bot credentials later
- recovering a device that can no longer join the previous router
Requirements
- a firmware build with the Wi-Fi onboarding portal enabled
- an ESP32-S3 board powered on and booted normally
- a phone or laptop that can join the temporary
MimiClaw-XXXXnetwork
First-Time Setup
- Power on the device.
- Wait for the onboarding hotspot
MimiClaw-XXXXto appear. - Join that hotspot from your phone or laptop.
- Open
http://192.168.4.1if the captive page does not open automatically. - Fill in at least:
SSIDPassword
- Add optional settings if needed:
API KeyModelProviderTelegramFeishuProxySearch
- Click
Save & Restart. - Wait for the device to reboot and join your normal Wi-Fi network.
Updating Settings Later
If the firmware keeps the admin AP online after normal Wi-Fi connection, you can reconnect to MimiClaw-XXXX later and open http://192.168.4.1 again.
The page should prefill the currently effective configuration so you can edit only the fields you want to change.
Config Priority
The onboarding page follows the same config priority as the firmware:
- saved NVS values
- build-time defaults from
main/mimi_secrets.h
That means:
- if a field exists in NVS, it overrides the build-time default
- if you clear a saved field and reboot, the device falls back to
main/mimi_secrets.h - if both NVS and build-time values are empty, the field stays empty
Clearing Saved Values
On firmware versions that support clearing fields from the portal:
- leaving a field blank and saving removes the corresponding NVS key
- after reboot, the page shows the build-time fallback if one exists
If you need to wipe all saved runtime settings, use:
mimi> config_resetTroubleshooting
No `MimiClaw-XXXX` hotspot appears
- verify that the running firmware actually includes the onboarding portal
- if the device already connects successfully and does not keep the admin AP online, clear Wi-Fi config and reboot
- confirm the board has finished booting before scanning for Wi-Fi
The page still shows old values
- refresh the page manually
- reconnect to the AP and open
http://192.168.4.1again - if needed, restart the browser once to clear stale captive portal state
The build-time provider/model do not show up
If the device already has model or provider saved in NVS, the saved values win over main/mimi_secrets.h.
To return to build-time defaults:
- clear those fields in the portal and save, or
- run
config_reset
Notes
- The onboarding AP is typically local-only and intended for nearby configuration.
- Current onboarding implementations may use an open AP for simplicity, so avoid leaving it exposed longer than necessary.
- If your deployment needs stronger local protection, add an AP password before using the flow in production.
Im Integration FEISHU SETUP (`docs/im-integration/FEISHU_SETUP.md`)
Feishu / Lark Bot Configuration Guide
This guide walks through setting up a Feishu (or Lark) bot to work with MimiClaw, turning your ESP32-S3 into a Feishu-connected AI assistant.
Table of Contents
- Overview
- Prerequisites
- Step 1: Create a Feishu App
- Step 2: Configure App Permissions
- Step 3: Set Up Event Subscription
- Step 4: Configure MimiClaw
- Step 5: Network Setup
- Step 6: Publish and Test
- Architecture
- CLI Commands
- Troubleshooting
- References
Overview
MimiClaw supports Feishu as a messaging channel alongside Telegram and WebSocket. The Feishu integration uses:
- Webhook receiver โ the ESP32 runs an HTTP server on port 18790 to receive messages from Feishu
- Send API โ MimiClaw sends replies via Feishu's REST API (
/im/v1/messages) - Tenant access token โ automatic token management with background refresh
Both direct messages (P2P) and group chats are supported.
Prerequisites
- A Feishu account (sign up at feishu.cn) or a Lark account (larksuite.com)
- Admin access to create apps on Feishu Open Platform (or Lark Developer)
- MimiClaw flashed on an ESP32-S3 with network access
- The ESP32 must be reachable from the internet (see Network Setup)
Step 1: Create a Feishu App
- Go to Feishu Open Platform and sign in
- Click Create Custom App (or "Create App" on Lark)
- Fill in the app details:
- App Name: Choose a name (e.g., "MimiClaw Bot")
- App Description: Brief description of your bot
- App Icon: Upload an icon (optional)
- After creation, you will see your App ID and App Secret on the app's Credentials & Basic Info page
Important: Save the App ID (
cli_xxxxxxxxxxxxxx) and App Secret (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx). You will need these to configure MimiClaw.
Step 2: Configure App Permissions
In your app's settings, go to Permissions & Scopes and add these required permissions:
| Permission | Scope ID | Description |
|---|---|---|
| Read/Send messages | im:message |
Receive and send messages |
| Send messages as bot | im:message:send_as_bot |
Send messages as the bot identity |
To add permissions:
- Navigate to Permissions & Scopes in the left sidebar
- Search for each scope ID listed above
- Click Add next to each permission
- The permissions will take effect after you publish or update the app version
Note: On Lark (international version), the permission names may differ slightly, but the scope IDs are the same.
Step 3: Set Up Event Subscription
Event subscription allows Feishu to push new messages to your ESP32 in real-time.
Configure the Webhook URL
- In your app settings, go to Event Subscriptions (or "Events & Callbacks")
- Set the Request URL to:
http://<ESP32_IP>:18790/feishu/eventsReplace <ESP32_IP> with your ESP32's public IP or domain name.
- Click Save โ Feishu will send a verification challenge to the URL
- MimiClaw automatically responds to the URL verification challenge, so this should succeed if the ESP32 is reachable
Subscribe to Events
Add the following event:
| Event | Event ID | Description |
|---|---|---|
| Receive messages | im.message.receive_v1 |
Triggered when users send messages to the bot |
To add events:
- In the Event Subscriptions page, click Add Event
- Search for
im.message.receive_v1 - Select it and click Confirm
Encryption Settings (Optional)
In the event subscription settings, you can optionally configure:
- Verification Token โ used to verify that events come from Feishu
- Encrypt Key โ encrypts event payloads
MimiClaw currently does not verify these tokens, so you can leave them empty for simplicity. For production use, consider implementing verification.
Step 4: Configure MimiClaw
You need to provide the App ID and App Secret to MimiClaw.
Option 1: Build-time Configuration
- Copy the secrets template if you haven't already:
cp main/mimi_secrets.h.example main/mimi_secrets.h- Edit
main/mimi_secrets.h:
#define MIMI_SECRET_FEISHU_APP_ID "cli_xxxxxxxxxxxxxx"
#define MIMI_SECRET_FEISHU_APP_SECRET "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"- Rebuild and flash:
idf.py fullclean && idf.py build
idf.py -p PORT flash monitorOption 2: Runtime Configuration via Serial CLI
Connect to the UART (COM) port and run:
mimi> set_feishu_creds cli_xxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxThis saves credentials to NVS flash immediately โ no rebuild needed.
Verify Configuration
mimi> config_showYou should see feishu_app_id: cli_**** and feishu_app_secret: **** in the output.
Step 5: Network Setup
Feishu's servers need to reach your ESP32's webhook endpoint. There are several approaches:
Option A: Direct Public IP
If your ESP32 is directly accessible from the internet:
Webhook URL: http://<PUBLIC_IP>:18790/feishu/eventsOption B: Port Forwarding
If the ESP32 is behind a router:
- Log into your router's admin panel
- Forward external port (e.g., 18790) to
<ESP32_LOCAL_IP>:18790 - Use your router's public IP in the webhook URL
Option C: Reverse Proxy / Tunnel
For development or when port forwarding isn't possible:
- ngrok:
ngrok http <ESP32_IP>:18790 - frp: Configure
frpc.tomlto proxy to the ESP32 - Cloudflare Tunnel: Route traffic through Cloudflare
Example with ngrok:
ngrok http 192.168.1.100:18790
# Use the generated URL: https://xxxx.ngrok.io/feishu/eventsOption D: Cloud Server Relay (Production)
For reliable production setups, deploy a lightweight reverse proxy on a cloud server (e.g., Volcengine ECS, AWS EC2) that forwards requests to your ESP32 via a VPN or WireGuard tunnel. This is the approach described in the Volcengine OpenClaw deployment guide.
Note: Feishu requires the webhook URL to be accessible and respond within 3 seconds. Ensure your network path has low latency.
Step 6: Publish and Test
Enable the Bot
- In your app settings, go to Bot in the left sidebar
- Toggle Enable Bot to ON
Publish the App
- Go to App Release (or "Version Management & Release")
- Click Create Version
- Set a version number and description
- Click Submit for Review (for enterprise apps) or Publish (for personal testing apps)
Tip: For testing, you can use the app in "development mode" without publishing โ just add yourself as a test user.
Test the Bot
- Open Feishu and search for your bot by name
- Send a message to the bot in a direct chat
- Check the ESP32 serial output โ you should see the message being received and processed
- The bot should reply through Feishu
For group chats:
- Add the bot to a group
- Mention the bot with
@BotNamefollowed by your message - The bot will process and reply in the group
Architecture
Feishu Cloud
|
| HTTP POST /feishu/events
| (im.message.receive_v1)
v
[ESP32 Webhook Server :18790]
|
| message_bus_push_inbound()
v
[Message Bus] โโ> [Agent Loop] โโ> [Message Bus]
(Claude/GPT) |
| outbound dispatch
v
[feishu_send_message()]
|
| POST /im/v1/messages
v
Feishu APIKey Components
| Component | Description |
|---|---|
| Webhook Server | HTTP server on port 18790, handles event callbacks |
| Token Manager | Manages tenant access tokens, auto-refreshes before expiry |
| Message Sender | Sends text messages via Feishu REST API with auto-chunking |
| Deduplication | Prevents processing duplicate events from Feishu retries |
Configuration Constants
These can be found in main/mimi_config.h:
| Constant | Default | Description |
|---|---|---|
MIMI_FEISHU_MAX_MSG_LEN |
4096 | Max message length per chunk |
MIMI_FEISHU_WEBHOOK_PORT |
18790 | Webhook HTTP server port |
MIMI_FEISHU_WEBHOOK_PATH |
/feishu/events |
Webhook endpoint path |
MIMI_FEISHU_WEBHOOK_MAX_BODY |
16 KB | Max webhook request body size |
CLI Commands
| Command | Description |
|---|---|
set_feishu_creds <app_id> <app_secret> |
Save Feishu credentials to NVS |
config_show |
Show all configuration (including Feishu, masked) |
config_reset |
Clear all NVS config, revert to build-time defaults |
Troubleshooting
Webhook URL verification fails
- Ensure the ESP32 is running and connected to WiFi:
wifi_status - Verify the webhook URL is reachable from the internet
- Check that port 18790 is not blocked by firewalls
- Look at ESP32 serial output for incoming HTTP requests
Bot doesn't respond to messages
- Check credentials:
config_showshould show Feishu app_id and app_secret - Check event subscription: Ensure
im.message.receive_v1is subscribed in the Feishu app settings - Check permissions: Both
im:messageandim:message:send_as_botmust be granted - Check serial output: Look for message processing logs on the ESP32
"Tenant access token" errors
- Verify your App ID and App Secret are correct
- The token auto-refreshes every 2 hours โ if you just set credentials, wait a moment for the first token fetch
- Ensure the ESP32 can reach
https://open.feishu.cn(check proxy settings if needed)
Messages are truncated
Feishu has a 4096-character limit per message. MimiClaw automatically chunks long messages, but if you see issues, check the serial output for chunking errors.
Bot works in DM but not in groups
- Ensure the bot is added to the group
- Users must
@mentionthe bot in group chats for it to receive messages - Check that group messaging permissions are enabled in the Feishu app settings
Event subscription shows errors in Feishu console
- Feishu retries failed events up to 5 times with exponential backoff
- MimiClaw deduplicates retried events, so duplicate processing is not a concern
- If events consistently fail, check the ESP32's network connectivity
References
- Feishu Open Platform Documentation
- Feishu Bot Development Guide
- Feishu Message API
- Feishu Event Subscription Guide
- Lark Developer Documentation (international version)
- Volcengine OpenClaw Deployment Guide (Chinese)
Tool Setup TAVILY SETUP (`docs/tool-setup/TAVILY_SETUP.md`)
Tavily Web Search Configuration Guide
Tavily is a real-time search engine designed for AI agents and RAG workflows. MimiClaw uses Tavily as the preferred web search provider (with Brave Search as a fallback).
Table of Contents
- Overview
- Getting an API Key
- Configuring MimiClaw
- How It Works in MimiClaw
- API Details
- Pricing
- Rate Limits
- Troubleshooting
Overview
MimiClaw's web_search tool allows the AI agent to search the internet for real-time information. When a Tavily API key is configured, MimiClaw will use Tavily as the search provider. If no Tavily key is set but a Brave Search key exists, it falls back to Brave Search.
Why Tavily?
- Purpose-built for AI agents โ returns clean, structured results
- Includes relevance scoring for each result
- Supports advanced search depth for higher quality results
- 1,000 free API credits per month (no credit card required)
Getting an API Key
- Sign up at app.tavily.com
- Create an account โ you can sign in with Google or email
- Copy your API key โ it starts with
tvly-and is available on the dashboard immediately - The free Researcher plan gives you 1,000 API credits per month with no credit card required
Your API key will look like: tvly-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Configuring MimiClaw
There are two ways to configure the Tavily API key:
Option 1: Build-time Configuration (Recommended for First Setup)
- Copy the secrets template if you haven't already:
cp main/mimi_secrets.h.example main/mimi_secrets.h- Edit
main/mimi_secrets.hand set your Tavily key:
#define MIMI_SECRET_TAVILY_KEY "tvly-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"- Rebuild the firmware:
idf.py fullclean && idf.py build- Flash to your ESP32-S3:
idf.py -p PORT flash monitorOption 2: Runtime Configuration via Serial CLI
Connect to the UART (COM) port and run:
mimi> set_tavily_key tvly-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxThis saves the key to NVS flash and takes effect immediately โ no rebuild needed. Runtime values override build-time defaults.
Verify Configuration
Check that the key is set:
mimi> config_showYou should see tavily_key: tvly-**** (masked) in the output.
How It Works in MimiClaw
When the AI agent needs to search the web, it calls the web_search tool. MimiClaw selects the search provider with this priority:
1. Tavily (if MIMI_SECRET_TAVILY_KEY is set) <-- preferred
2. Brave Search (if MIMI_SECRET_SEARCH_KEY is set)
3. No search available (tool returns error)The search flow:
User asks a question requiring web info
|
v
Agent decides to call web_search tool
|
v
MimiClaw sends POST to https://api.tavily.com/search
- Authorization: Bearer tvly-xxxxx
- Body: {"query": "...", "max_results": 5, "search_depth": "basic"}
|
v
Tavily returns structured results
|
v
Agent incorporates results into responseEach basic search costs 1 API credit. With the free plan's 1,000 credits/month, that's about 33 searches per day.
API Details
MimiClaw uses the Tavily Search API endpoint:
| Parameter | Value |
|---|---|
| Endpoint | POST https://api.tavily.com/search |
| Auth | Authorization: Bearer <API_KEY> |
| Content-Type | application/json |
Request Body (as sent by MimiClaw)
| Field | Type | Value | Description |
|---|---|---|---|
query |
string | (from agent) | The search query |
max_results |
integer | 5 |
Number of results to return |
search_depth |
string | "basic" |
Search depth (basic = 1 credit) |
Response Fields
| Field | Type | Description |
|---|---|---|
query |
string | The executed search query |
results |
array | Ranked search results |
results[].title |
string | Result title |
results[].url |
string | Source URL |
results[].content |
string | Summary snippet |
results[].score |
float | Relevance score (0-1) |
response_time |
float | Execution time in seconds |
HTTP Status Codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad Request โ invalid parameters |
| 401 | Unauthorized โ missing or invalid API key |
| 429 | Rate Limit โ too many requests |
| 432 | Plan Limit โ monthly quota exceeded |
| 500 | Server Error |
Pricing
Tavily offers a generous free tier and several paid plans:
| Plan | Monthly Credits | Cost | Per-Credit Rate |
|---|---|---|---|
| Researcher | 1,000 | Free | -- |
| Project | 4,000 | $30 | $0.0075 |
| Bootstrap | 15,000 | $100 | $0.0067 |
| Startup | 38,000 | $220 | $0.0058 |
| Growth | 100,000 | $500 | $0.005 |
| Pay-as-you-go | Variable | $0.008/credit | $0.008 |
Credit costs per search:
basicsearch depth: 1 creditadvancedsearch depth: 2 credits
MimiClaw uses basic by default, so each search = 1 credit.
Rate Limits
| Environment | Limit |
|---|---|
| Development | 100 requests per minute |
| Production | 1,000 requests per minute |
For an ESP32-based agent, you will never hit these limits in practice.
Troubleshooting
"No search provider configured"
The agent returns this when neither Tavily nor Brave Search keys are set.
Fix: Set a Tavily API key via set_tavily_key CLI command or in mimi_secrets.h.
Search returns empty results
- Verify your API key is correct:
config_showshould showtavily_key: tvly-**** - Check your monthly credit balance at app.tavily.com
- Ensure the ESP32 has internet access:
wifi_status
HTTP 401 Unauthorized
Your API key is invalid or expired. Generate a new one at app.tavily.com.
HTTP 432 Plan Limit
You've exceeded your monthly credit quota. Wait for the next billing cycle or upgrade your plan.
Search works but results are poor
Tavily's basic search depth is optimized for speed. The quality is generally sufficient for an AI agent's needs. If you need higher quality, you can modify SEARCH_RESULT_COUNT in tool_web_search.c.
References
--- METRICS ---
- Files Extracted: 9
- Estimated Token Budget: ~14950 tokens
- Canonical Reference: https://codewiki.google/github.com/memovai/mimiclaw