Zbot AI Agent

by LingaoMβ€’ 35β€’β€’ Scannedβ€’Claim this listingβ€’Request removal
Otherai agentclaude aiclawdbotdeepseekembeded

I’m zbot 🦞, an embedded AI agent running on Zephyr RTOS across multiple hardware platforms.

Zbot is an open-source ai agent by LingaoM, written mainly in C, with 35 GitHub stars and the Apache-2.0 license. Its code was last updated Apr 17, 2026.

<h1 align="center">🦞 zbot</h1> <p align="center"> An open-source embedded AI agent powered by Zephyr RTOS<br> zbot implements a ReAct (Reason + Act) loop that connects to any OpenAI-compatible LLM API, enabling hardware control, persistent memory, and multi-step skills. </p> <p align="center"> <img src="docs/logo.jpg" width="360"/> </p>

🎬 Demo

<p align="center"> <img src="docs/telegram.gif"/> <img src="docs/terminal.gif"/> </p>

Supported boards: nRF7002-DK (nRF5340 + nRF7002 WiFi), native_sim (Linux host) RTOS: Zephyr latest License: Apache-2.0


Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    zbot Agent                        β”‚
β”‚                                                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚  Config  β”‚  β”‚  Memory  β”‚  β”‚   LLM Client     β”‚    β”‚
β”‚  β”‚ endpoint β”‚  β”‚ slab poolβ”‚  β”‚  HTTPS β†’ OpenAI  β”‚    β”‚
β”‚  β”‚ model    β”‚  β”‚ + NVS    β”‚  β”‚  compatible API  β”‚    β”‚
β”‚  β”‚ api key  β”‚  β”‚ summary  β”‚  β”‚                  β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  LLM-visible Tools   β”‚  β”‚       Skills         β”‚  β”‚
β”‚  β”‚  (src/tools/)        β”‚  β”‚  (src/skills/)       β”‚  β”‚
β”‚  β”‚                      β”‚  β”‚                      β”‚  β”‚
β”‚  β”‚  tool_exec ──────────┼─►│  gpio  (read/write/  β”‚  β”‚
β”‚  β”‚    └─ skill_run()    β”‚  β”‚         blink/sos)   β”‚  β”‚
β”‚  β”‚                      β”‚  β”‚  system(board/uptime/β”‚  β”‚
β”‚  β”‚  read_skill ─────────┼─►│         heap/status) β”‚  β”‚
β”‚  β”‚    └─ skill_read_    β”‚  β”‚                      β”‚  β”‚
β”‚  β”‚       content()      β”‚  β”‚  (add more in        β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚   src/skills/<name>/)β”‚  β”‚
β”‚                            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Shell Commands  (zbot key / chat / skill ...) β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                        β”‚
β”‚  β”‚ Telegram β”‚  Long-poll thread β†’ agent β†’ sendMessageβ”‚
β”‚  β”‚   Bot    β”‚                                        β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Modules

ModuleFilePurpose
Configconfig.h/cLLM endpoint, model, API key + WiFi credentials (NVS persistence)
Memorymemory.h/ck_mem_slab conversation history + NVS rolling summary
LLM Clientllm_client.h/cHTTPS POST to OpenAI-compatible Chat Completions API
Toolstools.h/c + src/tools/LLM-visible tool registry; each tool in its own directory, self-registers via SYS_INIT
Skillsskills/skill.h/c + src/skills/Skill registry; each skill in its own directory, self-registers via SYS_INIT
Agentagent.h/c + src/AGENT.mdReAct loop; system prompt loaded from AGENT.md at build time
Telegramtelegram.h/cTelegram Bot long-poll thread; forwards messages to agent and replies
JSON Utiljson_util.h/cShared json_get_str() and json_escape()
Shellshell_cmd.cAll zbot shell subcommands

Tool & Skill Design

The LLM sees exactly two tools:

LLM ToolWhat it does
tool_execDispatches to any registered skill by name β€” all hardware/system operations go here
read_skillReturns the full Markdown documentation of a skill on demand

Skills are the execution units. They live in src/skills/<name>/ and self-register at boot via SYS_INIT. Each skill has:

  • SKILL.c β€” handler implementation, registered with SKILL_DEFINE
  • SKILL.md (optional) β€” Markdown documentation embedded at build time via generate_inc_file_for_target

The LLM receives only name + description for each skill per request. Full docs are fetched on demand via read_skill.

Hardware primitives (GPIO, uptime, heap) are themselves skills β€” the same mechanism, just without Markdown docs.

ReAct Loop

user input
    β”‚
    β–Ό
build messages JSON  ←────────────────────────────────────────────────┐
    β”‚                                                                 β”‚
    β–Ό                                                                 β”‚
LLM API call (tool_exec + read_skill exposed)                         β”‚
    β”‚                                                                 β”‚
    β”œβ”€β”€ finish_reason: tool_call ──► tools_execute(name, args)        β”‚
    β”‚                                    └─ skill_run(name, args) ───►│
    β”‚
    └── finish_reason: stop ──► return answer to user
                                        β”‚
                                        β–Ό
                                request summary ──► NVS

Max iterations per turn: 10

Conversation Memory

History uses a 10-node static pool (k_mem_slab) backed by a sys_slist_t linked list ordered oldest β†’ newest.

When the pool is full on memory_add_turn():

  1. Compress β€” the oldest nodes are summarised by the LLM; those nodes are freed back to the slab.
  2. Evict (fallback) β€” the oldest node is recycled directly.

After compression, the rolling summary is written to NVS and injected as prior context on the next boot.

Settings layout:

KeyTypeNotes
zbot/summarychar[768]Conversation summary
zbot/apikeychar[256]Set by zbot key
zbot/hostchar[128]LLM endpoint hostname
zbot/pathchar[128]LLM API path
zbot/modelchar[128]Model name
zbot/provider_idchar[64]X-Model-Provider-Id header
zbot/use_tlsuint8_tTLS enabled flag
zbot/portuint16_tTCP port
zbot/tg_tokenchar[128]Telegram Bot token
wifi/...β€”Managed by Zephyr wifi_credentials subsystem

Prerequisites

Set up a Zephyr development environment following the official guide: https://docs.zephyrproject.org/latest/develop/getting_started/index.html


Quick Start

1. Build & Flash

nRF7002-DK (physical hardware with WiFi):

west build -b nrf7002dk/nrf5340/cpuapp zbot
west flash

native_sim (Linux host simulation, no WiFi):

west build -b native_sim zbot
./build/zephyr/zephyr.exe

2. Connect Serial

For nRF7002-DK:

minicom -D /dev/ttyACM0 -b 115200

For native_sim, the shell is on the terminal where you launched zephyr.exe.

3. Connect to WiFi (nRF7002-DK only)

uart:~$ zbot wifi connect <SSID> <password>

Credentials are saved to flash and auto-connect on reboot.

native_sim: No WiFi configuration needed β€” the host OS provides the network stack.

4. Set API Key

Default Provider (OpenRouter) Get a free API key from: https://openrouter.ai/settings/keys

uart:~$ zbot key sk-...

The key is saved to NVS flash and restored on every reboot.

5. (Optional) Configure Endpoint

OpenAI:

uart:~$ zbot host api.openai.com
uart:~$ zbot path /v1/chat/completions
uart:~$ zbot model gpt-4o-mini
uart:~$ zbot key sk-...

DeepSeek:

uart:~$ zbot host api.deepseek.com
uart:~$ zbot path /chat/completions
uart:~$ zbot model deepseek-chat
uart:~$ zbot key sk-...

Local model (e.g. Ollama):

uart:~$ zbot host 192.168.1.100
uart:~$ zbot tls off 11434

6. (Optional) Configure Telegram Bot

Create a bot via @BotFather on Telegram to obtain a token.

uart:~$ zbot telegram token 1234567890:AAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
uart:~$ zbot telegram start

The token is saved to NVS flash. Polling starts automatically on the next reboot if a token is stored.

7. Chat

uart:~$ zbot chat
Entering interactive chat mode. Type /exit to quit.
zbot:~$ Hello! What can you do?
Thinking...

zbot: Hi! I'm zbot ...

zbot:~$ Turn on LED0
Thinking...

zbot: Done β€” LED0 is now on.

zbot:~$ /exit
Leaving chat mode.
uart:~$

Shell Commands

Configuration

CommandDescription
zbot key <key>Set API key (saved to flash)
zbot key_deleteDelete API key from flash
zbot config_resetReset all config to defaults and wipe from flash
zbot host <hostname>Set LLM endpoint host
zbot path <path>Set LLM API path
zbot model <name>Set model name
zbot provider <id>Set X-Model-Provider-Id header
zbot tls <on|off> [port]Enable/disable TLS and set port
zbot statusShow current config and agent state

WiFi (nRF7002-DK only)

CommandDescription
zbot wifi connect <ssid> [pass]Connect to WiFi and save credentials
zbot wifi disconnectDisconnect from WiFi
zbot wifi statusShow saved SSID

Conversation

CommandDescription
zbot chatEnter interactive chat mode (/exit to quit)
zbot historyPrint in-RAM conversation history
zbot summaryShow the NVS-persisted session summary
zbot clearClear RAM history (keeps NVS summary)
zbot wipeWipe all history and NVS summary

Telegram Bot

CommandDescription
zbot telegram token <token>Set Telegram Bot token (saved to flash)
zbot telegram startStart long-poll thread
zbot telegram stopStop long-poll thread
zbot telegram statusShow token and polling state

Skills & Tools

CommandDescription
zbot skill listList all registered skills with descriptions
zbot skill run <name> [arg]Run a skill directly from the shell
zbot toolsList all LLM-visible tools

Built-in Skills

Skills are registered at boot via SKILL_DEFINE / SYS_INIT and dispatched by tool_exec.

gpio β€” GPIO operations

ActionArgsDescription
readpin: led0/led1/button0Read GPIO pin level
writepin: led0/led1, value: 0/1Set GPIO output level
blinkcount: 1–20 (default 3)Blink LED0 N times at 300ms intervals
sosβ€”Transmit SOS morse code on LED0
zbot:~$ Turn on LED0
# LLM calls: tool_exec({"tool":"gpio","args":{"action":"write","pin":"led0","value":1}})

zbot:~$ Blink 5 times
# LLM calls: tool_exec({"tool":"gpio","args":{"action":"blink","count":5}})

system β€” System information

ActionDescription
board_infoBoard name, RTOS, firmware version
uptimeDevice uptime in ms and seconds
heap_infoHeap free / allocated / peak bytes
statusCombined report: board + uptime + heap
zbot:~$ What's the system status?
# LLM calls: tool_exec({"tool":"system","args":{"action":"status"}})

Shell shortcut:

uart:~$ zbot skill run system '{"action":"status"}'
uart:~$ zbot skill run gpio '{"action":"blink","count":3}'

Extending zbot

Adding a New Skill

  1. Create src/skills/<name>/SKILL.md (optional β€” for skills with documentation)
  2. Create src/skills/<name>/SKILL.c:
#include "skill.h"

static const char my_skill_md[] = {
#include "skills/<name>/SKILL.md.inc"
    0x00
};

static int handler(const char *arg, char *result, size_t res_len)
{
    snprintf(result, res_len, "{\"status\":\"ok\"}");
    return 0;
}

SKILL_DEFINE(my_skill, "my_skill", "One-line description",
             my_skill_md, sizeof(my_skill_md) - 1, handler);
  1. Create src/skills/<name>/CMakeLists.txt:
target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/SKILL.c)

generate_inc_file_for_target(
    app
    ${CMAKE_CURRENT_SOURCE_DIR}/SKILL.md
    ${gen_dir}/skills/<name>/SKILL.md.inc
)

The skill is immediately available to the LLM via tool_exec({"tool":"<name>","args":{...}}).

Customising the System Prompt

Edit src/AGENT.md.in β€” it is embedded into the firmware at build time via generate_inc_file_for_target. No code changes required.


Project Structure

zbot/
β”œβ”€β”€ CMakeLists.txt
β”œβ”€β”€ prj.conf
β”œβ”€β”€ boards/
β”‚   β”œβ”€β”€ nrf7002dk_nrf5340_cpuapp.conf
β”‚   └── native_sim.conf
β”œβ”€β”€ sysbuild/
β”‚   └── nrf7002dk_nrf5340_cpuapp.conf
└── src/
    β”œβ”€β”€ AGENT.md.in                 # System prompt (embedded at build time)
    β”œβ”€β”€ main.c
    β”œβ”€β”€ agent.h/c                   # ReAct loop
    β”œβ”€β”€ memory.h/c                  # Conversation history + NVS summary
    β”œβ”€β”€ llm_client.h/c              # HTTPS LLM client
    β”œβ”€β”€ config.h/c                  # Runtime config + NVS persistence
    β”œβ”€β”€ tools.h/c                   # LLM tool registry framework
    β”œβ”€β”€ json_util.h/c               # JSON helpers
    β”œβ”€β”€ shell_cmd.c                 # zbot shell commands
    β”œβ”€β”€ telegram.h/c                # Telegram Bot integration
    β”œβ”€β”€ certs/openrouter/           # TLS CA certificate
    β”œβ”€β”€ tools/
    β”‚   β”œβ”€β”€ tool_exec/              # LLM tool: dispatches to skill_run()
    β”‚   β”‚   └── TOOL.c
    β”‚   └── read_skill/             # LLM tool: returns skill Markdown docs
    β”‚       └── TOOL.c
    └── skills/
        β”œβ”€β”€ skill.h/c               # Skill registry framework
        β”œβ”€β”€ gpio/                   # GPIO: read, write, blink, sos
        β”‚   β”œβ”€β”€ SKILL.c
        β”‚   └── SKILL.md
        └── system/                 # System: board_info, uptime, heap, status
            β”œβ”€β”€ SKILL.c
            └── SKILL.md

Security Notes

  • API key is saved to NVS flash. Use zbot key_delete to remove it.
  • Telegram token is saved to NVS flash. Use zbot config_reset to wipe it.
  • WiFi passphrase is stored in flash as plain text. Acceptable for dev boards.
  • NVS summary is stored as plain text. Avoid sensitive information in conversations.

⭐ Star History

⭐ If you like this project, give it a star!

Zbot alternatives

View more β†’

Similar ai agents in Other, ranked by GitHub stars. Compare licence, recent activity and scan status before you choose.

NameStarsLicenceLast updatedScan
Zbot (this page)
LingaoM
35Apache-2.0Apr 17, 2026Scanned, no flagged issues
Hermes Desktop
fathah
15kMITOct 13, 2026Scanned, no flagged issues
CubeSandbox
TencentCloud
13kNone foundNov 1, 2026Not scanned yet
Openchamber
openchamber
12kMITNov 1, 2026Scanned, no flagged issues
Open Swe
langchain-ai
11kMITNov 1, 2026Scanned, no flagged issues
Moltworker
cloudflare
9.9kApache-2.0May 9, 2026Scanned, no flagged issues