From bee07b74aa029edf4a7a9355c78e402a51aa06e7 Mon Sep 17 00:00:00 2001 From: Asklv Date: Thu, 26 Feb 2026 10:00:00 +0800 Subject: [PATCH 1/6] feat: add weather skill as SPIFFS markdown Signed-off-by: Asklv --- spiffs_data/skills/weather.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 spiffs_data/skills/weather.md diff --git a/spiffs_data/skills/weather.md b/spiffs_data/skills/weather.md new file mode 100644 index 0000000..e6e2d30 --- /dev/null +++ b/spiffs_data/skills/weather.md @@ -0,0 +1,18 @@ +# Weather + +Get current weather and forecasts using web_search. + +## When to use +When the user asks about weather, temperature, or forecasts. + +## How to use +1. Use get_current_time to know the current date +2. Use web_search with a query like "weather in [city] today" +3. Extract temperature, conditions, and forecast from results +4. Present in a concise, friendly format + +## Example +User: "What's the weather in Tokyo?" +→ get_current_time +→ web_search "weather Tokyo today February 2026" +→ "Tokyo: 8°C, partly cloudy. High 12°C, low 4°C. Light wind from the north." From 92289e91222195b37a4024d9cf5b91ae5b882220 Mon Sep 17 00:00:00 2001 From: Asklv Date: Thu, 26 Feb 2026 11:00:00 +0800 Subject: [PATCH 2/6] feat: add daily-briefing skill as SPIFFS markdown Signed-off-by: Asklv --- spiffs_data/skills/daily-briefing.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 spiffs_data/skills/daily-briefing.md diff --git a/spiffs_data/skills/daily-briefing.md b/spiffs_data/skills/daily-briefing.md new file mode 100644 index 0000000..5e736ca --- /dev/null +++ b/spiffs_data/skills/daily-briefing.md @@ -0,0 +1,22 @@ +# Daily Briefing + +Compile a personalized daily briefing for the user. + +## When to use +When the user asks for a daily briefing, morning update, or "what's new today". +Also useful as a heartbeat/cron task. + +## How to use +1. Use get_current_time for today's date +2. Read /spiffs/memory/MEMORY.md for user preferences and context +3. Read today's daily note if it exists +4. Use web_search for relevant news based on user interests +5. Compile a concise briefing covering: + - Date and time + - Weather (if location known from USER.md) + - Relevant news/updates based on user interests + - Any pending tasks from memory + - Any scheduled cron jobs + +## Format +Keep it brief — 5-10 bullet points max. Use the user's preferred language. From 729b0f0eb883aed78bf5b4e50702dd9bd597fa51 Mon Sep 17 00:00:00 2001 From: Asklv Date: Thu, 26 Feb 2026 14:00:00 +0800 Subject: [PATCH 3/6] feat: add skill-creator skill as SPIFFS markdown Signed-off-by: Asklv --- spiffs_data/skills/skill-creator.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 spiffs_data/skills/skill-creator.md diff --git a/spiffs_data/skills/skill-creator.md b/spiffs_data/skills/skill-creator.md new file mode 100644 index 0000000..2b0e82a --- /dev/null +++ b/spiffs_data/skills/skill-creator.md @@ -0,0 +1,27 @@ +# Skill Creator + +Create new skills for MimiClaw. + +## When to use +When the user asks to create a new skill, teach the bot something, or add a new capability. + +## How to create a skill +1. Choose a short, descriptive name (lowercase, hyphens ok) +2. Write a SKILL.md file with this structure: + - `# Title` — clear name + - Brief description paragraph + - `## When to use` — trigger conditions + - `## How to use` — step-by-step instructions + - `## Example` — concrete example (optional but helpful) +3. Save to `/spiffs/skills/.md` using write_file +4. The skill will be automatically available after the next conversation + +## Best practices +- Keep skills concise — the context window is limited +- Focus on WHAT to do, not HOW (the agent is smart) +- Include specific tool calls the agent should use +- Test by asking the agent to use the new skill + +## Example +To create a "translate" skill: +write_file path="/spiffs/skills/translate.md" content="# Translate\n\nTranslate text between languages.\n\n## When to use\nWhen the user asks to translate text.\n\n## How to use\n1. Identify source and target languages\n2. Translate directly using your language knowledge\n3. For specialized terms, use web_search to verify\n" From f8b2a20c7a3bd04be18435c8f9c0b7bab792ef58 Mon Sep 17 00:00:00 2001 From: Asklv Date: Thu, 26 Feb 2026 16:00:00 +0800 Subject: [PATCH 4/6] refactor: remove hardcoded BUILTIN_* skill string macros Signed-off-by: Asklv --- main/skills/skill_loader.c | 96 ++------------------------------------ 1 file changed, 4 insertions(+), 92 deletions(-) diff --git a/main/skills/skill_loader.c b/main/skills/skill_loader.c index 0dc5e67..ec52720 100644 --- a/main/skills/skill_loader.c +++ b/main/skills/skill_loader.c @@ -8,98 +8,10 @@ static const char *TAG = "skills"; -/* ── Built-in skill contents ─────────────────────────────────── */ - -#define BUILTIN_WEATHER \ - "# Weather\n" \ - "\n" \ - "Get current weather and forecasts using web_search.\n" \ - "\n" \ - "## When to use\n" \ - "When the user asks about weather, temperature, or forecasts.\n" \ - "\n" \ - "## How to use\n" \ - "1. Use get_current_time to know the current date\n" \ - "2. Use web_search with a query like \"weather in [city] today\"\n" \ - "3. Extract temperature, conditions, and forecast from results\n" \ - "4. Present in a concise, friendly format\n" \ - "\n" \ - "## Example\n" \ - "User: \"What's the weather in Tokyo?\"\n" \ - "→ get_current_time\n" \ - "→ web_search \"weather Tokyo today February 2026\"\n" \ - "→ \"Tokyo: 8°C, partly cloudy. High 12°C, low 4°C. Light wind from the north.\"\n" - -#define BUILTIN_DAILY_BRIEFING \ - "# Daily Briefing\n" \ - "\n" \ - "Compile a personalized daily briefing for the user.\n" \ - "\n" \ - "## When to use\n" \ - "When the user asks for a daily briefing, morning update, or \"what's new today\".\n" \ - "Also useful as a heartbeat/cron task.\n" \ - "\n" \ - "## How to use\n" \ - "1. Use get_current_time for today's date\n" \ - "2. Read " MIMI_SPIFFS_MEMORY_DIR "/MEMORY.md for user preferences and context\n" \ - "3. Read today's daily note if it exists\n" \ - "4. Use web_search for relevant news based on user interests\n" \ - "5. Compile a concise briefing covering:\n" \ - " - Date and time\n" \ - " - Weather (if location known from USER.md)\n" \ - " - Relevant news/updates based on user interests\n" \ - " - Any pending tasks from memory\n" \ - " - Any scheduled cron jobs\n" \ - "\n" \ - "## Format\n" \ - "Keep it brief — 5-10 bullet points max. Use the user's preferred language.\n" - -#define BUILTIN_SKILL_CREATOR \ - "# Skill Creator\n" \ - "\n" \ - "Create new skills for MimiClaw.\n" \ - "\n" \ - "## When to use\n" \ - "When the user asks to create a new skill, teach the bot something, or add a new capability.\n" \ - "\n" \ - "## How to create a skill\n" \ - "1. Choose a short, descriptive name (lowercase, hyphens ok)\n" \ - "2. Write a SKILL.md file with this structure:\n" \ - " - `# Title` — clear name\n" \ - " - Brief description paragraph\n" \ - " - `## When to use` — trigger conditions\n" \ - " - `## How to use` — step-by-step instructions\n" \ - " - `## Example` — concrete example (optional but helpful)\n" \ - "3. Save to `" MIMI_SKILLS_PREFIX ".md` using write_file\n" \ - "4. The skill will be automatically available after the next conversation\n" \ - "\n" \ - "## Best practices\n" \ - "- Keep skills concise — the context window is limited\n" \ - "- Focus on WHAT to do, not HOW (the agent is smart)\n" \ - "- Include specific tool calls the agent should use\n" \ - "- Test by asking the agent to use the new skill\n" \ - "\n" \ - "## Example\n" \ - "To create a \"translate\" skill:\n" \ - "write_file path=\"" MIMI_SKILLS_PREFIX "translate.md\" content=\"# Translate\\n\\nTranslate text between languages.\\n\\n" \ - "## When to use\\nWhen the user asks to translate text.\\n\\n" \ - "## How to use\\n1. Identify source and target languages\\n" \ - "2. Translate directly using your language knowledge\\n" \ - "3. For specialized terms, use web_search to verify\\n\"\n" - -/* Built-in skill registry */ -typedef struct { - const char *filename; /* e.g. "weather" */ - const char *content; -} builtin_skill_t; - -static const builtin_skill_t s_builtins[] = { - { "weather", BUILTIN_WEATHER }, - { "daily-briefing", BUILTIN_DAILY_BRIEFING }, - { "skill-creator", BUILTIN_SKILL_CREATOR }, -}; - -#define NUM_BUILTINS (sizeof(s_builtins) / sizeof(s_builtins[0])) +/* + * Built-in skills are now stored as markdown files in spiffs_data/skills/ + * and pre-flashed into the SPIFFS partition at build time. + */ /* ── Install built-in skills if missing ──────────────────────── */ From fc17355640e242e4fb409f906b3ac8d6334f4cca Mon Sep 17 00:00:00 2001 From: Asklv Date: Fri, 27 Feb 2026 10:00:00 +0800 Subject: [PATCH 5/6] refactor: replace install_builtin with SPIFFS directory scan Signed-off-by: Asklv --- main/skills/skill_loader.c | 47 ++++++++++++++------------------------ 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/main/skills/skill_loader.c b/main/skills/skill_loader.c index ec52720..1be6a78 100644 --- a/main/skills/skill_loader.c +++ b/main/skills/skill_loader.c @@ -13,42 +13,29 @@ static const char *TAG = "skills"; * and pre-flashed into the SPIFFS partition at build time. */ -/* ── Install built-in skills if missing ──────────────────────── */ - -static void install_builtin(const builtin_skill_t *skill) -{ - char path[64]; - snprintf(path, sizeof(path), "%s%s.md", MIMI_SKILLS_PREFIX, skill->filename); - - /* Check if already exists */ - FILE *f = fopen(path, "r"); - if (f) { - fclose(f); - ESP_LOGD(TAG, "Skill exists: %s", path); - return; - } - - /* Write built-in skill */ - f = fopen(path, "w"); - if (!f) { - ESP_LOGE(TAG, "Cannot write skill: %s", path); - return; - } - - fputs(skill->content, f); - fclose(f); - ESP_LOGI(TAG, "Installed built-in skill: %s", path); -} - esp_err_t skill_loader_init(void) { ESP_LOGI(TAG, "Initializing skills system"); - for (size_t i = 0; i < NUM_BUILTINS; i++) { - install_builtin(&s_builtins[i]); + DIR *dir = opendir(MIMI_SPIFFS_BASE); + if (!dir) { + ESP_LOGW(TAG, "Cannot open SPIFFS — skills may not be available"); + return ESP_OK; } - ESP_LOGI(TAG, "Skills system ready (%d built-in)", (int)NUM_BUILTINS); + int count = 0; + struct dirent *ent; + while ((ent = readdir(dir)) != NULL) { + const char *name = ent->d_name; + size_t len = strlen(name); + if (strncmp(name, "skills/", 7) == 0 && len > 10 && + strcmp(name + len - 3, ".md") == 0) { + count++; + } + } + closedir(dir); + + ESP_LOGI(TAG, "Skills system ready (%d skills on SPIFFS)", count); return ESP_OK; } From 77fb31d6bd2b02364bb7867b888bffafc328d0e8 Mon Sep 17 00:00:00 2001 From: Asklv Date: Fri, 27 Feb 2026 14:00:00 +0800 Subject: [PATCH 6/6] chore: clean up skill_loader comments and extract_title signature Signed-off-by: Asklv --- main/skills/skill_loader.c | 11 +++++------ main/skills/skill_loader.h | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/main/skills/skill_loader.c b/main/skills/skill_loader.c index 1be6a78..f140f37 100644 --- a/main/skills/skill_loader.c +++ b/main/skills/skill_loader.c @@ -9,8 +9,8 @@ static const char *TAG = "skills"; /* - * Built-in skills are now stored as markdown files in spiffs_data/skills/ - * and pre-flashed into the SPIFFS partition at build time. + * Skills are stored as markdown files in spiffs_data/skills/ + * and flashed into the SPIFFS partition at build time. */ esp_err_t skill_loader_init(void) @@ -42,10 +42,10 @@ esp_err_t skill_loader_init(void) /* ── Build skills summary for system prompt ──────────────────── */ /** - * Parse first line as title: expects "# Title" - * Returns pointer past "# " or the line itself if no prefix. + * Parse first line as title: expects "# Title". + * Writes the title (without "# " prefix) into out. */ -static const char *extract_title(const char *line, size_t len, char *out, size_t out_size) +static void extract_title(const char *line, size_t len, char *out, size_t out_size) { const char *start = line; if (len >= 2 && line[0] == '#' && line[1] == ' ') { @@ -61,7 +61,6 @@ static const char *extract_title(const char *line, size_t len, char *out, size_t size_t copy = len < out_size - 1 ? len : out_size - 1; memcpy(out, start, copy); out[copy] = '\0'; - return out; } /** diff --git a/main/skills/skill_loader.h b/main/skills/skill_loader.h index 54759d4..895c234 100644 --- a/main/skills/skill_loader.h +++ b/main/skills/skill_loader.h @@ -5,7 +5,7 @@ /** * Initialize skills system. - * Installs built-in skill files to SPIFFS if they don't already exist. + * Scans SPIFFS for available skill markdown files. */ esp_err_t skill_loader_init(void);