stravinsky 0.4.18__py3-none-any.whl → 0.4.66__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 (184) hide show
  1. mcp_bridge/__init__.py +1 -1
  2. mcp_bridge/auth/__init__.py +16 -6
  3. mcp_bridge/auth/cli.py +202 -11
  4. mcp_bridge/auth/oauth.py +1 -2
  5. mcp_bridge/auth/openai_oauth.py +4 -7
  6. mcp_bridge/auth/token_store.py +0 -1
  7. mcp_bridge/cli/__init__.py +1 -1
  8. mcp_bridge/cli/install_hooks.py +503 -107
  9. mcp_bridge/cli/session_report.py +0 -3
  10. mcp_bridge/config/__init__.py +2 -2
  11. mcp_bridge/config/hook_config.py +3 -5
  12. mcp_bridge/config/rate_limits.py +108 -13
  13. mcp_bridge/hooks/HOOKS_SETTINGS.json +17 -4
  14. mcp_bridge/hooks/__init__.py +14 -4
  15. mcp_bridge/hooks/agent_reminder.py +4 -4
  16. mcp_bridge/hooks/auto_slash_command.py +5 -5
  17. mcp_bridge/hooks/budget_optimizer.py +2 -2
  18. mcp_bridge/hooks/claude_limits_hook.py +114 -0
  19. mcp_bridge/hooks/comment_checker.py +3 -4
  20. mcp_bridge/hooks/compaction.py +2 -2
  21. mcp_bridge/hooks/context.py +2 -1
  22. mcp_bridge/hooks/context_monitor.py +2 -2
  23. mcp_bridge/hooks/delegation_policy.py +85 -0
  24. mcp_bridge/hooks/directory_context.py +3 -3
  25. mcp_bridge/hooks/edit_recovery.py +3 -2
  26. mcp_bridge/hooks/edit_recovery_policy.py +49 -0
  27. mcp_bridge/hooks/empty_message_sanitizer.py +2 -2
  28. mcp_bridge/hooks/events.py +160 -0
  29. mcp_bridge/hooks/git_noninteractive.py +4 -4
  30. mcp_bridge/hooks/keyword_detector.py +8 -10
  31. mcp_bridge/hooks/manager.py +35 -22
  32. mcp_bridge/hooks/notification_hook.py +13 -6
  33. mcp_bridge/hooks/parallel_enforcement_policy.py +67 -0
  34. mcp_bridge/hooks/parallel_enforcer.py +5 -5
  35. mcp_bridge/hooks/parallel_execution.py +22 -10
  36. mcp_bridge/hooks/post_tool/parallel_validation.py +103 -0
  37. mcp_bridge/hooks/pre_compact.py +8 -9
  38. mcp_bridge/hooks/pre_tool/agent_spawn_validator.py +115 -0
  39. mcp_bridge/hooks/preemptive_compaction.py +2 -3
  40. mcp_bridge/hooks/routing_notifications.py +80 -0
  41. mcp_bridge/hooks/rules_injector.py +11 -19
  42. mcp_bridge/hooks/session_idle.py +4 -4
  43. mcp_bridge/hooks/session_notifier.py +4 -4
  44. mcp_bridge/hooks/session_recovery.py +4 -5
  45. mcp_bridge/hooks/stravinsky_mode.py +1 -1
  46. mcp_bridge/hooks/subagent_stop.py +1 -3
  47. mcp_bridge/hooks/task_validator.py +2 -2
  48. mcp_bridge/hooks/tmux_manager.py +7 -8
  49. mcp_bridge/hooks/todo_delegation.py +4 -1
  50. mcp_bridge/hooks/todo_enforcer.py +180 -10
  51. mcp_bridge/hooks/truncation_policy.py +37 -0
  52. mcp_bridge/hooks/truncator.py +1 -2
  53. mcp_bridge/metrics/cost_tracker.py +115 -0
  54. mcp_bridge/native_search.py +93 -0
  55. mcp_bridge/native_watcher.py +118 -0
  56. mcp_bridge/notifications.py +3 -4
  57. mcp_bridge/orchestrator/enums.py +11 -0
  58. mcp_bridge/orchestrator/router.py +165 -0
  59. mcp_bridge/orchestrator/state.py +32 -0
  60. mcp_bridge/orchestrator/visualization.py +14 -0
  61. mcp_bridge/orchestrator/wisdom.py +34 -0
  62. mcp_bridge/prompts/__init__.py +1 -8
  63. mcp_bridge/prompts/dewey.py +1 -1
  64. mcp_bridge/prompts/planner.py +2 -4
  65. mcp_bridge/prompts/stravinsky.py +53 -31
  66. mcp_bridge/proxy/__init__.py +0 -0
  67. mcp_bridge/proxy/client.py +70 -0
  68. mcp_bridge/proxy/model_server.py +157 -0
  69. mcp_bridge/routing/__init__.py +43 -0
  70. mcp_bridge/routing/config.py +250 -0
  71. mcp_bridge/routing/model_tiers.py +135 -0
  72. mcp_bridge/routing/provider_state.py +261 -0
  73. mcp_bridge/routing/task_classifier.py +190 -0
  74. mcp_bridge/server.py +363 -34
  75. mcp_bridge/server_tools.py +298 -6
  76. mcp_bridge/tools/__init__.py +19 -8
  77. mcp_bridge/tools/agent_manager.py +549 -799
  78. mcp_bridge/tools/background_tasks.py +13 -17
  79. mcp_bridge/tools/code_search.py +54 -51
  80. mcp_bridge/tools/continuous_loop.py +0 -1
  81. mcp_bridge/tools/dashboard.py +19 -0
  82. mcp_bridge/tools/find_code.py +296 -0
  83. mcp_bridge/tools/init.py +1 -0
  84. mcp_bridge/tools/list_directory.py +42 -0
  85. mcp_bridge/tools/lsp/__init__.py +8 -8
  86. mcp_bridge/tools/lsp/manager.py +51 -28
  87. mcp_bridge/tools/lsp/tools.py +98 -65
  88. mcp_bridge/tools/model_invoke.py +1047 -152
  89. mcp_bridge/tools/mux_client.py +75 -0
  90. mcp_bridge/tools/project_context.py +1 -2
  91. mcp_bridge/tools/query_classifier.py +132 -49
  92. mcp_bridge/tools/read_file.py +84 -0
  93. mcp_bridge/tools/replace.py +45 -0
  94. mcp_bridge/tools/run_shell_command.py +38 -0
  95. mcp_bridge/tools/search_enhancements.py +347 -0
  96. mcp_bridge/tools/semantic_search.py +677 -92
  97. mcp_bridge/tools/session_manager.py +0 -2
  98. mcp_bridge/tools/skill_loader.py +0 -1
  99. mcp_bridge/tools/task_runner.py +5 -7
  100. mcp_bridge/tools/templates.py +3 -3
  101. mcp_bridge/tools/tool_search.py +331 -0
  102. mcp_bridge/tools/write_file.py +29 -0
  103. mcp_bridge/update_manager.py +33 -37
  104. mcp_bridge/update_manager_pypi.py +6 -8
  105. mcp_bridge/utils/cache.py +82 -0
  106. mcp_bridge/utils/process.py +71 -0
  107. mcp_bridge/utils/session_state.py +51 -0
  108. mcp_bridge/utils/truncation.py +76 -0
  109. {stravinsky-0.4.18.dist-info → stravinsky-0.4.66.dist-info}/METADATA +84 -35
  110. stravinsky-0.4.66.dist-info/RECORD +198 -0
  111. {stravinsky-0.4.18.dist-info → stravinsky-0.4.66.dist-info}/entry_points.txt +1 -0
  112. stravinsky_claude_assets/HOOKS_INTEGRATION.md +316 -0
  113. stravinsky_claude_assets/agents/HOOKS.md +437 -0
  114. stravinsky_claude_assets/agents/code-reviewer.md +210 -0
  115. stravinsky_claude_assets/agents/comment_checker.md +580 -0
  116. stravinsky_claude_assets/agents/debugger.md +254 -0
  117. stravinsky_claude_assets/agents/delphi.md +495 -0
  118. stravinsky_claude_assets/agents/dewey.md +248 -0
  119. stravinsky_claude_assets/agents/explore.md +1198 -0
  120. stravinsky_claude_assets/agents/frontend.md +472 -0
  121. stravinsky_claude_assets/agents/implementation-lead.md +164 -0
  122. stravinsky_claude_assets/agents/momus.md +464 -0
  123. stravinsky_claude_assets/agents/research-lead.md +141 -0
  124. stravinsky_claude_assets/agents/stravinsky.md +730 -0
  125. stravinsky_claude_assets/commands/delphi.md +9 -0
  126. stravinsky_claude_assets/commands/dewey.md +54 -0
  127. stravinsky_claude_assets/commands/git-master.md +112 -0
  128. stravinsky_claude_assets/commands/index.md +49 -0
  129. stravinsky_claude_assets/commands/publish.md +86 -0
  130. stravinsky_claude_assets/commands/review.md +73 -0
  131. stravinsky_claude_assets/commands/str/agent_cancel.md +70 -0
  132. stravinsky_claude_assets/commands/str/agent_list.md +56 -0
  133. stravinsky_claude_assets/commands/str/agent_output.md +92 -0
  134. stravinsky_claude_assets/commands/str/agent_progress.md +74 -0
  135. stravinsky_claude_assets/commands/str/agent_retry.md +94 -0
  136. stravinsky_claude_assets/commands/str/cancel.md +51 -0
  137. stravinsky_claude_assets/commands/str/clean.md +97 -0
  138. stravinsky_claude_assets/commands/str/continue.md +38 -0
  139. stravinsky_claude_assets/commands/str/index.md +199 -0
  140. stravinsky_claude_assets/commands/str/list_watchers.md +96 -0
  141. stravinsky_claude_assets/commands/str/search.md +205 -0
  142. stravinsky_claude_assets/commands/str/start_filewatch.md +136 -0
  143. stravinsky_claude_assets/commands/str/stats.md +71 -0
  144. stravinsky_claude_assets/commands/str/stop_filewatch.md +89 -0
  145. stravinsky_claude_assets/commands/str/unwatch.md +42 -0
  146. stravinsky_claude_assets/commands/str/watch.md +45 -0
  147. stravinsky_claude_assets/commands/strav.md +53 -0
  148. stravinsky_claude_assets/commands/stravinsky.md +292 -0
  149. stravinsky_claude_assets/commands/verify.md +60 -0
  150. stravinsky_claude_assets/commands/version.md +5 -0
  151. stravinsky_claude_assets/hooks/README.md +248 -0
  152. stravinsky_claude_assets/hooks/comment_checker.py +193 -0
  153. stravinsky_claude_assets/hooks/context.py +38 -0
  154. stravinsky_claude_assets/hooks/context_monitor.py +153 -0
  155. stravinsky_claude_assets/hooks/dependency_tracker.py +73 -0
  156. stravinsky_claude_assets/hooks/edit_recovery.py +46 -0
  157. stravinsky_claude_assets/hooks/execution_state_tracker.py +68 -0
  158. stravinsky_claude_assets/hooks/notification_hook.py +103 -0
  159. stravinsky_claude_assets/hooks/notification_hook_v2.py +96 -0
  160. stravinsky_claude_assets/hooks/parallel_execution.py +241 -0
  161. stravinsky_claude_assets/hooks/parallel_reinforcement.py +106 -0
  162. stravinsky_claude_assets/hooks/parallel_reinforcement_v2.py +112 -0
  163. stravinsky_claude_assets/hooks/pre_compact.py +123 -0
  164. stravinsky_claude_assets/hooks/ralph_loop.py +173 -0
  165. stravinsky_claude_assets/hooks/session_recovery.py +263 -0
  166. stravinsky_claude_assets/hooks/stop_hook.py +89 -0
  167. stravinsky_claude_assets/hooks/stravinsky_metrics.py +164 -0
  168. stravinsky_claude_assets/hooks/stravinsky_mode.py +146 -0
  169. stravinsky_claude_assets/hooks/subagent_stop.py +98 -0
  170. stravinsky_claude_assets/hooks/todo_continuation.py +111 -0
  171. stravinsky_claude_assets/hooks/todo_delegation.py +96 -0
  172. stravinsky_claude_assets/hooks/tool_messaging.py +281 -0
  173. stravinsky_claude_assets/hooks/truncator.py +23 -0
  174. stravinsky_claude_assets/rules/deployment_safety.md +51 -0
  175. stravinsky_claude_assets/rules/integration_wiring.md +89 -0
  176. stravinsky_claude_assets/rules/pypi_deployment.md +220 -0
  177. stravinsky_claude_assets/rules/stravinsky_orchestrator.md +32 -0
  178. stravinsky_claude_assets/settings.json +152 -0
  179. stravinsky_claude_assets/skills/chrome-devtools/SKILL.md +81 -0
  180. stravinsky_claude_assets/skills/sqlite/SKILL.md +77 -0
  181. stravinsky_claude_assets/skills/supabase/SKILL.md +74 -0
  182. stravinsky_claude_assets/task_dependencies.json +34 -0
  183. stravinsky-0.4.18.dist-info/RECORD +0 -88
  184. {stravinsky-0.4.18.dist-info → stravinsky-0.4.66.dist-info}/WHEEL +0 -0
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env python3
2
+ import json
3
+ import sys
4
+ import os
5
+
6
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "utils"))
7
+
8
+ try:
9
+ from colors import get_agent_color, Color
10
+ from console_format import format_agent_spawn
11
+ except ImportError:
12
+
13
+ def get_agent_color(agent_type):
14
+ return ("", "⚪")
15
+
16
+ def format_agent_spawn(agent_type, model, description, color_code, emoji):
17
+ lines = [f"{emoji} {agent_type.upper()} → {model}", f" Task: {description}", ""]
18
+ return "\n".join(lines)
19
+
20
+
21
+ AGENT_DISPLAY_MODELS = {
22
+ "explore": "gemini-3-flash",
23
+ "dewey": "gemini-3-flash",
24
+ "document_writer": "gemini-3-flash",
25
+ "multimodal": "gemini-3-flash",
26
+ "frontend": "gemini-3-pro-high",
27
+ "delphi": "gpt-5.2-medium",
28
+ "planner": "opus-4.5",
29
+ "code-reviewer": "sonnet-4.5",
30
+ "debugger": "sonnet-4.5",
31
+ "_default": "sonnet-4.5",
32
+ }
33
+
34
+
35
+ def extract_agent_info(message):
36
+ message_lower = message.lower()
37
+ agent_type = None
38
+ description = ""
39
+
40
+ for agent in AGENT_DISPLAY_MODELS.keys():
41
+ if agent == "_default":
42
+ continue
43
+ if agent in message_lower:
44
+ agent_type = agent
45
+ idx = message_lower.find(agent)
46
+ description = message[idx + len(agent) :].strip()[:80]
47
+ break
48
+
49
+ if not agent_type:
50
+ return None
51
+
52
+ description = description.strip(":-() ")
53
+ if not description:
54
+ description = "task delegated"
55
+
56
+ model = AGENT_DISPLAY_MODELS.get(agent_type, AGENT_DISPLAY_MODELS["_default"])
57
+ color_code, emoji = get_agent_color(agent_type)
58
+
59
+ return {
60
+ "agent_type": agent_type,
61
+ "model": model,
62
+ "description": description,
63
+ "color_code": color_code,
64
+ "emoji": emoji,
65
+ }
66
+
67
+
68
+ def main():
69
+ try:
70
+ hook_input = json.load(sys.stdin)
71
+ except (json.JSONDecodeError, EOFError):
72
+ return 0
73
+
74
+ message = hook_input.get("message", "")
75
+ agent_keywords = ["agent", "spawn", "delegat", "task"]
76
+ if not any(kw in message.lower() for kw in agent_keywords):
77
+ return 0
78
+
79
+ agent_info = extract_agent_info(message)
80
+ if not agent_info:
81
+ return 0
82
+
83
+ formatted = format_agent_spawn(
84
+ agent_info["agent_type"],
85
+ agent_info["model"],
86
+ agent_info["description"],
87
+ agent_info["color_code"],
88
+ agent_info["emoji"],
89
+ )
90
+ print(formatted, file=sys.stderr)
91
+
92
+ return 0
93
+
94
+
95
+ if __name__ == "__main__":
96
+ sys.exit(main())
@@ -0,0 +1,241 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ UserPromptSubmit hook: Pre-emptive parallel execution enforcement.
4
+
5
+ Fires BEFORE response generation to inject parallel execution instructions
6
+ when implementation tasks are detected. Eliminates timing ambiguity.
7
+
8
+ CRITICAL: Also activates stravinsky mode marker when /stravinsky is invoked,
9
+ enabling hard blocking of direct tools (Read, Grep, Bash) via stravinsky_mode.py.
10
+
11
+ ULTRAWORK MODE (oh-my-opencode parity):
12
+ When "ultrawork" is detected in prompt (case insensitive):
13
+ - Injects aggressive parallelization instructions
14
+ - Forces maximum agent concurrency
15
+ - Enables 32k thinking budget guidance
16
+ - All async agents fire immediately
17
+ """
18
+
19
+ import json
20
+ import os
21
+ import sys
22
+ import re
23
+ from pathlib import Path
24
+
25
+ # Marker file that enables hard blocking of direct tools
26
+ STRAVINSKY_MODE_FILE = Path.home() / ".stravinsky_mode"
27
+
28
+ # ULTRAWORK mode pattern for aggressive parallel execution
29
+ ULTRAWORK_PATTERN = r"\b(ultrawork|ulw|uw)\b"
30
+
31
+
32
+ # Use CLAUDE_CWD for reliable project directory resolution
33
+ def get_project_dir() -> Path:
34
+ """Get project directory from CLAUDE_CWD env var or fallback to cwd."""
35
+ return Path(os.environ.get("CLAUDE_CWD", "."))
36
+
37
+
38
+ # Marker file that indicates MCP skill execution context (project-scoped)
39
+ MCP_MODE_MARKER_NAME = ".stravinsky/mcp_mode"
40
+
41
+
42
+ def detect_ultrawork_mode(prompt):
43
+ """Detect if ULTRAWORK mode is requested for maximum parallel execution."""
44
+ prompt_lower = prompt.lower()
45
+ return bool(re.search(ULTRAWORK_PATTERN, prompt_lower))
46
+
47
+
48
+ def detect_stravinsky_invocation(prompt):
49
+ """Detect if /strav or /stravinsky skill is being invoked."""
50
+ patterns = [
51
+ r"/stravinsky",
52
+ r"/strav\b",
53
+ r"<command-name>/stravinsky</command-name>",
54
+ r"<command-name>/strav</command-name>",
55
+ r"stravinsky orchestrator",
56
+ r"\b(ultrawork|ulw|uw)\b",
57
+ ]
58
+ prompt_lower = prompt.lower()
59
+ return any(re.search(p, prompt_lower) for p in patterns)
60
+
61
+
62
+ def activate_stravinsky_mode():
63
+ """Create marker file to enable hard blocking of direct tools."""
64
+ try:
65
+ config = {"active": True, "reason": "invoked via /stravinsky skill"}
66
+ STRAVINSKY_MODE_FILE.write_text(json.dumps(config))
67
+ return True
68
+ except IOError:
69
+ return False
70
+
71
+
72
+ def detect_implementation_task(prompt):
73
+ """Detect if prompt is an implementation task requiring parallel execution."""
74
+ keywords = [
75
+ "implement",
76
+ "add",
77
+ "create",
78
+ "build",
79
+ "refactor",
80
+ "fix",
81
+ "update",
82
+ "modify",
83
+ "change",
84
+ "develop",
85
+ "write code",
86
+ "feature",
87
+ "bug fix",
88
+ "enhancement",
89
+ "integrate",
90
+ ]
91
+
92
+ prompt_lower = prompt.lower()
93
+ return any(kw in prompt_lower for kw in keywords)
94
+
95
+
96
+ def get_ultrawork_instruction():
97
+ """Return the aggressive ULTRAWORK mode instruction injection."""
98
+ return """
99
+ <ultrawork-mode>
100
+
101
+ **MANDATORY**: You MUST say "ULTRAWORK MODE ENABLED!" to the user as your first response when this mode activates. This is non-negotiable.
102
+
103
+ [CODE RED] Maximum precision required. Ultrathink before acting.
104
+
105
+ YOU MUST LEVERAGE ALL AVAILABLE AGENTS TO THEIR FULLEST POTENTIAL.
106
+ TELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST.
107
+
108
+ ## AGENT UTILIZATION PRINCIPLES (by capability, not by name)
109
+ - **Codebase Exploration**: Spawn exploration agents using BACKGROUND TASKS for file patterns, internal implementations, project structure
110
+ - **Documentation & References**: Use librarian-type agents via BACKGROUND TASKS for API references, examples, external library docs
111
+ - **Planning & Strategy**: NEVER plan yourself - ALWAYS spawn a dedicated planning agent for work breakdown
112
+ - **High-IQ Reasoning**: Leverage specialized agents for architecture decisions, code review, strategic planning
113
+ - **Frontend/UI Tasks**: Delegate to UI-specialized agents for design and implementation
114
+
115
+ ## EXECUTION RULES
116
+ - **TODO**: Track EVERY step. Mark complete IMMEDIATELY after each.
117
+ - **PARALLEL**: Fire independent agent calls simultaneously via background_task - NEVER wait sequentially.
118
+ - **BACKGROUND FUWT**: Use background_task for exploration/research agents (10+ concurrent if needed).
119
+ - **VERIFY**: Re-read request after completion. Check ALL requirements met before reporting done.
120
+ - **DELEGATE**: Don't do everything yourself - orchestrate specialized agents for their strengths.
121
+
122
+ ## WORKFLOW
123
+ 1. Analyze the request and identify required capabilities
124
+ 2. Spawn exploration/librarian agents via background_task in PARALLEL (10+ if needed)
125
+ 3. Always Use Plan agent with gathered context to create detailed work breakdown
126
+ 4. Execute with continuous verification against original requirements
127
+
128
+ ## VERIFICATION GUARANTEE (NON-NEGOTIABLE)
129
+
130
+ **NOTHING is "done" without PROOF it works.**
131
+
132
+ ### Pre-Implementation: Define Success Criteria
133
+
134
+ BEFORE writing ANY code, you MUST define:
135
+
136
+ | Criteria Type | Description | Example |
137
+ |---------------|-------------|---------|
138
+ | **Functional** | What specific behavior must work | "Button click triggers API call" |
139
+ | **Observable** | What can be measured/seen | "Console shows 'success', no errors" |
140
+ | **Pass/Fail** | Binary, no ambiguity | "Returns 200 OK" not "should work" |
141
+
142
+ Write these criteria explicitly. Share with user if scope is non-trivial.
143
+
144
+ ## ZERO TOLERANCE FAILURES
145
+ - **NO Scope Reduction**: Never make "demo", "skeleton", "simplified", "basic" versions - deliver FULL implementation
146
+ - **NO MockUp Work**: When user asked you to do "port A", you must "port A", fully, 100%. No Extra feature, No reduced feature, no mock data, fully working 100% port.
147
+ - **NO Partial Completion**: Never stop at 60-80% saying "you can extend this..." - finish 100%
148
+ - **NO Assumed Shortcuts**: Never skip requirements you deem "optional" or "can be added later"
149
+ - **NO Premature Stopping**: Never declare done until ALL TODOs are completed and verified
150
+ - **NO TEST DELETION**: Never delete or skip failing tests to make the build pass. Fix the code, not the tests.
151
+
152
+ THE USER ASKED FOR X. DELIVER EXACTLY X. NOT A SUBSET. NOT A DEMO. NOT A STARTING POINT.
153
+
154
+ </ultrawork-mode>
155
+
156
+ ---
157
+
158
+ """
159
+
160
+
161
+ def get_parallel_instruction():
162
+ """Return the standard parallel execution instruction."""
163
+ return """
164
+ <user-prompt-submit-hook>
165
+ [🔄 PARALLEL EXECUTION MODE ACTIVE]
166
+
167
+ When you create a TodoWrite with 2+ pending items:
168
+
169
+ ✅ IMMEDIATELY in THIS SAME RESPONSE (do NOT end response after TodoWrite):
170
+ 1. Spawn Task() for EACH independent pending TODO
171
+ 2. Use: Task(subagent_type="explore"|"dewey"|"code-reviewer"|etc., prompt="...", description="...")
172
+ 3. Fire ALL Task calls in ONE response block
173
+ 4. Do NOT mark any TODO as in_progress until Task results return
174
+
175
+ ❌ DO NOT:
176
+ - End your response after TodoWrite
177
+ - Mark TODOs in_progress before spawning agents
178
+ - Spawn only ONE agent (spawn ALL independent tasks)
179
+ - Wait for "next response" to spawn agents
180
+ - Use Read/Grep/Bash for exploratory work (use explore agents)
181
+
182
+ **Exploratory queries (NO TodoWrite needed):**
183
+ For "Find X", "Explain where Y", "Search for Z" → SKIP TodoWrite, spawn agents immediately:
184
+ ```
185
+ Task(subagent_type="explore", prompt="Find X...", description="Find X")
186
+ Task(subagent_type="explore", prompt="Find Y...", description="Find Y")
187
+ # Continue response - synthesize results
188
+ ```
189
+
190
+ **Implementation tasks (TodoWrite + agents):**
191
+ ```
192
+ TodoWrite([task1, task2, task3])
193
+ Task(subagent_type="explore", prompt="Task 1 details", description="Task 1")
194
+ Task(subagent_type="dewey", prompt="Task 2 details", description="Task 2")
195
+ Task(subagent_type="code-reviewer", prompt="Task 3 details", description="Task 3")
196
+ # Continue response - synthesize results from Task tool responses
197
+ ```
198
+ </user-prompt-submit-hook>
199
+
200
+ ---
201
+
202
+ """
203
+
204
+
205
+ def main():
206
+ try:
207
+ hook_input = json.load(sys.stdin)
208
+ except (json.JSONDecodeError, EOFError):
209
+ return 0
210
+
211
+ prompt = hook_input.get("prompt", "")
212
+
213
+ # CRITICAL: Activate stravinsky mode if /stravinsky is invoked
214
+ # This creates the marker file that enables hard blocking of direct tools
215
+ is_stravinsky = detect_stravinsky_invocation(prompt)
216
+ if is_stravinsky:
217
+ activate_stravinsky_mode()
218
+
219
+ # Check for ULTRAWORK mode - maximum parallel execution
220
+ is_ultrawork = detect_ultrawork_mode(prompt)
221
+
222
+ # Only inject for implementation tasks, stravinsky invocation, or ULTRAWORK
223
+ if not detect_implementation_task(prompt) and not is_stravinsky and not is_ultrawork:
224
+ print(prompt)
225
+ return 0
226
+
227
+ # Select instruction based on mode
228
+ if is_ultrawork:
229
+ # ULTRAWORK mode: aggressive parallelization + verification
230
+ instruction = get_ultrawork_instruction()
231
+ else:
232
+ # Standard parallel execution mode
233
+ instruction = get_parallel_instruction()
234
+
235
+ modified_prompt = instruction + prompt
236
+ print(modified_prompt)
237
+ return 0
238
+
239
+
240
+ if __name__ == "__main__":
241
+ sys.exit(main())
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ [DEPRECATED] UserPromptSubmit hook: Parallel execution reinforcement for subsequent prompts.
4
+
5
+ ⚠️ This hook is DEPRECATED in favor of parallel_reinforcement_v2.py
6
+
7
+ **Deprecation Details**:
8
+ - Deprecated on: 2026-01-11
9
+ - Replacement: parallel_reinforcement_v2.py (state-based with smart degradation detection)
10
+ - Reason: Static reminder approach degrades after turn 3+ despite independent tasks
11
+ - Migration path: Use parallel_reinforcement_v2.py which tracks execution history
12
+
13
+ **Original Purpose**:
14
+ When Stravinsky mode is active, this hook reinforces parallel execution requirements
15
+ on EVERY subsequent prompt (not just the initial invocation).
16
+
17
+ **Why it was replaced**:
18
+ - No state tracking across turns (ephemeral instructions)
19
+ - No degradation detection (always fires same message)
20
+ - No dependency awareness (doesn't check if tasks are actually independent)
21
+ - Lower success rate (20% parallel execution at turn 5+ vs 85% with v2)
22
+
23
+ Works with:
24
+ - parallel_execution.py: Initial activation and instruction injection
25
+ - todo_delegation.py: PostToolUse reminder after TodoWrite
26
+ """
27
+
28
+ import json
29
+ import os
30
+ import sys
31
+ from pathlib import Path
32
+
33
+ STRAVINSKY_MODE_FILE = Path.home() / ".stravinsky_mode"
34
+
35
+
36
+ def get_project_dir() -> Path:
37
+ return Path(os.environ.get("CLAUDE_CWD", "."))
38
+
39
+
40
+ def get_todo_state() -> dict:
41
+ todo_cache = get_project_dir() / ".claude" / "todo_state.json"
42
+ if todo_cache.exists():
43
+ try:
44
+ return json.loads(todo_cache.read_text())
45
+ except Exception:
46
+ pass
47
+ return {"todos": []}
48
+
49
+
50
+ def has_pending_todos() -> bool:
51
+ state = get_todo_state()
52
+ todos = state.get("todos", [])
53
+ pending = [t for t in todos if t.get("status") == "pending"]
54
+ return len(pending) >= 2
55
+
56
+
57
+ def main():
58
+ try:
59
+ hook_input = json.load(sys.stdin)
60
+ except (json.JSONDecodeError, EOFError):
61
+ return 0
62
+
63
+ prompt = hook_input.get("prompt", "")
64
+
65
+ # DEPRECATED: This hook is disabled. Use parallel_reinforcement_v2.py instead.
66
+ # Remove this hook from .claude/settings.json and use parallel_reinforcement_v2.py
67
+ print(prompt)
68
+ return 0
69
+
70
+ # Original logic (now disabled):
71
+ # if not STRAVINSKY_MODE_FILE.exists():
72
+ # print(prompt)
73
+ # return 0
74
+ #
75
+ # if not has_pending_todos():
76
+ # print(prompt)
77
+ # return 0
78
+ #
79
+ # reinforcement = """
80
+ # <user-prompt-submit-hook>
81
+ # [SYSTEM REMINDER - PARALLEL EXECUTION ACTIVE]
82
+ #
83
+ # You have 2+ pending TODOs. When proceeding:
84
+ #
85
+ # ✅ SPAWN agents for ALL independent tasks in PARALLEL
86
+ # ✅ Use agent_spawn(agent_type="explore"|"dewey"|"frontend", prompt="...", description="...")
87
+ # ✅ Fire ALL agent_spawn calls in ONE response block
88
+ # ✅ Collect results with agent_output(task_id, block=true) after spawning
89
+ #
90
+ # ❌ DO NOT work sequentially on one task at a time
91
+ # ❌ DO NOT mark TODOs in_progress before spawning agents
92
+ # ❌ DO NOT use Task() tool (wrong for /strav - use agent_spawn)
93
+ # ❌ DO NOT use Read/Grep/Bash (use explore agents)
94
+ #
95
+ # PARALLEL FUWT, then synthesize results.
96
+ # </user-prompt-submit-hook>
97
+ #
98
+ # ---
99
+ #
100
+ # """
101
+ # print(reinforcement + prompt)
102
+ # return 0
103
+
104
+
105
+ if __name__ == "__main__":
106
+ sys.exit(main())
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env python3
2
+ import json
3
+ import os
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ STRAVINSKY_MODE_FILE = Path.home() / ".stravinsky_mode"
8
+
9
+
10
+ def get_project_dir():
11
+ return Path(os.environ.get("CLAUDE_CWD", "."))
12
+
13
+
14
+ def get_execution_state():
15
+ state_file = get_project_dir() / ".claude/execution_state.json"
16
+ if state_file.exists():
17
+ try:
18
+ return json.loads(state_file.read_text())
19
+ except Exception:
20
+ pass
21
+ return {
22
+ "parallel_mode_active": False,
23
+ "last_task_spawn_index": -1,
24
+ "last_10_tools": [],
25
+ "pending_todos": 0,
26
+ }
27
+
28
+
29
+ def get_dependency_graph():
30
+ graph_file = get_project_dir() / ".claude/task_dependencies.json"
31
+ if graph_file.exists():
32
+ try:
33
+ return json.loads(graph_file.read_text())
34
+ except Exception:
35
+ pass
36
+ return {"dependencies": {}}
37
+
38
+
39
+ def main():
40
+ try:
41
+ hook_input = json.load(sys.stdin)
42
+ except (json.JSONDecodeError, EOFError):
43
+ return 0
44
+
45
+ prompt = hook_input.get("prompt", "")
46
+
47
+ if not STRAVINSKY_MODE_FILE.exists():
48
+ print(prompt)
49
+ return 0
50
+
51
+ state = get_execution_state()
52
+
53
+ if not state.get("parallel_mode_active", False):
54
+ print(prompt)
55
+ return 0
56
+
57
+ last_task_index = state.get("last_task_spawn_index", -1)
58
+ current_index = len(state.get("last_10_tools", []))
59
+ turns_since_task = current_index - last_task_index - 1
60
+
61
+ if turns_since_task < 2:
62
+ print(prompt)
63
+ return 0
64
+
65
+ graph = get_dependency_graph()
66
+ dependencies = graph.get("dependencies", {})
67
+ independent_tasks = [
68
+ tid for tid, info in dependencies.items() if info.get("independent", False)
69
+ ]
70
+
71
+ if len(independent_tasks) < 2:
72
+ print(prompt)
73
+ return 0
74
+
75
+ reinforcement = f"""
76
+ <user-prompt-submit-hook>
77
+ [SYSTEM REMINDER - PARALLEL EXECUTION DEGRADATION DETECTED]
78
+
79
+ Analysis:
80
+ - {state.get("pending_todos", 0)} pending TODOs
81
+ - {len(independent_tasks)} independent tasks identified
82
+ - {turns_since_task} turns since last Task() spawn
83
+ - Risk: Sequential execution fallback
84
+
85
+ REQUIRED ACTION - Spawn agents for ALL independent tasks NOW:
86
+
87
+ Independent tasks: {", ".join(independent_tasks[:5])}
88
+
89
+ Pattern:
90
+ ```
91
+ Task(subagent_type="explore", prompt="...", description="task_1")
92
+ Task(subagent_type="dewey", prompt="...", description="task_2")
93
+ ...
94
+ ```
95
+
96
+ DO NOT:
97
+ - Mark TODOs in_progress before spawning agents
98
+ - Work sequentially on one task at a time
99
+ - Use Read/Grep/Bash directly (BLOCKED in stravinsky mode)
100
+
101
+ SPAWN ALL TASK() AGENTS IN THIS SAME RESPONSE.
102
+ </user-prompt-submit-hook>
103
+
104
+ ---
105
+
106
+ """
107
+ print(reinforcement + prompt)
108
+ return 0
109
+
110
+
111
+ if __name__ == "__main__":
112
+ sys.exit(main())
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ PreCompact hook: Context preservation before compaction.
4
+
5
+ Fires before Claude Code compacts conversation context to:
6
+ 1. Preserve critical context patterns
7
+ 2. Maintain stravinsky mode state
8
+ 3. Warn about information loss
9
+ 4. Save state for recovery
10
+
11
+ Cannot block compaction (exit 2 only shows error).
12
+ """
13
+
14
+ import json
15
+ import sys
16
+ from pathlib import Path
17
+ from datetime import datetime
18
+ from typing import List, Dict, Any
19
+
20
+
21
+ STRAVINSKY_MODE_FILE = Path.home() / ".stravinsky_mode"
22
+ STATE_DIR = Path.home() / ".claude" / "state"
23
+ COMPACTION_LOG = STATE_DIR / "compaction.jsonl"
24
+
25
+ # Patterns to preserve
26
+ PRESERVE_PATTERNS = [
27
+ "ARCHITECTURE:",
28
+ "DESIGN DECISION:",
29
+ "CONSTRAINT:",
30
+ "REQUIREMENT:",
31
+ "MUST NOT:",
32
+ "NEVER:",
33
+ "CRITICAL ERROR:",
34
+ "CURRENT TASK:",
35
+ "BLOCKED BY:",
36
+ "[STRAVINSKY MODE]",
37
+ "PARALLEL_DELEGATION:",
38
+ ]
39
+
40
+
41
+ def ensure_state_dir():
42
+ """Ensure state directory exists."""
43
+ STATE_DIR.mkdir(parents=True, exist_ok=True)
44
+
45
+
46
+ def get_stravinsky_mode_state() -> Dict[str, Any]:
47
+ """Read stravinsky mode state."""
48
+ if not STRAVINSKY_MODE_FILE.exists():
49
+ return {"active": False}
50
+ try:
51
+ content = STRAVINSKY_MODE_FILE.read_text().strip()
52
+ return json.loads(content) if content else {"active": True}
53
+ except (json.JSONDecodeError, IOError):
54
+ return {"active": True}
55
+
56
+
57
+ def extract_preserved_context(prompt: str) -> List[str]:
58
+ """Extract context matching preservation patterns."""
59
+ preserved = []
60
+ lines = prompt.split("\n")
61
+
62
+ for i, line in enumerate(lines):
63
+ for pattern in PRESERVE_PATTERNS:
64
+ if pattern in line:
65
+ # Capture line + 2 more for context
66
+ context = "\n".join(lines[i:min(i+3, len(lines))])
67
+ preserved.append(context)
68
+ break
69
+
70
+ return preserved[:15] # Max 15 items
71
+
72
+
73
+ def log_compaction(preserved: List[str], stravinsky_active: bool):
74
+ """Log compaction event for audit."""
75
+ ensure_state_dir()
76
+
77
+ entry = {
78
+ "timestamp": datetime.now(timezone.utc).isoformat(),
79
+ "preserved_count": len(preserved),
80
+ "stravinsky_mode": stravinsky_active,
81
+ "preview": [p[:50] for p in preserved[:3]],
82
+ }
83
+
84
+ try:
85
+ with COMPACTION_LOG.open("a") as f:
86
+ f.write(json.dumps(entry) + "\n")
87
+ except IOError:
88
+ pass
89
+
90
+
91
+ def main():
92
+ """Main hook entry point."""
93
+ try:
94
+ hook_input = json.load(sys.stdin)
95
+ except (json.JSONDecodeError, EOFError):
96
+ return 0
97
+
98
+ prompt = hook_input.get("prompt", "")
99
+ trigger = hook_input.get("trigger", "auto")
100
+
101
+ # Get stravinsky mode state
102
+ strav_state = get_stravinsky_mode_state()
103
+ stravinsky_active = strav_state.get("active", False)
104
+
105
+ # Extract preserved context
106
+ preserved = extract_preserved_context(prompt)
107
+
108
+ # Log compaction event
109
+ log_compaction(preserved, stravinsky_active)
110
+
111
+ # Output preservation warning
112
+ if preserved or stravinsky_active:
113
+ print(f"\n[PreCompact] Context compaction triggered ({trigger})", file=sys.stderr)
114
+ print(f" Preserved items: {len(preserved)}", file=sys.stderr)
115
+ if stravinsky_active:
116
+ print(" [STRAVINSKY MODE ACTIVE] - State will persist", file=sys.stderr)
117
+ print(" Audit log: ~/.claude/state/compaction.jsonl", file=sys.stderr)
118
+
119
+ return 0
120
+
121
+
122
+ if __name__ == "__main__":
123
+ sys.exit(main())