From 243aed25231b30a1f2a09f05deabf44bb2b6743b Mon Sep 17 00:00:00 2001 From: "Mikhail [azalio] Petrov" Date: Thu, 26 Mar 2026 12:56:23 +0300 Subject: [PATCH 1/3] feat: persist /map-learn lessons to .claude/rules/learned/ for auto-loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously /map-learn extracted lessons via Reflector but output was ephemeral — never persisted where Claude Code loads automatically. The learning loop was broken. Now /map-learn writes lessons to .claude/rules/learned/*.md files that Claude Code natively loads at session start (unconditional or path-scoped via YAML frontmatter). This closes the LEARN loop from the SPEC→PLAN→TEST→CODE→REVIEW→LEARN cycle. Changes: - Rewrite map-learn.md: add Step 2a (read existing rules for dedup), Step 3 (write rules files with section mapping and path frontmatter), Step 4 (updated summary with persistence info) - Add create_rules_dir() to file_copier.py: creates .claude/rules/learned/ with README during mapify init, never touched by upgrade - Wire create_rules_dir into init flow - Add rules template: src/mapify_cli/templates/rules/learned/README.md - Add tests: rules dir creation, preservation, idempotency, map-learn references rules directory --- .claude/commands/map-learn.md | 251 +++++++++++------- src/mapify_cli/__init__.py | 10 + src/mapify_cli/delivery/__init__.py | 2 + src/mapify_cli/delivery/file_copier.py | 32 +++ .../templates/commands/map-learn.md | 251 +++++++++++------- .../templates/rules/learned/README.md | 18 ++ tests/test_command_templates.py | 15 ++ tests/test_decomposition.py | 39 +++ 8 files changed, 422 insertions(+), 196 deletions(-) create mode 100644 src/mapify_cli/templates/rules/learned/README.md diff --git a/.claude/commands/map-learn.md b/.claude/commands/map-learn.md index 69521c7a..c3c5eed0 100644 --- a/.claude/commands/map-learn.md +++ b/.claude/commands/map-learn.md @@ -2,9 +2,9 @@ description: Extract and preserve lessons from completed workflows (OPTIONAL learning step) --- -# MAP Learn - Post-Workflow Learning +# MAP Learn - Post-Workflow Learning with Persistence -**Purpose:** Standalone command to extract lessons AFTER completing any MAP workflow. +**Purpose:** Extract lessons AFTER completing any MAP workflow and persist them to `.claude/rules/learned/` so Claude Code loads them automatically in future sessions. **When to use:** - After `/map-efficient` completes (to preserve patterns from the workflow) @@ -12,8 +12,10 @@ description: Extract and preserve lessons from completed workflows (OPTIONAL lea - After `/map-fast` completes (to retroactively add learning when learning was skipped) **What it does:** -1. Calls Reflector agent to analyze workflow outputs and extract patterns -2. Outputs a structured learning summary for the user to review +1. Reads existing learned rules (for deduplication) +2. Calls Reflector agent to analyze workflow outputs and extract patterns +3. Writes new lessons to `.claude/rules/learned/*.md` files +4. Outputs a structured learning summary **Workflow Summary Input:** $ARGUMENTS @@ -21,7 +23,7 @@ description: Extract and preserve lessons from completed workflows (OPTIONAL lea ## IMPORTANT: This is an OPTIONAL step -**You are NOT required to run this command.** No MAP workflow includes automatic learning -- learning is always a separate step via this command. +**You are NOT required to run this command.** No MAP workflow includes automatic learning — learning is always a separate step via this command. Use /map-learn when: - You completed /map-efficient, /map-debug, or /map-fast and want to extract lessons @@ -45,27 +47,23 @@ Check that $ARGUMENTS contains workflow summary: - Analysis results (Predictor/Evaluator outputs, if available) - Workflow metrics (total subtasks, iterations, files changed) -**Example valid input:** -``` -Workflow: /map-efficient "Add user authentication" -Subtasks completed: 3 -Files changed: api/auth.py, models/user.py, tests/test_auth.py -Iterations: 5 total (Actor->Monitor loops) +**If input is incomplete:** Ask user to provide missing information before proceeding. -Subtask 1 (Actor output): -[paste Actor JSON output] +--- -Subtask 1 (Monitor result): -[paste Monitor validation] +## Step 2: Read Existing Rules and Call Reflector -... -``` +### Step 2a: Gather existing lessons for deduplication -**If input is incomplete:** Ask user to provide missing information before proceeding. +Before calling the Reflector, read all existing `.claude/rules/learned/*.md` files (excluding README.md). Extract the bullet points from each file. ---- +```bash +ls .claude/rules/learned/*.md 2>/dev/null || echo "NO_EXISTING_RULES" +``` + +If files exist, read each one and collect all lines starting with `- **`. These are existing lessons that the Reflector should NOT duplicate. -## Step 2: Reflector Analysis +### Step 2b: Call Reflector **MUST use subagent_type="reflector"** (NOT general-purpose): @@ -78,6 +76,9 @@ Task( **Workflow Summary:** $ARGUMENTS +**Existing learned rules (do NOT duplicate these):** +[paste extracted bullets from Step 2a, or 'None — first learning session' if no files exist] + **Analysis Instructions:** Analyze holistically across ALL subtasks: @@ -93,47 +94,127 @@ Analyze holistically across ALL subtasks: - Testing patterns (edge cases, test structure) - Performance patterns (optimization, resource usage) - Error patterns (what went wrong, how it was fixed) +- Architecture patterns (system design, component boundaries) + +**IMPORTANT:** Do NOT repeat any pattern from the 'Existing learned rules' list above. +Only suggest genuinely new patterns not already captured. **Output JSON with:** -- key_insight: string (one sentence takeaway for entire workflow) +- key_insight: string (one sentence takeaway in 'When X, always Y because Z' format) - patterns_used: array of strings (existing patterns applied successfully) - patterns_discovered: array of strings (new patterns worth preserving) -- bullet_updates: array of {bullet_id, tag: 'helpful'|'harmful', reason} -- suggested_new_bullets: array of {section, content, code_example, rationale} +- suggested_new_bullets: array of {section, title, content, code_example, rationale} + where section is one of: SECURITY_PATTERNS, IMPLEMENTATION_PATTERNS, PERFORMANCE_PATTERNS, + ERROR_PATTERNS, ARCHITECTURE_PATTERNS, TESTING_STRATEGIES - workflow_efficiency: {total_iterations, avg_per_subtask, bottlenecks: array of strings}" ) ``` --- -## Step 3: Summary Report +## Step 3: Write Rules Files + +Transform Reflector output into `.claude/rules/learned/` markdown files. + +### Section-to-file mapping + +| Reflector section | File | `paths:` frontmatter | +|---|---|---| +| `SECURITY_PATTERNS` | `security-patterns.md` | None (loads always) | +| `IMPLEMENTATION_PATTERNS` | `implementation-patterns.md` | Derived from file extensions in workflow | +| `PERFORMANCE_PATTERNS` | `performance-patterns.md` | Derived from file extensions in workflow | +| `ERROR_PATTERNS` | `error-patterns.md` | None (loads always) | +| `ARCHITECTURE_PATTERNS` | `architecture-patterns.md` | None (loads always) | +| `TESTING_STRATEGIES` | `testing-strategies.md` | `["**/test_*", "**/tests/**", "**/*_test.*", "**/*.test.*"]` | + +### Deriving `paths:` frontmatter + +For `IMPLEMENTATION_PATTERNS` and `PERFORMANCE_PATTERNS`: +1. Extract file extensions from the workflow summary (e.g., `.py`, `.go`, `.ts`) +2. Generate glob patterns: `.py` → `["**/*.py"]`, `.go` → `["**/*.go"]` +3. If no extensions found or multiple languages, omit `paths:` (unconditional loading) + +### Writing each file + +For each `suggested_new_bullet` from the Reflector: + +1. **Determine target file** from the section mapping above. + +2. **If file does NOT exist**, create it with this structure: + +```markdown +--- +paths: + - "**/*.py" +--- + +# {Section Title} (Learned) + + + +``` + +Omit the `paths:` frontmatter block entirely for sections that load unconditionally. + +3. **Append the bullet** to the file: + +```markdown +- **{title}** ({YYYY-MM-DD}): {content} [workflow: {workflow_type}] +``` + +If `code_example` is present, add it indented below: + +```markdown +- **{title}** ({YYYY-MM-DD}): {content} [workflow: {workflow_type}] + ```{language} + {code_example} + ``` +``` + +4. **Also write `key_insight`** from the top-level Reflector output as a bullet in the most relevant section file. Use section `IMPLEMENTATION_PATTERNS` as default if no better match. + +### File size check + +After writing, count bullets in each modified file. If any file exceeds 50 bullets, print a warning: + +``` +⚠ {filename} has {N} rules (recommended max: 50). Consider pruning old or low-value rules. +``` + +--- + +## Step 4: Summary Report -Provide learning summary: +Print the learning summary: ```markdown ## /map-learn Completion Summary **Workflow Analyzed:** [workflow type from input] **Total Subtasks:** [N] -**Iterations Required:** [total Actor->Monitor loops] + +### Rules Written to .claude/rules/learned/ +[For each file written:] +- {filename}: +{N} rules ({action: 'new file created' | 'appended'}) +[If duplicates were skipped:] +- Duplicates skipped: {N} ### Reflector Insights -- **Key Insight:** [key_insight from Reflector] -- **Patterns Used:** [count] existing patterns applied successfully +- **Key Insight:** [key_insight] +- **Patterns Applied:** [count] existing patterns used successfully - **Patterns Discovered:** [count] new patterns identified -### Discovered Patterns -[List each pattern from patterns_discovered with description] - -### Suggested Improvements -[List each suggested_new_bullet with section and rationale] - ### Workflow Efficiency - **Total Iterations:** [total_iterations] - **Average per Subtask:** [avg_per_subtask] - **Bottlenecks:** [list bottlenecks] -**Learning extraction complete.** +### Next Steps +- Review written rules: open `.claude/rules/learned/` files +- Rules will auto-load in next Claude Code session +- Commit to share with team: `git add .claude/rules/` + +**Learning extraction and persistence complete.** ``` --- @@ -141,90 +222,71 @@ Provide learning summary: ## Token Budget Estimate **Typical /map-learn execution:** +- Read existing rules: ~500 tokens - Reflector: ~3K tokens (depends on workflow size) -- Summary: ~500 tokens -- **Total:** 3-4K tokens for standard workflow +- Write rules + summary: ~1K tokens +- **Total:** 4-5K tokens for standard workflow **Large workflow (8+ subtasks):** +- Read existing rules: ~1K tokens - Reflector: ~6K tokens -- Summary: ~1K tokens -- **Total:** 6-7K tokens +- Write rules + summary: ~2K tokens +- **Total:** 8-9K tokens --- ## Examples -### Example 1: Learning from /map-fast workflow - -User completed `/map-fast "Implement real-time dashboard"` (no learning performed). - -Now retroactively extract lessons: +### Example 1: First learning session (no existing rules) ``` -User: /map-learn "Workflow: /map-fast real-time dashboard -Subtasks: 4 (WebSocket setup, React components, state management, styling) -Files: ws-server.js, Dashboard.jsx, useWebSocket.js, dashboard.css -Iterations: 2 (minor Monitor feedback) - -Key implementation: -- WebSocket reconnection with exponential backoff -- React hooks for real-time state updates -- Optimistic UI updates before server confirmation" +User: /map-learn "Workflow: /map-efficient 'Add user authentication' +Subtasks: 3 (JWT setup, middleware, tests) +Files: api/auth.py, middleware/jwt.py, tests/test_auth.py +Iterations: 5 + +Key decisions: +- Used PyJWT with RS256 +- Middleware validates on every request +- Refresh token rotation implemented" ``` -Reflector extracts: -- Pattern: WebSocket reconnection logic -- Pattern: Optimistic UI updates +Result: Creates `.claude/rules/learned/security-patterns.md` and `implementation-patterns.md` with new rules. -### Example 2: Batched learning - -User completed 3 separate debugging sessions, wants to batch-learn: +### Example 2: Second learning session (deduplication) ``` -User: /map-learn "Workflows: 3 debugging sessions this week - -Session 1: Fixed race condition in payment processing -- Pattern: Added database transaction locks -- Iterations: 4 +User: /map-learn "Workflow: /map-efficient 'Add API rate limiting' +Subtasks: 2 (rate limiter, tests) +Files: middleware/rate_limit.py, tests/test_rate_limit.py +Iterations: 3" +``` -Session 2: Resolved memory leak in WebSocket connections -- Pattern: Implemented connection pooling with limits -- Iterations: 3 +Reflector sees existing JWT/auth patterns in `security-patterns.md`, does NOT duplicate them, only adds new rate-limiting patterns. -Session 3: Fixed timezone bug in scheduler -- Pattern: Always use UTC internally, convert at display layer -- Iterations: 2 +### Example 3: Batched learning -Common theme: Concurrency issues" +``` +User: /map-learn "Workflows: 3 debugging sessions this week +Session 1: Race condition in payment processing → DB transaction locks +Session 2: Memory leak in WebSocket → connection pooling +Session 3: Timezone bug in scheduler → always UTC internally" ``` -Reflector extracts: -- Common pattern: Concurrency control -- New patterns: DB locks, connection pooling, timezone handling +Result: Appends patterns across multiple topic files. --- ## Integration with Other Commands ### After /map-efficient (recommended) - -/map-efficient does NOT include automatic learning. Use /map-learn to: -- Extract patterns from completed implementation -- Preserve successful approaches for future reference -- Document any edge cases discovered +/map-efficient prints: "Optional: Run /map-learn to preserve patterns." ### After /map-debug (recommended) - -/map-debug does NOT include automatic learning. Use /map-learn to: -- Capture holistic debugging strategy -- Preserve error investigation patterns -- Document root cause analysis approach +Preserves debugging patterns and root cause analysis approaches. ### After /map-fast (optional) - -/map-fast is a reduced-analysis workflow. Use /map-learn only if: -- The work revealed patterns worth preserving -- You want to retroactively capture learnings +Only if the work revealed patterns worth preserving. --- @@ -232,15 +294,8 @@ Reflector extracts: **This command is OPTIONAL.** You are not required to run it after every workflow. -**When to skip /map-learn:** -- No meaningful patterns emerged -- Throwaway code with no reusable insights -- Time constraints (learning can happen later) +**Where rules are stored:** `.claude/rules/learned/` — committed with the project, shared with team, auto-loaded by Claude Code. -**When to use /map-learn:** -- Batching multiple workflows for efficient pattern extraction -- Retroactively adding learning to /map-fast workflows -- Capturing holistic patterns across subtasks -- Custom workflows that didn't include learning +**Rules are yours to edit.** Add context, fix inaccuracies, prune outdated patterns. They are project knowledge, not framework artifacts. -**Remember:** The goal is to build organizational knowledge, not to learn from every single task. Quality over quantity. +**Goal:** Each `/map-learn` invocation makes the next session stronger. If you're still explaining the same gotchas to Claude after running `/map-learn`, the rules need to be more specific. diff --git a/src/mapify_cli/__init__.py b/src/mapify_cli/__init__.py index 631dfd79..f77496f1 100644 --- a/src/mapify_cli/__init__.py +++ b/src/mapify_cli/__init__.py @@ -123,6 +123,7 @@ def create_ssl_context(): create_config_files, create_commands_dir, create_map_tools, + create_rules_dir, ) from mapify_cli.config import ( configure_global_permissions, @@ -809,6 +810,15 @@ def init( except Exception as e: tracker.error("map-config", f"skipped: {e}") + # Create .claude/rules/learned/ directory for /map-learn persistence + tracker.add("rules-dir", "Create learned rules directory") + tracker.start("rules-dir") + rules_count = create_rules_dir(project_path) + tracker.complete( + "rules-dir", + f"{rules_count} file" if rules_count <= 1 else f"{rules_count} files", + ) + if selected_mcp_servers: # Create internal MCP config (for MAP Framework agent mappings) tracker.add("mcp-config", "Create internal MCP config") diff --git a/src/mapify_cli/delivery/__init__.py b/src/mapify_cli/delivery/__init__.py index 906784cb..c8ba565e 100644 --- a/src/mapify_cli/delivery/__init__.py +++ b/src/mapify_cli/delivery/__init__.py @@ -21,6 +21,7 @@ create_config_files, create_commands_dir, create_map_tools, + create_rules_dir, ) from mapify_cli.delivery.managed_file_copier import ( CopyResult, @@ -48,6 +49,7 @@ "create_config_files", "create_commands_dir", "create_map_tools", + "create_rules_dir", "CopyResult", "DriftReport", "copy_managed_file", diff --git a/src/mapify_cli/delivery/file_copier.py b/src/mapify_cli/delivery/file_copier.py index 455c3c02..8279e014 100644 --- a/src/mapify_cli/delivery/file_copier.py +++ b/src/mapify_cli/delivery/file_copier.py @@ -408,3 +408,35 @@ def create_config_files( count += 1 return count + + +def create_rules_dir( + project_path: Path, + drift_report: DriftReport | None = None, +) -> int: + """Create .claude/rules/learned/ directory with README. + + Creates the directory structure for persisting lessons extracted by + /map-learn. The README is copied from templates and managed; existing + user rules files are never touched. + + Returns: + Number of files installed (0 or 1 for README). + """ + rules_dir = project_path / ".claude" / "rules" / "learned" + rules_dir.mkdir(parents=True, exist_ok=True) + + templates_dir = get_templates_dir() + readme_template = templates_dir / "rules" / "learned" / "README.md" + + count = 0 + if readme_template.exists(): + dest = rules_dir / "README.md" + if not dest.exists(): + version = _get_version() + result = copy_managed_file(readme_template, dest, version) + if drift_report is not None: + drift_report.results.append(result) + count += 1 + + return count diff --git a/src/mapify_cli/templates/commands/map-learn.md b/src/mapify_cli/templates/commands/map-learn.md index 69521c7a..c3c5eed0 100644 --- a/src/mapify_cli/templates/commands/map-learn.md +++ b/src/mapify_cli/templates/commands/map-learn.md @@ -2,9 +2,9 @@ description: Extract and preserve lessons from completed workflows (OPTIONAL learning step) --- -# MAP Learn - Post-Workflow Learning +# MAP Learn - Post-Workflow Learning with Persistence -**Purpose:** Standalone command to extract lessons AFTER completing any MAP workflow. +**Purpose:** Extract lessons AFTER completing any MAP workflow and persist them to `.claude/rules/learned/` so Claude Code loads them automatically in future sessions. **When to use:** - After `/map-efficient` completes (to preserve patterns from the workflow) @@ -12,8 +12,10 @@ description: Extract and preserve lessons from completed workflows (OPTIONAL lea - After `/map-fast` completes (to retroactively add learning when learning was skipped) **What it does:** -1. Calls Reflector agent to analyze workflow outputs and extract patterns -2. Outputs a structured learning summary for the user to review +1. Reads existing learned rules (for deduplication) +2. Calls Reflector agent to analyze workflow outputs and extract patterns +3. Writes new lessons to `.claude/rules/learned/*.md` files +4. Outputs a structured learning summary **Workflow Summary Input:** $ARGUMENTS @@ -21,7 +23,7 @@ description: Extract and preserve lessons from completed workflows (OPTIONAL lea ## IMPORTANT: This is an OPTIONAL step -**You are NOT required to run this command.** No MAP workflow includes automatic learning -- learning is always a separate step via this command. +**You are NOT required to run this command.** No MAP workflow includes automatic learning — learning is always a separate step via this command. Use /map-learn when: - You completed /map-efficient, /map-debug, or /map-fast and want to extract lessons @@ -45,27 +47,23 @@ Check that $ARGUMENTS contains workflow summary: - Analysis results (Predictor/Evaluator outputs, if available) - Workflow metrics (total subtasks, iterations, files changed) -**Example valid input:** -``` -Workflow: /map-efficient "Add user authentication" -Subtasks completed: 3 -Files changed: api/auth.py, models/user.py, tests/test_auth.py -Iterations: 5 total (Actor->Monitor loops) +**If input is incomplete:** Ask user to provide missing information before proceeding. -Subtask 1 (Actor output): -[paste Actor JSON output] +--- -Subtask 1 (Monitor result): -[paste Monitor validation] +## Step 2: Read Existing Rules and Call Reflector -... -``` +### Step 2a: Gather existing lessons for deduplication -**If input is incomplete:** Ask user to provide missing information before proceeding. +Before calling the Reflector, read all existing `.claude/rules/learned/*.md` files (excluding README.md). Extract the bullet points from each file. ---- +```bash +ls .claude/rules/learned/*.md 2>/dev/null || echo "NO_EXISTING_RULES" +``` + +If files exist, read each one and collect all lines starting with `- **`. These are existing lessons that the Reflector should NOT duplicate. -## Step 2: Reflector Analysis +### Step 2b: Call Reflector **MUST use subagent_type="reflector"** (NOT general-purpose): @@ -78,6 +76,9 @@ Task( **Workflow Summary:** $ARGUMENTS +**Existing learned rules (do NOT duplicate these):** +[paste extracted bullets from Step 2a, or 'None — first learning session' if no files exist] + **Analysis Instructions:** Analyze holistically across ALL subtasks: @@ -93,47 +94,127 @@ Analyze holistically across ALL subtasks: - Testing patterns (edge cases, test structure) - Performance patterns (optimization, resource usage) - Error patterns (what went wrong, how it was fixed) +- Architecture patterns (system design, component boundaries) + +**IMPORTANT:** Do NOT repeat any pattern from the 'Existing learned rules' list above. +Only suggest genuinely new patterns not already captured. **Output JSON with:** -- key_insight: string (one sentence takeaway for entire workflow) +- key_insight: string (one sentence takeaway in 'When X, always Y because Z' format) - patterns_used: array of strings (existing patterns applied successfully) - patterns_discovered: array of strings (new patterns worth preserving) -- bullet_updates: array of {bullet_id, tag: 'helpful'|'harmful', reason} -- suggested_new_bullets: array of {section, content, code_example, rationale} +- suggested_new_bullets: array of {section, title, content, code_example, rationale} + where section is one of: SECURITY_PATTERNS, IMPLEMENTATION_PATTERNS, PERFORMANCE_PATTERNS, + ERROR_PATTERNS, ARCHITECTURE_PATTERNS, TESTING_STRATEGIES - workflow_efficiency: {total_iterations, avg_per_subtask, bottlenecks: array of strings}" ) ``` --- -## Step 3: Summary Report +## Step 3: Write Rules Files + +Transform Reflector output into `.claude/rules/learned/` markdown files. + +### Section-to-file mapping + +| Reflector section | File | `paths:` frontmatter | +|---|---|---| +| `SECURITY_PATTERNS` | `security-patterns.md` | None (loads always) | +| `IMPLEMENTATION_PATTERNS` | `implementation-patterns.md` | Derived from file extensions in workflow | +| `PERFORMANCE_PATTERNS` | `performance-patterns.md` | Derived from file extensions in workflow | +| `ERROR_PATTERNS` | `error-patterns.md` | None (loads always) | +| `ARCHITECTURE_PATTERNS` | `architecture-patterns.md` | None (loads always) | +| `TESTING_STRATEGIES` | `testing-strategies.md` | `["**/test_*", "**/tests/**", "**/*_test.*", "**/*.test.*"]` | + +### Deriving `paths:` frontmatter + +For `IMPLEMENTATION_PATTERNS` and `PERFORMANCE_PATTERNS`: +1. Extract file extensions from the workflow summary (e.g., `.py`, `.go`, `.ts`) +2. Generate glob patterns: `.py` → `["**/*.py"]`, `.go` → `["**/*.go"]` +3. If no extensions found or multiple languages, omit `paths:` (unconditional loading) + +### Writing each file + +For each `suggested_new_bullet` from the Reflector: + +1. **Determine target file** from the section mapping above. + +2. **If file does NOT exist**, create it with this structure: + +```markdown +--- +paths: + - "**/*.py" +--- + +# {Section Title} (Learned) + + + +``` + +Omit the `paths:` frontmatter block entirely for sections that load unconditionally. + +3. **Append the bullet** to the file: + +```markdown +- **{title}** ({YYYY-MM-DD}): {content} [workflow: {workflow_type}] +``` + +If `code_example` is present, add it indented below: + +```markdown +- **{title}** ({YYYY-MM-DD}): {content} [workflow: {workflow_type}] + ```{language} + {code_example} + ``` +``` + +4. **Also write `key_insight`** from the top-level Reflector output as a bullet in the most relevant section file. Use section `IMPLEMENTATION_PATTERNS` as default if no better match. + +### File size check + +After writing, count bullets in each modified file. If any file exceeds 50 bullets, print a warning: + +``` +⚠ {filename} has {N} rules (recommended max: 50). Consider pruning old or low-value rules. +``` + +--- + +## Step 4: Summary Report -Provide learning summary: +Print the learning summary: ```markdown ## /map-learn Completion Summary **Workflow Analyzed:** [workflow type from input] **Total Subtasks:** [N] -**Iterations Required:** [total Actor->Monitor loops] + +### Rules Written to .claude/rules/learned/ +[For each file written:] +- {filename}: +{N} rules ({action: 'new file created' | 'appended'}) +[If duplicates were skipped:] +- Duplicates skipped: {N} ### Reflector Insights -- **Key Insight:** [key_insight from Reflector] -- **Patterns Used:** [count] existing patterns applied successfully +- **Key Insight:** [key_insight] +- **Patterns Applied:** [count] existing patterns used successfully - **Patterns Discovered:** [count] new patterns identified -### Discovered Patterns -[List each pattern from patterns_discovered with description] - -### Suggested Improvements -[List each suggested_new_bullet with section and rationale] - ### Workflow Efficiency - **Total Iterations:** [total_iterations] - **Average per Subtask:** [avg_per_subtask] - **Bottlenecks:** [list bottlenecks] -**Learning extraction complete.** +### Next Steps +- Review written rules: open `.claude/rules/learned/` files +- Rules will auto-load in next Claude Code session +- Commit to share with team: `git add .claude/rules/` + +**Learning extraction and persistence complete.** ``` --- @@ -141,90 +222,71 @@ Provide learning summary: ## Token Budget Estimate **Typical /map-learn execution:** +- Read existing rules: ~500 tokens - Reflector: ~3K tokens (depends on workflow size) -- Summary: ~500 tokens -- **Total:** 3-4K tokens for standard workflow +- Write rules + summary: ~1K tokens +- **Total:** 4-5K tokens for standard workflow **Large workflow (8+ subtasks):** +- Read existing rules: ~1K tokens - Reflector: ~6K tokens -- Summary: ~1K tokens -- **Total:** 6-7K tokens +- Write rules + summary: ~2K tokens +- **Total:** 8-9K tokens --- ## Examples -### Example 1: Learning from /map-fast workflow - -User completed `/map-fast "Implement real-time dashboard"` (no learning performed). - -Now retroactively extract lessons: +### Example 1: First learning session (no existing rules) ``` -User: /map-learn "Workflow: /map-fast real-time dashboard -Subtasks: 4 (WebSocket setup, React components, state management, styling) -Files: ws-server.js, Dashboard.jsx, useWebSocket.js, dashboard.css -Iterations: 2 (minor Monitor feedback) - -Key implementation: -- WebSocket reconnection with exponential backoff -- React hooks for real-time state updates -- Optimistic UI updates before server confirmation" +User: /map-learn "Workflow: /map-efficient 'Add user authentication' +Subtasks: 3 (JWT setup, middleware, tests) +Files: api/auth.py, middleware/jwt.py, tests/test_auth.py +Iterations: 5 + +Key decisions: +- Used PyJWT with RS256 +- Middleware validates on every request +- Refresh token rotation implemented" ``` -Reflector extracts: -- Pattern: WebSocket reconnection logic -- Pattern: Optimistic UI updates +Result: Creates `.claude/rules/learned/security-patterns.md` and `implementation-patterns.md` with new rules. -### Example 2: Batched learning - -User completed 3 separate debugging sessions, wants to batch-learn: +### Example 2: Second learning session (deduplication) ``` -User: /map-learn "Workflows: 3 debugging sessions this week - -Session 1: Fixed race condition in payment processing -- Pattern: Added database transaction locks -- Iterations: 4 +User: /map-learn "Workflow: /map-efficient 'Add API rate limiting' +Subtasks: 2 (rate limiter, tests) +Files: middleware/rate_limit.py, tests/test_rate_limit.py +Iterations: 3" +``` -Session 2: Resolved memory leak in WebSocket connections -- Pattern: Implemented connection pooling with limits -- Iterations: 3 +Reflector sees existing JWT/auth patterns in `security-patterns.md`, does NOT duplicate them, only adds new rate-limiting patterns. -Session 3: Fixed timezone bug in scheduler -- Pattern: Always use UTC internally, convert at display layer -- Iterations: 2 +### Example 3: Batched learning -Common theme: Concurrency issues" +``` +User: /map-learn "Workflows: 3 debugging sessions this week +Session 1: Race condition in payment processing → DB transaction locks +Session 2: Memory leak in WebSocket → connection pooling +Session 3: Timezone bug in scheduler → always UTC internally" ``` -Reflector extracts: -- Common pattern: Concurrency control -- New patterns: DB locks, connection pooling, timezone handling +Result: Appends patterns across multiple topic files. --- ## Integration with Other Commands ### After /map-efficient (recommended) - -/map-efficient does NOT include automatic learning. Use /map-learn to: -- Extract patterns from completed implementation -- Preserve successful approaches for future reference -- Document any edge cases discovered +/map-efficient prints: "Optional: Run /map-learn to preserve patterns." ### After /map-debug (recommended) - -/map-debug does NOT include automatic learning. Use /map-learn to: -- Capture holistic debugging strategy -- Preserve error investigation patterns -- Document root cause analysis approach +Preserves debugging patterns and root cause analysis approaches. ### After /map-fast (optional) - -/map-fast is a reduced-analysis workflow. Use /map-learn only if: -- The work revealed patterns worth preserving -- You want to retroactively capture learnings +Only if the work revealed patterns worth preserving. --- @@ -232,15 +294,8 @@ Reflector extracts: **This command is OPTIONAL.** You are not required to run it after every workflow. -**When to skip /map-learn:** -- No meaningful patterns emerged -- Throwaway code with no reusable insights -- Time constraints (learning can happen later) +**Where rules are stored:** `.claude/rules/learned/` — committed with the project, shared with team, auto-loaded by Claude Code. -**When to use /map-learn:** -- Batching multiple workflows for efficient pattern extraction -- Retroactively adding learning to /map-fast workflows -- Capturing holistic patterns across subtasks -- Custom workflows that didn't include learning +**Rules are yours to edit.** Add context, fix inaccuracies, prune outdated patterns. They are project knowledge, not framework artifacts. -**Remember:** The goal is to build organizational knowledge, not to learn from every single task. Quality over quantity. +**Goal:** Each `/map-learn` invocation makes the next session stronger. If you're still explaining the same gotchas to Claude after running `/map-learn`, the rules need to be more specific. diff --git a/src/mapify_cli/templates/rules/learned/README.md b/src/mapify_cli/templates/rules/learned/README.md new file mode 100644 index 00000000..3b3ed41e --- /dev/null +++ b/src/mapify_cli/templates/rules/learned/README.md @@ -0,0 +1,18 @@ +# Learned Rules (MAP Framework) + +This directory contains lessons extracted by `/map-learn` from completed MAP workflows. +Claude Code loads these files at session start, making past lessons available in future sessions. + +## How it works + +- `/map-learn` calls the Reflector agent to analyze a completed workflow +- Patterns are written as markdown bullets in topic-based files (e.g., `security-patterns.md`) +- Files with `paths:` frontmatter only load when Claude works with matching files +- Files without `paths:` frontmatter load in every session + +## Managing rules + +- **Edit freely**: these files are yours — add, modify, or remove any rule +- **Prune periodically**: remove outdated rules that no longer apply +- **Keep files under 50 rules each** for best Claude Code adherence +- **Commit with your project**: `git add .claude/rules/` to share with team diff --git a/tests/test_command_templates.py b/tests/test_command_templates.py index fa50f7c2..789939d1 100644 --- a/tests/test_command_templates.py +++ b/tests/test_command_templates.py @@ -90,6 +90,21 @@ def test_map_efficient_suggests_map_learn(self, templates_commands_dir): assert "/map-learn" in content, "Should suggest /map-learn for learning" assert "optional" in content.lower(), "Should mention /map-learn is optional" + def test_map_learn_persists_to_rules(self, templates_commands_dir): + """Test that map-learn.md writes to .claude/rules/learned/ for persistence.""" + map_learn = templates_commands_dir / "map-learn.md" + content = map_learn.read_text() + + assert ".claude/rules/learned/" in content, ( + "map-learn should write to .claude/rules/learned/" + ) + assert "Write Rules Files" in content, ( + "map-learn should have a 'Write Rules Files' step" + ) + assert "deduplication" in content.lower() or "duplicate" in content.lower(), ( + "map-learn should handle deduplication" + ) + def test_all_command_templates_exist(self, templates_commands_dir): """Test that all 12 expected command template files exist.""" expected_commands = [ diff --git a/tests/test_decomposition.py b/tests/test_decomposition.py index 0b392802..3b21561f 100644 --- a/tests/test_decomposition.py +++ b/tests/test_decomposition.py @@ -459,3 +459,42 @@ def test_wrong_type_falls_back_to_defaults(self, tmp_path): # Should get defaults since constructor will fail with bad types assert result.actor_monitor_max_retries == defaults.actor_monitor_max_retries assert result.confidence_threshold == defaults.confidence_threshold + + +class TestRulesDir: + """Test .claude/rules/learned/ directory creation.""" + + def test_create_rules_dir_creates_directory(self, tmp_path): + from mapify_cli.delivery.file_copier import create_rules_dir + + count = create_rules_dir(tmp_path) + rules_dir = tmp_path / ".claude" / "rules" / "learned" + assert rules_dir.is_dir() + readme = rules_dir / "README.md" + assert readme.exists() + assert "MAP Framework" in readme.read_text() + assert count == 1 + + def test_create_rules_dir_preserves_existing_readme(self, tmp_path): + from mapify_cli.delivery.file_copier import create_rules_dir + + # Pre-create with custom content + rules_dir = tmp_path / ".claude" / "rules" / "learned" + rules_dir.mkdir(parents=True) + readme = rules_dir / "README.md" + readme.write_text("My custom README\n") + + count = create_rules_dir(tmp_path) + assert readme.read_text() == "My custom README\n" + assert count == 0 # nothing installed + + def test_create_rules_dir_idempotent(self, tmp_path): + from mapify_cli.delivery.file_copier import create_rules_dir + + create_rules_dir(tmp_path) + create_rules_dir(tmp_path) # second call + rules_dir = tmp_path / ".claude" / "rules" / "learned" + assert rules_dir.is_dir() + # Only README, no duplicates + files = list(rules_dir.iterdir()) + assert len(files) == 1 From 17d1d219b05d6a510cb406abaa8aaff22378dbf2 Mon Sep 17 00:00:00 2001 From: "Mikhail [azalio] Petrov" Date: Thu, 26 Mar 2026 16:06:52 +0300 Subject: [PATCH 2/3] feat: convert map-learn to skill format with supporting templates - Add SKILL.md with proper frontmatter (disable-model-invocation, trigger phrases, negative triggers, troubleshooting section) - Add supporting templates: rules-unconditional.md, rules-with-paths.md, example-rules.md (real-world Go controller examples with code snippets) - SKILL.md references templates via ${CLAUDE_SKILL_DIR}/templates/ for reliable format when creating new rules files - Add map-learn entry to skill-rules.json with trigger keywords - Keep .claude/commands/map-learn.md for backward compatibility (skill takes precedence per Claude Code docs) --- .claude/skills/map-learn/SKILL.md | 321 ++++++++++++++++++ .../map-learn/templates/example-rules.md | 19 ++ .../templates/rules-unconditional.md | 5 + .../map-learn/templates/rules-with-paths.md | 10 + .claude/skills/skill-rules.json | 22 ++ .../templates/skills/map-learn/SKILL.md | 321 ++++++++++++++++++ .../map-learn/templates/example-rules.md | 19 ++ .../templates/rules-unconditional.md | 5 + .../map-learn/templates/rules-with-paths.md | 10 + .../templates/skills/skill-rules.json | 22 ++ 10 files changed, 754 insertions(+) create mode 100644 .claude/skills/map-learn/SKILL.md create mode 100644 .claude/skills/map-learn/templates/example-rules.md create mode 100644 .claude/skills/map-learn/templates/rules-unconditional.md create mode 100644 .claude/skills/map-learn/templates/rules-with-paths.md create mode 100644 src/mapify_cli/templates/skills/map-learn/SKILL.md create mode 100644 src/mapify_cli/templates/skills/map-learn/templates/example-rules.md create mode 100644 src/mapify_cli/templates/skills/map-learn/templates/rules-unconditional.md create mode 100644 src/mapify_cli/templates/skills/map-learn/templates/rules-with-paths.md diff --git a/.claude/skills/map-learn/SKILL.md b/.claude/skills/map-learn/SKILL.md new file mode 100644 index 00000000..5aa64cdd --- /dev/null +++ b/.claude/skills/map-learn/SKILL.md @@ -0,0 +1,321 @@ +--- +name: map-learn +description: Extract and preserve lessons from completed workflows. Use when you want to capture patterns after /map-efficient, /map-debug, or /map-fast completes. Do NOT use for active workflow execution or trivial tasks with no reusable patterns. +disable-model-invocation: true +--- + +# MAP Learn - Post-Workflow Learning with Persistence + +**Purpose:** Extract lessons AFTER completing any MAP workflow and persist them to `.claude/rules/learned/` so Claude Code loads them automatically in future sessions. + +**When to use:** +- After `/map-efficient` completes (to preserve patterns from the workflow) +- After `/map-debug` completes (to preserve debugging patterns) +- After `/map-fast` completes (to retroactively add learning when learning was skipped) + +**What it does:** +1. Reads existing learned rules (for deduplication) +2. Calls Reflector agent to analyze workflow outputs and extract patterns +3. Writes new lessons to `.claude/rules/learned/*.md` files +4. Outputs a structured learning summary + +**Workflow Summary Input:** $ARGUMENTS + +## Templates + +Reference templates for the rules file format are bundled with this skill: +- [rules-unconditional.md](templates/rules-unconditional.md) — format for cross-cutting rules (security, architecture, errors) that load in every session +- [rules-with-paths.md](templates/rules-with-paths.md) — format for language-specific rules with `paths:` frontmatter scoping +- [example-rules.md](templates/example-rules.md) — real-world example showing Go controller lessons with code snippets + +Use these templates when creating new rules files in Step 3. Copy the appropriate template structure, replace placeholders, and append bullets. + +--- + +## IMPORTANT: This is an OPTIONAL step + +**You are NOT required to run this command.** No MAP workflow includes automatic learning — learning is always a separate step via this command. + +Use /map-learn when: +- You completed /map-efficient, /map-debug, or /map-fast and want to extract lessons +- You want to batch-learn from multiple workflows at once +- You want to manually trigger learning for custom workflows + +**Do NOT use this command:** +- During active workflow execution (run after workflow completes) +- If no meaningful patterns emerged from the workflow + +--- + +## Step 1: Validate Input + +Check that $ARGUMENTS contains workflow summary: + +**Required information:** +- Workflow type (feature, debug, refactor, review, custom) +- Subtask outputs (Actor implementations) +- Validation results (Monitor feedback) +- Analysis results (Predictor/Evaluator outputs, if available) +- Workflow metrics (total subtasks, iterations, files changed) + +**If input is incomplete:** Ask user to provide missing information before proceeding. + +--- + +## Step 2: Read Existing Rules and Call Reflector + +### Step 2a: Gather existing lessons for deduplication + +Before calling the Reflector, read all existing `.claude/rules/learned/*.md` files (excluding README.md). Extract the bullet points from each file. + +```bash +ls .claude/rules/learned/*.md 2>/dev/null || echo "NO_EXISTING_RULES" +``` + +If files exist, read each one and collect all lines starting with `- **`. These are existing lessons that the Reflector should NOT duplicate. + +### Step 2b: Call Reflector + +**MUST use subagent_type="reflector"** (NOT general-purpose): + +``` +Task( + subagent_type="reflector", + description="Extract lessons from completed workflow", + prompt="Extract structured lessons from this workflow: + +**Workflow Summary:** +$ARGUMENTS + +**Existing learned rules (do NOT duplicate these):** +[paste extracted bullets from Step 2a, or 'None — first learning session' if no files exist] + +**Analysis Instructions:** + +Analyze holistically across ALL subtasks: +- What patterns emerged consistently? +- What worked well that should be repeated? +- What could be improved for future similar tasks? +- What knowledge should be preserved? +- What trade-offs were made and why? + +**Focus areas:** +- Implementation patterns (code structure, design decisions) +- Security patterns (auth, validation, error handling) +- Testing patterns (edge cases, test structure) +- Performance patterns (optimization, resource usage) +- Error patterns (what went wrong, how it was fixed) +- Architecture patterns (system design, component boundaries) + +**IMPORTANT:** Do NOT repeat any pattern from the 'Existing learned rules' list above. +Only suggest genuinely new patterns not already captured. + +**Output JSON with:** +- key_insight: string (one sentence takeaway in 'When X, always Y because Z' format) +- patterns_used: array of strings (existing patterns applied successfully) +- patterns_discovered: array of strings (new patterns worth preserving) +- suggested_new_bullets: array of {section, title, content, code_example, rationale} + where section is one of: SECURITY_PATTERNS, IMPLEMENTATION_PATTERNS, PERFORMANCE_PATTERNS, + ERROR_PATTERNS, ARCHITECTURE_PATTERNS, TESTING_STRATEGIES +- workflow_efficiency: {total_iterations, avg_per_subtask, bottlenecks: array of strings}" +) +``` + +--- + +## Step 3: Write Rules Files + +Transform Reflector output into `.claude/rules/learned/` markdown files. + +**Use the bundled templates** from `${CLAUDE_SKILL_DIR}/templates/` as the format reference: +- `rules-unconditional.md` for sections without `paths:` frontmatter +- `rules-with-paths.md` for language-scoped sections +- `example-rules.md` for bullet format with code snippets + +### Section-to-file mapping + +| Reflector section | File | `paths:` frontmatter | +|---|---|---| +| `SECURITY_PATTERNS` | `security-patterns.md` | None (loads always) | +| `IMPLEMENTATION_PATTERNS` | `implementation-patterns.md` | Derived from file extensions in workflow | +| `PERFORMANCE_PATTERNS` | `performance-patterns.md` | Derived from file extensions in workflow | +| `ERROR_PATTERNS` | `error-patterns.md` | None (loads always) | +| `ARCHITECTURE_PATTERNS` | `architecture-patterns.md` | None (loads always) | +| `TESTING_STRATEGIES` | `testing-strategies.md` | `["**/test_*", "**/tests/**", "**/*_test.*", "**/*.test.*"]` | + +### Deriving `paths:` frontmatter + +For `IMPLEMENTATION_PATTERNS` and `PERFORMANCE_PATTERNS`: +1. Extract file extensions from the workflow summary (e.g., `.py`, `.go`, `.ts`) +2. Generate glob patterns: `.py` → `["**/*.py"]`, `.go` → `["**/*.go"]` +3. If no extensions found or multiple languages, omit `paths:` (unconditional loading) + +### Writing each file + +For each `suggested_new_bullet` from the Reflector: + +1. **Determine target file** from the section mapping above. + +2. **If file does NOT exist**, create it using the template from `${CLAUDE_SKILL_DIR}/templates/`: + - Use `rules-with-paths.md` template for sections with path scoping + - Use `rules-unconditional.md` template for cross-cutting sections + - Replace `{SECTION_TITLE}` with the human-readable section name + - Replace `{EXT}` with the derived extension glob + +3. **Append the bullet** to the file: + +```markdown +- **{title}** ({YYYY-MM-DD}): {content} [workflow: {workflow_type}] +``` + +If `code_example` is present, add it indented below (see `example-rules.md` for format): + +```markdown +- **{title}** ({YYYY-MM-DD}): {content} [workflow: {workflow_type}] + ```{language} + {code_example} + ``` +``` + +4. **Also write `key_insight`** from the top-level Reflector output as a bullet in the most relevant section file. Use section `IMPLEMENTATION_PATTERNS` as default if no better match. + +### File size check + +After writing, count bullets in each modified file. If any file exceeds 50 bullets, print a warning: + +``` +⚠ {filename} has {N} rules (recommended max: 50). Consider pruning old or low-value rules. +``` + +--- + +## Step 4: Summary Report + +Print the learning summary: + +```markdown +## /map-learn Completion Summary + +**Workflow Analyzed:** [workflow type from input] +**Total Subtasks:** [N] + +### Rules Written to .claude/rules/learned/ +[For each file written:] +- {filename}: +{N} rules ({action: 'new file created' | 'appended'}) +[If duplicates were skipped:] +- Duplicates skipped: {N} + +### Reflector Insights +- **Key Insight:** [key_insight] +- **Patterns Applied:** [count] existing patterns used successfully +- **Patterns Discovered:** [count] new patterns identified + +### Workflow Efficiency +- **Total Iterations:** [total_iterations] +- **Average per Subtask:** [avg_per_subtask] +- **Bottlenecks:** [list bottlenecks] + +### Next Steps +- Review written rules: open `.claude/rules/learned/` files +- Rules will auto-load in next Claude Code session +- Commit to share with team: `git add .claude/rules/` + +**Learning extraction and persistence complete.** +``` + +--- + +## Token Budget Estimate + +**Typical /map-learn execution:** +- Read existing rules: ~500 tokens +- Reflector: ~3K tokens (depends on workflow size) +- Write rules + summary: ~1K tokens +- **Total:** 4-5K tokens for standard workflow + +**Large workflow (8+ subtasks):** +- Read existing rules: ~1K tokens +- Reflector: ~6K tokens +- Write rules + summary: ~2K tokens +- **Total:** 8-9K tokens + +--- + +## Examples + +### Example 1: First learning session (no existing rules) + +``` +User: /map-learn "Workflow: /map-efficient 'Add user authentication' +Subtasks: 3 (JWT setup, middleware, tests) +Files: api/auth.py, middleware/jwt.py, tests/test_auth.py +Iterations: 5 + +Key decisions: +- Used PyJWT with RS256 +- Middleware validates on every request +- Refresh token rotation implemented" +``` + +Result: Creates `.claude/rules/learned/security-patterns.md` and `implementation-patterns.md` with new rules. + +### Example 2: Second learning session (deduplication) + +``` +User: /map-learn "Workflow: /map-efficient 'Add API rate limiting' +Subtasks: 2 (rate limiter, tests) +Files: middleware/rate_limit.py, tests/test_rate_limit.py +Iterations: 3" +``` + +Reflector sees existing JWT/auth patterns in `security-patterns.md`, does NOT duplicate them, only adds new rate-limiting patterns. + +### Example 3: Batched learning + +``` +User: /map-learn "Workflows: 3 debugging sessions this week +Session 1: Race condition in payment processing → DB transaction locks +Session 2: Memory leak in WebSocket → connection pooling +Session 3: Timezone bug in scheduler → always UTC internally" +``` + +Result: Appends patterns across multiple topic files. + +--- + +## Integration with Other Commands + +### After /map-efficient (recommended) +/map-efficient prints: "Optional: Run /map-learn to preserve patterns." + +### After /map-debug (recommended) +Preserves debugging patterns and root cause analysis approaches. + +### After /map-fast (optional) +Only if the work revealed patterns worth preserving. + +--- + +## Troubleshooting + +**No `.claude/rules/learned/` directory:** Run `mapify init` or create it manually: `mkdir -p .claude/rules/learned` + +**Rules not loading in next session:** Verify files are `.md` format in `.claude/rules/learned/`. Check that `paths:` frontmatter globs match your file structure. Run `/memory` to see loaded rules. + +**Too many rules (>50 per file):** Prune outdated lessons. Remove rules that no longer apply or are too project-specific. Keep only patterns that prevent real mistakes. + +**Duplicate rules appearing:** Ensure Step 2a reads existing rules before calling Reflector. If duplicates persist, manually remove them — the deduplication is LLM-based and not perfect. + +**Reflector returns empty results:** Provide more detail in the workflow summary. Include specific files changed, iterations, and key decisions. + +--- + +## Final Notes + +**This command is OPTIONAL.** You are not required to run it after every workflow. + +**Where rules are stored:** `.claude/rules/learned/` — committed with the project, shared with team, auto-loaded by Claude Code. + +**Rules are yours to edit.** Add context, fix inaccuracies, prune outdated patterns. They are project knowledge, not framework artifacts. + +**Goal:** Each `/map-learn` invocation makes the next session stronger. If you're still explaining the same gotchas to Claude after running `/map-learn`, the rules need to be more specific. diff --git a/.claude/skills/map-learn/templates/example-rules.md b/.claude/skills/map-learn/templates/example-rules.md new file mode 100644 index 00000000..522b692e --- /dev/null +++ b/.claude/skills/map-learn/templates/example-rules.md @@ -0,0 +1,19 @@ +--- +paths: + - "**/*.go" +--- + +# Implementation Patterns (Learned) + + + +- **Re-fetch after update** (2026-03-15): When calling r.Update() on a Kubernetes resource, always re-fetch with r.Get() before reading updated fields because the in-memory object is stale after update. [workflow: map-efficient] + +- **SetStatusCondition needs observedGeneration** (2026-03-16): When using meta.SetStatusCondition(), always set ObservedGeneration to the resource's current Generation to prevent stale condition reporting. [workflow: map-debug] + ```go + meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{ + ObservedGeneration: obj.Generation, // required + }) + ``` + +- **Webhook latency** (2026-03-18): When implementing admission webhooks, always read from status/cache instead of listing pods or querying external APIs because webhook timeout is 10s and slow webhooks block all API operations. [workflow: map-efficient] diff --git a/.claude/skills/map-learn/templates/rules-unconditional.md b/.claude/skills/map-learn/templates/rules-unconditional.md new file mode 100644 index 00000000..32bb15ea --- /dev/null +++ b/.claude/skills/map-learn/templates/rules-unconditional.md @@ -0,0 +1,5 @@ +# {SECTION_TITLE} (Learned) + + + +- **{title}** ({YYYY-MM-DD}): When {situation}, always {action} because {reason}. [workflow: {type}] diff --git a/.claude/skills/map-learn/templates/rules-with-paths.md b/.claude/skills/map-learn/templates/rules-with-paths.md new file mode 100644 index 00000000..5a3770a9 --- /dev/null +++ b/.claude/skills/map-learn/templates/rules-with-paths.md @@ -0,0 +1,10 @@ +--- +paths: + - "**/*.{EXT}" +--- + +# {SECTION_TITLE} (Learned) + + + +- **{title}** ({YYYY-MM-DD}): When {situation}, always {action} because {reason}. [workflow: {type}] diff --git a/.claude/skills/skill-rules.json b/.claude/skills/skill-rules.json index 6212eeb7..eedaa7c8 100644 --- a/.claude/skills/skill-rules.json +++ b/.claude/skills/skill-rules.json @@ -48,6 +48,28 @@ ] } }, + "map-learn": { + "type": "domain", + "enforcement": "suggest", + "priority": "low", + "description": "Extract and persist workflow lessons to .claude/rules/learned/", + "promptTriggers": { + "keywords": [ + "extract lessons", + "save patterns", + "learn from workflow", + "preserve learnings", + "map-learn", + "project memory", + "capture gotchas" + ], + "intentPatterns": [ + "(extract|save|preserve|capture).*(lesson|pattern|learning|gotcha)", + "(learn|remember).*(workflow|session|implementation)", + "map-learn" + ] + } + }, "map-cli-reference": { "type": "domain", "enforcement": "suggest", diff --git a/src/mapify_cli/templates/skills/map-learn/SKILL.md b/src/mapify_cli/templates/skills/map-learn/SKILL.md new file mode 100644 index 00000000..5aa64cdd --- /dev/null +++ b/src/mapify_cli/templates/skills/map-learn/SKILL.md @@ -0,0 +1,321 @@ +--- +name: map-learn +description: Extract and preserve lessons from completed workflows. Use when you want to capture patterns after /map-efficient, /map-debug, or /map-fast completes. Do NOT use for active workflow execution or trivial tasks with no reusable patterns. +disable-model-invocation: true +--- + +# MAP Learn - Post-Workflow Learning with Persistence + +**Purpose:** Extract lessons AFTER completing any MAP workflow and persist them to `.claude/rules/learned/` so Claude Code loads them automatically in future sessions. + +**When to use:** +- After `/map-efficient` completes (to preserve patterns from the workflow) +- After `/map-debug` completes (to preserve debugging patterns) +- After `/map-fast` completes (to retroactively add learning when learning was skipped) + +**What it does:** +1. Reads existing learned rules (for deduplication) +2. Calls Reflector agent to analyze workflow outputs and extract patterns +3. Writes new lessons to `.claude/rules/learned/*.md` files +4. Outputs a structured learning summary + +**Workflow Summary Input:** $ARGUMENTS + +## Templates + +Reference templates for the rules file format are bundled with this skill: +- [rules-unconditional.md](templates/rules-unconditional.md) — format for cross-cutting rules (security, architecture, errors) that load in every session +- [rules-with-paths.md](templates/rules-with-paths.md) — format for language-specific rules with `paths:` frontmatter scoping +- [example-rules.md](templates/example-rules.md) — real-world example showing Go controller lessons with code snippets + +Use these templates when creating new rules files in Step 3. Copy the appropriate template structure, replace placeholders, and append bullets. + +--- + +## IMPORTANT: This is an OPTIONAL step + +**You are NOT required to run this command.** No MAP workflow includes automatic learning — learning is always a separate step via this command. + +Use /map-learn when: +- You completed /map-efficient, /map-debug, or /map-fast and want to extract lessons +- You want to batch-learn from multiple workflows at once +- You want to manually trigger learning for custom workflows + +**Do NOT use this command:** +- During active workflow execution (run after workflow completes) +- If no meaningful patterns emerged from the workflow + +--- + +## Step 1: Validate Input + +Check that $ARGUMENTS contains workflow summary: + +**Required information:** +- Workflow type (feature, debug, refactor, review, custom) +- Subtask outputs (Actor implementations) +- Validation results (Monitor feedback) +- Analysis results (Predictor/Evaluator outputs, if available) +- Workflow metrics (total subtasks, iterations, files changed) + +**If input is incomplete:** Ask user to provide missing information before proceeding. + +--- + +## Step 2: Read Existing Rules and Call Reflector + +### Step 2a: Gather existing lessons for deduplication + +Before calling the Reflector, read all existing `.claude/rules/learned/*.md` files (excluding README.md). Extract the bullet points from each file. + +```bash +ls .claude/rules/learned/*.md 2>/dev/null || echo "NO_EXISTING_RULES" +``` + +If files exist, read each one and collect all lines starting with `- **`. These are existing lessons that the Reflector should NOT duplicate. + +### Step 2b: Call Reflector + +**MUST use subagent_type="reflector"** (NOT general-purpose): + +``` +Task( + subagent_type="reflector", + description="Extract lessons from completed workflow", + prompt="Extract structured lessons from this workflow: + +**Workflow Summary:** +$ARGUMENTS + +**Existing learned rules (do NOT duplicate these):** +[paste extracted bullets from Step 2a, or 'None — first learning session' if no files exist] + +**Analysis Instructions:** + +Analyze holistically across ALL subtasks: +- What patterns emerged consistently? +- What worked well that should be repeated? +- What could be improved for future similar tasks? +- What knowledge should be preserved? +- What trade-offs were made and why? + +**Focus areas:** +- Implementation patterns (code structure, design decisions) +- Security patterns (auth, validation, error handling) +- Testing patterns (edge cases, test structure) +- Performance patterns (optimization, resource usage) +- Error patterns (what went wrong, how it was fixed) +- Architecture patterns (system design, component boundaries) + +**IMPORTANT:** Do NOT repeat any pattern from the 'Existing learned rules' list above. +Only suggest genuinely new patterns not already captured. + +**Output JSON with:** +- key_insight: string (one sentence takeaway in 'When X, always Y because Z' format) +- patterns_used: array of strings (existing patterns applied successfully) +- patterns_discovered: array of strings (new patterns worth preserving) +- suggested_new_bullets: array of {section, title, content, code_example, rationale} + where section is one of: SECURITY_PATTERNS, IMPLEMENTATION_PATTERNS, PERFORMANCE_PATTERNS, + ERROR_PATTERNS, ARCHITECTURE_PATTERNS, TESTING_STRATEGIES +- workflow_efficiency: {total_iterations, avg_per_subtask, bottlenecks: array of strings}" +) +``` + +--- + +## Step 3: Write Rules Files + +Transform Reflector output into `.claude/rules/learned/` markdown files. + +**Use the bundled templates** from `${CLAUDE_SKILL_DIR}/templates/` as the format reference: +- `rules-unconditional.md` for sections without `paths:` frontmatter +- `rules-with-paths.md` for language-scoped sections +- `example-rules.md` for bullet format with code snippets + +### Section-to-file mapping + +| Reflector section | File | `paths:` frontmatter | +|---|---|---| +| `SECURITY_PATTERNS` | `security-patterns.md` | None (loads always) | +| `IMPLEMENTATION_PATTERNS` | `implementation-patterns.md` | Derived from file extensions in workflow | +| `PERFORMANCE_PATTERNS` | `performance-patterns.md` | Derived from file extensions in workflow | +| `ERROR_PATTERNS` | `error-patterns.md` | None (loads always) | +| `ARCHITECTURE_PATTERNS` | `architecture-patterns.md` | None (loads always) | +| `TESTING_STRATEGIES` | `testing-strategies.md` | `["**/test_*", "**/tests/**", "**/*_test.*", "**/*.test.*"]` | + +### Deriving `paths:` frontmatter + +For `IMPLEMENTATION_PATTERNS` and `PERFORMANCE_PATTERNS`: +1. Extract file extensions from the workflow summary (e.g., `.py`, `.go`, `.ts`) +2. Generate glob patterns: `.py` → `["**/*.py"]`, `.go` → `["**/*.go"]` +3. If no extensions found or multiple languages, omit `paths:` (unconditional loading) + +### Writing each file + +For each `suggested_new_bullet` from the Reflector: + +1. **Determine target file** from the section mapping above. + +2. **If file does NOT exist**, create it using the template from `${CLAUDE_SKILL_DIR}/templates/`: + - Use `rules-with-paths.md` template for sections with path scoping + - Use `rules-unconditional.md` template for cross-cutting sections + - Replace `{SECTION_TITLE}` with the human-readable section name + - Replace `{EXT}` with the derived extension glob + +3. **Append the bullet** to the file: + +```markdown +- **{title}** ({YYYY-MM-DD}): {content} [workflow: {workflow_type}] +``` + +If `code_example` is present, add it indented below (see `example-rules.md` for format): + +```markdown +- **{title}** ({YYYY-MM-DD}): {content} [workflow: {workflow_type}] + ```{language} + {code_example} + ``` +``` + +4. **Also write `key_insight`** from the top-level Reflector output as a bullet in the most relevant section file. Use section `IMPLEMENTATION_PATTERNS` as default if no better match. + +### File size check + +After writing, count bullets in each modified file. If any file exceeds 50 bullets, print a warning: + +``` +⚠ {filename} has {N} rules (recommended max: 50). Consider pruning old or low-value rules. +``` + +--- + +## Step 4: Summary Report + +Print the learning summary: + +```markdown +## /map-learn Completion Summary + +**Workflow Analyzed:** [workflow type from input] +**Total Subtasks:** [N] + +### Rules Written to .claude/rules/learned/ +[For each file written:] +- {filename}: +{N} rules ({action: 'new file created' | 'appended'}) +[If duplicates were skipped:] +- Duplicates skipped: {N} + +### Reflector Insights +- **Key Insight:** [key_insight] +- **Patterns Applied:** [count] existing patterns used successfully +- **Patterns Discovered:** [count] new patterns identified + +### Workflow Efficiency +- **Total Iterations:** [total_iterations] +- **Average per Subtask:** [avg_per_subtask] +- **Bottlenecks:** [list bottlenecks] + +### Next Steps +- Review written rules: open `.claude/rules/learned/` files +- Rules will auto-load in next Claude Code session +- Commit to share with team: `git add .claude/rules/` + +**Learning extraction and persistence complete.** +``` + +--- + +## Token Budget Estimate + +**Typical /map-learn execution:** +- Read existing rules: ~500 tokens +- Reflector: ~3K tokens (depends on workflow size) +- Write rules + summary: ~1K tokens +- **Total:** 4-5K tokens for standard workflow + +**Large workflow (8+ subtasks):** +- Read existing rules: ~1K tokens +- Reflector: ~6K tokens +- Write rules + summary: ~2K tokens +- **Total:** 8-9K tokens + +--- + +## Examples + +### Example 1: First learning session (no existing rules) + +``` +User: /map-learn "Workflow: /map-efficient 'Add user authentication' +Subtasks: 3 (JWT setup, middleware, tests) +Files: api/auth.py, middleware/jwt.py, tests/test_auth.py +Iterations: 5 + +Key decisions: +- Used PyJWT with RS256 +- Middleware validates on every request +- Refresh token rotation implemented" +``` + +Result: Creates `.claude/rules/learned/security-patterns.md` and `implementation-patterns.md` with new rules. + +### Example 2: Second learning session (deduplication) + +``` +User: /map-learn "Workflow: /map-efficient 'Add API rate limiting' +Subtasks: 2 (rate limiter, tests) +Files: middleware/rate_limit.py, tests/test_rate_limit.py +Iterations: 3" +``` + +Reflector sees existing JWT/auth patterns in `security-patterns.md`, does NOT duplicate them, only adds new rate-limiting patterns. + +### Example 3: Batched learning + +``` +User: /map-learn "Workflows: 3 debugging sessions this week +Session 1: Race condition in payment processing → DB transaction locks +Session 2: Memory leak in WebSocket → connection pooling +Session 3: Timezone bug in scheduler → always UTC internally" +``` + +Result: Appends patterns across multiple topic files. + +--- + +## Integration with Other Commands + +### After /map-efficient (recommended) +/map-efficient prints: "Optional: Run /map-learn to preserve patterns." + +### After /map-debug (recommended) +Preserves debugging patterns and root cause analysis approaches. + +### After /map-fast (optional) +Only if the work revealed patterns worth preserving. + +--- + +## Troubleshooting + +**No `.claude/rules/learned/` directory:** Run `mapify init` or create it manually: `mkdir -p .claude/rules/learned` + +**Rules not loading in next session:** Verify files are `.md` format in `.claude/rules/learned/`. Check that `paths:` frontmatter globs match your file structure. Run `/memory` to see loaded rules. + +**Too many rules (>50 per file):** Prune outdated lessons. Remove rules that no longer apply or are too project-specific. Keep only patterns that prevent real mistakes. + +**Duplicate rules appearing:** Ensure Step 2a reads existing rules before calling Reflector. If duplicates persist, manually remove them — the deduplication is LLM-based and not perfect. + +**Reflector returns empty results:** Provide more detail in the workflow summary. Include specific files changed, iterations, and key decisions. + +--- + +## Final Notes + +**This command is OPTIONAL.** You are not required to run it after every workflow. + +**Where rules are stored:** `.claude/rules/learned/` — committed with the project, shared with team, auto-loaded by Claude Code. + +**Rules are yours to edit.** Add context, fix inaccuracies, prune outdated patterns. They are project knowledge, not framework artifacts. + +**Goal:** Each `/map-learn` invocation makes the next session stronger. If you're still explaining the same gotchas to Claude after running `/map-learn`, the rules need to be more specific. diff --git a/src/mapify_cli/templates/skills/map-learn/templates/example-rules.md b/src/mapify_cli/templates/skills/map-learn/templates/example-rules.md new file mode 100644 index 00000000..522b692e --- /dev/null +++ b/src/mapify_cli/templates/skills/map-learn/templates/example-rules.md @@ -0,0 +1,19 @@ +--- +paths: + - "**/*.go" +--- + +# Implementation Patterns (Learned) + + + +- **Re-fetch after update** (2026-03-15): When calling r.Update() on a Kubernetes resource, always re-fetch with r.Get() before reading updated fields because the in-memory object is stale after update. [workflow: map-efficient] + +- **SetStatusCondition needs observedGeneration** (2026-03-16): When using meta.SetStatusCondition(), always set ObservedGeneration to the resource's current Generation to prevent stale condition reporting. [workflow: map-debug] + ```go + meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{ + ObservedGeneration: obj.Generation, // required + }) + ``` + +- **Webhook latency** (2026-03-18): When implementing admission webhooks, always read from status/cache instead of listing pods or querying external APIs because webhook timeout is 10s and slow webhooks block all API operations. [workflow: map-efficient] diff --git a/src/mapify_cli/templates/skills/map-learn/templates/rules-unconditional.md b/src/mapify_cli/templates/skills/map-learn/templates/rules-unconditional.md new file mode 100644 index 00000000..32bb15ea --- /dev/null +++ b/src/mapify_cli/templates/skills/map-learn/templates/rules-unconditional.md @@ -0,0 +1,5 @@ +# {SECTION_TITLE} (Learned) + + + +- **{title}** ({YYYY-MM-DD}): When {situation}, always {action} because {reason}. [workflow: {type}] diff --git a/src/mapify_cli/templates/skills/map-learn/templates/rules-with-paths.md b/src/mapify_cli/templates/skills/map-learn/templates/rules-with-paths.md new file mode 100644 index 00000000..5a3770a9 --- /dev/null +++ b/src/mapify_cli/templates/skills/map-learn/templates/rules-with-paths.md @@ -0,0 +1,10 @@ +--- +paths: + - "**/*.{EXT}" +--- + +# {SECTION_TITLE} (Learned) + + + +- **{title}** ({YYYY-MM-DD}): When {situation}, always {action} because {reason}. [workflow: {type}] diff --git a/src/mapify_cli/templates/skills/skill-rules.json b/src/mapify_cli/templates/skills/skill-rules.json index 6212eeb7..eedaa7c8 100644 --- a/src/mapify_cli/templates/skills/skill-rules.json +++ b/src/mapify_cli/templates/skills/skill-rules.json @@ -48,6 +48,28 @@ ] } }, + "map-learn": { + "type": "domain", + "enforcement": "suggest", + "priority": "low", + "description": "Extract and persist workflow lessons to .claude/rules/learned/", + "promptTriggers": { + "keywords": [ + "extract lessons", + "save patterns", + "learn from workflow", + "preserve learnings", + "map-learn", + "project memory", + "capture gotchas" + ], + "intentPatterns": [ + "(extract|save|preserve|capture).*(lesson|pattern|learning|gotcha)", + "(learn|remember).*(workflow|session|implementation)", + "map-learn" + ] + } + }, "map-cli-reference": { "type": "domain", "enforcement": "suggest", From 8d14dabfdfd262df96c6f966bedfdbdb3bdf5646 Mon Sep 17 00:00:00 2001 From: "Mikhail [azalio] Petrov" Date: Thu, 26 Mar 2026 16:14:06 +0300 Subject: [PATCH 3/3] docs: add first learned rules from /map-learn (7 patterns) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First /map-learn invocation on map-learn-improvement workflow. Rules auto-load in future Claude Code sessions via .claude/rules/. - architecture-patterns.md: contract-first JSON schemas, extract shared helpers before monolith decomposition - implementation-patterns.md (Python-scoped): dataclass type validation, validation function return semantics - error-patterns.md: timestamped backups, control char sanitization - testing-strategies.md (test-scoped): Monitor bugs → regression tests --- .claude/rules/learned/architecture-patterns.md | 16 ++++++++++++++++ .claude/rules/learned/error-patterns.md | 13 +++++++++++++ .claude/rules/learned/implementation-patterns.md | 12 ++++++++++++ .claude/rules/learned/testing-strategies.md | 13 +++++++++++++ 4 files changed, 54 insertions(+) create mode 100644 .claude/rules/learned/architecture-patterns.md create mode 100644 .claude/rules/learned/error-patterns.md create mode 100644 .claude/rules/learned/implementation-patterns.md create mode 100644 .claude/rules/learned/testing-strategies.md diff --git a/.claude/rules/learned/architecture-patterns.md b/.claude/rules/learned/architecture-patterns.md new file mode 100644 index 00000000..9428d161 --- /dev/null +++ b/.claude/rules/learned/architecture-patterns.md @@ -0,0 +1,16 @@ +# Architecture Patterns (Learned) + + + +- **Contract-First Inter-Component JSON Schemas** (2026-03-26): When two components share a JSON data format (file, IPC, API), always define the schema once as a Python TypedDict or dataclass and import it in both producer and consumer, because organic field names cause silent KeyError failures that only surface in production. [workflow: map-learn-improvement] + ```python + from typing import TypedDict + + class StepState(TypedDict): + current_step_phase: str # canonical name, one definition + current_subtask_id: str | None + + # Producer and consumer both import StepState + ``` + +- **Monolith Decomposition: Extract Shared Helpers First** (2026-03-26): When decomposing a large Python module into submodules, always identify helpers shared by multiple extraction targets and extract them to a utility module FIRST, because copy-pasting helpers creates DRY violations that diverge silently. Re-export all extracted symbols from the original module to preserve backward compatibility. [workflow: map-learn-improvement] diff --git a/.claude/rules/learned/error-patterns.md b/.claude/rules/learned/error-patterns.md new file mode 100644 index 00000000..7d6e7554 --- /dev/null +++ b/.claude/rules/learned/error-patterns.md @@ -0,0 +1,13 @@ +# Error Patterns (Learned) + + + +- **Idempotent File Backups Need Timestamps** (2026-03-26): When creating backup files during upgrade operations, always use a timestamp suffix (not fixed .bak), because repeated upgrades silently overwrite previous backups, destroying the user's customizations permanently. [workflow: map-learn-improvement] + ```python + # WRONG: backup = dest.with_suffix(".bak") # overwritten next run + # CORRECT: + ts = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%S") + backup = dest.with_suffix(f"{dest.suffix}.{ts}.bak") + ``` + +- **Sanitize Control Characters Before External Tools** (2026-03-26): When building JSON that will be consumed by jq, log aggregators, or APIs, always strip ASCII control characters (U+0000-U+001F except \n \r \t) from string values before serialization, because Python json.dumps escapes them correctly but bash variable expansion and external parsers can corrupt them. [workflow: map-learn-improvement] diff --git a/.claude/rules/learned/implementation-patterns.md b/.claude/rules/learned/implementation-patterns.md new file mode 100644 index 00000000..5db2df41 --- /dev/null +++ b/.claude/rules/learned/implementation-patterns.md @@ -0,0 +1,12 @@ +--- +paths: + - "**/*.py" +--- + +# Implementation Patterns (Learned) + + + +- **Python Dataclass Type Validation** (2026-03-26): When building a dataclass from parsed YAML/JSON config, always add explicit type checking (isinstance in __post_init__ or pre-filter before construction), because Python dataclass type hints are documentation only — a string where int is expected passes silently and breaks downstream operations. [workflow: map-learn-improvement] + +- **Validation Functions Must Return None on Invalid** (2026-03-26): When writing a function named load_and_validate or similar, always return None (or raise) on invalid input and return data only on valid, because callers use `if result is not None:` as a validity signal — returning data on failure inverts the contract silently. [workflow: map-learn-improvement] diff --git a/.claude/rules/learned/testing-strategies.md b/.claude/rules/learned/testing-strategies.md new file mode 100644 index 00000000..7f5a6bae --- /dev/null +++ b/.claude/rules/learned/testing-strategies.md @@ -0,0 +1,13 @@ +--- +paths: + - "**/test_*" + - "**/tests/**" + - "**/*_test.*" + - "**/*.test.*" +--- + +# Testing Strategies (Learned) + + + +- **Monitor Bugs Must Generate Regression Tests** (2026-03-26): When Monitor (or any review tool) finds a bug, always write a failing test that reproduces the bug BEFORE fixing it, because without a regression test the same bug silently reappears during future refactors. Name tests `test__` to serve as living documentation. [workflow: map-learn-improvement]