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:

  1. Sends a request to the LLM with the current tool descriptions and conversation context.

  2. Parses the LLM’s tool-call response.

  3. Dispatches the tool call to the corresponding Capability and collects the result.

  4. Appends the result as a tool response, then starts the next reasoning round.

  5. 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.