feat: implement P0 auto-activation system for MAP workflows#23
Conversation
Implements P0 feature from claude-code-infrastructure-showcase analysis (commit 29cfeb1). What's new: - UserPromptSubmit hook automatically suggests workflows based on user prompt context - workflow-rules.json configuration with trigger patterns for all 5 MAP workflows - Session tracking prevents repeat suggestions (.claude/cache/workflow_suggestions_session.txt) - Keyword + intent pattern + file path matching (future enhancement) - Comprehensive test suite (7 test cases) Security fixes (CRITICAL): - Fixed command injection via stdin input (replaced --message argument) - Fixed heredoc variable expansion vulnerability (quoted delimiter + manual substitution) - Added ReDoS protection (regex timeout 2s, pattern validation, nested quantifier detection) - Backward compatibility maintained for Python helpers (stdin preferred, --message fallback) Benefits: - Users don't need to remember slash commands - Proactive workflow suggestions based on task description - Context-aware analysis of prompt keywords - Reduces cognitive load for workflow selection - Improves discoverability of MAP workflows Usage examples: - "Fix failing tests" → MAP suggests /map-debug (reason: Keywords: fix, failing test) - "Implement new feature" → MAP suggests /map-feature (reason: Keywords: implement, new feature) - "Optimize database queries" → MAP suggests /map-efficient (reason: Keywords: optimize) - "Restructure auth module" → MAP suggests /map-refactor (reason: Keywords: restructure) - "Quick prototype" → MAP suggests /map-fast (reason: Keywords: quick, prototype) Customization: - Edit .claude/workflow-rules.json to add project-specific triggers - Add keywords, regex patterns, file path patterns per workflow - Adjust priority levels for tie-breaking Testing: - Manual testing via: echo '{"prompt": "fix bug"}' | .claude/hooks/user-prompt-submit.sh - Automated testing: .claude/hooks/tests/test_auto_activation.sh - Session tracking verified (first suggestion shown, subsequent skipped) Template synchronization: - All files synced to src/mapify_cli/templates/ for distribution - Users running 'mapify init' get auto-activation feature automatically References: - Implementation plan: docs/AUTO_ACTIVATION_IMPLEMENTATION.md - Analysis: docs/MAP_VS_SHOWCASE_COMPARISON.md - Original pattern: claude-code-infrastructure-showcase (commit 29cfeb1) Effort: 4 hours (2-4 hours estimated, extended due to security fixes) Impact: Transforms MAP UX from manual workflow selection to proactive context-based suggestions Files modified/created: - .claude/workflow-rules.json (NEW) - .claude/hooks/user-prompt-submit.sh (MODIFIED - security fixes) - .claude/hooks/helpers/suggest_workflow.py (NEW) - .claude/hooks/helpers/inject_playbook_bullets.py (MODIFIED - stdin support) - .claude/hooks/settings.hooks.json (MODIFIED - description update) - .claude/hooks/README.md (MODIFIED - auto-activation section) - .claude/hooks/tests/test_auto_activation.sh (NEW) - src/mapify_cli/templates/* (SYNCED - all above files)
There was a problem hiding this comment.
Pull Request Overview
This PR introduces an intelligent workflow auto-activation system that automatically suggests appropriate MAP workflows based on user prompts. Instead of requiring users to remember specific slash commands, the system analyzes keywords and intent patterns to recommend workflows like /map-debug, /map-feature, or /map-efficient.
- Adds workflow suggestion logic with keyword and regex pattern matching
- Implements session tracking to prevent repeated suggestions
- Integrates security fixes (stdin input, quoted heredocs, regex timeout protection)
Reviewed Changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/mapify_cli/templates/workflow-rules.json |
Defines workflow trigger rules with keywords and intent patterns for 5 MAP workflows |
src/mapify_cli/templates/hooks/user-prompt-submit.sh |
Enhanced to suggest workflows alongside playbook injection with security improvements |
src/mapify_cli/templates/hooks/helpers/suggest_workflow.py |
New helper script implementing workflow matching logic with ReDoS protection |
src/mapify_cli/templates/hooks/helpers/inject_playbook_bullets.py |
Updated to accept stdin input instead of command arguments |
src/mapify_cli/templates/hooks/tests/test_auto_activation.sh |
Test suite validating workflow suggestion functionality |
src/mapify_cli/templates/hooks/settings.hooks.json |
Updated hook descriptions and added SessionStart hook |
src/mapify_cli/templates/hooks/README.md |
Comprehensive documentation for the auto-activation system |
.claude/workflow-rules.json |
Production instance of workflow rules configuration |
.claude/hooks/* |
Production instances of updated hook scripts |
README.md |
User-facing documentation explaining the auto-activation feature |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| for pattern in patterns: | ||
| is_valid, error = validate_regex_pattern(pattern) | ||
| if not is_valid: | ||
| print(f"[suggest_workflow] Invalid pattern in '{workflow_id}': {error}", file=sys.stderr) | ||
| # Remove invalid pattern instead of failing entire workflow | ||
| patterns.remove(pattern) |
There was a problem hiding this comment.
Modifying a list while iterating over it causes incorrect iteration behavior and may skip elements. The iterator becomes invalid after patterns.remove(pattern). Use a list comprehension or iterate over a copy instead: for pattern in patterns[:]: or filter invalid patterns after the loop.
| for pattern in patterns: | |
| is_valid, error = validate_regex_pattern(pattern) | |
| if not is_valid: | |
| print(f"[suggest_workflow] Invalid pattern in '{workflow_id}': {error}", file=sys.stderr) | |
| # Remove invalid pattern instead of failing entire workflow | |
| patterns.remove(pattern) | |
| valid_patterns = [] | |
| for pattern in patterns: | |
| is_valid, error = validate_regex_pattern(pattern) | |
| if not is_valid: | |
| print(f"[suggest_workflow] Invalid pattern in '{workflow_id}': {error}", file=sys.stderr) | |
| else: | |
| valid_patterns.append(pattern) | |
| # Replace with only valid patterns | |
| config['promptTriggers']['intentPatterns'] = valid_patterns |
| for pattern in patterns: | ||
| is_valid, error = validate_regex_pattern(pattern) | ||
| if not is_valid: | ||
| print(f"[suggest_workflow] Invalid pattern in '{workflow_id}': {error}", file=sys.stderr) | ||
| # Remove invalid pattern instead of failing entire workflow | ||
| patterns.remove(pattern) |
There was a problem hiding this comment.
Modifying a list while iterating over it causes incorrect iteration behavior and may skip elements. The iterator becomes invalid after patterns.remove(pattern). Use a list comprehension or iterate over a copy instead: for pattern in patterns[:]: or filter invalid patterns after the loop.
| for pattern in patterns: | |
| is_valid, error = validate_regex_pattern(pattern) | |
| if not is_valid: | |
| print(f"[suggest_workflow] Invalid pattern in '{workflow_id}': {error}", file=sys.stderr) | |
| # Remove invalid pattern instead of failing entire workflow | |
| patterns.remove(pattern) | |
| valid_patterns = [] | |
| for pattern in patterns: | |
| is_valid, error = validate_regex_pattern(pattern) | |
| if not is_valid: | |
| print(f"[suggest_workflow] Invalid pattern in '{workflow_id}': {error}", file=sys.stderr) | |
| else: | |
| valid_patterns.append(pattern) | |
| # Replace with filtered list of valid patterns | |
| config.setdefault('promptTriggers', {})['intentPatterns'] = valid_patterns |
…ility Root cause: After adding stdin support for security, both helpers checked sys.stdin.isatty() BEFORE args.message, causing pytest to fail with: "OSError: pytest: reading from stdin while output is captured!" Solution: Check args.message FIRST, then stdin. This maintains: - Backward compatibility with existing tests using --message flag - Secure stdin input when called from bash hooks - Tests can pass --message without triggering stdin read Files changed: - .claude/hooks/helpers/inject_playbook_bullets.py (lines 160-171) - .claude/hooks/helpers/suggest_workflow.py (lines 324-335) - Synced both to src/mapify_cli/templates/hooks/helpers/ References: PR #23, test failures in test_inject_playbook_bullets.py
Addresses reviewer feedback: modifying a list while iterating over it
causes incorrect iteration behavior and may skip elements.
Changed from:
for pattern in patterns:
if not is_valid:
patterns.remove(pattern) # ❌ Invalid iterator
To:
valid_patterns = []
for pattern in patterns:
if not is_valid:
# log error
else:
valid_patterns.append(pattern)
config['promptTriggers']['intentPatterns'] = valid_patterns
This ensures all patterns are validated correctly without iterator issues.
Reviewer: claude-reviewer (PR #23)
Files: .claude/hooks/helpers/suggest_workflow.py (line 110)
src/mapify_cli/templates/hooks/helpers/suggest_workflow.py (line 110)
…-35) MEDIUM fixes: - #8: Remove dead RETRY_LOOP phase from orchestrator STEP_PHASES - #10: Fix plan path to branch-scoped .map/<branch>/task_plan_<branch>.md - #11: Fix findings path to branch-scoped .map/<branch>/findings_<branch>.md - #12: Remove references to non-existent ralph-loop-config.json - #13/#14: Rewrite map-resume to use step_state.json instead of progress.md - #15: Fix INIT_PLAN heading format (### ST-XXX with - **Status:** prefix) - #16: Fix regex in step_runner to match plan format (### heading, - **Status:**) - #17: Fix map-learn contradiction about automatic learning LOW fixes: - #9/#31: Document dual state file system (step_state.json vs workflow_state.json) - #19: Document intentional Evaluator/Reflector/Curator omission in map-efficient - #20: Fix line count reference (~150 → ~540 lines) - #21: Standardize all AskUserQuestion to Python function call syntax - #22: Rename Steps 2.5/2.6 to 2a/2b to avoid phase number collision - #23/#24: Fix map-debate comparison table (map-efficient uses single Actor) - #25: Replace cat commands with Read tool comments in map-check - #28/#29: Replace undefined thrashing_detected()/max_redecompositions - #30: Add - **Status:** pending field to map-plan template - #32: Note map-fast max 3 vs map-efficient max 5 intentional difference - #33: Remove Evaluator from map-fast skipped agents list - #34: Move AskUserQuestion to "Built-in Tools" section in map-release - #35: Replace parallel bash & processes with sequential && in map-release Template sync: All .claude/ changes mirrored to src/mapify_cli/templates/
Summary
Implements P0 auto-activation system from claude-code-infrastructure-showcase analysis. Users no longer need to remember slash commands - MAP automatically suggests appropriate workflows based on prompt context.
What's New
Core Features
Security Fixes (CRITICAL)
Usage Examples
Files Modified
.claude/ (7 files):
src/mapify_cli/templates/ (7 files synced)
mapify initRoot:
Security Impact
Vulnerabilities Fixed:
New Playbook Patterns:
Testing
Benefits
mapify initImplementation Details
Workflow: MAP Efficient (batched learning, conditional Predictor)
Subtasks: 8/8 completed
Iterations: 9 total (1.125 avg per subtask)
Time: 4 hours
Token Usage: 125K / 200K (62.8%)
References
Test Plan
Ready for review. Security fixes are critical - recommend security-focused review of ST-002 implementation.