Add three knowledge distillation skills: /log, /reflect-logs, /distill-best-practices
- /log: end-of-session capture of decisions, gotchas, open questions to memory/log/ - /reflect-logs: processes session logs into topic memory files with staleness detection - /distill-best-practices: cross-project best practices extraction with interactive proposals - README.md: updated skill table with all three new skills Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
145
skills/distill-best-practices/SKILL.md
Normal file
145
skills/distill-best-practices/SKILL.md
Normal file
@@ -0,0 +1,145 @@
|
||||
---
|
||||
name: distill-best-practices
|
||||
description: >
|
||||
Cross-project best practices distillation. Reads changed memory files from all tracked
|
||||
projects and proposes additions, updates, or removals to claude-foundations/best-practices/.
|
||||
Run from any project — always targets claude-foundations as output. Interactive — presents
|
||||
proposals for approval before making changes.
|
||||
allowed-tools: Read, Edit, Write, Glob, Grep, Bash(git -C *), Bash(git rev-parse *), Bash(ls *), Bash(cat *), Bash(head *), Bash(date *)
|
||||
---
|
||||
|
||||
# Distill Best Practices Skill
|
||||
|
||||
You are extracting generalisable best practices from project-specific memory files across all tracked projects.
|
||||
|
||||
## Pre-gathered context
|
||||
|
||||
### Distill state
|
||||
!`cat ~/dev/claude/projects/claude-foundations/best-practices/.distill-state.json 2>/dev/null || echo "{}"`
|
||||
|
||||
### Settings
|
||||
!`cat ~/dev/claude/projects/claude-foundations/settings.yaml 2>/dev/null || echo "No settings file found"`
|
||||
|
||||
### Current best-practices index
|
||||
!`cat ~/dev/claude/projects/claude-foundations/best-practices/INDEX.md 2>/dev/null || echo "No index found"`
|
||||
|
||||
### Available best-practices files
|
||||
!`ls -1 ~/dev/claude/projects/claude-foundations/best-practices/ 2>/dev/null || echo "No best-practices directory"`
|
||||
|
||||
### Projects directory listing
|
||||
!`ls -1d ~/dev/claude/projects/*/ 2>/dev/null || echo "No projects directory"`
|
||||
|
||||
## Instructions
|
||||
|
||||
### Step 1: Discover changes per project
|
||||
|
||||
Read `settings.yaml` for the list of tracked projects and `projects_dir`.
|
||||
|
||||
For each project in `distill.projects`:
|
||||
|
||||
1. Get the project path: `<projects_dir>/<project_name>`
|
||||
2. Get current HEAD: `git -C <path> rev-parse HEAD`
|
||||
3. Look up `last_sha` from `.distill-state.json` for this project
|
||||
4. If SHA matches → skip this project (no changes)
|
||||
5. If `last_sha` exists → find changed files: `git -C <path> diff --name-only <last_sha>..HEAD -- memory/`
|
||||
6. If `last_sha` is missing (first run) → list all memory files: `ls <path>/memory/*.md`
|
||||
|
||||
Filter to only `memory/*.md` files (exclude `memory/log/` — those are raw, unprocessed).
|
||||
|
||||
If no projects have changes, say so and stop.
|
||||
|
||||
### Step 2: Read changed memory files
|
||||
|
||||
For each changed memory file, read its full content using the Read tool.
|
||||
|
||||
Also identify which existing best-practices topic files cover the same domain. Use this mapping as a guide:
|
||||
- `gotchas-k8s.md` → `kubernetes.md`
|
||||
- `gotchas-cilium.md` → `kubernetes.md`
|
||||
- `gotchas-helm.md` → `helm.md`
|
||||
- `gotchas-ansible.md` → `ansible.md`
|
||||
- `gotchas-sops.md` → `secrets-management.md`
|
||||
- `process-lessons.md` → `validation.md`, `debugging.md`
|
||||
- `decisions.md` → various (match by content)
|
||||
- Other gotchas → match by topic or propose a new file
|
||||
|
||||
Read the matching best-practices files so you can compare.
|
||||
|
||||
### Step 3: Analyse and propose
|
||||
|
||||
For each potential change, classify it:
|
||||
|
||||
- **ADD**: A lesson that is project-agnostic and valuable across projects. When generalising:
|
||||
- Strip project-specific details (IPs, namespace names, service names, hostnames)
|
||||
- Replace specifics with generic descriptions (e.g., "10.111.0.5" → "the DNS server IP")
|
||||
- Keep the principle and the reasoning — lose the implementation detail
|
||||
- Only promote lessons that would apply to at least one other project type
|
||||
|
||||
- **UPDATE**: An existing best-practice entry that has new supporting evidence, needs refinement, or should be expanded with a new example.
|
||||
|
||||
- **REMOVE**: A best-practice that has been invalidated — version-specific bug fixed, tool changed, approach superseded. Cross-reference: if the source gotcha was removed from the project's memory, the best-practice may be stale.
|
||||
|
||||
### Step 4: Present proposals
|
||||
|
||||
**Do NOT make any changes yet.** Present a numbered list of proposals:
|
||||
|
||||
```
|
||||
Proposals:
|
||||
|
||||
1. ADD to kubernetes.md: "<brief description of the new entry>"
|
||||
Source: cluster-bootstrap/memory/gotchas-k8s.md
|
||||
|
||||
2. UPDATE validation.md: "<what changes and why>"
|
||||
Source: cluster-bootstrap/memory/process-lessons.md
|
||||
|
||||
3. REMOVE helm.md: "<entry to remove and why it's stale>"
|
||||
Reason: Source gotcha removed in cluster-bootstrap commit abc1234
|
||||
```
|
||||
|
||||
Wait for the user to approve, modify, or reject proposals. The user may say "all", give specific numbers, or ask for changes.
|
||||
|
||||
### Step 5: Apply approved changes
|
||||
|
||||
For each approved proposal:
|
||||
- **ADD**: Append the new entry to the target file, matching the existing style (heading level, bullet format, explanation depth)
|
||||
- **UPDATE**: Edit the existing entry in place
|
||||
- **REMOVE**: Delete the entry from the file
|
||||
|
||||
If a new best-practices topic file is needed:
|
||||
- Create it following the format of existing files (top-level heading, subheadings per entry, 2-6 lines per entry)
|
||||
- Add it to `INDEX.md` with a one-line description
|
||||
|
||||
### Step 6: Update distill state
|
||||
|
||||
Write `best-practices/.distill-state.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"last_run": "<ISO-8601 timestamp>",
|
||||
"projects": {
|
||||
"<project_name>": {
|
||||
"path": "<absolute_path>",
|
||||
"last_sha": "<current HEAD sha>",
|
||||
"last_run": "<ISO-8601 timestamp>"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Preserve entries for projects that weren't processed this run (no changes).
|
||||
|
||||
### Step 7: Summary
|
||||
|
||||
Print:
|
||||
- Projects scanned and number of changed memory files per project
|
||||
- Number of proposals (add/update/remove)
|
||||
- Number approved and applied
|
||||
- Any new best-practices files created
|
||||
|
||||
## Quality checks
|
||||
|
||||
- Best practices must be **project-agnostic** — no hardcoded IPs, namespaces, or service names
|
||||
- Each entry should include the **principle and reasoning**, not just the rule
|
||||
- Entries must be **deduplicated** against existing best-practices content
|
||||
- The **INDEX.md** must stay accurate after any file additions
|
||||
- Proposals are **always presented before applying** — never auto-apply
|
||||
96
skills/log/SKILL.md
Normal file
96
skills/log/SKILL.md
Normal file
@@ -0,0 +1,96 @@
|
||||
---
|
||||
name: log
|
||||
description: >
|
||||
End-of-session logging. Captures key decisions, gotchas, open questions, and discussion
|
||||
points into memory/log/ for later reflection. Run before ending a session to preserve
|
||||
context. Fast and low-friction — just run /log.
|
||||
allowed-tools: Read, Write, Glob, Bash(date *), Bash(ls *), Bash(cat *), Bash(find *), Bash(rm *), Bash(mkdir *)
|
||||
---
|
||||
|
||||
# Session Log Skill
|
||||
|
||||
You are capturing key points from the current session into a structured log file.
|
||||
|
||||
## Pre-gathered context
|
||||
|
||||
### Current date and session timestamp
|
||||
!`date +%Y-%m-%d`
|
||||
!`date +%Y%m%d-%H%M%S`
|
||||
|
||||
### Existing log files
|
||||
!`ls -1 memory/log/ 2>/dev/null || echo "No log directory yet"`
|
||||
|
||||
### Settings
|
||||
!`cat ~/dev/claude/projects/claude-foundations/settings.yaml 2>/dev/null || echo "No settings file found"`
|
||||
|
||||
### Reflection state (to check what has been reflected)
|
||||
!`cat .reflection-state.json 2>/dev/null || echo "No reflection state yet"`
|
||||
|
||||
### Current MEMORY.md index
|
||||
!`cat MEMORY.md 2>/dev/null || echo "No MEMORY.md found"`
|
||||
|
||||
## Instructions
|
||||
|
||||
Review the **full conversation history** in your context window and extract the key points worth preserving. Not every session needs a log — if the session was trivial (a typo fix, a quick question), say so and skip.
|
||||
|
||||
### Step 1: Create the log directory if needed
|
||||
|
||||
If `memory/log/` does not exist, create it with `mkdir -p memory/log/`.
|
||||
|
||||
### Step 2: Write the log file
|
||||
|
||||
Generate the filename as `memory/log/YYYY-MM-DD.<HHMMSS>.md` using the pre-gathered date and timestamp values.
|
||||
|
||||
Write the file using this format:
|
||||
|
||||
```markdown
|
||||
# Session Log — YYYY-MM-DD
|
||||
|
||||
## Summary
|
||||
<!-- 1-2 sentence overview of what was accomplished or discussed -->
|
||||
|
||||
## Decisions
|
||||
<!-- Bulleted list of decisions made and brief rationale. Omit section if none. -->
|
||||
- Decision: <what> — Rationale: <why>
|
||||
|
||||
## Gotchas Discovered
|
||||
<!-- Symptom + fix format, tagged by topic area. Omit section if none. -->
|
||||
- **[topic]** Symptom: <what happened> — Fix: <what resolved it>
|
||||
|
||||
## Open Questions
|
||||
<!-- Things unresolved that need follow-up. Omit section if none. -->
|
||||
- <question>
|
||||
|
||||
## Key Context
|
||||
<!-- Important facts, configurations, or patterns worth remembering. Omit section if none. -->
|
||||
- <fact>
|
||||
|
||||
## Process Notes
|
||||
<!-- What went well, what was slow, what to do differently. Omit section if none. -->
|
||||
- <note>
|
||||
```
|
||||
|
||||
**Guidelines:**
|
||||
- Omit empty sections entirely rather than leaving them blank
|
||||
- The `[topic]` tag on gotchas should match existing memory topic names where possible (e.g., `[k8s]`, `[cilium]`, `[ansible]`, `[sops]`, `[helm]`). Use new tags for new topics.
|
||||
- Keep entries concise — this is raw material for `/reflect-logs`, not a polished document
|
||||
- Include enough context that each entry makes sense on its own without the full conversation
|
||||
|
||||
### Step 3: Prune old logs
|
||||
|
||||
After writing the log file, check for old logs that should be pruned:
|
||||
|
||||
1. Read `retention_days` and `warn_unreflected_days` from the settings (defaults: 7 and 14)
|
||||
2. Read `.reflection-state.json` to know which logs have been reflected on
|
||||
3. For each file in `memory/log/`:
|
||||
- Parse the date from the filename (first 10 characters: `YYYY-MM-DD`)
|
||||
- If **older than `retention_days`** AND **present in `.reflection-state.json`** → delete it and note the deletion
|
||||
- If **older than `warn_unreflected_days`** AND **NOT in `.reflection-state.json`** → print a warning: `WARNING: <filename> is N days old and has NOT been reflected on. Run /reflect-logs.`
|
||||
- Otherwise → leave it alone
|
||||
|
||||
### Step 4: Summary
|
||||
|
||||
Print a brief summary:
|
||||
- Log file created (with path)
|
||||
- Number of entries by section
|
||||
- Any files pruned or warnings issued
|
||||
121
skills/reflect-logs/SKILL.md
Normal file
121
skills/reflect-logs/SKILL.md
Normal file
@@ -0,0 +1,121 @@
|
||||
---
|
||||
name: reflect-logs
|
||||
description: >
|
||||
Process session logs into structured memory. Reads unprocessed logs from memory/log/,
|
||||
extracts lessons into topic memory files (gotchas, process-lessons, decisions, etc.),
|
||||
updates MEMORY.md index, and flags stale entries. Run periodically or after several sessions.
|
||||
allowed-tools: Read, Edit, Write, Glob, Grep, Bash(md5sum *), Bash(ls *), Bash(cat *), Bash(date *), Bash(find *), Bash(git log *), Bash(git diff *), Bash(head *)
|
||||
---
|
||||
|
||||
# Reflect Logs Skill
|
||||
|
||||
You are processing session logs into structured, topic-based memory files.
|
||||
|
||||
## Pre-gathered context
|
||||
|
||||
### Reflection state
|
||||
!`cat .reflection-state.json 2>/dev/null || echo "{}"`
|
||||
|
||||
### Available log files
|
||||
!`ls -1t memory/log/ 2>/dev/null || echo "No logs found"`
|
||||
|
||||
### Current MEMORY.md index
|
||||
!`cat MEMORY.md 2>/dev/null || echo "No MEMORY.md found"`
|
||||
|
||||
### Existing memory topic files
|
||||
!`ls -1 memory/ 2>/dev/null || echo "No memory directory"`
|
||||
|
||||
### Settings
|
||||
!`cat ~/dev/claude/projects/claude-foundations/settings.yaml 2>/dev/null || echo "No settings file found"`
|
||||
|
||||
### Recent git log (for staleness detection)
|
||||
!`git log --oneline -30 2>/dev/null || echo "Not a git repo"`
|
||||
|
||||
## Instructions
|
||||
|
||||
### Step 1: Identify unprocessed logs
|
||||
|
||||
Compare `memory/log/` contents against `.reflection-state.json`:
|
||||
- A log is **new** if its filename is not in the `processed` map
|
||||
- A log is **changed** if its filename exists but the md5sum differs from the stored hash
|
||||
- Respect `max_logs_per_run` from settings (default: 10) — process oldest first
|
||||
|
||||
To compute hashes, run `md5sum memory/log/<filename>` for each file and compare against the stored values.
|
||||
|
||||
If there are no unprocessed logs, say so and stop.
|
||||
|
||||
### Step 2: Read and categorise
|
||||
|
||||
Read each unprocessed log file. Group the extracted content by destination:
|
||||
|
||||
**Routing rules:**
|
||||
- Gotchas tagged `[topic]` → `memory/gotchas-<topic>.md` (e.g., `[k8s]` → `memory/gotchas-k8s.md`)
|
||||
- Decisions → `memory/decisions.md`
|
||||
- Process Notes → `memory/process-lessons.md`
|
||||
- Key Context that represents a stable pattern → `memory/process-lessons.md` or a new topic file
|
||||
- Open Questions that were resolved across sessions → note the resolution, don't carry forward
|
||||
|
||||
If a `[topic]` tag doesn't match any existing gotchas file, create a new `memory/gotchas-<topic>.md` file following the format of existing ones (title heading, individual gotcha subheadings with 2-4 line explanations).
|
||||
|
||||
### Step 3: Update memory files
|
||||
|
||||
For each destination file:
|
||||
|
||||
1. **Read** the existing content using the Read tool
|
||||
2. **Deduplicate**: Do NOT add entries that already exist in substance, even if worded differently. Check for semantic overlap, not just string matching.
|
||||
3. **Append** new entries in the same style as existing content:
|
||||
- Gotcha files: `## Heading` with 2-4 lines of explanation including symptom and fix
|
||||
- Process lessons: Imperative rule format ("Always X before Y", "Never assume Z")
|
||||
- Decisions: `## Heading` with rationale paragraph
|
||||
4. If creating a new topic file, include a top-level `# <Topic> Gotchas` heading and make it self-contained
|
||||
|
||||
### Step 4: Staleness detection
|
||||
|
||||
Scan existing entries in the memory topic files you touched (not all files — only the ones relevant to this run):
|
||||
|
||||
- **Version-based**: If an entry mentions a specific version (e.g., "Cilium 1.19.1", "chart v39.x"), check `git log` for version bumps past that number. If found, add `<!-- STALE? Project has upgraded past <version> -->` as a comment after the entry.
|
||||
- **Fix-based**: If an entry describes a workaround for a bug, grep recent log files and git commits for keywords suggesting the bug was fixed upstream. If found, flag it.
|
||||
- **Automation-based**: If a process lesson describes a manual sequence, check if a script in `scripts/` now handles it. If so, flag or update the entry.
|
||||
|
||||
Print all flagged items in the summary so the user can confirm removal.
|
||||
|
||||
### Step 5: Update MEMORY.md index
|
||||
|
||||
If any new topic files were created:
|
||||
- Add a one-line entry to the appropriate section of MEMORY.md
|
||||
- Follow the existing format: `- [Title](memory/filename.md) -- Description`
|
||||
- Make the description specific and searchable — it's used to decide what to read
|
||||
|
||||
### Step 6: Update reflection state
|
||||
|
||||
Write `.reflection-state.json` with updated hashes:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"last_run": "<ISO-8601 timestamp>",
|
||||
"processed": {
|
||||
"log/YYYY-MM-DD.HHMMSS.md": "<md5hash>",
|
||||
...existing entries...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Preserve existing entries. Add new ones for the logs just processed. Use `date -u +%Y-%m-%dT%H:%M:%SZ` for the timestamp.
|
||||
|
||||
### Step 7: Summary
|
||||
|
||||
Print:
|
||||
- Number of logs processed
|
||||
- New entries added (listed by destination file)
|
||||
- Stale entries flagged (with the reason)
|
||||
- Any new topic files created
|
||||
- Any open questions resolved
|
||||
|
||||
## Quality checks
|
||||
|
||||
- Every new entry must be **actionable or informative** — no filler
|
||||
- Gotchas include **symptom AND fix**, not just "X was tricky"
|
||||
- Process lessons are phrased as **rules** ("Always X before Y")
|
||||
- New entries match the **formatting style** of existing entries in the target file
|
||||
- Deduplication is by **substance**, not exact string match
|
||||
Reference in New Issue
Block a user