Summary
mavis skill show <name> returns "description": "" even when the on-disk SKILL.md has a clean YAML frontmatter block, the corresponding row exists in ~/.minimax/sqlite.db with the right description, and the agent tool can load the skill once prompted. The desktop daemon's in-memory skillIndex is populated only once at boot and is never refreshed when an already-indexed skill's file is rewritten.
Steps to reproduce
-
Open MiniMax Code.app so the desktop daemon (PID 53290 in our environment) is up.
-
Pick any skill whose SKILL.md originally lacked a YAML frontmatter block. The shipped bundle ships at least one (e.g. secure-by-design-review) and the legacy # Skill: header shape is easy to introduce by importing a marketplace bundle written before the YAML contract landed.
-
Rewrite the file to add a canonical frontmatter block, save the file.
-
Re-run the same query without restarting the app:
$ mavis skill show secure-by-design-review | jq .description
""
$ mavis skill ls mavis | jq '.skills[] | select(.name == "secure-by-design-review").description'
null
$ sqlite3 ~/.minimax/sqlite.db \
"SELECT length(description) FROM skills WHERE name='secure-by-design-review';"
142
$ # But the agent tool *can* load it:
$ # claude /skill secure-by-design-review -> works
Expected
mavis skill show should return the on-disk description (or the row description, whichever wins) without a daemon restart.
Actual
show keeps returning "" until the daemon is restarted (launchctl kickstart -k gui/$UID/com.mavis.daemon on macOS). A clean restart sometimes still fails with Cannot find module 'better-sqlite3' in ~/.minavis/logs/launchd-stderr.log until MAVIS_SQLITE3_MODULE_PATH is exported to the app.asar.unpacked directory.
Root cause (reverse-engineered from MiniMax Code.app/Contents/Resources/resources/daemon/daemon.js)
In packages/skill/dist/skill.js (extracted from the bundled daemon.js):
async readSkill(req) {
const { skill_name, agent_name } = req;
// ... (fs lookup chain)
const meta = this.skillIndex.get(skill_name, actualAgentName); // in-memory cache
const fallback = meta ? null : this.frontmatterFallback(content);
const description2 = meta?.description ?? fallback?.description ?? "";
// ...
}
skillIndex is hydrated at daemon boot from ~/.minimax/sqlite.db. Two failure modes compound:
- Boot-scan skip. If the file lacks valid YAML frontmatter at boot time, the indexer silently drops the row (the description is empty string). Without a row in
skills, every later API hit falls through to frontmatterFallback(content), which also yields "".
- Cache staleness. Even when a row is later
INSERT-ed by hand into skills, the running daemon never refreshes its in-memory skillIndex. The skill is invisible to the agent tool until restart.
Workaround (validated end-to-end on 2026-07-04)
A community skill patch is already in flight — see MiniMax-AI/skills#107 which adds skill-hygiene plus a reference doc with three recovery paths. The cleanest one is:
mavis skill update <name> -a mavis --file <absolute-path-to-SKILL.md>
This invokes the file-watcher's onSkillFileChange handler in the daemon, which calls this.skillIndex.upsert(...) and brings the in-memory cache back in sync without restarting the desktop app.
A launchctl kickstart -k gui/$UID/com.mavis.daemon also works but forces the user to relaunch the whole UI; see workaround doc for MAVIS_SQLITE3_MODULE_PATH export if you go that route.
Proposed fix in the daemon
Two minimum-touch changes:
- Boot-scan must retry on
frontmatterFallback. If parsed?.description is empty and the file has a # Skill: style header, attempt a tolerant fallback parse (regex over the first five lines, same algorithm as the community script) before giving up on the file.
- File-watch must upsert on every change. The current
onSkillFileChange already calls this.skillIndex.upsert(...) when content changes — but the upsert guard rejects rows whose description is empty. Drop that guard, or better, fall back to the tolerant parse above whenever parsed?.description is empty.
A third, larger change is a mavis skill reindex [--agent <name>] [--skill <ref>] CLI command so contributors can recover from cache drift without a restart at all.
Environment
- Product:
MiniMax Code.app (bundle id com.minimax.agent)
- Daemon PID 53290 launched by the Electron app with
--port 15321 --owner electron --skip-pid-port
- macOS 15.x, Apple Silicon
- ~/.minimax/sqlite.db size ~39 MB, schema includes
skills (PK name+agent_name), skill_hub, skill_hub_added
- Reproduced on
secure-by-design-review and 48 other SKILL.md files in the bundled ~/.minimax/skills/
Severity
Medium — the agent tool still loads the skill through available_skills once the user mentions it, but any tooling built on top of mavis skill show (publishing, marketplace linting, contribution checks) is silently broken until restart.
Summary
mavis skill show <name>returns"description": ""even when the on-diskSKILL.mdhas a clean YAML frontmatter block, the corresponding row exists in~/.minimax/sqlite.dbwith the right description, and the agent tool can load the skill once prompted. The desktop daemon's in-memoryskillIndexis populated only once at boot and is never refreshed when an already-indexed skill's file is rewritten.Steps to reproduce
Open
MiniMax Code.appso the desktop daemon (PID 53290 in our environment) is up.Pick any skill whose
SKILL.mdoriginally lacked a YAML frontmatter block. The shipped bundle ships at least one (e.g.secure-by-design-review) and the legacy# Skill:header shape is easy to introduce by importing a marketplace bundle written before the YAML contract landed.Rewrite the file to add a canonical frontmatter block, save the file.
Re-run the same query without restarting the app:
Expected
mavis skill showshould return the on-disk description (or the row description, whichever wins) without a daemon restart.Actual
showkeeps returning""until the daemon is restarted (launchctl kickstart -k gui/$UID/com.mavis.daemonon macOS). A clean restart sometimes still fails withCannot find module 'better-sqlite3'in~/.minavis/logs/launchd-stderr.loguntilMAVIS_SQLITE3_MODULE_PATHis exported to theapp.asar.unpackeddirectory.Root cause (reverse-engineered from
MiniMax Code.app/Contents/Resources/resources/daemon/daemon.js)In
packages/skill/dist/skill.js(extracted from the bundleddaemon.js):skillIndexis hydrated at daemon boot from~/.minimax/sqlite.db. Two failure modes compound:skills, every later API hit falls through tofrontmatterFallback(content), which also yields"".INSERT-ed by hand intoskills, the running daemon never refreshes its in-memoryskillIndex. The skill is invisible to the agent tool until restart.Workaround (validated end-to-end on 2026-07-04)
A community skill patch is already in flight — see
MiniMax-AI/skills#107which addsskill-hygieneplus a reference doc with three recovery paths. The cleanest one is:This invokes the file-watcher's
onSkillFileChangehandler in the daemon, which callsthis.skillIndex.upsert(...)and brings the in-memory cache back in sync without restarting the desktop app.A
launchctl kickstart -k gui/$UID/com.mavis.daemonalso works but forces the user to relaunch the whole UI; see workaround doc forMAVIS_SQLITE3_MODULE_PATHexport if you go that route.Proposed fix in the daemon
Two minimum-touch changes:
frontmatterFallback. Ifparsed?.descriptionis empty and the file has a# Skill:style header, attempt a tolerant fallback parse (regex over the first five lines, same algorithm as the community script) before giving up on the file.onSkillFileChangealready callsthis.skillIndex.upsert(...)when content changes — but the upsert guard rejects rows whosedescriptionis empty. Drop that guard, or better, fall back to the tolerant parse above wheneverparsed?.descriptionis empty.A third, larger change is a
mavis skill reindex [--agent <name>] [--skill <ref>]CLI command so contributors can recover from cache drift without a restart at all.Environment
MiniMax Code.app(bundle idcom.minimax.agent)--port 15321 --owner electron --skip-pid-portskills(PK name+agent_name),skill_hub,skill_hub_addedsecure-by-design-reviewand 48 other SKILL.md files in the bundled~/.minimax/skills/Severity
Medium — the agent tool still loads the skill through
available_skillsonce the user mentions it, but any tooling built on top ofmavis skill show(publishing, marketplace linting, contribution checks) is silently broken until restart.