diff --git a/README.md b/README.md index 8c16ead..517d568 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,9 @@ The install script creates symlinks from `~/.claude/skills/` to this repo, makin | Skill | Invocation | Description | |-------|-----------|-------------| | reflect | `/reflect M8` | Milestone reflection — reviews conversation history, git log, and project docs to produce structured reflection artifacts across MEMORY.md, FUTURE.md, README.md, and CLAUDE.md | +| log | `/log` | End-of-session logging — captures decisions, gotchas, open questions to `memory/log/`. Prunes old reflected logs. | +| reflect-logs | `/reflect-logs` | Processes session logs into topic memory files, deduplicates, flags stale entries. Run periodically. | +| distill-best-practices | `/distill-best-practices` | Cross-project best practices distillation into `claude-foundations/best-practices/`. Interactive — proposes changes for approval. | ## Adding a New Skill diff --git a/skills/distill-best-practices/SKILL.md b/skills/distill-best-practices/SKILL.md new file mode 100644 index 0000000..9ad9f5a --- /dev/null +++ b/skills/distill-best-practices/SKILL.md @@ -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: `/` +2. Get current HEAD: `git -C 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 diff --name-only ..HEAD -- memory/` +6. If `last_sha` is missing (first run) → list all memory files: `ls /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: "" + Source: cluster-bootstrap/memory/gotchas-k8s.md + +2. UPDATE validation.md: "" + Source: cluster-bootstrap/memory/process-lessons.md + +3. REMOVE helm.md: "" + 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": "", + "projects": { + "": { + "path": "", + "last_sha": "", + "last_run": "" + } + } +} +``` + +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 diff --git a/skills/log/SKILL.md b/skills/log/SKILL.md new file mode 100644 index 0000000..e43c129 --- /dev/null +++ b/skills/log/SKILL.md @@ -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..md` using the pre-gathered date and timestamp values. + +Write the file using this format: + +```markdown +# Session Log — YYYY-MM-DD + +## Summary + + +## Decisions + +- Decision: — Rationale: + +## Gotchas Discovered + +- **[topic]** Symptom: — Fix: + +## Open Questions + +- + +## Key Context + +- + +## Process Notes + +- +``` + +**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: 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 diff --git a/skills/reflect-logs/SKILL.md b/skills/reflect-logs/SKILL.md new file mode 100644 index 0000000..35d6824 --- /dev/null +++ b/skills/reflect-logs/SKILL.md @@ -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/` 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-.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-.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 `# 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 `` 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": "", + "processed": { + "log/YYYY-MM-DD.HHMMSS.md": "", + ...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