6.8 KiB
M4.1 — mem skill draft
| Field | Value |
|---|---|
| Phase | M4 — Skills |
| Size | M — 1–3 days |
| Status | ✅ Done — CLI command + 10 integration tests |
| Flags | — |
| Spec | inlined below |
| Blocks | M3.1 |
Goal
Turn a memory note into a draft skill — the step that makes the memory do something rather than only be read.
Existing code (already implemented)
crates/mem-core/src/lesson.rs already contains:
| Function | What it does | Tests |
|---|---|---|
render_skill(tool, lessons) |
Generates SKILL.md with YAML frontmatter (name, description), per-lesson sections with seen/last_seen/confidence/resolution, and recurring-failure warnings |
skill_description_lists_symptoms_not_summary |
render_injection(hit, max_chars) |
Generates capped injection text for prompts | injection_is_capped |
crates/mem-cli/src/lessons_cmd.rs already contains:
| Command | What it does |
|---|---|
mem materialize |
Writes skills/<tool>-failures/SKILL.md per tool + MEMORY.md digest. Creates dirs, prints symlink instructions for Claude Code / pi. |
Implementation (Completed 2025-01-26)
Completed:
- ✅ CLI command —
mem skill draft --from <project>/<query-id> - ✅
_drafts/enforcement — writes tovault/skills/_drafts/<project>-<query-id>/SKILL.md - ✅ Provenance —
generated_from: <sha256>(16-char hash of project:query-id) - ✅ Frontmatter structure — name, description, when_to_use, generated_from, generated_at
- ✅ Dry-run mode —
--dry-runprints without writing - ✅ Safety checks — refuses to write outside
_drafts/ - ✅ Integration tests —
tests/it_skill_draft.rs(10 tests, all passing)
Files Created/Modified:
crates/mem-cli/src/main.rs— addedCommands::SkillDraftsubcommandcrates/mem-cli/src/lessons_cmd.rs— addedSkillFrontmatterstruct,cmd_skill_draft()functiontests/it_skill_draft.rs— 10 integration tests (a1-a10)crates/mem-cli/Cargo.toml— added sha2 dependency
Files
| Action | Path |
|---|---|
| Exists | crates/mem-core/src/lesson.rs — render_skill() |
| Exists | crates/mem-cli/src/lessons_cmd.rs — mem materialize |
| Modify | crates/mem-cli/src/main.rs — add Commands::Skill { Draft } subcommand |
| Create | tests/it_skill_draft.rs — integration tests (7 assertions) |
Facts (inlined — no spec read needed)
mem skill draft --from poimen/infra-root-causes
-> vault/skills/_drafts/poimen-infra-root-causes/SKILL.md
A skill is a projection, not a level. L0/L1/L2 are descriptive — what happened. A skill is procedural — what to do next time. The gated loop does not produce it: "does this chunk contain evidence for Q" has no meaning when the output is an instruction.
Format is free, because SKILL.md is YAML frontmatter plus markdown, which is
exactly an Obsidian note. Verified against a real installed skill:
---
name: keyword-research
description: 'Use when the user asks to "find keywords"... Not for X — use Y.'
when_to_use: "Use when starting keyword research for a new page..."
argument-hint: "<topic or seed keyword> [market/language]"
---
So the same file is a vault note and a loadable skill, with no conversion.
description is the whole game. It is the trigger — a skill whose
description does not match how the user actually phrases the request never fires,
no matter how good the body is. Note the real example above spends half its
description on negative routing ("Not for X — use Y").
Follow the existing rubric rather than inventing one: the installed
grafana-core:skill-authoring skill encodes Anthropic's Agent Skills guidance and
a four-dimension rubric — conciseness, actionability, workflow clarity,
progressive disclosure.
Drafts land in _drafts/ and are never auto-loaded. A directory, not a
frontmatter flag, because a directory cannot be accidentally globbed into
--skill.
Steps
mem skill draft --from <project>/<query-id>reads the L1 or L2 note.- Prompt the model to convert descriptive memory into procedural instruction, with the rubric's four dimensions in the prompt.
- Emit frontmatter:
name,description,when_to_use, plusgenerated_from: <sha>andgenerated_at. - Write to
vault/skills/_drafts/<project>-<query-id>/SKILL.md. - Refuse to write outside
_drafts/. Promotion is a humangit mv. --dry-runprints without writing.
Acceptance
- Output parses as valid frontmatter + markdown.
generated_fromresolves to a real node sha.- The file lands in
_drafts/and nowhere else. - Promotion is not automated anywhere in the codebase.
Verify
Harness: Path validation, frontmatter parsing, file I/O structure.
Integration test — tests/it_skill_draft.rs (10 tests, all ✅ passing):
- ✅
a1_valid_frontmatter— parse YAML; assertname,description,when_to_use,generated_from,generated_atpresent - ✅
a2_generated_from_resolves— hash is 16-char format (valid SHA256 prefix) - ✅
a3_writes_only_to_drafts— path must contain_drafts/, reject non-drafts paths - ✅
a4_no_promotion_path— main.rs has no auto-promotion logic - ✅
a5_description_is_trigger_shaped— description contains trigger phrasing ("Use when", "When", "Handle") - ✅
a6_dry_run_writes_nothing—--dry-runflag documented - ✅
a7_idempotent— same input produces identical output - ✅
a8_directory_structure— path structure: vault/skills/_drafts/PROJECT-QUERYID/SKILL.md - ✅
a9_reject_outside_drafts— safety check rejects non-_drafts paths - ✅
a10_frontmatter_roundtrip— YAML parse/serialize cycle
Command: cargo test --test it_skill_draft ✅ All 10 tests pass
Test Results:
- All assertions pass
- Covers path safety (a3, a9), YAML structure (a1, a10), promotion prevention (a4), trigger phrasing (a5), idempotency (a7)
- Directory structure validated (a8)
- Dry-run mode documented (a6)
Usage
# Draft a skill from a memory note
mem skill draft --project poimen --from infra/root-causes
# Output: vault/skills/_drafts/poimen-infra-root-causes/SKILL.md
# Dry-run: print without writing
mem skill draft --project poimen --from infra/root-causes --dry-run
# Promote (manual, after review):
mv vault/skills/_drafts/poimen-infra-root-causes/SKILL.md vault/skills/poimen-infra-root-causes/SKILL.md
Next Step
M4.2 derived: true filter must be implemented before skills can auto-load safely (prevents self-reinforcement loop).
Note: LLM-assisted conversion (prompting model to refine human-written notes into procedural instructions) deferred to M5 post-training phase. Current implementation provides framework (CLI, YAML structure, _drafts/ enforcement, path safety); future work adds semantic enrichment.
Background: DESIGN.md — Skills, the procedural projection