Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ set(EC_CORE_SOURCES
src/core/ec_session.c
src/core/ec_agent.c
src/core/ec_io.c
src/core/ec_skill.c
src/core/ec_skill_table.c
src/core/ec_capability.c
src/core/ec_capability_table.c
)

if(EC_PLATFORM STREQUAL "POSIX")
Expand Down Expand Up @@ -153,8 +153,8 @@ if(EC_PLATFORM STREQUAL "POSIX")
src/core/ec_io.c
src/platform/posix/ec_io_posix_uart.c
src/platform/posix/ec_io_posix_telnet.c
src/core/ec_skill.c
src/core/ec_skill_table.c
src/core/ec_capability.c
src/core/ec_capability_table.c
)

add_executable(embedclaw_tests
Expand All @@ -163,7 +163,7 @@ if(EC_PLATFORM STREQUAL "POSIX")
tests/test_e2e.c
)
target_include_directories(embedclaw_tests PRIVATE include tests)
# Tests use mock HTTP — force TLS off so ec_skill_table.c doesn't try
# Tests use mock HTTP — force TLS off so ec_capability_table.c doesn't try
# to include mbedTLS headers
target_compile_definitions(embedclaw_tests PRIVATE EC_CONFIG_USE_TLS=0)

Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ It is the embedded counterpart to OpenClaw — same agentic loop, same OpenAI to
│ │
▼ ▼
┌────────────┐ ┌─────────────────────────────────────┐
│ Model Adapter │ │ Skill System (ec_skill)
│ Model Adapter │ │ Capability Bundles (ec_capability)
│ (ec_model) │ │ ┌───────────────────────────────┐ │
│ provider │ │ │ hw_register_control │ │
│ selection │ │ │ hw_register_read/write │ │
Expand Down Expand Up @@ -83,7 +83,7 @@ It is the embedded counterpart to OpenClaw — same agentic loop, same OpenAI to
The source tree follows the same boundary:

```text
src/core/ Agent, model, HTTP, JSON, session, tools, skills
src/core/ Agent, model, HTTP, JSON, session, tools, capability bundles
src/platform/posix/ POSIX socket, stdin/stdout UART shim, Telnet, mock MMIO
src/platform/freertos/ FreeRTOS+TCP, UART HAL bridge, Telnet, direct MMIO
src/platform/baremetal/ UART HAL bridge, socket HAL bridge, direct MMIO
Expand Down Expand Up @@ -310,16 +310,16 @@ All limits are compile-time constants in `include/ec_config.h`:
| `EC_CONFIG_MAX_HISTORY` | `64` | Max messages in conversation history |
| `EC_CONFIG_MAX_TOOL_CALLS` | `4` | Max tool calls per LLM response |
| `EC_CONFIG_MAX_AGENT_ITERS` | `8` | Max tool-call iterations per turn |
| **Tool / skill framework** | | |
| **Tool / capability bundle framework** | | |
| `EC_CONFIG_MAX_TOOLS` | `16` | Max registered tools |
| `EC_CONFIG_MAX_SKILLS` | `16` | Max registered capability bundles |
| `EC_CONFIG_MAX_CAPABILITY_BUNDLES` | `16` | Max registered capability bundles |
| `EC_CONFIG_SYSTEM_PROMPT_BUF` | `2048` | Combined system prompt buffer (bytes) |
| **I/O layer** | | |
| `EC_CONFIG_IO_LINE_BUF` | `256` | User input line buffer (bytes) |
| `EC_CONFIG_TELNET_PORT` | `2323` | Telnet listen port |
| `EC_CONFIG_UART_RX_TIMEOUT_MS` | `100` | FreeRTOS UART read poll timeout (ms) |
| `EC_CONFIG_UART_TX_TIMEOUT_MS` | `1000` | FreeRTOS UART write timeout (ms) |
| **Web browsing skill** | | |
| **Web browsing capability bundle** | | |
| `EC_CONFIG_BRAVE_API_HOST` | `api.search.brave.com` | Brave Search API hostname |
| `EC_CONFIG_BRAVE_API_PORT` | `443` | Brave Search API port |
| `EC_CONFIG_BRAVE_API_KEY` | `BSA-CHANGE-ME` | Brave Search subscription token |
Expand Down Expand Up @@ -472,7 +472,7 @@ const ec_hw_module_t *EC_HW_MODULES = s_my_modules;
const size_t EC_HW_MODULE_COUNT = sizeof(s_my_modules) / sizeof(s_my_modules[0]);
```

Then include your header from `ec_skill_table.c` in place of `ec_hw_example_asic.h`.
Then include your header from `ec_capability_table.c` in place of `ec_hw_example_asic.h`.

---

Expand Down
31 changes: 12 additions & 19 deletions include/ec_skill.h → include/ec_capability.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef EC_SKILL_H
#define EC_SKILL_H
#ifndef EC_CAPABILITY_H
#define EC_CAPABILITY_H

#include "ec_tool.h"
#include "ec_config.h"
Expand All @@ -25,7 +25,7 @@ typedef enum {
* - tools[] — tool definitions registered with the tool
* framework and advertised to the LLM.
*
* Bundles are defined in ec_skill_table.c. That is the only file you
* Bundles are defined in ec_capability_table.c. That is the only file you
* need to edit to add, remove, or reconfigure capabilities.
*/
typedef struct {
Expand All @@ -38,44 +38,37 @@ typedef struct {
ec_capability_policy_t policy;
} ec_capability_bundle_t;

/* Backward-compatible alias while the rest of the codebase transitions. */
typedef ec_capability_bundle_t ec_skill_t;

/* -------------------------------------------------------------------------
* Skill table — defined in ec_skill_table.c, referenced here.
* Capability table — defined in ec_capability_table.c, referenced here.
* ------------------------------------------------------------------------- */

extern const ec_capability_bundle_t *EC_CAPABILITY_TABLE;
extern const size_t EC_CAPABILITY_TABLE_COUNT;

/* Backward-compatible aliases while callers migrate to the new terminology. */
#define EC_SKILL_TABLE EC_CAPABILITY_TABLE
#define EC_SKILL_TABLE_COUNT EC_CAPABILITY_TABLE_COUNT

/*
* Base system prompt — defined in ec_skill_table.c.
* Describes the device personality before any skill contexts are appended.
* Base system prompt — defined in ec_capability_table.c.
* Describes the device personality before any capability contexts are appended.
*/
extern const char EC_BASE_SYSTEM_PROMPT[];

/* -------------------------------------------------------------------------
* Skill framework API
* Capability bundle API
* ------------------------------------------------------------------------- */

/**
* Initialise the skill framework.
* Initialise the capability bundle framework.
* Iterates EC_CAPABILITY_TABLE, registers every tool with ec_tool, and builds
* the combined system prompt. Call once at startup before the agent loop.
*/
void ec_skill_init(void);
void ec_capability_init(void);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The ec_capability_init function currently returns void, but it performs several operations that could fail, such as registering tools (which can fail if the registry is full) and building the system prompt (which can fail if the buffer overflows). Consider returning an error code (e.g., int) to allow the caller to handle initialization failures gracefully, especially in an embedded context where silent truncation of the system prompt or missing tools can lead to confusing behavior.


/**
* Return the combined system prompt built by ec_skill_init():
* Return the combined system prompt built by ec_capability_init():
* EC_BASE_SYSTEM_PROMPT + each capability bundle's system_context/policy_note
* The returned pointer is to a static buffer valid for the lifetime of
* the program.
*/
const char *ec_skill_get_system_prompt(void);
const char *ec_capability_get_system_prompt(void);

const ec_capability_bundle_t *ec_capability_bundles(size_t *count);
const char *ec_capability_policy_name(ec_capability_policy_t policy);
Expand All @@ -84,4 +77,4 @@ const char *ec_capability_policy_name(ec_capability_policy_t policy);
}
#endif

#endif /* EC_SKILL_H */
#endif /* EC_CAPABILITY_H */
6 changes: 3 additions & 3 deletions include/ec_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@
#define EC_CONFIG_UART_RX_TIMEOUT_MS 100 /* FreeRTOS UART read poll timeout */
#define EC_CONFIG_UART_TX_TIMEOUT_MS 1000 /* FreeRTOS UART write timeout */

/* Skill layer */
/* Capability Bundle layer */
#define EC_CONFIG_SYSTEM_PROMPT_BUF 2048 /* combined system prompt buffer */
#define EC_CONFIG_MAX_SKILLS 16 /* max registered skills */
#define EC_CONFIG_MAX_CAPABILITY_BUNDLES 16 /* max registered capability bundles */

/* Web browsing skill */
/* Web browsing capability bundle */
#define EC_CONFIG_BRAVE_API_HOST "api.search.brave.com"
#define EC_CONFIG_BRAVE_API_PORT 443
#define EC_CONFIG_BRAVE_API_KEY "BSA-CHANGE-ME"
Expand Down
6 changes: 3 additions & 3 deletions include/ec_hw_datasheet.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
* 2. Define const arrays of ec_hw_bitfield_t, ec_hw_register_t, and
* ec_hw_module_t.
* 3. Define EC_HW_MODULES and EC_HW_MODULE_COUNT pointing to your tables.
* 4. Include the header from ec_skill_table.c (or set it via a CMake option).
* 4. Include the header from ec_capability_table.c (or set it via a CMake option).
*
* The hw_datasheet skill provides two tools that query these tables:
* The hw_datasheet capability bundle provides two tools that query these tables:
* hw_module_list — list all modules (name + description)
* hw_register_lookup — look up registers and bit fields in a module
*/
Expand Down Expand Up @@ -59,7 +59,7 @@ typedef struct {

/**
* These symbols must be defined by the ASIC-specific header.
* If no ASIC header is included, ec_skill_table.c provides empty defaults.
* If no ASIC header is included, ec_capability_table.c provides empty defaults.
*/
extern const ec_hw_module_t *EC_HW_MODULES;
extern const size_t EC_HW_MODULE_COUNT;
Expand Down
2 changes: 1 addition & 1 deletion include/ec_hw_example_asic.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* hw_module_list → lists all modules
* hw_register_lookup → returns registers and bit fields for a module
*
* Include this header from ec_skill_table.c to activate it.
* Include this header from ec_capability_table.c to activate it.
*/

#include "ec_hw_datasheet.h"
Expand Down
4 changes: 2 additions & 2 deletions include/ec_tool.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ int ec_tool_dispatch(const ec_model_tool_call_t *call,
*/
const ec_model_tool_def_t *ec_tool_model_defs(size_t *count);

/* Tool definitions and implementations live in ec_skill_table.c.
* Register them by calling ec_skill_init() at startup. */
/* Tool definitions and implementations live in ec_capability_table.c.
* Register them by calling ec_capability_init() at startup. */

#ifdef __cplusplus
}
Expand Down
18 changes: 9 additions & 9 deletions plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ The FreeRTOS backend remains stubbed, pending target hardware bring-up.
| JSON builder/parser | `ec_json.c/h` | Done (writer + path-based parser) |
| Chat API | `ec_api.c/h` | Done (text + tool_calls responses) |
| Tool framework | `ec_tool.c/h` | Done (registry + dispatcher) |
| Skill system | `ec_skill.c/h`, `ec_skill_table.c` | Done (compile-time skill bundles) |
| HW register skill | `ec_skill_table.c` | Done (read/write, POSIX mock array) |
| HW datasheet skill | `ec_skill_table.c`, `ec_hw_datasheet.h` | Done (module list, register lookup) |
| Web browsing skill | `ec_skill_table.c` | Done (web_search via Brave, web_fetch) |
| Capability bundle system | `ec_capability.c/h`, `ec_capability_table.c` | Done (compile-time capability bundles) |
| HW register capability bundle | `ec_capability_table.c` | Done (read/write, POSIX mock array) |
| HW datasheet capability bundle | `ec_capability_table.c`, `ec_hw_datasheet.h` | Done (module list, register lookup) |
| Web browsing capability bundle | `ec_capability_table.c` | Done (web_search via Brave, web_fetch) |
| Session layer | `ec_session.c/h` | Done (ring buffer, tool_call support) |
| Agent loop | `ec_agent.c/h` | Done (multi-iteration tool dispatch) |
| I/O abstraction | `ec_io.c/h` | Done |
Expand Down Expand Up @@ -84,10 +84,10 @@ server). I/O mode selected via `EC_IO` environment variable on POSIX.

---

### Phase 6 — Skill System ✅
### Phase 6 — Capability Bundle System ✅

**Completed.** Compile-time skill bundles in `ec_skill_table.c`. Each skill
registers tools and contributes system prompt context. Two built-in skills:
**Completed.** Compile-time capability bundles in `ec_capability_table.c`. Each capability bundle
registers tools and contributes system prompt context. Two built-in capability bundles:
`hw_register_control` and `web_browsing`.

---
Expand All @@ -107,7 +107,7 @@ verification. Certificate validation set to `MBEDTLS_SSL_VERIFY_REQUIRED`.

**Completed.** `web_search` tool calls the Brave Search API
(`GET /res/v1/web/search?q=...&count=N`). `web_fetch` tool performs HTTP GET on
arbitrary URLs. Both registered via the `web_browsing` skill with appropriate
arbitrary URLs. Both registered via the `web_browsing` capability bundle with appropriate
system context for the LLM.

---
Expand All @@ -127,7 +127,7 @@ dispatches, and agent loop iterations. All output goes to stderr.
query the ASIC register map on demand. Register descriptors are compile-time
const tables defined in `ec_hw_datasheet.h` structs. Each ASIC has its own
header (e.g., `ec_hw_example_asic.h` with UART0 and GPIO modules). The
`hw_datasheet` skill system context instructs the LLM to always look up
`hw_datasheet` capability bundle system context instructs the LLM to always look up
register details before reading/writing — no guessing addresses or bit layouts.

---
Expand Down
10 changes: 5 additions & 5 deletions spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protocol, different execution environment.
built in. mbedTLS is the only third-party dependency (for TLS/HTTPS).
- **OpenAI-compatible protocol**: Tool calls use the standard OpenAI
`tool_calls` JSON format. No custom protocol invented.
- **Extensible via skills**: New capabilities are added as skills — compile-time
- **Extensible via capability bundles**: New capabilities are added as capability bundles — compile-time
bundles that contribute tools and LLM system context.
- **Extensible I/O**: New input sources can be added without touching the agent
core.
Expand Down Expand Up @@ -64,7 +64,7 @@ protocol, different execution environment.
│ 1. Append user message to history │
│ 2. Send full history to LLM │
│ 3. Receive response │
│ 4. If tool_calls → dispatch to skill/tool layer │
│ 4. If tool_calls → dispatch to capability bundle/tool layer │
│ append tool results → go to 2 │
│ 5. If text response → send to user via I/O layer │
│ │
Expand All @@ -73,7 +73,7 @@ protocol, different execution environment.
│ │
▼ ▼
┌────────────────────┐ ┌─────────────────────────────┐
│ Chat API Layer │ │ Skill System (ec_skill)
│ Chat API Layer │ │ Capability Bundles (ec_capability)
│ (ec_api) │ │ ┌────────────────────────┐ │
│ JSON build/parse │ │ │ hw_register_control │ │
│ /v1/chat/complete │ │ │ hw_register_read/ │ │
Expand Down Expand Up @@ -214,7 +214,7 @@ int ec_tool_dispatch(const ec_api_tool_call_t *call, char *out_json, size_t out_
const ec_api_tool_def_t *ec_tool_api_defs(size_t *count);
```

### 6. Capability Bundle System (`ec_skill.h` / `ec_skill.c` / `ec_skill_table.c`)
### 6. Capability Bundle System (`ec_capability.h` / `ec_capability.c` / `ec_capability_table.c`)

Capability bundles are compile-time capability groups. Each bundle contributes:
- One or more tools (registered via `ec_tool_register`)
Expand Down Expand Up @@ -372,7 +372,7 @@ socket/TLS stack.
| `EC_CONFIG_MAX_TOOL_CALLS` | 4 | Max tool_calls in one LLM response |
| `EC_CONFIG_MAX_HISTORY` | 64 | Max messages in conversation history |
| `EC_CONFIG_MAX_TOOLS` | 16 | Max registered tools |
| `EC_CONFIG_MAX_SKILLS` | 16 | Max registered capability bundles |
| `EC_CONFIG_MAX_CAPABILITY_BUNDLES` | 16 | Max registered capability bundles |
| `EC_CONFIG_MAX_AGENT_ITERS` | 8 | Max agentic loop iterations per turn |

---
Expand Down
8 changes: 4 additions & 4 deletions src/app/ec_posix_main.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "ec_model.h"
#include "ec_agent.h"
#include "ec_session.h"
#include "ec_skill.h"
#include "ec_capability.h"
#include "ec_io.h"
#include "ec_config.h"
#include "ec_log.h"
Expand All @@ -18,10 +18,10 @@ static void run_agent_loop(const ec_model_config_t *config, const char *model)
/* Initialise debug logging (checks EC_DEBUG env on POSIX) */
ec_log_init();

/* Initialise skills: registers all tools and builds the system prompt */
ec_skill_init();
/* Initialise capability bundles: registers all tools and builds the system prompt */
ec_capability_init();

ec_session_init(&s_session, ec_skill_get_system_prompt());
ec_session_init(&s_session, ec_capability_get_system_prompt());
ec_agent_init(&s_agent, config, model, &s_session);

char line[EC_CONFIG_IO_LINE_BUF];
Expand Down
6 changes: 3 additions & 3 deletions src/core/ec_skill.c → src/core/ec_capability.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "ec_skill.h"
#include "ec_capability.h"

#include <string.h>
#include <stdio.h>
Expand Down Expand Up @@ -27,7 +27,7 @@ const ec_capability_bundle_t *ec_capability_bundles(size_t *count)
return EC_CAPABILITY_TABLE;
}

void ec_skill_init(void)
void ec_capability_init(void)
{
/* Build combined system prompt */
memset(s_system_prompt, 0, sizeof(s_system_prompt));
Expand Down Expand Up @@ -69,7 +69,7 @@ void ec_skill_init(void)
}
}

const char *ec_skill_get_system_prompt(void)
const char *ec_capability_get_system_prompt(void)
{
return s_system_prompt;
}
6 changes: 3 additions & 3 deletions src/core/ec_skill_table.c → src/core/ec_capability_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
* ============================================================================
*/

#include "ec_skill.h"
#include "ec_capability.h"
#include "ec_hw_access.h"
#include "ec_mmio.h"
#include "ec_json.h"
Expand All @@ -34,7 +34,7 @@
/* ============================================================================
* Base system prompt
*
* Describes the device personality before any skill contexts are appended.
* Describes the device personality before any capability bundle contexts are appended.
* Edit this string to change the overall agent behaviour.
* ============================================================================ */

Expand Down Expand Up @@ -746,7 +746,7 @@ static const ec_capability_bundle_t s_capability_table[] = {

};

/* Exported symbols referenced by ec_skill.c */
/* Exported symbols referenced by ec_capability.c */
const ec_capability_bundle_t *EC_CAPABILITY_TABLE = s_capability_table;
const size_t EC_CAPABILITY_TABLE_COUNT =
sizeof(s_capability_table) / sizeof(s_capability_table[0]);
4 changes: 2 additions & 2 deletions src/core/ec_tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
* Tool registry and dispatcher.
*
* This file is pure infrastructure — it knows nothing about specific tools.
* All tool definitions and implementations live in ec_skill_table.c and are
* registered via ec_skill_init() at startup.
* All tool definitions and implementations live in ec_capability_table.c and are
* registered via ec_capability_init() at startup.
* ========================================================================= */

static const ec_tool_def_t *s_tools[EC_CONFIG_MAX_TOOLS];
Expand Down
Loading
Loading