Project Architecture
This page is for developers and explains the overall structure of Ameba-Claw, its core components, and the filesystem layout.
Architecture Overview
Ameba-Claw is an on-chip AI Agent framework that runs entirely on Ameba-RTOS — no Linux kernel, no external server. The system is organized in three tiers:
┌──────────────────────────────────────────────────────┐
│ User Input Layer │
│ Telegram / Feishu / WeChat / QQ / WebUI / AT Serial │
└──────────────────────┬───────────────────────────────┘
│
┌──────────────────────▼───────────────────────────────┐
│ Agent Reasoning Layer │
│ claw_agent — ReAct loop (LLM + tool calls) │
└──────────────────────┬───────────────────────────────┘
│
┌──────────────────────▼───────────────────────────────┐
│ Capability Execution Layer │
│ Lua engine / File system / Board HW / Scheduler │
└──────────────────────────────────────────────────────┘
Messages arrive through an IM channel (or the serial AT interface), and claw_agent starts a ReAct reasoning loop: the LLM decides what tool to call next, the corresponding Capability executes, the result is fed back to the LLM as a tool response, and this continues until the LLM produces a final reply to the user.
Core Components
claw_agent — Agent Loop
Implements the ReAct (Reasoning + Acting) loop. Each conversation request is handled in its own task:
Sends a request to the LLM with the current tool descriptions and conversation context.
Parses the LLM’s tool-call response.
Dispatches the tool call to the corresponding Capability and collects the result.
Appends the result as a tool response, then starts the next reasoning round.
Delivers the final reply to the user when the LLM produces one.
A watchdog task monitors heartbeat timestamps. If no tool-call heartbeat is received for 7 minutes (indicating a hung Capability or a stalled LLM request), the watchdog triggers a soft reset via sys_reset().
Capability System (claw_cap)
Capabilities are C-layer callable tools registered in claw_cap. Each has a unique id, a JSON input schema, and an execute function. The LLM invokes them through the tool-call interface; developers can also call them via AT+CLAW=cap,<id> or via cap.call() inside Lua scripts.
Capabilities are organized into groups (cap_groups). Some groups are hidden from the LLM by default and become visible only after the corresponding Skill is activated — for example, the board group is unlocked by activating the board_hardware_info Skill.
See Capability System for the full reference.
Skill Manager (cap_skill_mgr)
Manages the Skill catalog under rolfs:/skills/ (built-in) and vfs:/skills/ (user-created). It parses SKILL.md frontmatter, maintains a per-session activation list persisted in vfs:/session/, and dynamically controls which Capability groups are visible to the LLM based on the activation state.
See Skill System for details.
Lua Execution Engine (cap_lua)
Provides the lua_run (synchronous) and lua_run_async (asynchronous) Capabilities for executing Skill scripts and user scripts. Key design points:
Every call creates a fresh, isolated
lua_State— no shared global state between runs.The Lua VM runs in a dedicated 8 KB task stack (not the caller’s stack) to prevent stack overflow during script parsing.
The sandbox strips
io,os,debug,load,loadfile,dofile, and raw-access primitives.Default sync timeout is 30 s; a cancel hook fires every 500 Lua instructions.
Async jobs have 4 slots (2 concurrent max, shared with sync runs), each with a 2 KB ring log readable via
lua_job_get.
See Lua Module Reference for the module reference and scripting conventions.
IM Dispatcher (claw_im_dispatch)
Receives messages from all supported channels — Telegram, Feishu, WeChat, QQ, local WebUI, and the serial AT interface — and wraps them into a standard claw_agent_request_t before submitting to the Agent loop. Each channel runs its own receive task and maps replies back to the originating chat.
Filesystem Layout
Ameba-Claw uses two independent littlefs partitions:
Read-Only Firmware Partition (rolfs:/)
Embedded inside the application binary. Updated atomically with OTA — always consistent with the running firmware version. Never user-writable at runtime.
rolfs:/
├── skills/ Built-in Skills
│ └── <name>/
│ ├── SKILL.md Skill metadata + documentation
│ └── scripts/ Script-type Skill entry point (main.lua)
├── docs/ Lua module API quick-reference docs (.md)
└── lib/ Lua shared libraries (require-able from Skill scripts)
Writable Flash Partition (vfs:/)
User-readable and writable. Persists across reboots and power cycles.
vfs:/
├── skills/ User-created Skills
│ └── <name>/
│ ├── SKILL.md
│ └── scripts/main.lua
├── scripts/ Persistent user application scripts (not in skill catalog)
├── tmp/ Throwaway scripts (cleared on each boot)
├── session/ Per-session activation lists, memory, runtime state
└── ... Config files, inbox attachments, etc.