stravinsky 0.2.40__py3-none-any.whl → 0.2.67__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of stravinsky might be problematic. Click here for more details.

Files changed (52) hide show
  1. mcp_bridge/__init__.py +1 -1
  2. mcp_bridge/auth/token_refresh.py +130 -0
  3. mcp_bridge/cli/__init__.py +6 -0
  4. mcp_bridge/cli/install_hooks.py +1265 -0
  5. mcp_bridge/cli/session_report.py +585 -0
  6. mcp_bridge/hooks/HOOKS_SETTINGS.json +175 -0
  7. mcp_bridge/hooks/README.md +215 -0
  8. mcp_bridge/hooks/__init__.py +117 -46
  9. mcp_bridge/hooks/edit_recovery.py +42 -37
  10. mcp_bridge/hooks/git_noninteractive.py +89 -0
  11. mcp_bridge/hooks/keyword_detector.py +30 -0
  12. mcp_bridge/hooks/manager.py +50 -0
  13. mcp_bridge/hooks/notification_hook.py +103 -0
  14. mcp_bridge/hooks/parallel_enforcer.py +127 -0
  15. mcp_bridge/hooks/parallel_execution.py +111 -0
  16. mcp_bridge/hooks/pre_compact.py +123 -0
  17. mcp_bridge/hooks/preemptive_compaction.py +81 -7
  18. mcp_bridge/hooks/rules_injector.py +507 -0
  19. mcp_bridge/hooks/session_idle.py +116 -0
  20. mcp_bridge/hooks/session_notifier.py +125 -0
  21. mcp_bridge/{native_hooks → hooks}/stravinsky_mode.py +51 -16
  22. mcp_bridge/hooks/subagent_stop.py +98 -0
  23. mcp_bridge/hooks/task_validator.py +73 -0
  24. mcp_bridge/hooks/tmux_manager.py +141 -0
  25. mcp_bridge/hooks/todo_continuation.py +90 -0
  26. mcp_bridge/hooks/todo_delegation.py +88 -0
  27. mcp_bridge/hooks/tool_messaging.py +164 -0
  28. mcp_bridge/hooks/truncator.py +21 -17
  29. mcp_bridge/prompts/__init__.py +3 -1
  30. mcp_bridge/prompts/dewey.py +30 -20
  31. mcp_bridge/prompts/explore.py +46 -8
  32. mcp_bridge/prompts/multimodal.py +24 -3
  33. mcp_bridge/prompts/planner.py +222 -0
  34. mcp_bridge/prompts/stravinsky.py +107 -28
  35. mcp_bridge/server.py +76 -10
  36. mcp_bridge/server_tools.py +164 -32
  37. mcp_bridge/tools/agent_manager.py +203 -96
  38. mcp_bridge/tools/background_tasks.py +2 -1
  39. mcp_bridge/tools/code_search.py +81 -9
  40. mcp_bridge/tools/lsp/tools.py +6 -2
  41. mcp_bridge/tools/model_invoke.py +270 -47
  42. mcp_bridge/tools/templates.py +32 -18
  43. stravinsky-0.2.67.dist-info/METADATA +284 -0
  44. stravinsky-0.2.67.dist-info/RECORD +76 -0
  45. stravinsky-0.2.67.dist-info/entry_points.txt +5 -0
  46. mcp_bridge/native_hooks/edit_recovery.py +0 -46
  47. mcp_bridge/native_hooks/truncator.py +0 -23
  48. stravinsky-0.2.40.dist-info/METADATA +0 -204
  49. stravinsky-0.2.40.dist-info/RECORD +0 -57
  50. stravinsky-0.2.40.dist-info/entry_points.txt +0 -3
  51. /mcp_bridge/{native_hooks → hooks}/context.py +0 -0
  52. {stravinsky-0.2.40.dist-info → stravinsky-0.2.67.dist-info}/WHEEL +0 -0
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ UserPromptSubmit hook: Todo Continuation Enforcer
4
+
5
+ Checks if there are incomplete todos (in_progress or pending) and injects
6
+ a reminder to continue working on them before starting new work.
7
+
8
+ Aligned with oh-my-opencode's [SYSTEM REMINDER - TODO CONTINUATION] pattern.
9
+ """
10
+ import json
11
+ import os
12
+ import sys
13
+ from pathlib import Path
14
+
15
+
16
+ def get_todo_state() -> dict:
17
+ """Try to get current todo state from Claude Code session or local cache."""
18
+ # Claude Code stores todo state - we can check via session files
19
+ # For now, we'll use a simple file-based approach
20
+ cwd = Path(os.environ.get("CLAUDE_CWD", "."))
21
+ todo_cache = cwd / ".claude" / "todo_state.json"
22
+
23
+ if todo_cache.exists():
24
+ try:
25
+ return json.loads(todo_cache.read_text())
26
+ except Exception:
27
+ pass
28
+
29
+ return {"todos": []}
30
+
31
+
32
+ def main():
33
+ try:
34
+ data = json.load(sys.stdin)
35
+ prompt = data.get("prompt", "")
36
+ except Exception:
37
+ return 0
38
+
39
+ # Get current todo state
40
+ state = get_todo_state()
41
+ todos = state.get("todos", [])
42
+
43
+ if not todos:
44
+ # No todos tracked, pass through
45
+ print(prompt)
46
+ return 0
47
+
48
+ # Count incomplete todos
49
+ in_progress = [t for t in todos if t.get("status") == "in_progress"]
50
+ pending = [t for t in todos if t.get("status") == "pending"]
51
+
52
+ if not in_progress and not pending:
53
+ # All todos complete, pass through
54
+ print(prompt)
55
+ return 0
56
+
57
+ # Build reminder
58
+ reminder_parts = ["[SYSTEM REMINDER - TODO CONTINUATION]", ""]
59
+
60
+ if in_progress:
61
+ reminder_parts.append(f"IN PROGRESS ({len(in_progress)} items):")
62
+ for t in in_progress:
63
+ reminder_parts.append(f" - {t.get('content', 'Unknown task')}")
64
+ reminder_parts.append("")
65
+
66
+ if pending:
67
+ reminder_parts.append(f"PENDING ({len(pending)} items):")
68
+ for t in pending[:5]: # Show max 5 pending
69
+ reminder_parts.append(f" - {t.get('content', 'Unknown task')}")
70
+ if len(pending) > 5:
71
+ reminder_parts.append(f" ... and {len(pending) - 5} more")
72
+ reminder_parts.append("")
73
+
74
+ reminder_parts.extend([
75
+ "IMPORTANT: You have incomplete work. Before starting anything new:",
76
+ "1. Continue working on IN_PROGRESS todos first",
77
+ "2. If blocked, explain why and move to next PENDING item",
78
+ "3. Only start NEW work if all todos are complete or explicitly abandoned",
79
+ "",
80
+ "---",
81
+ "",
82
+ ])
83
+
84
+ reminder = "\n".join(reminder_parts)
85
+ print(reminder + prompt)
86
+ return 0
87
+
88
+
89
+ if __name__ == "__main__":
90
+ sys.exit(main())
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ PostToolUse hook for TodoWrite: CRITICAL parallel execution enforcer.
4
+
5
+ This hook fires AFTER TodoWrite completes. If there are 2+ pending items,
6
+ it outputs a STRONG reminder that Task agents must be spawned immediately.
7
+
8
+ Exit code 2 is used to signal a HARD BLOCK - Claude should see this as
9
+ a failure condition requiring immediate correction.
10
+
11
+ Works in tandem with:
12
+ - parallel_execution.py (UserPromptSubmit): Pre-emptive instruction injection
13
+ - stravinsky_mode.py (PreToolUse): Hard blocking of Read/Grep/Bash tools
14
+ """
15
+ import json
16
+ import sys
17
+ from pathlib import Path
18
+
19
+ # Check if stravinsky mode is active (hard blocking enabled)
20
+ STRAVINSKY_MODE_FILE = Path.home() / ".stravinsky_mode"
21
+
22
+
23
+ def is_stravinsky_mode():
24
+ """Check if hard blocking mode is active."""
25
+ return STRAVINSKY_MODE_FILE.exists()
26
+
27
+
28
+ def main():
29
+ # Read hook input from stdin
30
+ try:
31
+ hook_input = json.load(sys.stdin)
32
+ except (json.JSONDecodeError, EOFError):
33
+ return 0
34
+
35
+ tool_name = hook_input.get("tool_name", "")
36
+
37
+ if tool_name != "TodoWrite":
38
+ return 0
39
+
40
+ # Get the todos that were just written
41
+ tool_input = hook_input.get("tool_input", {})
42
+ todos = tool_input.get("todos", [])
43
+
44
+ # Count pending todos
45
+ pending_count = sum(1 for t in todos if t.get("status") == "pending")
46
+
47
+ if pending_count < 2:
48
+ return 0
49
+
50
+ # Check if stravinsky mode is active
51
+ stravinsky_active = is_stravinsky_mode()
52
+
53
+ # CRITICAL: Output urgent reminder for parallel Task spawning
54
+ mode_warning = ""
55
+ if stravinsky_active:
56
+ mode_warning = """
57
+ ⚠️ STRAVINSKY MODE ACTIVE - Direct tools (Read, Grep, Bash) are BLOCKED.
58
+ You MUST use Task(subagent_type="explore", ...) for ALL file operations.
59
+ """
60
+
61
+ error_message = f"""
62
+ 🚨 PARALLEL DELEGATION REQUIRED 🚨
63
+
64
+ TodoWrite created {pending_count} pending items.
65
+ {mode_warning}
66
+ You MUST spawn Task agents for ALL independent TODOs in THIS SAME RESPONSE.
67
+
68
+ Required pattern (IMMEDIATELY after this message):
69
+ Task(subagent_type="explore", prompt="TODO 1...", description="TODO 1", run_in_background=true)
70
+ Task(subagent_type="explore", prompt="TODO 2...", description="TODO 2", run_in_background=true)
71
+ ...
72
+
73
+ DO NOT:
74
+ - End your response without spawning Tasks
75
+ - Mark TODOs in_progress before spawning Tasks
76
+ - Use Read/Grep/Bash directly (BLOCKED in stravinsky mode)
77
+
78
+ Your NEXT action MUST be multiple Task() calls, one for each independent TODO.
79
+ """
80
+ print(error_message, file=sys.stderr)
81
+
82
+ # Exit code 2 = HARD BLOCK in stravinsky mode
83
+ # Exit code 1 = WARNING otherwise
84
+ return 2 if stravinsky_active else 1
85
+
86
+
87
+ if __name__ == "__main__":
88
+ sys.exit(main())
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ PostToolUse hook for user-friendly tool messaging.
4
+
5
+ Outputs concise messages about which agent/tool was used and what it did.
6
+ Format examples:
7
+ - ast-grep('Searching for authentication patterns')
8
+ - delphi:openai/gpt-5.2-medium('Analyzing architecture trade-offs')
9
+ - explore:gemini-3-flash('Finding all API endpoints')
10
+ """
11
+
12
+ import json
13
+ import os
14
+ import sys
15
+
16
+ # Agent model mappings
17
+ AGENT_MODELS = {
18
+ "explore": "gemini-3-flash",
19
+ "dewey": "gemini-3-flash",
20
+ "code-reviewer": "sonnet",
21
+ "debugger": "sonnet",
22
+ "frontend": "gemini-3-pro-high",
23
+ "delphi": "gpt-5.2-medium",
24
+ }
25
+
26
+ # Tool display names
27
+ TOOL_NAMES = {
28
+ "mcp__stravinsky__ast_grep_search": "ast-grep",
29
+ "mcp__stravinsky__grep_search": "grep",
30
+ "mcp__stravinsky__glob_files": "glob",
31
+ "mcp__stravinsky__lsp_diagnostics": "lsp-diagnostics",
32
+ "mcp__stravinsky__lsp_hover": "lsp-hover",
33
+ "mcp__stravinsky__lsp_goto_definition": "lsp-goto-def",
34
+ "mcp__stravinsky__lsp_find_references": "lsp-find-refs",
35
+ "mcp__stravinsky__lsp_document_symbols": "lsp-symbols",
36
+ "mcp__stravinsky__lsp_workspace_symbols": "lsp-workspace-symbols",
37
+ "mcp__stravinsky__invoke_gemini": "gemini",
38
+ "mcp__stravinsky__invoke_openai": "openai",
39
+ "mcp__grep-app__searchCode": "grep.app",
40
+ "mcp__grep-app__github_file": "github-file",
41
+ }
42
+
43
+
44
+ def extract_description(tool_name: str, params: dict) -> str:
45
+ """Extract a concise description of what the tool did."""
46
+
47
+ # AST-grep
48
+ if "ast_grep" in tool_name:
49
+ pattern = params.get("pattern", "")
50
+ directory = params.get("directory", ".")
51
+ return f"Searching AST in {directory} for '{pattern[:40]}...'"
52
+
53
+ # Grep/search
54
+ if "grep_search" in tool_name or "searchCode" in tool_name:
55
+ pattern = params.get("pattern", params.get("query", ""))
56
+ return f"Searching for '{pattern[:40]}...'"
57
+
58
+ # Glob
59
+ if "glob_files" in tool_name:
60
+ pattern = params.get("pattern", "")
61
+ return f"Finding files matching '{pattern}'"
62
+
63
+ # LSP diagnostics
64
+ if "lsp_diagnostics" in tool_name:
65
+ file_path = params.get("file_path", "")
66
+ filename = os.path.basename(file_path) if file_path else "file"
67
+ return f"Checking {filename} for errors"
68
+
69
+ # LSP hover
70
+ if "lsp_hover" in tool_name:
71
+ file_path = params.get("file_path", "")
72
+ line = params.get("line", "")
73
+ filename = os.path.basename(file_path) if file_path else "file"
74
+ return f"Type info for {filename}:{line}"
75
+
76
+ # LSP goto definition
77
+ if "lsp_goto" in tool_name:
78
+ file_path = params.get("file_path", "")
79
+ filename = os.path.basename(file_path) if file_path else "symbol"
80
+ return f"Finding definition in {filename}"
81
+
82
+ # LSP find references
83
+ if "lsp_find_references" in tool_name:
84
+ file_path = params.get("file_path", "")
85
+ filename = os.path.basename(file_path) if file_path else "symbol"
86
+ return f"Finding all references to symbol in {filename}"
87
+
88
+ # LSP symbols
89
+ if "lsp_symbols" in tool_name or "lsp_document_symbols" in tool_name:
90
+ file_path = params.get("file_path", "")
91
+ filename = os.path.basename(file_path) if file_path else "file"
92
+ return f"Getting symbols from {filename}"
93
+
94
+ if "lsp_workspace_symbols" in tool_name:
95
+ query = params.get("query", "")
96
+ return f"Searching workspace for symbol '{query}'"
97
+
98
+ # Gemini invocation
99
+ if "invoke_gemini" in tool_name:
100
+ prompt = params.get("prompt", "")
101
+ # Extract first meaningful line
102
+ first_line = prompt.split('\n')[0][:50] if prompt else "Processing"
103
+ return first_line
104
+
105
+ # OpenAI invocation
106
+ if "invoke_openai" in tool_name:
107
+ prompt = params.get("prompt", "")
108
+ first_line = prompt.split('\n')[0][:50] if prompt else "Strategic analysis"
109
+ return first_line
110
+
111
+ # GitHub file fetch
112
+ if "github_file" in tool_name:
113
+ path = params.get("path", "")
114
+ repo = params.get("repo", "")
115
+ return f"Fetching {path} from {repo}"
116
+
117
+ # Task delegation
118
+ if tool_name == "Task":
119
+ subagent_type = params.get("subagent_type", "unknown")
120
+ description = params.get("description", "")
121
+ model = AGENT_MODELS.get(subagent_type, "unknown")
122
+ return f"{subagent_type}:{model}('{description}')"
123
+
124
+ return "Processing"
125
+
126
+
127
+ def main():
128
+ try:
129
+ # Read hook input from stdin
130
+ hook_input = json.loads(sys.stdin.read())
131
+
132
+ tool_name = hook_input.get("toolName", hook_input.get("tool_name", ""))
133
+ params = hook_input.get("params", hook_input.get("tool_input", {}))
134
+
135
+ # Only output messages for MCP tools and Task delegations
136
+ if not (tool_name.startswith("mcp__") or tool_name == "Task"):
137
+ sys.exit(0)
138
+
139
+ # Get tool display name
140
+ display_name = TOOL_NAMES.get(tool_name, tool_name)
141
+
142
+ # Special handling for Task delegations
143
+ if tool_name == "Task":
144
+ subagent_type = params.get("subagent_type", "unknown")
145
+ description = params.get("description", "")
146
+ model = AGENT_MODELS.get(subagent_type, "unknown")
147
+
148
+ # Show full agent delegation message
149
+ print(f"🎯 {subagent_type}:{model}('{description}')", file=sys.stderr)
150
+ else:
151
+ # Regular tool usage
152
+ description = extract_description(tool_name, params)
153
+ print(f"🔧 {display_name}('{description}')", file=sys.stderr)
154
+
155
+ sys.exit(0)
156
+
157
+ except Exception as e:
158
+ # On error, fail silently (don't disrupt workflow)
159
+ print(f"Tool messaging hook error: {e}", file=sys.stderr)
160
+ sys.exit(0)
161
+
162
+
163
+ if __name__ == "__main__":
164
+ main()
@@ -1,19 +1,23 @@
1
- """
2
- Tool output truncator hook.
3
- Limits the size of tool outputs to prevent context bloat.
4
- """
1
+ import os
2
+ import sys
3
+ import json
5
4
 
6
- from typing import Any, Dict, Optional
5
+ MAX_CHARS = 30000
7
6
 
8
- async def output_truncator_hook(tool_name: str, arguments: Dict[str, Any], output: str) -> Optional[str]:
9
- """
10
- Truncates tool output if it exceeds a certain length.
11
- """
12
- MAX_LENGTH = 30000 # 30k characters limit
13
-
14
- if len(output) > MAX_LENGTH:
15
- truncated = output[:MAX_LENGTH]
16
- summary = f"\n\n... (Result truncated from {len(output)} chars to {MAX_LENGTH} chars) ..."
17
- return truncated + summary
18
-
19
- return None
7
+ def main():
8
+ try:
9
+ data = json.load(sys.stdin)
10
+ tool_response = data.get("tool_response", "")
11
+ except Exception:
12
+ return
13
+
14
+ if len(tool_response) > MAX_CHARS:
15
+ header = f"[TRUNCATED - {len(tool_response)} chars reduced to {MAX_CHARS}]\n"
16
+ footer = "\n...[TRUNCATED]"
17
+ truncated = tool_response[:MAX_CHARS]
18
+ print(header + truncated + footer)
19
+ else:
20
+ print(tool_response)
21
+
22
+ if __name__ == "__main__":
23
+ main()
@@ -6,13 +6,15 @@ from . import explore
6
6
  from . import frontend
7
7
  from . import document_writer
8
8
  from . import multimodal
9
+ from . import planner
9
10
 
10
11
  __all__ = [
11
12
  "stravinsky",
12
- "delphi",
13
+ "delphi",
13
14
  "dewey",
14
15
  "explore",
15
16
  "frontend",
16
17
  "document_writer",
17
18
  "multimodal",
19
+ "planner",
18
20
  ]
@@ -50,8 +50,8 @@ Classify EVERY request into one of these categories before taking action:
50
50
 
51
51
  | Type | Trigger Examples | Tools |
52
52
  |------|------------------|-------|
53
- | **TYPE A: CONCEPTUAL** | "How do I use X?", "Best practice for Y?" | docs + websearch (parallel) |
54
- | **TYPE B: IMPLEMENTATION** | "How does X implement Y?", "Show me source of Z" | gh clone + read + blame |
53
+ | **TYPE A: CONCEPTUAL** | "How do I use X?", "Best practice for Y?" | exa websearch + grep-app GitHub search (parallel) |
54
+ | **TYPE B: IMPLEMENTATION** | "How does X implement Y?", "Show me source of Z" | gh clone + ast-grep + read + blame |
55
55
  | **TYPE C: CONTEXT** | "Why was this changed?", "History of X?" | gh issues/prs + git log/blame |
56
56
  | **TYPE D: COMPREHENSIVE** | Complex/ambiguous requests | ALL tools in parallel |
57
57
 
@@ -64,12 +64,15 @@ Classify EVERY request into one of these categories before taking action:
64
64
 
65
65
  **Execute in parallel (3+ calls)**:
66
66
  ```
67
- Tool 1: Search official documentation
68
- Tool 2: Web search for recent articles/tutorials ("library-name topic 2025")
69
- Tool 3: GitHub code search for usage patterns (grep_search)
67
+ Tool 1: mcp__MCP_DOCKER__web_search_exa(query="library-name topic 2026", num_results=5)
68
+ -> Current articles, blog posts, best practices (ALWAYS use Exa instead of native WebSearch)
69
+ Tool 2: mcp__grep-app__searchCode(query="library-name implementation pattern")
70
+ -> Real GitHub code examples with permalinks
71
+ Tool 3: gh search repos "library-name" --sort stars --limit 5
72
+ -> Popular repositories for reference
70
73
  ```
71
74
 
72
- **Output**: Summarize findings with links to official docs and real-world examples.
75
+ **Output**: Synthesize with evidence links (Exa URLs + GitHub permalinks).
73
76
 
74
77
  ---
75
78
 
@@ -85,8 +88,8 @@ Step 2: Get commit SHA for permalinks
85
88
  cd ${TMPDIR:-/tmp}/repo-name && git rev-parse HEAD
86
89
 
87
90
  Step 3: Find the implementation
88
- - grep_search for function/class
89
- - ast_grep_search for AST patterns
91
+ - mcp__ast-grep__find_code(pattern="function $NAME", language="typescript") for structural search
92
+ - grep_search for function/class names
90
93
  - Read the specific file
91
94
  - git blame for context if needed
92
95
 
@@ -97,9 +100,9 @@ Step 4: Construct permalink
97
100
  **Parallel acceleration (4+ calls)**:
98
101
  ```
99
102
  Tool 1: gh repo clone owner/repo ${TMPDIR:-/tmp}/repo -- --depth 1
100
- Tool 2: GitHub code search for function_name
103
+ Tool 2: mcp__grep-app__searchCode(query="repo:owner/repo function_name")
101
104
  Tool 3: gh api repos/owner/repo/commits/HEAD --jq '.sha'
102
- Tool 4: Documentation search for relevant API
105
+ Tool 4: mcp__MCP_DOCKER__web_search_exa(query="library-name function_name documentation 2026")
103
106
  ```
104
107
 
105
108
  ---
@@ -131,13 +134,15 @@ gh api repos/owner/repo/pulls/<number>/files
131
134
 
132
135
  **Execute ALL in parallel (6+ calls)**:
133
136
  ```
134
- // Documentation & Web
135
- Tool 1: Documentation search
136
- Tool 2: Web search ("topic recent updates 2025")
137
+ // Web Search (ALWAYS use Exa)
138
+ Tool 1: mcp__MCP_DOCKER__web_search_exa(query="topic recent updates 2026", num_results=10)
137
139
 
138
- // Code Search
139
- Tool 3: grep_search(pattern1)
140
- Tool 4: grep_search(pattern2) or ast_grep_search
140
+ // GitHub Code Search
141
+ Tool 2: mcp__grep-app__searchCode(query="topic implementation pattern")
142
+ Tool 3: mcp__grep-app__searchCode(query="topic usage example")
143
+
144
+ // AST Pattern Search
145
+ Tool 4: mcp__ast-grep__find_code(pattern="$PATTERN", language="typescript")
141
146
 
142
147
  // Source Analysis
143
148
  Tool 5: gh repo clone owner/repo ${TMPDIR:-/tmp}/repo -- --depth 1
@@ -182,15 +187,20 @@ https://github.com/tanstack/query/blob/abc123def/packages/react-query/src/useQue
182
187
 
183
188
  ---
184
189
 
185
- ## TOOL REFERENCE (Stravinsky Tools)
190
+ ## TOOL REFERENCE (Stravinsky + MCP DOCKER Tools)
186
191
 
187
192
  ### Primary Tools by Purpose
188
193
 
189
194
  | Purpose | Tool | Usage |
190
195
  |---------|------|-------|
191
- | **Code Search** | grep_search | Pattern-based search in local/cloned repos |
192
- | **AST Search** | ast_grep_search | AST-aware code pattern search |
193
- | **File Glob** | glob_files | Find files by pattern |
196
+ | **Web Search** | `mcp__MCP_DOCKER__web_search_exa` | **ALWAYS use instead of native WebSearch** - Real-time web search for current articles, docs, tutorials |
197
+ | **GitHub Code Search** | `mcp__grep-app__searchCode` | Search across public GitHub repositories - returns permalinks |
198
+ | **GitHub File Fetch** | `mcp__grep-app__github_file` | Fetch specific file from GitHub repo |
199
+ | **AST Pattern Search** | `mcp__ast-grep__find_code` | Structural code search across 25+ languages with AST awareness |
200
+ | **AST Replace** | `mcp__ast-grep__replace` | AST-aware code refactoring and replacement |
201
+ | **Local Code Search** | `grep_search` | Pattern-based search in local/cloned repos (uses ripgrep) |
202
+ | **Local AST Search** | `ast_grep_search` | AST search in cloned repos |
203
+ | **File Glob** | `glob_files` | Find files by pattern |
194
204
  | **Clone Repo** | gh CLI | `gh repo clone owner/repo ${TMPDIR:-/tmp}/name -- --depth 1` |
195
205
  | **Issues/PRs** | gh CLI | `gh search issues/prs "query" --repo owner/repo` |
196
206
  | **View Issue/PR** | gh CLI | `gh issue/pr view <num> --repo owner/repo --comments` |
@@ -96,14 +96,52 @@ Your response has **FAILED** if:
96
96
  - **No emojis**: Keep output clean and parseable
97
97
  - **No file creation**: Report findings as message text, never write files
98
98
 
99
- ## Tool Strategy
100
-
101
- Use the right tool for the job:
102
- - **Semantic search** (definitions, references): LSP tools
103
- - **Structural patterns** (function shapes, class structures): ast_grep_search
104
- - **Text patterns** (strings, comments, logs): grep
105
- - **File patterns** (find by name/extension): glob
106
- - **History/evolution** (when added, who changed): git commands
99
+ ## Tool Strategy & Available Tools
100
+
101
+ ### Local Codebase Tools
102
+ - **Semantic search** (definitions, references): `lsp_goto_definition`, `lsp_find_references`, `lsp_workspace_symbols`
103
+ - **Structural patterns** (function shapes, class structures): `ast_grep_search` (local), `mcp__ast-grep__find_code` (enhanced)
104
+ - **Text patterns** (strings, comments, logs): `grep_search` (local ripgrep)
105
+ - **File patterns** (find by name/extension): `glob_files`
106
+ - **History/evolution** (when added, who changed): git commands (`git log`, `git blame`)
107
+
108
+ ### MCP DOCKER Enhanced Tools (ALWAYS prefer these when searching)
109
+ - **`mcp__MCP_DOCKER__web_search_exa`**: Real-time web search for documentation, articles, best practices
110
+ - Use when: Researching external libraries, finding current tutorials, checking API docs
111
+ - Example: `mcp__MCP_DOCKER__web_search_exa(query="library-name best practices 2026", num_results=5)`
112
+
113
+ ### GitHub Code Search (MCP grep-app)
114
+ - **`mcp__grep-app__searchCode`**: Search across ALL public GitHub repositories
115
+ - Use when: Finding implementation examples, usage patterns, community solutions
116
+ - Returns: GitHub permalinks with full context
117
+ - Example: `mcp__grep-app__searchCode(query="repo:owner/repo pattern")`
118
+ - **`mcp__grep-app__github_file`**: Fetch specific files from GitHub repos
119
+ - Use when: Need to read implementation from remote repo
120
+ - Example: `mcp__grep-app__github_file(owner="facebook", repo="react", path="src/hooks/useEffect.ts")`
121
+
122
+ ### AST-Aware Search (MCP ast-grep)
123
+ - **`mcp__ast-grep__find_code`**: Structural code search across 25+ languages
124
+ - Use when: Finding code patterns by structure, not just text
125
+ - Supports: TypeScript, Python, Rust, Go, Java, JavaScript, and 20+ more
126
+ - Example: `mcp__ast-grep__find_code(pattern="function $NAME($$$ARGS) { $$$ }", language="typescript")`
127
+ - **`mcp__ast-grep__find_code_by_rule`**: Advanced AST search with YAML rules
128
+ - Use when: Complex pattern matching with constraints
129
+ - Example: Find all async functions that don't handle errors
130
+
131
+ ### Parallel Search Strategy
132
+
133
+ **ALWAYS spawn 4-6 tools in parallel** for comprehensive search:
134
+
135
+ ```
136
+ # Example: "Find authentication implementation"
137
+ Parallel execution:
138
+ 1. lsp_workspace_symbols(query="auth")
139
+ 2. mcp__ast-grep__find_code(pattern="function $AUTH", language="typescript")
140
+ 3. mcp__grep-app__searchCode(query="repo:your-org/repo authentication")
141
+ 4. grep_search(pattern="authenticate|login|verify")
142
+ 5. glob_files(pattern="**/*auth*.ts")
143
+ 6. mcp__MCP_DOCKER__web_search_exa(query="library-name authentication implementation 2026")
144
+ ```
107
145
 
108
146
  Flood with parallel calls. Cross-validate findings across multiple tools."""
109
147
 
@@ -18,32 +18,53 @@ MULTIMODAL_SYSTEM_PROMPT = """You interpret media files that cannot be read as p
18
18
 
19
19
  Your job: examine the attached file and extract ONLY what was requested.
20
20
 
21
+ ## TOKEN OPTIMIZATION (CRITICAL)
22
+
23
+ You exist to REDUCE context token consumption. Instead of passing 50k tokens of raw
24
+ image/PDF data to the main agent, you summarize into 500-2000 tokens of actionable
25
+ information. This is a 95%+ reduction in context usage.
26
+
21
27
  When to use you:
22
28
  - Media files the Read tool cannot interpret
23
29
  - Extracting specific information or summaries from documents
24
30
  - Describing visual content in images or diagrams
25
31
  - When analyzed/extracted data is needed, not raw file contents
32
+ - UI screenshots for analysis (NOT for exact CSS recreation)
33
+ - PDF documents requiring data extraction
26
34
 
27
35
  When NOT to use you:
28
36
  - Source code or plain text files needing exact contents (use Read)
29
37
  - Files that need editing afterward (need literal content from Read)
30
38
  - Simple file reading where no interpretation is needed
31
39
 
32
- How you work:
40
+ ## How you work
41
+
33
42
  1. Receive a file path and a goal describing what to extract
34
- 2. Read and analyze the file deeply
35
- 3. Return ONLY the relevant extracted information
43
+ 2. Use invoke_gemini with the image/PDF for vision analysis:
44
+ ```
45
+ invoke_gemini(
46
+ prompt="Analyze this image: [goal]",
47
+ model="gemini-3-flash",
48
+ image_path="/path/to/file.png", # Vision API
49
+ agent_context={"agent_type": "multimodal"}
50
+ )
51
+ ```
52
+ 3. Return ONLY the relevant extracted information (compressed summary)
36
53
  4. The main agent never processes the raw file - you save context tokens
37
54
 
55
+ ## Output Guidelines
56
+
38
57
  For PDFs: extract text, structure, tables, data from specific sections
39
58
  For images: describe layouts, UI elements, text, diagrams, charts
40
59
  For diagrams: explain relationships, flows, architecture depicted
60
+ For screenshots: describe visible UI, key elements, layout structure
41
61
 
42
62
  Response rules:
43
63
  - Return extracted information directly, no preamble
44
64
  - If info not found, state clearly what's missing
45
65
  - Match the language of the request
46
66
  - Be thorough on the goal, concise on everything else
67
+ - Keep response under 2000 tokens when possible
47
68
 
48
69
  Your output goes straight to the main agent for continued work."""
49
70