Skip to content
Open
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Development skills for AI coding agents. Plug into your favorite AI coding tool
| `minimax-music-gen` | Generate vocal songs, instrumentals, and covers using MiniMax Music API. Two modes: Basic (one-liner in, song out) and Advanced Control (edit lyrics, refine prompt, plan structure). Supports lyrics generation, style vocabulary, streaming playback, and iterative feedback. | Official |
| `buddy-sings` | Let your Claude Code pet (/buddy) sing a personalized song. Interprets the pet's name and personality into a unique cached vocal identity, auto-gathers context (conversation, memory, git history) for themed lyrics, and generates music via minimax-music-gen. | Official |
| `minimax-music-playlist` | Generate personalized playlists by analyzing your music taste. Builds a taste profile (genre, mood, language, vocal preferences), plans a themed tracklist, generates songs with album cover art, and refines the profile from feedback. | Official |
| `skill-hygiene` | Detect and repair SKILL.md files that are missing YAML frontmatter (the legacy `# Skill:` shape), plus work around the `MiniMax Code` daemon cache bug where `mavis skill show` keeps returning `"description": ""` until the file is re-published. Use when a skill vanishes from the agent tool or shows up with an empty description. | Community |

## Installation

Expand Down
1 change: 1 addition & 0 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
| `minimax-music-gen` | 使用 MiniMax Music API 生成人声歌曲、纯音乐和翻唱。支持基础模式(一句话生成)和强控制模式(编辑歌词、调整 prompt、规划曲式)。内置歌词生成、风格词表、流式播放和迭代反馈。 | Official |
| `buddy-sings` | 让你的 Claude Code 宠物(/buddy)唱一首专属歌曲。根据宠物名字和个性生成独特声线并缓存,自动采集上下文(对话、记忆、git 历史)生成主题歌词,调用 minimax-music-gen 完成创作。 | Official |
| `minimax-music-playlist` | 分析用户音乐品味生成个性化歌单。构建音乐画像(曲风、情绪、语言、声线偏好),规划主题曲目,生成歌曲与专辑封面,根据反馈持续优化画像。 | Official |
| `skill-hygiene` | 检测并修复缺失 YAML frontmatter(遗留 `# Skill:` 格式)的 SKILL.md 文件,并提供 `MiniMax Code` 守护进程缓存缺陷的绕过方案:当 `mavis skill show` 持续返回 `"description": ""` 时,需要重新发布文件才能让内存中的 `skillIndex` 同步。适用于技能从 agent 工具中消失或 description 为空的场景。 | Community |

## 安装

Expand Down
182 changes: 182 additions & 0 deletions skills/skill-hygiene/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
---
name: skill-hygiene
description: |
Detect and repair broken SKILL.md files used by MiniMax Code and other
MiniMax plugin hosts, plus work around a known in-memory cache bug in
the desktop daemon (`mavis skill show` returns an empty description
for skills that were originally scanned without valid YAML frontmatter).
Use when: (a) `mavis skill ls` lists a skill with an empty description,
(b) `mavis skill show <name>` returns `"description": ""` even though
the file on disk has a clean `--- name/description ---` block,
(c) the agent tool fails to load a skill that is present on disk, or
(d) auditing a skills folder before publishing a new skill collection.
license: MIT
metadata:
version: "1.0.0"
category: meta
audience: skill-authors, contributors, ops
sources:
- MiniMax Code desktop daemon (com.minimax.agent) — bundle reverse engineering during
smoke test on 2026-07-04 (MiniMax Team, San Francisco).
- Gray-matter / YAML frontmatter convention used by Anthropic's
claude-code skill plugins and adopted by MiniMax plugins.
---

# Skill Hygiene

MiniMax Code, OpenCode, Cursor, Claude Code and Codex all read agent
skills from a flat directory of `SKILL.md` files. When those files
break the YAML-frontmatter contract, three failure modes appear:

1. The boot-time indexer skips the skill entirely. `mavis skill ls`
then shows the skill with an empty `description` (or omits it from
`/api/agent/:name/skill`).
2. `mavis skill show <name>` returns a stale empty response because
the daemon keeps an in-memory copy that pre-dates the on-disk fix
(`packages/skill/dist/skill.js` — `this.skillIndex.get(...)`
fallback chain at line 80). The on-disk SKILL.md is correct, but
the daemon will not refresh it until you restart the desktop
client or push an explicit `mavis skill update`.
3. The agent tool cannot load the skill because `available_skills`
were never injected into the system prompt at boot.

This skill gives you a one-shot scanner + repair script for case 1
and the exact commands to recover from cases 2 and 3 without
restarting the whole desktop app.

## When to invoke

Trigger this skill the moment you see any of:

```
$ mavis skill ls mavis | jq '.skills[] | select(.description == "")'
"secure-by-design-review"
```

```
$ mavis skill show secure-by-design-review | jq .description
""
```

```
$ claude /skill secure-by-design-review
skill_not_found
```

Do **not** invoke it for routine content edits — frontmatter is the
only thing this skill touches.

## Quick start

```bash
# 1. Audit (read-only) — see which SKILL.md files are missing or have
# invalid YAML frontmatter.
python3 scripts/fix-skill-frontmatter.py --dry \
--skills-dir ~/.minimax/skills
python3 scripts/fix-skill-frontmatter.py --dry \
--skills-dir ~/.minimax/agents/mavis/skills

# 2. Apply the fix in place (atomic write per file).
SKILLS_DIR=~/.minimax/skills python3 scripts/fix-skill-frontmatter.py
SKILLS_DIR=~/.minimax/agents/mavis/skills python3 scripts/fix-skill-frontmatter.py

# 3. Re-scan with the daemon. Use `mavis skill update --file <path>`
# for each repair so the in-memory `skillIndex` catches up
# *without* a desktop restart.
mavis skill update secure-by-design-review \
-a mavis \
--file ~/.minimax/skills/secure-by-design-review/SKILL.md
```

The script recognises two frontmatter shapes used in the wild and
repairs both. It only modifies files that genuinely need fixing, and
it never touches the body content below the frontmatter.

## Recognised shapes

**Shape A — correct frontmatter** (left alone):

```markdown
---
name: example
description: One-line summary that includes trigger conditions.
---

# Example skill
```

**Shape B — legacy human-readable header** (repaired):

```markdown
# Skill: Example

name: example
description: One-line summary that includes trigger conditions.

## Workflow
```

Shape B is what the MiniMax desktop daemon emits when a skill is
installed from a marketplace bundle where the original author skipped
the YAML block. The daemon silently indexes it with `description=""`
and the entry then disappears from `mavis skill ls` after the first
crash or restart.

## Repair algorithm

The script is intentionally trivial so it is auditable in one read:

1. Read the first 5 lines.
2. If line 1 starts with `---`, treat the file as already valid.
3. Else, if line 1 starts with `# Skill:`, extract `name:` and
`description:` from lines 1–5, prepend a fresh frontmatter block,
drop the duplicate `name:` / `description:` lines, and atomically
rewrite the file.
4. Else, abort with a clear "unknown shape" error and **do not**
touch the file.

No diffs, no merges, no opt-in flags beyond `--dry`.

## Cache recovery (case 2)

`mavis skill show` reads from an in-memory `skillIndex` that hydrates
once at daemon boot from `~/.minimax/sqlite.db`. Even after a clean
on-disk repair, the daemon will keep returning the stale empty
description until you kick the index. Two recovery paths:

```bash
# Path A — preferred. Re-publish the file through the CLI so the
# daemon re-runs the file-watcher upsert path.
mavis skill update <skill-name> -a mavis \
--file <absolute-path-to-SKILL.md>

# Path B — last resort. Force the desktop app to restart.
launchctl kickstart -k gui/$(id -u)/com.mavis.daemon
```

`launchctl kickstart` is a sledgehammer — it tears down a live
daemon and can produce `MODULE_NOT_FOUND` noise in
`~/.minimax/logs/launchd-stderr.log` if it cannot resolve
`better-sqlite3` (set `MAVIS_SQLITE3_MODULE_PATH` to
`/Applications/MiniMax Code.app/Contents/Resources/app.asar.unpacked`
to force the right `node_modules` lookup). Path A avoids all of that.

## Files

| Path | Purpose |
|------|---------|
| `scripts/fix-skill-frontmatter.py` | Audit + repair script (pure stdlib). |
| `references/daemon-cache-workaround.md` | Deep dive on the cache bug and the recovery paths. |

## Limits

- The script only repairs SKILL.md files whose first line is `# Skill:`.
Files with a different preamble are reported and left untouched —
the goal is to be boring and reviewable, not magical.
- The repair is a structural rewrite — it does not retry every front
edge case (anchor names, multi-line scalars, escaping). If you
author skills with exotic YAML, validate them yourself.
- The cache-recovery instructions target `MiniMax Code.app` on macOS.
Adjust the `launchctl` label for the local platform.
151 changes: 151 additions & 0 deletions skills/skill-hygiene/references/daemon-cache-workaround.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Daemon cache workaround — `mavis skill show` returning an empty `description`

This reference documents a reproducible interaction between
`MiniMax Code.app` (the desktop daemon, bundle id `com.mavis.daemon`,
distribution bundle `MiniMax Code.app/Contents/Resources/resources/daemon/`),
its SQLite index, and the in-memory `skillIndex` that the daemon uses
to serve `mavis skill show`. The bug was reverse-engineered from the
shipped `daemon.js` bundle during the July 2026 smoke test and the
recovery steps below are what make `secure-by-design-review` —
presently affected — visible again without restarting the whole
desktop app.

## Symptoms

```bash
$ mavis skill show secure-by-design-review | jq .description
"" # empty even though the on-disk file is correct
```

```bash
$ mavis skill ls mavis | jq '.skills[] | select(.description == "") | .name'
"a-long-list-of-fantasies" # many skills are affected by the same bug
```

```bash
$ sqlite3 ~/.minimax/sqlite.db \
"SELECT name, agent_name, length(description) FROM skills WHERE description='';"
# ... above may be empty for the agent `mavis` even though `show` is empty
```

## Root cause

Three things conspire:

1. The desktop daemon reads `SKILL.md` at boot to populate an
in-memory `skillIndex`. When the YAML frontmatter block is
missing or malformed, the indexer logs the skill as
`description=""` and the row never gets upserted into the
`skills` table of `~/.minimax/sqlite.db`.
2. `mavis skill show` returns what the in-memory `skillIndex` says.
It does **not** re-parse the file from disk on every request —
it only falls back to the file when the index entry does not
exist (`packages/skill/dist/skill.js` — `readSkill()` method,
the chain `meta ?? frontmatterFallback(content) ?? ""`).
3. Even when you manually `INSERT` a row into `skills`, the daemon
does not refresh the in-memory `skillIndex` until restart. SQLite
inserts never propagate to the running process.

The desktop bundle is not currently distributed as source, so
applying an upstream patch is not an option. The two recovery
paths below are reversible and avoid touching the desktop bundle.

## Path A — `mavis skill update` (preferred)

This is the only fix that pushes the new description through the
daemon's file-watcher upsert path without restarting the process.

```bash
# 1. Confirm the on-disk SKILL.md is correct.
head -3 ~/.minimax/skills/secure-by-design-review/SKILL.md
# ---
# name: secure-by-design-review
# description: Review and implement software with defensive security: …

# 2. Push it back through the CLI. The daemon's file watcher fires
# the `onSkillFileChange` handler which calls
# `this.skillIndex.upsert(skillInfo)` — at that point the
# in-memory index agrees with the file and `show` returns the
# real description.
mavis skill update secure-by-design-review \
-a mavis \
--file ~/.minimax/skills/secure-by-design-review/SKILL.md
```

If the CLI returns `50001 internal error`, the daemon failed to
parse the YAML. Double-check the file with `head` and retry. If it
returns `40400 not found`, the row does not exist in `skills` yet —
the desktop daemon skipped it at boot, which is exactly the
condition this skill exists to repair.

## Path B — kickstart (last resort)

Only useful when `mavis skill update` is unreachable (for example
when you cannot place the file in a path the daemon watches).

```bash
launchctl kickstart -k gui/$(id -u)/com.mavis.daemon
```

This tears down the daemon and asks launchd to relaunch it. Be
aware:

- The official service label is `com.mavis.daemon` (`brew services`
equivalent). The CLI command `mavis restart` is intentionally a
no-op on macOS because the desktop app supervises the daemon;
the `launchctl` call below is the only way to actually cycle it.
- After kickstart, `~/.minimax/logs/launchd-stderr.log` may show
repeated `Cannot find module 'better-sqlite3'` errors. Set
`MAVIS_SQLITE3_MODULE_PATH` to
`/Applications/MiniMax Code.app/Contents/Resources/app.asar.unpacked`
before the kickstart if you want a clean boot.

## Path C — sandboxed SQLite insert (extreme)

If the desktop app is offline and you only need the agent tool to
load the skill (not the `show` CLI), an `INSERT` into
`~/.minimax/sqlite.db` is enough to make the row show up. The CLI
itself will keep returning empty until Path A is used.

```bash
python3 - <<'PY'
import sqlite3, time
db = "/Users/jordelmirsdevhome/.minimax/sqlite.db"
desc = "Review and implement software with defensive security: ..."
now = int(time.time() * 1000)
loc = "/Users/jordelmirsdevhome/.minimax/skills/secure-by-design-review/SKILL.md"
con = sqlite3.connect(db)
cur = con.cursor()
for agent_name in ("mavis", "coder", "general", "verifier"):
cur.execute(
"""INSERT OR REPLACE INTO skills
(name, agent_name, description, location, source_type, source_kind, created_at, updated_at)
VALUES (?, ?, ?, ?, 2, 'user-mavis', ?, ?)""",
("secure-by-design-review", agent_name, desc, loc, now, now),
)
con.commit()
PY
```

Pre-conditions:

- Backup `~/.minimax/sqlite.db` first.
- The daemon must be stopped. Use `pgrep -f daemon.js` to find the
PID and kill it; let launchd relaunch.

## Verifying recovery

```bash
mavis skill show <name> | jq .description
# Should print the real description, not "".

mavis skill ls <agent> | jq '.skills[] | select(.name == "<name>").description'
# Same.

claude /skill <name> # or the matching tool name in your client
# Should now load the skill instructions.
```

If `description` is still empty after Path A, the on-disk file is
probably still in Shape B (legacy human-readable header). Re-run
`scripts/fix-skill-frontmatter.py` and try Path A again.
Loading