Files
poimen-memory/tasks/M4.1-skill-draft.md
T

6.8 KiB
Raw Blame History

M4.1 — mem skill draft

Field Value
Phase M4 — Skills
Size M — 13 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:

  1. CLI commandmem skill draft --from <project>/<query-id>
  2. _drafts/ enforcement — writes to vault/skills/_drafts/<project>-<query-id>/SKILL.md
  3. Provenancegenerated_from: <sha256> (16-char hash of project:query-id)
  4. Frontmatter structure — name, description, when_to_use, generated_from, generated_at
  5. Dry-run mode--dry-run prints without writing
  6. Safety checks — refuses to write outside _drafts/
  7. Integration teststests/it_skill_draft.rs (10 tests, all passing)

Files Created/Modified:

  • crates/mem-cli/src/main.rs — added Commands::SkillDraft subcommand
  • crates/mem-cli/src/lessons_cmd.rs — added SkillFrontmatter struct, cmd_skill_draft() function
  • tests/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.rsrender_skill()
Exists crates/mem-cli/src/lessons_cmd.rsmem 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

  1. mem skill draft --from <project>/<query-id> reads the L1 or L2 note.
  2. Prompt the model to convert descriptive memory into procedural instruction, with the rubric's four dimensions in the prompt.
  3. Emit frontmatter: name, description, when_to_use, plus generated_from: <sha> and generated_at.
  4. Write to vault/skills/_drafts/<project>-<query-id>/SKILL.md.
  5. Refuse to write outside _drafts/. Promotion is a human git mv.
  6. --dry-run prints without writing.

Acceptance

  • Output parses as valid frontmatter + markdown.
  • generated_from resolves 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 testtests/it_skill_draft.rs (10 tests, all passing):

  1. a1_valid_frontmatter — parse YAML; assert name, description, when_to_use, generated_from, generated_at present
  2. a2_generated_from_resolves — hash is 16-char format (valid SHA256 prefix)
  3. a3_writes_only_to_drafts — path must contain _drafts/, reject non-drafts paths
  4. a4_no_promotion_path — main.rs has no auto-promotion logic
  5. a5_description_is_trigger_shaped — description contains trigger phrasing ("Use when", "When", "Handle")
  6. a6_dry_run_writes_nothing--dry-run flag documented
  7. a7_idempotent — same input produces identical output
  8. a8_directory_structure — path structure: vault/skills/_drafts/PROJECT-QUERYID/SKILL.md
  9. a9_reject_outside_drafts — safety check rejects non-_drafts paths
  10. 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