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

115 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# M4.1 — `mem skill draft`
| Field | Value |
|---|---|
| Phase | M4 — Skills |
| Size | M — 13 days |
| Status | ⬜ Not started |
| 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.
## 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:
```yaml
---
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:** seeded vault and log; scripted model client for determinism.
**Integration test**`tests/it_skill_draft.rs`:
1. `a1_valid_frontmatter` — parse the output; assert `name`, `description`,
`when_to_use`, `generated_from` present and non-empty.
2. `a2_generated_from_resolves` — the sha exists in `memory_node`.
3. `a3_writes_only_to_drafts` — assert the path contains `_drafts/`; attempt to
pass a path outside it and assert refusal.
4. `a4_no_promotion_path` — grep the workspace for any code writing to
`vault/skills/` that is not under `_drafts/`; assert none. Promotion must be
manual.
5. `a5_description_is_trigger_shaped` — assert `description` contains at least one
phrasing cue (a quoted user phrase or "Use when"), matching the installed
examples.
6. `a6_dry_run_writes_nothing` — assert no file created.
7. `a7_idempotent` — same input twice produces identical bytes apart from
`generated_at`.
**Command:** `cargo test -p mem-cli skill_draft`
**False pass:**
- Asserting the file was written without asserting *where*. The entire safety
property of this task is the location, and a draft written to `vault/skills/`
is immediately loadable.
- Accepting any non-empty `description`. A one-line restatement of the title
never triggers, so the feature appears to work and the skill never fires —
assertion 5 is a weak but real guard.
## Traps
- Auto-promoting "when the draft looks good". That closes the loop this design
deliberately leaves open, and there is no external verifier inside it.
- Generating the body from L0 evidence. Skills are procedure distilled from
synthesis; raw transcript produces a narrative, not an instruction.
---
Background: [DESIGN.md](../DESIGN.md) — Skills, the procedural projection