stravinsky 0.1.2__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 (42) hide show
  1. mcp_bridge/__init__.py +1 -5
  2. mcp_bridge/auth/cli.py +89 -44
  3. mcp_bridge/auth/oauth.py +88 -63
  4. mcp_bridge/hooks/__init__.py +49 -0
  5. mcp_bridge/hooks/agent_reminder.py +61 -0
  6. mcp_bridge/hooks/auto_slash_command.py +186 -0
  7. mcp_bridge/hooks/budget_optimizer.py +38 -0
  8. mcp_bridge/hooks/comment_checker.py +136 -0
  9. mcp_bridge/hooks/compaction.py +32 -0
  10. mcp_bridge/hooks/context_monitor.py +58 -0
  11. mcp_bridge/hooks/directory_context.py +40 -0
  12. mcp_bridge/hooks/edit_recovery.py +41 -0
  13. mcp_bridge/hooks/empty_message_sanitizer.py +240 -0
  14. mcp_bridge/hooks/keyword_detector.py +122 -0
  15. mcp_bridge/hooks/manager.py +96 -0
  16. mcp_bridge/hooks/preemptive_compaction.py +157 -0
  17. mcp_bridge/hooks/session_recovery.py +186 -0
  18. mcp_bridge/hooks/todo_enforcer.py +75 -0
  19. mcp_bridge/hooks/truncator.py +19 -0
  20. mcp_bridge/native_hooks/context.py +38 -0
  21. mcp_bridge/native_hooks/edit_recovery.py +46 -0
  22. mcp_bridge/native_hooks/stravinsky_mode.py +109 -0
  23. mcp_bridge/native_hooks/truncator.py +23 -0
  24. mcp_bridge/prompts/delphi.py +3 -2
  25. mcp_bridge/prompts/dewey.py +105 -21
  26. mcp_bridge/prompts/stravinsky.py +452 -118
  27. mcp_bridge/server.py +491 -668
  28. mcp_bridge/server_tools.py +547 -0
  29. mcp_bridge/tools/__init__.py +13 -3
  30. mcp_bridge/tools/agent_manager.py +359 -190
  31. mcp_bridge/tools/continuous_loop.py +67 -0
  32. mcp_bridge/tools/init.py +50 -0
  33. mcp_bridge/tools/lsp/tools.py +15 -15
  34. mcp_bridge/tools/model_invoke.py +594 -48
  35. mcp_bridge/tools/skill_loader.py +51 -47
  36. mcp_bridge/tools/task_runner.py +141 -0
  37. mcp_bridge/tools/templates.py +175 -0
  38. {stravinsky-0.1.2.dist-info → stravinsky-0.2.38.dist-info}/METADATA +55 -10
  39. stravinsky-0.2.38.dist-info/RECORD +57 -0
  40. stravinsky-0.1.2.dist-info/RECORD +0 -32
  41. {stravinsky-0.1.2.dist-info → stravinsky-0.2.38.dist-info}/WHEEL +0 -0
  42. {stravinsky-0.1.2.dist-info → stravinsky-0.2.38.dist-info}/entry_points.txt +0 -0
@@ -17,21 +17,21 @@ from typing import Any
17
17
  def parse_frontmatter(content: str) -> tuple[dict[str, Any], str]:
18
18
  """
19
19
  Parse YAML frontmatter from markdown content.
20
-
20
+
21
21
  Returns:
22
22
  Tuple of (metadata dict, body content)
23
23
  """
24
24
  if not content.startswith("---"):
25
25
  return {}, content
26
-
26
+
27
27
  # Find the closing ---
28
28
  end_match = content.find("---", 3)
29
29
  if end_match == -1:
30
30
  return {}, content
31
-
31
+
32
32
  frontmatter = content[3:end_match].strip()
33
- body = content[end_match + 3:].strip()
34
-
33
+ body = content[end_match + 3 :].strip()
34
+
35
35
  # Simple YAML parsing for key: value pairs
36
36
  metadata = {}
37
37
  for line in frontmatter.split("\n"):
@@ -40,122 +40,126 @@ def parse_frontmatter(content: str) -> tuple[dict[str, Any], str]:
40
40
  key = key.strip()
41
41
  value = value.strip().strip('"').strip("'")
42
42
  metadata[key] = value
43
-
43
+
44
44
  return metadata, body
45
45
 
46
46
 
47
47
  def discover_skills(project_path: str | None = None) -> list[dict[str, Any]]:
48
48
  """
49
49
  Discover available skills/commands.
50
-
50
+
51
51
  Searches:
52
52
  1. Project-local: {project}/.claude/commands/
53
53
  2. User-global: ~/.claude/commands/
54
-
54
+
55
55
  Args:
56
56
  project_path: Project directory to search (defaults to cwd)
57
-
57
+
58
58
  Returns:
59
59
  List of skill definitions.
60
60
  """
61
61
  skills = []
62
62
  search_paths = []
63
-
63
+
64
64
  # Project-local commands
65
65
  project = Path(project_path) if project_path else Path.cwd()
66
66
  project_commands = project / ".claude" / "commands"
67
67
  if project_commands.exists():
68
68
  search_paths.append(("project", project_commands))
69
-
69
+
70
70
  # User-global commands
71
71
  user_commands = Path.home() / ".claude" / "commands"
72
72
  if user_commands.exists():
73
73
  search_paths.append(("user", user_commands))
74
-
74
+
75
75
  for scope, commands_dir in search_paths:
76
- for md_file in commands_dir.glob("*.md"):
76
+ for md_file in commands_dir.glob("**/*.md"):
77
77
  try:
78
78
  content = md_file.read_text()
79
79
  metadata, body = parse_frontmatter(content)
80
-
81
- skills.append({
82
- "name": md_file.stem,
83
- "scope": scope,
84
- "path": str(md_file),
85
- "description": metadata.get("description", ""),
86
- "allowed_tools": metadata.get("allowed-tools", "").split(",") if metadata.get("allowed-tools") else [],
87
- "body_preview": body[:200] + "..." if len(body) > 200 else body,
88
- })
80
+
81
+ skills.append(
82
+ {
83
+ "name": md_file.stem,
84
+ "scope": scope,
85
+ "path": str(md_file),
86
+ "description": metadata.get("description", ""),
87
+ "allowed_tools": metadata.get("allowed-tools", "").split(",")
88
+ if metadata.get("allowed-tools")
89
+ else [],
90
+ "body_preview": body[:200] + "..." if len(body) > 200 else body,
91
+ }
92
+ )
89
93
  except Exception:
90
94
  continue
91
-
95
+
92
96
  return skills
93
97
 
94
98
 
95
99
  def list_skills(project_path: str | None = None) -> str:
96
100
  """
97
101
  List all available skills for MCP tool.
98
-
102
+
99
103
  Args:
100
104
  project_path: Project directory to search
101
-
105
+
102
106
  Returns:
103
107
  Formatted skill listing.
104
108
  """
105
109
  skills = discover_skills(project_path)
106
-
110
+
107
111
  if not skills:
108
112
  return "No skills found. Create .claude/commands/*.md files to add skills."
109
-
113
+
110
114
  lines = [f"Found {len(skills)} skill(s):\n"]
111
-
115
+
112
116
  for skill in skills:
113
117
  scope_badge = "[project]" if skill["scope"] == "project" else "[user]"
114
118
  lines.append(f" /{skill['name']} {scope_badge}")
115
119
  if skill["description"]:
116
120
  lines.append(f" {skill['description']}")
117
-
121
+
118
122
  return "\n".join(lines)
119
123
 
120
124
 
121
125
  def get_skill(name: str, project_path: str | None = None) -> str:
122
126
  """
123
127
  Get the content of a specific skill.
124
-
128
+
125
129
  Args:
126
130
  name: Skill name (filename without .md)
127
131
  project_path: Project directory to search
128
-
132
+
129
133
  Returns:
130
134
  Skill content or error message.
131
135
  """
132
136
  skills = discover_skills(project_path)
133
-
137
+
134
138
  skill = next((s for s in skills if s["name"] == name), None)
135
139
  if not skill:
136
140
  available = ", ".join(s["name"] for s in skills)
137
141
  return f"Skill '{name}' not found. Available: {available or 'none'}"
138
-
142
+
139
143
  try:
140
144
  content = Path(skill["path"]).read_text()
141
145
  metadata, body = parse_frontmatter(content)
142
-
146
+
143
147
  lines = [
144
148
  f"## Skill: {name}",
145
149
  f"**Scope**: {skill['scope']}",
146
150
  f"**Path**: {skill['path']}",
147
151
  ]
148
-
152
+
149
153
  if metadata.get("description"):
150
154
  lines.append(f"**Description**: {metadata['description']}")
151
-
155
+
152
156
  if metadata.get("allowed-tools"):
153
157
  lines.append(f"**Allowed Tools**: {metadata['allowed-tools']}")
154
-
158
+
155
159
  lines.extend(["", "---", "", body])
156
-
160
+
157
161
  return "\n".join(lines)
158
-
162
+
159
163
  except Exception as e:
160
164
  return f"Error reading skill: {e}"
161
165
 
@@ -169,34 +173,34 @@ def create_skill(
169
173
  ) -> str:
170
174
  """
171
175
  Create a new skill file.
172
-
176
+
173
177
  Args:
174
178
  name: Skill name (will be used as filename)
175
179
  description: Short description for frontmatter
176
180
  content: Skill body content
177
181
  scope: "project" or "user"
178
182
  project_path: Project directory for project-scope skills
179
-
183
+
180
184
  Returns:
181
185
  Success or error message.
182
186
  """
183
187
  # Sanitize name
184
188
  name = re.sub(r"[^a-zA-Z0-9_-]", "-", name.lower())
185
-
189
+
186
190
  if scope == "project":
187
191
  base_dir = Path(project_path) if project_path else Path.cwd()
188
192
  commands_dir = base_dir / ".claude" / "commands"
189
193
  else:
190
194
  commands_dir = Path.home() / ".claude" / "commands"
191
-
195
+
192
196
  # Ensure directory exists
193
197
  commands_dir.mkdir(parents=True, exist_ok=True)
194
-
198
+
195
199
  skill_path = commands_dir / f"{name}.md"
196
-
200
+
197
201
  if skill_path.exists():
198
202
  return f"Skill '{name}' already exists at {skill_path}"
199
-
203
+
200
204
  # Create skill content
201
205
  skill_content = f"""---
202
206
  description: {description}
@@ -204,7 +208,7 @@ description: {description}
204
208
 
205
209
  {content}
206
210
  """
207
-
211
+
208
212
  try:
209
213
  skill_path.write_text(skill_content)
210
214
  return f"Created skill '{name}' at {skill_path}"
@@ -0,0 +1,141 @@
1
+ """
2
+ Task Runner for Stravinsky background sub-agents.
3
+
4
+ This script is executed as a background process to handle agent tasks,
5
+ capture output, and update status in tasks.json.
6
+ """
7
+
8
+ import argparse
9
+ import json
10
+ import logging
11
+ import os
12
+ import sys
13
+ import asyncio
14
+ import subprocess
15
+ from datetime import datetime
16
+ from pathlib import Path
17
+
18
+ # Setup logging
19
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
20
+ logger = logging.getLogger("task_runner")
21
+
22
+
23
+ async def run_task(task_id: str, base_dir: str):
24
+ base_path = Path(base_dir)
25
+ tasks_file = base_path / "tasks.json"
26
+ agents_dir = base_path / "agents"
27
+
28
+ # Load task details
29
+ try:
30
+ with open(tasks_file, "r") as f:
31
+ tasks = json.load(f)
32
+ task = tasks.get(task_id)
33
+ except Exception as e:
34
+ logger.error(f"Failed to load tasks: {e}")
35
+ return
36
+
37
+ if not task:
38
+ logger.error(f"Task {task_id} not found")
39
+ return
40
+
41
+ prompt = task.get("prompt")
42
+ model = task.get("model", "gemini-2.0-flash")
43
+
44
+ output_file = agents_dir / f"{task_id}.out"
45
+ agents_dir.mkdir(parents=True, exist_ok=True)
46
+
47
+ try:
48
+ # Use Claude CLI for background tasks to ensure tool access
49
+ # Discover CLI path
50
+ claude_cli = os.environ.get("CLAUDE_CLI", "/opt/homebrew/bin/claude")
51
+
52
+ cmd = [
53
+ claude_cli,
54
+ "-p",
55
+ ]
56
+
57
+ if model:
58
+ cmd.extend(["--model", model])
59
+
60
+ cmd.append(prompt)
61
+
62
+ logger.info(f"Executing task {task_id} via CLI ({model})...")
63
+
64
+ # Open output and log files
65
+ with (
66
+ open(output_file, "w") as out_f,
67
+ open(base_path / "tasks" / f"{task_id}.log", "a") as log_f,
68
+ ):
69
+ process = await asyncio.create_subprocess_exec(
70
+ *cmd, stdout=out_f, stderr=log_f, cwd=os.getcwd()
71
+ )
72
+
73
+ await process.wait()
74
+
75
+ # Read result
76
+ if output_file.exists():
77
+ result = output_file.read_text()
78
+ else:
79
+ result = ""
80
+
81
+ # Save result
82
+ with open(output_file, "w") as f:
83
+ f.write(result)
84
+
85
+ # Update status
86
+ with open(tasks_file, "r") as f:
87
+ tasks = json.load(f)
88
+
89
+ if task_id in tasks:
90
+ tasks[task_id].update(
91
+ {
92
+ "status": "completed",
93
+ "result": result,
94
+ "completed_at": datetime.now().isoformat(),
95
+ }
96
+ )
97
+ with open(tasks_file, "w") as f:
98
+ json.dump(tasks, f, indent=2)
99
+
100
+ logger.info(f"Task {task_id} completed successfully")
101
+
102
+ except Exception as e:
103
+ logger.exception(f"Task {task_id} failed: {e}")
104
+
105
+ # Update status with error
106
+ try:
107
+ with open(tasks_file, "r") as f:
108
+ tasks = json.load(f)
109
+ if task_id in tasks:
110
+ tasks[task_id].update(
111
+ {
112
+ "status": "failed",
113
+ "error": str(e),
114
+ "completed_at": datetime.now().isoformat(),
115
+ }
116
+ )
117
+ with open(tasks_file, "w") as f:
118
+ json.dump(tasks, f, indent=2)
119
+ except:
120
+ pass
121
+
122
+
123
+ if __name__ == "__main__":
124
+ parser = argparse.ArgumentParser(
125
+ description="Internal task runner for Stravinsky background agents. "
126
+ "Executes agent tasks via Claude CLI and manages output/status.",
127
+ prog="task_runner",
128
+ )
129
+ parser.add_argument(
130
+ "--task-id",
131
+ required=True,
132
+ help="Unique identifier for the task to execute",
133
+ )
134
+ parser.add_argument(
135
+ "--base-dir",
136
+ required=True,
137
+ help="Base directory containing tasks.json and agents/ output folder",
138
+ )
139
+ args = parser.parse_args()
140
+
141
+ asyncio.run(run_task(args.task_id, args.base_dir))
@@ -0,0 +1,175 @@
1
+ """
2
+ Templates for stravinsky repository initialization.
3
+ """
4
+
5
+ CLAUDE_MD_TEMPLATE = """## stravinsky MCP (Parallel Agents)
6
+
7
+ Use stravinsky MCP tools. **DEFAULT: spawn parallel agents for multi-step tasks.**
8
+
9
+ ### Agent Tools
10
+ - `agent_spawn(prompt, agent_type, description)` - Spawn background agent with full tool access
11
+ - `agent_output(task_id, block)` - Get results (block=True to wait)
12
+ - `agent_progress(task_id)` - Check real-time progress
13
+ - `agent_list()` - Overview of all running agents
14
+ - `agent_cancel(task_id)` - Stop a running agent
15
+
16
+ ### Agent Types
17
+ - `explore` - Codebase search, "where is X?" questions
18
+ - `dewey` - Documentation research, implementation examples
19
+ - `frontend` - UI/UX work, component design
20
+ - `delphi` - Strategic advice, architecture review
21
+
22
+ ### Parallel Execution (IRONSTAR)
23
+ For ANY task with 2+ independent steps:
24
+ 1. **Immediately use agent_spawn** for each independent component
25
+ 2. Fire all agents simultaneously, don't wait
26
+ 3. Monitor with agent_progress, collect with agent_output
27
+
28
+ ### Trigger Commands
29
+ - **IRONSTAR** / **IRS**: Maximum parallel execution - spawn agents aggressively for every subtask
30
+ - **ULTRATHINK**: Engage exhaustive deep reasoning, multi-dimensional analysis
31
+ - **SEARCH**: Maximize search effort across codebase and external resources
32
+ - **ANALYZE**: Deep analysis mode with delphi consultation for complex issues
33
+ """
34
+
35
+ COMMAND_STRAVINSKY = """---
36
+ description: stravinsky Orchestrator - Parallel agent execution for complex workflows.
37
+ ---
38
+
39
+ ## CRITICAL: USE STRAVINSKY MCP TOOLS
40
+
41
+ You MUST use the Stravinsky MCP server tools for ALL file reading, searching, and parallel work.
42
+
43
+ ### MANDATORY TOOL USAGE:
44
+
45
+ **For ANY file reading or searching:**
46
+ ```
47
+ stravinsky:agent_spawn(
48
+ prompt="Read and analyze [file path]. Return: [what you need]",
49
+ agent_type="explore",
50
+ description="Read [file]"
51
+ )
52
+ ```
53
+
54
+ **For documentation/library research:**
55
+ ```
56
+ stravinsky:agent_spawn(
57
+ prompt="Find documentation for [topic]",
58
+ agent_type="dewey",
59
+ description="Research [topic]"
60
+ )
61
+ ```
62
+
63
+ **For 2+ independent tasks (ALWAYS parallel):**
64
+ ```
65
+ // Fire ALL at once in ONE response - NEVER sequential
66
+ stravinsky:agent_spawn(prompt="Task 1...", agent_type="explore", description="Task 1")
67
+ stravinsky:agent_spawn(prompt="Task 2...", agent_type="explore", description="Task 2")
68
+ stravinsky:agent_spawn(prompt="Task 3...", agent_type="dewey", description="Task 3")
69
+ // Then immediately continue - don't wait
70
+ ```
71
+
72
+ **To get results:**
73
+ ```
74
+ stravinsky:agent_output(task_id="[id]", block=true)
75
+ ```
76
+
77
+ ### DO NOT USE:
78
+ - ❌ Built-in Read tool for file reading
79
+ - ❌ Built-in Search/Glob for searching
80
+ - ❌ Built-in Task tool for subagents
81
+
82
+ ### ALWAYS USE:
83
+ - ✅ stravinsky:agent_spawn for ALL exploration
84
+ - ✅ stravinsky:agent_output for collecting results
85
+ - ✅ stravinsky:agent_list to see running agents
86
+
87
+ ### Execution Modes:
88
+ - `ironstar` / `irs` / `ultrawork` - Maximum parallel execution (10+ agents)
89
+ - `ultrathink` - Deep reasoning with delphi consultation
90
+ - `search` - Exhaustive multi-agent search
91
+
92
+ **Your FIRST action must be spawning agents, not using Read/Search tools.**
93
+ """
94
+
95
+ COMMAND_PARALLEL = """---
96
+ description: Execute a task with multiple parallel agents for speed.
97
+ ---
98
+
99
+ Use the stravinsky MCP tools to execute this task with PARALLEL AGENTS.
100
+
101
+ **MANDATORY:** For the following task items, spawn a SEPARATE `agent_spawn` call for EACH independent item. Do not work on them sequentially - fire all agents simultaneously:
102
+
103
+ $ARGUMENTS
104
+
105
+ After spawning all agents:
106
+ 1. Use `agent_list` to show running agents
107
+ 2. Use `agent_progress(task_id)` to monitor each
108
+ 3. Collect results with `agent_output(task_id, block=True)` when ready
109
+ """
110
+
111
+ COMMAND_CONTEXT = """---
112
+ description: Refresh project situational awareness (Git, Rules, Top Todos).
113
+ ---
114
+
115
+ Call the `get_project_context` tool to retrieve the current Git branch, modified files, local project rules from `.claude/rules/`, and any pending `[ ]` todos in the current scope.
116
+ """
117
+
118
+ COMMAND_HEALTH = """---
119
+ description: Perform a comprehensive system health and dependency check.
120
+ ---
121
+
122
+ Call the `get_system_health` tool to verify that all CLI dependencies (rg, fd, sg, tsc, etc.) are installed and that authentication for Gemini and OpenAI is active.
123
+ """
124
+
125
+ COMMAND_DELPHI = """---
126
+ description: Consult the delphi Strategic Advisor for architecture and hard debugging.
127
+ ---
128
+
129
+ Use the `delphi` prompt to analyze the current problem. This triggers a GPT-based consulting phase focused on strategic reasoning, architectural trade-offs, and root-cause analysis for difficult bugs.
130
+
131
+ **When to use delphi:**
132
+ - Complex architecture design decisions
133
+ - After 2+ failed fix attempts
134
+ - Multi-system tradeoffs
135
+ - Security/performance concerns
136
+ - Unfamiliar code patterns
137
+ """
138
+
139
+ COMMAND_LIST = """---
140
+ description: List all active and recent background agent tasks.
141
+ ---
142
+
143
+ Call the `agent_list` tool to see an overview of all currently running and completed background agents, including their Task IDs and statuses.
144
+ """
145
+
146
+ COMMAND_DEWEY = """---
147
+ description: Trigger dewey for documentation research and implementation examples.
148
+ ---
149
+
150
+ Use the `dewey` prompt to find evidence and documentation for the topic at hand. dewey specializes in multi-repository search and official documentation retrieval.
151
+
152
+ **When to use dewey:**
153
+ - Unfamiliar npm/pip/cargo packages
154
+ - "How do I use [library]?"
155
+ - "What's the best practice for [framework feature]?"
156
+ - Finding OSS implementation examples
157
+ """
158
+
159
+ COMMAND_VERSION = """---
160
+ description: Returns the current version and diagnostic info for stravinsky.
161
+ ---
162
+
163
+ Display the stravinsky MCP version, registered hooks, available agents, and system health status.
164
+ """
165
+
166
+ SLASH_COMMANDS = {
167
+ "stravinsky.md": COMMAND_STRAVINSKY,
168
+ "parallel.md": COMMAND_PARALLEL,
169
+ "list.md": COMMAND_LIST,
170
+ "context.md": COMMAND_CONTEXT,
171
+ "health.md": COMMAND_HEALTH,
172
+ "delphi.md": COMMAND_DELPHI,
173
+ "dewey.md": COMMAND_DEWEY,
174
+ "version.md": COMMAND_VERSION,
175
+ }
@@ -1,7 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stravinsky
3
- Version: 0.1.2
3
+ Version: 0.2.38
4
4
  Summary: MCP Bridge for Claude Code with Multi-Model Support. Install globally: claude mcp add --scope user stravinsky -- uvx stravinsky. Add to CLAUDE.md: See https://pypi.org/project/stravinsky/
5
+ Project-URL: Repository, https://github.com/GratefulDave/stravinsky
6
+ Project-URL: Issues, https://github.com/GratefulDave/stravinsky/issues
5
7
  Author: Stravinsky Team
6
8
  License: MIT
7
9
  Keywords: claude,gemini,mcp,oauth,openai
@@ -13,14 +15,14 @@ Requires-Dist: google-auth>=2.20.0
13
15
  Requires-Dist: httpx>=0.24.0
14
16
  Requires-Dist: jedi>=0.19.2
15
17
  Requires-Dist: keyring>=25.7.0
16
- Requires-Dist: mcp>=1.0.0
18
+ Requires-Dist: mcp>=1.2.1
17
19
  Requires-Dist: openai>=1.0.0
18
20
  Requires-Dist: psutil>=5.9.0
19
21
  Requires-Dist: pydantic>=2.0.0
20
22
  Requires-Dist: python-dotenv>=1.0.0
21
23
  Requires-Dist: rich>=13.0.0
22
24
  Requires-Dist: ruff>=0.14.10
23
- Requires-Dist: uuid-utils>=0.9.0
25
+ Requires-Dist: tenacity>=8.5.0
24
26
  Provides-Extra: dev
25
27
  Requires-Dist: mypy>=1.10.0; extra == 'dev'
26
28
  Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
@@ -29,7 +31,7 @@ Requires-Dist: ruff>=0.4.0; extra == 'dev'
29
31
  Description-Content-Type: text/markdown
30
32
 
31
33
  <div align="center">
32
- <img src=".gemini/antigravity/brain/d170f128-7b96-4abe-b1dc-77cfecd0fc18/stravinsky_logo_1767303800556.png" width="200" alt="Stravinsky Logo">
34
+ <img src="https://raw.githubusercontent.com/GratefulDave/stravinsky/main/assets/logo.png" width="300" alt="Stravinsky Logo">
33
35
  <h1>Stravinsky</h1>
34
36
  <p><strong>The Avant-Garde MCP Bridge for Claude Code</strong></p>
35
37
  <p><em>Movement • Rhythm • Precision</em></p>
@@ -75,7 +77,7 @@ claude mcp add stravinsky -- stravinsky
75
77
 
76
78
  ### Authentication
77
79
 
78
- ```bash
80
+ ````bash
79
81
  # Login to Google (Gemini)
80
82
  stravinsky-auth login gemini
81
83
 
@@ -87,7 +89,54 @@ stravinsky-auth status
87
89
 
88
90
  # Logout
89
91
  stravinsky-auth logout gemini
90
- ```
92
+
93
+ ### Slash Commands
94
+
95
+ Slash commands are discovered from:
96
+ - Project-local: `.claude/commands/**/*.md` (recursive)
97
+ - User-global: `~/.claude/commands/**/*.md` (recursive)
98
+
99
+ Commands can be organized in subdirectories (e.g., `.claude/commands/strav/stravinsky.md`).
100
+
101
+ ````
102
+
103
+ ## Add to Your CLAUDE.md
104
+
105
+ After installing globally, add this to your project's `CLAUDE.md`:
106
+
107
+ ```markdown
108
+ ## Stravinsky MCP (Parallel Agents)
109
+
110
+ Use Stravinsky MCP tools. **DEFAULT: spawn parallel agents for multi-step tasks.**
111
+
112
+ ### Agent Tools
113
+
114
+ - `agent_spawn(prompt, agent_type, description)` - Spawn background agent with full tool access
115
+ - `agent_output(task_id, block)` - Get results (block=True to wait)
116
+ - `agent_progress(task_id)` - Check real-time progress
117
+ - `agent_list()` - Overview of all running agents
118
+ - `agent_cancel(task_id)` - Stop a running agent
119
+
120
+ ### Agent Types
121
+
122
+ - `explore` - Codebase search, "where is X?" questions
123
+ - `dewey` - Documentation research, implementation examples
124
+ - `frontend` - UI/UX work, component design
125
+ - `delphi` - Strategic advice, architecture review
126
+
127
+ ### Parallel Execution (MANDATORY)
128
+
129
+ For ANY task with 2+ independent steps:
130
+
131
+ 1. **Immediately use agent_spawn** for each independent component
132
+ 2. Fire all agents simultaneously, don't wait
133
+ 3. Monitor with agent_progress, collect with agent_output
134
+
135
+ ### ULTRATHINK / ULTRAWORK
136
+
137
+ - **ULTRATHINK**: Engage exhaustive deep reasoning, multi-dimensional analysis
138
+ - **ULTRAWORK**: Maximum parallel execution - spawn agents aggressively for every subtask
139
+ ````
91
140
 
92
141
  ## Tools (31)
93
142
 
@@ -153,7 +202,3 @@ The Codex CLI uses the same port. Stop it with: `killall codex`
153
202
  MIT
154
203
 
155
204
  ---
156
-
157
- <div align="center">
158
- <small>Built with obsession by the Google Deepmind team.</small>
159
- </div>