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.
- mcp_bridge/__init__.py +1 -1
- mcp_bridge/auth/__init__.py +16 -6
- mcp_bridge/auth/cli.py +202 -11
- mcp_bridge/auth/oauth.py +1 -2
- mcp_bridge/auth/openai_oauth.py +4 -7
- mcp_bridge/auth/token_store.py +0 -1
- mcp_bridge/cli/__init__.py +1 -1
- mcp_bridge/cli/install_hooks.py +503 -107
- mcp_bridge/cli/session_report.py +0 -3
- mcp_bridge/config/__init__.py +2 -2
- mcp_bridge/config/hook_config.py +3 -5
- mcp_bridge/config/rate_limits.py +108 -13
- mcp_bridge/hooks/HOOKS_SETTINGS.json +17 -4
- mcp_bridge/hooks/__init__.py +14 -4
- mcp_bridge/hooks/agent_reminder.py +4 -4
- mcp_bridge/hooks/auto_slash_command.py +5 -5
- mcp_bridge/hooks/budget_optimizer.py +2 -2
- mcp_bridge/hooks/claude_limits_hook.py +114 -0
- mcp_bridge/hooks/comment_checker.py +3 -4
- mcp_bridge/hooks/compaction.py +2 -2
- mcp_bridge/hooks/context.py +2 -1
- mcp_bridge/hooks/context_monitor.py +2 -2
- mcp_bridge/hooks/delegation_policy.py +85 -0
- mcp_bridge/hooks/directory_context.py +3 -3
- mcp_bridge/hooks/edit_recovery.py +3 -2
- mcp_bridge/hooks/edit_recovery_policy.py +49 -0
- mcp_bridge/hooks/empty_message_sanitizer.py +2 -2
- mcp_bridge/hooks/events.py +160 -0
- mcp_bridge/hooks/git_noninteractive.py +4 -4
- mcp_bridge/hooks/keyword_detector.py +8 -10
- mcp_bridge/hooks/manager.py +35 -22
- mcp_bridge/hooks/notification_hook.py +13 -6
- mcp_bridge/hooks/parallel_enforcement_policy.py +67 -0
- mcp_bridge/hooks/parallel_enforcer.py +5 -5
- mcp_bridge/hooks/parallel_execution.py +22 -10
- mcp_bridge/hooks/post_tool/parallel_validation.py +103 -0
- mcp_bridge/hooks/pre_compact.py +8 -9
- mcp_bridge/hooks/pre_tool/agent_spawn_validator.py +115 -0
- mcp_bridge/hooks/preemptive_compaction.py +2 -3
- mcp_bridge/hooks/routing_notifications.py +80 -0
- mcp_bridge/hooks/rules_injector.py +11 -19
- mcp_bridge/hooks/session_idle.py +4 -4
- mcp_bridge/hooks/session_notifier.py +4 -4
- mcp_bridge/hooks/session_recovery.py +4 -5
- mcp_bridge/hooks/stravinsky_mode.py +1 -1
- mcp_bridge/hooks/subagent_stop.py +1 -3
- mcp_bridge/hooks/task_validator.py +2 -2
- mcp_bridge/hooks/tmux_manager.py +7 -8
- mcp_bridge/hooks/todo_delegation.py +4 -1
- mcp_bridge/hooks/todo_enforcer.py +180 -10
- mcp_bridge/hooks/truncation_policy.py +37 -0
- mcp_bridge/hooks/truncator.py +1 -2
- mcp_bridge/metrics/cost_tracker.py +115 -0
- mcp_bridge/native_search.py +93 -0
- mcp_bridge/native_watcher.py +118 -0
- mcp_bridge/notifications.py +3 -4
- mcp_bridge/orchestrator/enums.py +11 -0
- mcp_bridge/orchestrator/router.py +165 -0
- mcp_bridge/orchestrator/state.py +32 -0
- mcp_bridge/orchestrator/visualization.py +14 -0
- mcp_bridge/orchestrator/wisdom.py +34 -0
- mcp_bridge/prompts/__init__.py +1 -8
- mcp_bridge/prompts/dewey.py +1 -1
- mcp_bridge/prompts/planner.py +2 -4
- mcp_bridge/prompts/stravinsky.py +53 -31
- mcp_bridge/proxy/__init__.py +0 -0
- mcp_bridge/proxy/client.py +70 -0
- mcp_bridge/proxy/model_server.py +157 -0
- mcp_bridge/routing/__init__.py +43 -0
- mcp_bridge/routing/config.py +250 -0
- mcp_bridge/routing/model_tiers.py +135 -0
- mcp_bridge/routing/provider_state.py +261 -0
- mcp_bridge/routing/task_classifier.py +190 -0
- mcp_bridge/server.py +363 -34
- mcp_bridge/server_tools.py +298 -6
- mcp_bridge/tools/__init__.py +19 -8
- mcp_bridge/tools/agent_manager.py +549 -799
- mcp_bridge/tools/background_tasks.py +13 -17
- mcp_bridge/tools/code_search.py +54 -51
- mcp_bridge/tools/continuous_loop.py +0 -1
- mcp_bridge/tools/dashboard.py +19 -0
- mcp_bridge/tools/find_code.py +296 -0
- mcp_bridge/tools/init.py +1 -0
- mcp_bridge/tools/list_directory.py +42 -0
- mcp_bridge/tools/lsp/__init__.py +8 -8
- mcp_bridge/tools/lsp/manager.py +51 -28
- mcp_bridge/tools/lsp/tools.py +98 -65
- mcp_bridge/tools/model_invoke.py +1047 -152
- mcp_bridge/tools/mux_client.py +75 -0
- mcp_bridge/tools/project_context.py +1 -2
- mcp_bridge/tools/query_classifier.py +132 -49
- mcp_bridge/tools/read_file.py +84 -0
- mcp_bridge/tools/replace.py +45 -0
- mcp_bridge/tools/run_shell_command.py +38 -0
- mcp_bridge/tools/search_enhancements.py +347 -0
- mcp_bridge/tools/semantic_search.py +677 -92
- mcp_bridge/tools/session_manager.py +0 -2
- mcp_bridge/tools/skill_loader.py +0 -1
- mcp_bridge/tools/task_runner.py +5 -7
- mcp_bridge/tools/templates.py +3 -3
- mcp_bridge/tools/tool_search.py +331 -0
- mcp_bridge/tools/write_file.py +29 -0
- mcp_bridge/update_manager.py +33 -37
- mcp_bridge/update_manager_pypi.py +6 -8
- mcp_bridge/utils/cache.py +82 -0
- mcp_bridge/utils/process.py +71 -0
- mcp_bridge/utils/session_state.py +51 -0
- mcp_bridge/utils/truncation.py +76 -0
- {stravinsky-0.4.18.dist-info → stravinsky-0.4.66.dist-info}/METADATA +84 -35
- stravinsky-0.4.66.dist-info/RECORD +198 -0
- {stravinsky-0.4.18.dist-info → stravinsky-0.4.66.dist-info}/entry_points.txt +1 -0
- stravinsky_claude_assets/HOOKS_INTEGRATION.md +316 -0
- stravinsky_claude_assets/agents/HOOKS.md +437 -0
- stravinsky_claude_assets/agents/code-reviewer.md +210 -0
- stravinsky_claude_assets/agents/comment_checker.md +580 -0
- stravinsky_claude_assets/agents/debugger.md +254 -0
- stravinsky_claude_assets/agents/delphi.md +495 -0
- stravinsky_claude_assets/agents/dewey.md +248 -0
- stravinsky_claude_assets/agents/explore.md +1198 -0
- stravinsky_claude_assets/agents/frontend.md +472 -0
- stravinsky_claude_assets/agents/implementation-lead.md +164 -0
- stravinsky_claude_assets/agents/momus.md +464 -0
- stravinsky_claude_assets/agents/research-lead.md +141 -0
- stravinsky_claude_assets/agents/stravinsky.md +730 -0
- stravinsky_claude_assets/commands/delphi.md +9 -0
- stravinsky_claude_assets/commands/dewey.md +54 -0
- stravinsky_claude_assets/commands/git-master.md +112 -0
- stravinsky_claude_assets/commands/index.md +49 -0
- stravinsky_claude_assets/commands/publish.md +86 -0
- stravinsky_claude_assets/commands/review.md +73 -0
- stravinsky_claude_assets/commands/str/agent_cancel.md +70 -0
- stravinsky_claude_assets/commands/str/agent_list.md +56 -0
- stravinsky_claude_assets/commands/str/agent_output.md +92 -0
- stravinsky_claude_assets/commands/str/agent_progress.md +74 -0
- stravinsky_claude_assets/commands/str/agent_retry.md +94 -0
- stravinsky_claude_assets/commands/str/cancel.md +51 -0
- stravinsky_claude_assets/commands/str/clean.md +97 -0
- stravinsky_claude_assets/commands/str/continue.md +38 -0
- stravinsky_claude_assets/commands/str/index.md +199 -0
- stravinsky_claude_assets/commands/str/list_watchers.md +96 -0
- stravinsky_claude_assets/commands/str/search.md +205 -0
- stravinsky_claude_assets/commands/str/start_filewatch.md +136 -0
- stravinsky_claude_assets/commands/str/stats.md +71 -0
- stravinsky_claude_assets/commands/str/stop_filewatch.md +89 -0
- stravinsky_claude_assets/commands/str/unwatch.md +42 -0
- stravinsky_claude_assets/commands/str/watch.md +45 -0
- stravinsky_claude_assets/commands/strav.md +53 -0
- stravinsky_claude_assets/commands/stravinsky.md +292 -0
- stravinsky_claude_assets/commands/verify.md +60 -0
- stravinsky_claude_assets/commands/version.md +5 -0
- stravinsky_claude_assets/hooks/README.md +248 -0
- stravinsky_claude_assets/hooks/comment_checker.py +193 -0
- stravinsky_claude_assets/hooks/context.py +38 -0
- stravinsky_claude_assets/hooks/context_monitor.py +153 -0
- stravinsky_claude_assets/hooks/dependency_tracker.py +73 -0
- stravinsky_claude_assets/hooks/edit_recovery.py +46 -0
- stravinsky_claude_assets/hooks/execution_state_tracker.py +68 -0
- stravinsky_claude_assets/hooks/notification_hook.py +103 -0
- stravinsky_claude_assets/hooks/notification_hook_v2.py +96 -0
- stravinsky_claude_assets/hooks/parallel_execution.py +241 -0
- stravinsky_claude_assets/hooks/parallel_reinforcement.py +106 -0
- stravinsky_claude_assets/hooks/parallel_reinforcement_v2.py +112 -0
- stravinsky_claude_assets/hooks/pre_compact.py +123 -0
- stravinsky_claude_assets/hooks/ralph_loop.py +173 -0
- stravinsky_claude_assets/hooks/session_recovery.py +263 -0
- stravinsky_claude_assets/hooks/stop_hook.py +89 -0
- stravinsky_claude_assets/hooks/stravinsky_metrics.py +164 -0
- stravinsky_claude_assets/hooks/stravinsky_mode.py +146 -0
- stravinsky_claude_assets/hooks/subagent_stop.py +98 -0
- stravinsky_claude_assets/hooks/todo_continuation.py +111 -0
- stravinsky_claude_assets/hooks/todo_delegation.py +96 -0
- stravinsky_claude_assets/hooks/tool_messaging.py +281 -0
- stravinsky_claude_assets/hooks/truncator.py +23 -0
- stravinsky_claude_assets/rules/deployment_safety.md +51 -0
- stravinsky_claude_assets/rules/integration_wiring.md +89 -0
- stravinsky_claude_assets/rules/pypi_deployment.md +220 -0
- stravinsky_claude_assets/rules/stravinsky_orchestrator.md +32 -0
- stravinsky_claude_assets/settings.json +152 -0
- stravinsky_claude_assets/skills/chrome-devtools/SKILL.md +81 -0
- stravinsky_claude_assets/skills/sqlite/SKILL.md +77 -0
- stravinsky_claude_assets/skills/supabase/SKILL.md +74 -0
- stravinsky_claude_assets/task_dependencies.json +34 -0
- stravinsky-0.4.18.dist-info/RECORD +0 -88
- {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())
|