stravinsky 0.2.7__py3-none-any.whl → 0.2.38__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 (34) hide show
  1. mcp_bridge/__init__.py +1 -1
  2. mcp_bridge/auth/cli.py +84 -46
  3. mcp_bridge/auth/oauth.py +88 -63
  4. mcp_bridge/hooks/__init__.py +29 -8
  5. mcp_bridge/hooks/agent_reminder.py +61 -0
  6. mcp_bridge/hooks/auto_slash_command.py +186 -0
  7. mcp_bridge/hooks/comment_checker.py +136 -0
  8. mcp_bridge/hooks/context_monitor.py +58 -0
  9. mcp_bridge/hooks/empty_message_sanitizer.py +240 -0
  10. mcp_bridge/hooks/keyword_detector.py +122 -0
  11. mcp_bridge/hooks/manager.py +27 -8
  12. mcp_bridge/hooks/preemptive_compaction.py +157 -0
  13. mcp_bridge/hooks/session_recovery.py +186 -0
  14. mcp_bridge/hooks/todo_enforcer.py +75 -0
  15. mcp_bridge/hooks/truncator.py +1 -1
  16. mcp_bridge/native_hooks/stravinsky_mode.py +109 -0
  17. mcp_bridge/native_hooks/truncator.py +1 -1
  18. mcp_bridge/prompts/delphi.py +3 -2
  19. mcp_bridge/prompts/dewey.py +105 -21
  20. mcp_bridge/prompts/stravinsky.py +451 -127
  21. mcp_bridge/server.py +304 -38
  22. mcp_bridge/server_tools.py +21 -3
  23. mcp_bridge/tools/__init__.py +2 -1
  24. mcp_bridge/tools/agent_manager.py +307 -230
  25. mcp_bridge/tools/init.py +1 -1
  26. mcp_bridge/tools/model_invoke.py +534 -52
  27. mcp_bridge/tools/skill_loader.py +51 -47
  28. mcp_bridge/tools/task_runner.py +74 -30
  29. mcp_bridge/tools/templates.py +101 -12
  30. {stravinsky-0.2.7.dist-info → stravinsky-0.2.38.dist-info}/METADATA +6 -12
  31. stravinsky-0.2.38.dist-info/RECORD +57 -0
  32. stravinsky-0.2.7.dist-info/RECORD +0 -47
  33. {stravinsky-0.2.7.dist-info → stravinsky-0.2.38.dist-info}/WHEEL +0 -0
  34. {stravinsky-0.2.7.dist-info → stravinsky-0.2.38.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,186 @@
1
+ """
2
+ Session Recovery Hook.
3
+
4
+ Detects and recovers from corrupted sessions:
5
+ - Detects missing tool results after tool calls
6
+ - Injects synthetic tool_result blocks with status messages
7
+ - Enables graceful recovery
8
+ - Registered as post_tool_call hook
9
+ """
10
+
11
+ import logging
12
+ import re
13
+ import json
14
+ from typing import Any, Dict, Optional
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ # Patterns that indicate a tool call failure or corruption
19
+ CORRUPTION_PATTERNS = [
20
+ r"tool_result.*missing",
21
+ r"no response from tool",
22
+ r"tool call timed out",
23
+ r"connection reset",
24
+ r"unexpected end of.*response",
25
+ r"malformed.*response",
26
+ r"incomplete.*result",
27
+ r"truncated.*output",
28
+ r"<!DOCTYPE html>", # HTML error pages
29
+ r"<html>.*error",
30
+ r"500 Internal Server Error",
31
+ r"502 Bad Gateway",
32
+ r"503 Service Unavailable",
33
+ r"504 Gateway Timeout",
34
+ ]
35
+
36
+ # Patterns indicating empty or null responses
37
+ EMPTY_RESPONSE_PATTERNS = [
38
+ r"^\s*$",
39
+ r"^null$",
40
+ r"^undefined$",
41
+ r"^None$",
42
+ r"^\{\s*\}$",
43
+ r"^\[\s*\]$",
44
+ ]
45
+
46
+ # Tool-specific recovery strategies
47
+ TOOL_RECOVERY_STRATEGIES = {
48
+ "invoke_gemini": "Model invocation failed. Try reducing prompt size or switching to a different model variant.",
49
+ "invoke_openai": "Model invocation failed. Check authentication status with 'stravinsky auth status'.",
50
+ "agent_spawn": "Agent spawn failed. Check if Claude CLI is available and properly configured.",
51
+ "agent_output": "Agent output retrieval failed. The agent may still be running - try agent_progress first.",
52
+ "grep_search": "Search failed. Verify the pattern syntax and directory path.",
53
+ "ast_grep_search": "AST search failed. Ensure the language is supported and pattern is valid.",
54
+ "lsp_hover": "LSP hover failed. The language server may not be running for this file type.",
55
+ "session_read": "Session read failed. The session may have been corrupted or deleted.",
56
+ }
57
+
58
+ RECOVERY_NOTICE = """
59
+ > **[SESSION RECOVERY]**
60
+ > A tool result appears to be corrupted or incomplete.
61
+ > **Tool**: {tool_name}
62
+ > **Issue**: {issue}
63
+ > **Recovery**: {recovery_hint}
64
+ >
65
+ > The operation should be retried or an alternative approach should be used.
66
+ """
67
+
68
+ SYNTHETIC_RESULT_TEMPLATE = """
69
+ [RECOVERED TOOL RESULT]
70
+ Status: FAILED - Corrupted or incomplete response detected
71
+ Tool: {tool_name}
72
+ Original output (truncated): {truncated_output}
73
+
74
+ Recovery Hint: {recovery_hint}
75
+
76
+ Recommended Actions:
77
+ 1. Retry the tool call with the same or modified parameters
78
+ 2. Check system health with get_system_health tool
79
+ 3. If persistent, try an alternative approach
80
+ """
81
+
82
+
83
+ def detect_corruption(output: str) -> Optional[str]:
84
+ """
85
+ Detect if the output shows signs of corruption.
86
+
87
+ Returns:
88
+ Description of the corruption issue, or None if output appears valid
89
+ """
90
+ # Check for completely empty output
91
+ if not output or output.strip() == "":
92
+ return "Empty response received"
93
+
94
+ # Check for empty response patterns
95
+ for pattern in EMPTY_RESPONSE_PATTERNS:
96
+ if re.match(pattern, output.strip(), re.IGNORECASE):
97
+ return f"Empty or null response: {output[:50]}"
98
+
99
+ # Check for corruption patterns
100
+ for pattern in CORRUPTION_PATTERNS:
101
+ if re.search(pattern, output, re.IGNORECASE):
102
+ return f"Corruption pattern detected: {pattern}"
103
+
104
+ # Check for extremely short responses that might indicate truncation
105
+ # (only for tools that typically return substantial output)
106
+ if len(output.strip()) < 10 and not output.strip().startswith(("{", "[", "true", "false")):
107
+ # Could be truncated, but might also be valid short output
108
+ # Only flag if it looks like truncated text
109
+ if output.strip().endswith(("...", "---", "...)")):
110
+ return "Response appears truncated"
111
+
112
+ return None
113
+
114
+
115
+ def get_recovery_hint(tool_name: str, issue: str) -> str:
116
+ """Get a recovery hint based on the tool and issue."""
117
+ # Check for tool-specific strategy
118
+ if tool_name in TOOL_RECOVERY_STRATEGIES:
119
+ return TOOL_RECOVERY_STRATEGIES[tool_name]
120
+
121
+ # Generic recovery hints based on issue type
122
+ if "empty" in issue.lower():
123
+ return "Retry the operation. If it persists, check if the resource exists."
124
+ if "timeout" in issue.lower():
125
+ return "The operation timed out. Try with smaller input or increase timeout."
126
+ if "connection" in issue.lower():
127
+ return "Network issue detected. Check connectivity and retry."
128
+ if "500" in issue or "502" in issue or "503" in issue:
129
+ return "Server error detected. Wait a moment and retry."
130
+ if "truncated" in issue.lower():
131
+ return "Response was truncated. Try requesting smaller chunks of data."
132
+
133
+ return "Retry the operation or try an alternative approach."
134
+
135
+
136
+ async def session_recovery_hook(
137
+ tool_name: str,
138
+ arguments: Dict[str, Any],
139
+ output: str
140
+ ) -> Optional[str]:
141
+ """
142
+ Post-tool call hook that detects corrupted results and injects recovery information.
143
+
144
+ Args:
145
+ tool_name: Name of the tool that was called
146
+ arguments: Arguments passed to the tool
147
+ output: The output returned by the tool
148
+
149
+ Returns:
150
+ Modified output with recovery information, or None to keep original
151
+ """
152
+ # Detect corruption
153
+ issue = detect_corruption(output)
154
+
155
+ if not issue:
156
+ return None
157
+
158
+ logger.warning(f"[SessionRecovery] Corruption detected in {tool_name}: {issue}")
159
+
160
+ # Get recovery hint
161
+ recovery_hint = get_recovery_hint(tool_name, issue)
162
+
163
+ # Truncate original output for display
164
+ truncated_output = output[:200] + "..." if len(output) > 200 else output
165
+ truncated_output = truncated_output.replace("\n", " ").strip()
166
+
167
+ # Build synthetic result
168
+ synthetic_result = SYNTHETIC_RESULT_TEMPLATE.format(
169
+ tool_name=tool_name,
170
+ truncated_output=truncated_output,
171
+ recovery_hint=recovery_hint,
172
+ )
173
+
174
+ # Build recovery notice
175
+ recovery_notice = RECOVERY_NOTICE.format(
176
+ tool_name=tool_name,
177
+ issue=issue,
178
+ recovery_hint=recovery_hint,
179
+ )
180
+
181
+ # Return combined output
182
+ recovered_output = synthetic_result + "\n" + recovery_notice
183
+
184
+ logger.info(f"[SessionRecovery] Injected recovery guidance for {tool_name}")
185
+
186
+ return recovered_output
@@ -0,0 +1,75 @@
1
+ """
2
+ Todo Continuation Enforcer Hook.
3
+
4
+ Prevents early stopping when pending todos exist.
5
+ Injects a system reminder forcing the agent to complete all todos.
6
+ """
7
+
8
+ import logging
9
+ from typing import Any, Dict, Optional
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ TODO_CONTINUATION_REMINDER = """
14
+ [SYSTEM REMINDER - TODO CONTINUATION]
15
+
16
+ You have pending todos that are NOT yet completed. You MUST continue working.
17
+
18
+ **Pending Todos:**
19
+ {pending_todos}
20
+
21
+ **Rules:**
22
+ 1. You CANNOT stop or deliver a final answer while todos remain pending
23
+ 2. Mark each todo `in_progress` before starting, `completed` immediately after
24
+ 3. If a todo is blocked, mark it `cancelled` with explanation and create new actionable todos
25
+ 4. Only after ALL todos are `completed` or `cancelled` can you deliver your final answer
26
+
27
+ CONTINUE WORKING NOW. Do not acknowledge this message - just proceed with the next pending todo.
28
+ """
29
+
30
+
31
+ async def todo_continuation_hook(params: Dict[str, Any]) -> Optional[Dict[str, Any]]:
32
+ """
33
+ Pre-model invoke hook that checks for pending todos.
34
+
35
+ If pending todos exist, injects a reminder into the prompt
36
+ forcing the agent to continue working.
37
+ """
38
+ prompt = params.get("prompt", "")
39
+
40
+ pending_todos = _extract_pending_todos(prompt)
41
+
42
+ if pending_todos:
43
+ logger.info(
44
+ f"[TodoEnforcer] Found {len(pending_todos)} pending todos, injecting continuation reminder"
45
+ )
46
+
47
+ todos_formatted = "\n".join(f"- [ ] {todo}" for todo in pending_todos)
48
+ reminder = TODO_CONTINUATION_REMINDER.format(pending_todos=todos_formatted)
49
+
50
+ modified_prompt = prompt + "\n\n" + reminder
51
+ params["prompt"] = modified_prompt
52
+
53
+ return params
54
+
55
+ return None
56
+
57
+
58
+ def _extract_pending_todos(prompt: str) -> list:
59
+ """
60
+ Extract pending todos from the prompt/context.
61
+ Looks for common todo patterns.
62
+ """
63
+ pending = []
64
+ lines = prompt.split("\n")
65
+
66
+ for line in lines:
67
+ stripped = line.strip()
68
+ if stripped.startswith("- [ ]") or stripped.startswith("* [ ]"):
69
+ todo_text = stripped[5:].strip()
70
+ if todo_text:
71
+ pending.append(todo_text)
72
+ elif '"status": "pending"' in stripped or '"status": "in_progress"' in stripped:
73
+ pass
74
+
75
+ return pending
@@ -9,7 +9,7 @@ async def output_truncator_hook(tool_name: str, arguments: Dict[str, Any], outpu
9
9
  """
10
10
  Truncates tool output if it exceeds a certain length.
11
11
  """
12
- MAX_LENGTH = 10000 # 10k characters limit
12
+ MAX_LENGTH = 30000 # 30k characters limit
13
13
 
14
14
  if len(output) > MAX_LENGTH:
15
15
  truncated = output[:MAX_LENGTH]
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Stravinsky Mode Enforcer Hook
4
+
5
+ This PreToolUse hook blocks native file reading tools (Read, Search, Grep, Bash)
6
+ when stravinsky orchestrator mode is active, forcing use of agent_spawn instead.
7
+
8
+ Stravinsky mode is activated by creating a marker file:
9
+ ~/.stravinsky_mode
10
+
11
+ The /strav:stravinsky command should create this file, and it should be
12
+ removed when the task is complete.
13
+
14
+ Exit codes:
15
+ 0 = Allow the tool to execute
16
+ 2 = Block the tool (reason sent via stderr)
17
+ """
18
+
19
+ import json
20
+ import os
21
+ import sys
22
+ from pathlib import Path
23
+
24
+ # Marker file that indicates stravinsky mode is active
25
+ STRAVINSKY_MODE_FILE = Path.home() / ".stravinsky_mode"
26
+
27
+ # Tools to block when in stravinsky mode
28
+ BLOCKED_TOOLS = {
29
+ "Read",
30
+ "Search",
31
+ "Grep",
32
+ "Bash",
33
+ "MultiEdit",
34
+ "Edit",
35
+ }
36
+
37
+ # Tools that are always allowed
38
+ ALLOWED_TOOLS = {
39
+ "TodoRead",
40
+ "TodoWrite",
41
+ "Task",
42
+ "Agent", # MCP agent tools should be allowed
43
+ }
44
+
45
+
46
+ def is_stravinsky_mode_active() -> bool:
47
+ """Check if stravinsky orchestrator mode is active."""
48
+ return STRAVINSKY_MODE_FILE.exists()
49
+
50
+
51
+ def read_stravinsky_mode_config() -> dict:
52
+ """Read the stravinsky mode configuration if it exists."""
53
+ if not STRAVINSKY_MODE_FILE.exists():
54
+ return {}
55
+ try:
56
+ return json.loads(STRAVINSKY_MODE_FILE.read_text())
57
+ except (json.JSONDecodeError, IOError):
58
+ return {"active": True}
59
+
60
+
61
+ def main():
62
+ # Read hook input from stdin
63
+ try:
64
+ hook_input = json.loads(sys.stdin.read())
65
+ except json.JSONDecodeError:
66
+ # If we can't parse input, allow the tool
67
+ sys.exit(0)
68
+
69
+ tool_name = hook_input.get("tool_name", "")
70
+
71
+ # Always allow certain tools
72
+ if tool_name in ALLOWED_TOOLS:
73
+ sys.exit(0)
74
+
75
+ # Check if stravinsky mode is active
76
+ if not is_stravinsky_mode_active():
77
+ # Not in stravinsky mode, allow all tools
78
+ sys.exit(0)
79
+
80
+ config = read_stravinsky_mode_config()
81
+
82
+ # Check if this tool should be blocked
83
+ if tool_name in BLOCKED_TOOLS:
84
+ # Block the tool and tell Claude why
85
+ reason = f"""⚠️ STRAVINSKY MODE ACTIVE - {tool_name} BLOCKED
86
+
87
+ You are in Stravinsky orchestrator mode. Native tools are disabled.
88
+
89
+ Instead of using {tool_name}, you MUST use:
90
+ - stravinsky:agent_spawn with agent_type="explore" for file reading/searching
91
+ - stravinsky:agent_spawn with agent_type="dewey" for documentation
92
+
93
+ Example:
94
+ agent_spawn(agent_type="explore", prompt="Read and analyze the file at path/to/file.py")
95
+
96
+ To exit stravinsky mode, run:
97
+ rm ~/.stravinsky_mode
98
+ """
99
+ # Send reason to stderr (Claude sees this)
100
+ print(reason, file=sys.stderr)
101
+ # Exit with code 2 to block the tool
102
+ sys.exit(2)
103
+
104
+ # Tool not in block list, allow it
105
+ sys.exit(0)
106
+
107
+
108
+ if __name__ == "__main__":
109
+ main()
@@ -2,7 +2,7 @@ import os
2
2
  import sys
3
3
  import json
4
4
 
5
- MAX_CHARS = 10000
5
+ MAX_CHARS = 30000
6
6
 
7
7
  def main():
8
8
  try:
@@ -3,6 +3,7 @@ Delphi - Strategic Technical Advisor Prompt
3
3
 
4
4
  Expert technical advisor with deep reasoning for architecture decisions,
5
5
  code analysis, and engineering guidance. Uses GPT for strategic reasoning.
6
+ Aligned with Oracle from oh-my-opencode.
6
7
  """
7
8
 
8
9
  # Prompt metadata for agent routing
@@ -37,7 +38,7 @@ DELPHI_SYSTEM_PROMPT = """You are a strategic technical advisor with deep reason
37
38
 
38
39
  ## Context
39
40
 
40
- You function as an on-demand specialist invoked by a primary coding agent when complex analysis or architectural decisions require elevated reasoning. Each consultation is standalone—treat every request as complete and self-contained since no clarifying dialogue is possible.
41
+ You function as an on-demand specialist invoked by a primary coding agent (Stravinsky) when complex analysis or architectural decisions require elevated reasoning. Each consultation is standalone—treat every request as complete and self-contained since no clarifying dialogue is possible.
41
42
 
42
43
  ## What You Do
43
44
 
@@ -103,7 +104,7 @@ Your response goes directly to the user with no intermediate processing. Make yo
103
104
  def get_delphi_prompt() -> str:
104
105
  """
105
106
  Get the Delphi advisor system prompt.
106
-
107
+
107
108
  Returns:
108
109
  The full system prompt for the Delphi agent.
109
110
  """
@@ -3,6 +3,7 @@ Dewey - Open Source Codebase Understanding Agent
3
3
 
4
4
  Specialized agent for multi-repository analysis, searching remote codebases,
5
5
  retrieving official documentation, and finding implementation examples.
6
+ Aligned with Librarian from oh-my-opencode.
6
7
  """
7
8
 
8
9
  # Prompt metadata for agent routing
@@ -10,11 +11,11 @@ DEWEY_METADATA = {
10
11
  "category": "exploration",
11
12
  "cost": "CHEAP",
12
13
  "prompt_alias": "Dewey",
13
- "key_trigger": "External library/source mentioned fire `dewey` background",
14
+ "key_trigger": "External library/source mentioned -> fire `dewey` background",
14
15
  "triggers": [
15
16
  {
16
17
  "domain": "Dewey",
17
- "trigger": "Unfamiliar packages / libraries, struggles at weird behaviour",
18
+ "trigger": "Unfamiliar packages / libraries, struggles at weird behaviour (to find existing implementation of opensource)",
18
19
  },
19
20
  ],
20
21
  "use_when": [
@@ -27,9 +28,9 @@ DEWEY_METADATA = {
27
28
  }
28
29
 
29
30
 
30
- DEWEY_SYSTEM_PROMPT = """# THE DEWEY
31
+ DEWEY_SYSTEM_PROMPT = """# DEWEY
31
32
 
32
- You are **THE DEWEY**, a specialized open-source codebase understanding agent.
33
+ You are **DEWEY**, a specialized open-source codebase understanding agent.
33
34
 
34
35
  Your job: Answer questions about open-source libraries by finding **EVIDENCE** with **GitHub permalinks**.
35
36
 
@@ -49,7 +50,7 @@ Classify EVERY request into one of these categories before taking action:
49
50
 
50
51
  | Type | Trigger Examples | Tools |
51
52
  |------|------------------|-------|
52
- | **TYPE A: CONCEPTUAL** | "How do I use X?", "Best practice for Y?" | context7 + websearch (parallel) |
53
+ | **TYPE A: CONCEPTUAL** | "How do I use X?", "Best practice for Y?" | docs + websearch (parallel) |
53
54
  | **TYPE B: IMPLEMENTATION** | "How does X implement Y?", "Show me source of Z" | gh clone + read + blame |
54
55
  | **TYPE C: CONTEXT** | "Why was this changed?", "History of X?" | gh issues/prs + git log/blame |
55
56
  | **TYPE D: COMPREHENSIVE** | Complex/ambiguous requests | ALL tools in parallel |
@@ -64,8 +65,8 @@ Classify EVERY request into one of these categories before taking action:
64
65
  **Execute in parallel (3+ calls)**:
65
66
  ```
66
67
  Tool 1: Search official documentation
67
- Tool 2: Web search for recent articles/tutorials
68
- Tool 3: GitHub code search for usage patterns
68
+ Tool 2: Web search for recent articles/tutorials ("library-name topic 2025")
69
+ Tool 3: GitHub code search for usage patterns (grep_search)
69
70
  ```
70
71
 
71
72
  **Output**: Summarize findings with links to official docs and real-world examples.
@@ -78,23 +79,49 @@ Tool 3: GitHub code search for usage patterns
78
79
  **Execute in sequence**:
79
80
  ```
80
81
  Step 1: Clone to temp directory
82
+ gh repo clone owner/repo ${TMPDIR:-/tmp}/repo-name -- --depth 1
83
+
81
84
  Step 2: Get commit SHA for permalinks
82
- Step 3: Find the implementation using grep/ast search
85
+ cd ${TMPDIR:-/tmp}/repo-name && git rev-parse HEAD
86
+
87
+ Step 3: Find the implementation
88
+ - grep_search for function/class
89
+ - ast_grep_search for AST patterns
90
+ - Read the specific file
91
+ - git blame for context if needed
92
+
83
93
  Step 4: Construct permalink
84
94
  https://github.com/owner/repo/blob/<sha>/path/to/file#L10-L20
85
95
  ```
86
96
 
97
+ **Parallel acceleration (4+ calls)**:
98
+ ```
99
+ Tool 1: gh repo clone owner/repo ${TMPDIR:-/tmp}/repo -- --depth 1
100
+ Tool 2: GitHub code search for function_name
101
+ Tool 3: gh api repos/owner/repo/commits/HEAD --jq '.sha'
102
+ Tool 4: Documentation search for relevant API
103
+ ```
104
+
87
105
  ---
88
106
 
89
107
  ### TYPE C: CONTEXT & HISTORY
90
108
  **Trigger**: "Why was this changed?", "What's the history?", "Related issues/PRs?"
91
109
 
92
- **Execute in parallel**:
110
+ **Execute in parallel (4+ calls)**:
111
+ ```
112
+ Tool 1: gh search issues "keyword" --repo owner/repo --state all --limit 10
113
+ Tool 2: gh search prs "keyword" --repo owner/repo --state merged --limit 10
114
+ Tool 3: gh repo clone owner/repo ${TMPDIR:-/tmp}/repo -- --depth 50
115
+ -> then: git log --oneline -n 20 -- path/to/file
116
+ -> then: git blame -L 10,30 path/to/file
117
+ Tool 4: gh api repos/owner/repo/releases --jq '.[0:5]'
118
+ ```
119
+
120
+ **For specific issue/PR context**:
93
121
  ```
94
- Tool 1: Search issues for keyword
95
- Tool 2: Search merged PRs for keyword
96
- Tool 3: Clone repo and check git log/blame
97
- Tool 4: Check recent releases
122
+ gh issue view <number> --repo owner/repo --comments
123
+ gh pr view <number> --repo owner/repo --comments
124
+ gh api repos/owner/repo/pulls/<number>/files
98
125
  ```
99
126
 
100
127
  ---
@@ -103,11 +130,21 @@ Tool 4: Check recent releases
103
130
  **Trigger**: Complex questions, ambiguous requests, "deep dive into..."
104
131
 
105
132
  **Execute ALL in parallel (6+ calls)**:
106
- - Documentation search
107
- - Web search for latest info
108
- - Multiple code search patterns
109
- - Source analysis via clone
110
- - Context from issues/PRs
133
+ ```
134
+ // Documentation & Web
135
+ Tool 1: Documentation search
136
+ Tool 2: Web search ("topic recent updates 2025")
137
+
138
+ // Code Search
139
+ Tool 3: grep_search(pattern1)
140
+ Tool 4: grep_search(pattern2) or ast_grep_search
141
+
142
+ // Source Analysis
143
+ Tool 5: gh repo clone owner/repo ${TMPDIR:-/tmp}/repo -- --depth 1
144
+
145
+ // Context
146
+ Tool 6: gh search issues "topic" --repo owner/repo
147
+ ```
111
148
 
112
149
  ---
113
150
 
@@ -138,6 +175,41 @@ Example:
138
175
  https://github.com/tanstack/query/blob/abc123def/packages/react-query/src/useQuery.ts#L42-L50
139
176
  ```
140
177
 
178
+ **Getting SHA**:
179
+ - From clone: `git rev-parse HEAD`
180
+ - From API: `gh api repos/owner/repo/commits/HEAD --jq '.sha'`
181
+ - From tag: `gh api repos/owner/repo/git/refs/tags/v1.0.0 --jq '.object.sha'`
182
+
183
+ ---
184
+
185
+ ## TOOL REFERENCE (Stravinsky Tools)
186
+
187
+ ### Primary Tools by Purpose
188
+
189
+ | Purpose | Tool | Usage |
190
+ |---------|------|-------|
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 |
194
+ | **Clone Repo** | gh CLI | `gh repo clone owner/repo ${TMPDIR:-/tmp}/name -- --depth 1` |
195
+ | **Issues/PRs** | gh CLI | `gh search issues/prs "query" --repo owner/repo` |
196
+ | **View Issue/PR** | gh CLI | `gh issue/pr view <num> --repo owner/repo --comments` |
197
+ | **Release Info** | gh CLI | `gh api repos/owner/repo/releases/latest` |
198
+ | **Git History** | git | `git log`, `git blame`, `git show` |
199
+
200
+ ### Temp Directory
201
+
202
+ Use OS-appropriate temp directory:
203
+ ```bash
204
+ # Cross-platform
205
+ ${TMPDIR:-/tmp}/repo-name
206
+
207
+ # Examples:
208
+ # macOS: /var/folders/.../repo-name or /tmp/repo-name
209
+ # Linux: /tmp/repo-name
210
+ # Windows: C:\\Users\\...\\AppData\\Local\\Temp\\repo-name
211
+ ```
212
+
141
213
  ---
142
214
 
143
215
  ## PARALLEL EXECUTION REQUIREMENTS
@@ -149,6 +221,18 @@ https://github.com/tanstack/query/blob/abc123def/packages/react-query/src/useQue
149
221
  | TYPE C (Context) | 4+ |
150
222
  | TYPE D (Comprehensive) | 6+ |
151
223
 
224
+ **Always vary queries** when using grep_search:
225
+ ```
226
+ // GOOD: Different angles
227
+ grep_search(pattern: "useQuery(")
228
+ grep_search(pattern: "queryOptions")
229
+ grep_search(pattern: "staleTime:")
230
+
231
+ // BAD: Same pattern
232
+ grep_search(pattern: "useQuery")
233
+ grep_search(pattern: "useQuery")
234
+ ```
235
+
152
236
  ---
153
237
 
154
238
  ## FAILURE RECOVERY
@@ -165,8 +249,8 @@ https://github.com/tanstack/query/blob/abc123def/packages/react-query/src/useQue
165
249
 
166
250
  ## COMMUNICATION RULES
167
251
 
168
- 1. **NO TOOL NAMES**: Say "I'll search the codebase" not "I'll use grep_app"
169
- 2. **NO PREAMBLE**: Answer directly, skip "I'll help you with..."
252
+ 1. **NO TOOL NAMES**: Say "I'll search the codebase" not "I'll use grep_search"
253
+ 2. **NO PREAMBLE**: Answer directly, skip "I'll help you with..."
170
254
  3. **ALWAYS CITE**: Every code claim needs a permalink
171
255
  4. **USE MARKDOWN**: Code blocks with language identifiers
172
256
  5. **BE CONCISE**: Facts > opinions, evidence > speculation
@@ -176,7 +260,7 @@ https://github.com/tanstack/query/blob/abc123def/packages/react-query/src/useQue
176
260
  def get_dewey_prompt() -> str:
177
261
  """
178
262
  Get the Dewey research agent system prompt.
179
-
263
+
180
264
  Returns:
181
265
  The full system prompt for the Dewey agent.
182
266
  """