stravinsky 0.2.40__py3-none-any.whl → 0.3.4__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.
Files changed (56) hide show
  1. mcp_bridge/__init__.py +1 -1
  2. mcp_bridge/auth/token_refresh.py +130 -0
  3. mcp_bridge/cli/__init__.py +6 -0
  4. mcp_bridge/cli/install_hooks.py +1265 -0
  5. mcp_bridge/cli/session_report.py +585 -0
  6. mcp_bridge/hooks/HOOKS_SETTINGS.json +175 -0
  7. mcp_bridge/hooks/README.md +215 -0
  8. mcp_bridge/hooks/__init__.py +119 -43
  9. mcp_bridge/hooks/edit_recovery.py +42 -37
  10. mcp_bridge/hooks/git_noninteractive.py +89 -0
  11. mcp_bridge/hooks/keyword_detector.py +30 -0
  12. mcp_bridge/hooks/manager.py +50 -0
  13. mcp_bridge/hooks/notification_hook.py +103 -0
  14. mcp_bridge/hooks/parallel_enforcer.py +127 -0
  15. mcp_bridge/hooks/parallel_execution.py +111 -0
  16. mcp_bridge/hooks/pre_compact.py +123 -0
  17. mcp_bridge/hooks/preemptive_compaction.py +81 -7
  18. mcp_bridge/hooks/rules_injector.py +507 -0
  19. mcp_bridge/hooks/session_idle.py +116 -0
  20. mcp_bridge/hooks/session_notifier.py +125 -0
  21. mcp_bridge/{native_hooks → hooks}/stravinsky_mode.py +51 -16
  22. mcp_bridge/hooks/subagent_stop.py +98 -0
  23. mcp_bridge/hooks/task_validator.py +73 -0
  24. mcp_bridge/hooks/tmux_manager.py +141 -0
  25. mcp_bridge/hooks/todo_continuation.py +90 -0
  26. mcp_bridge/hooks/todo_delegation.py +88 -0
  27. mcp_bridge/hooks/tool_messaging.py +164 -0
  28. mcp_bridge/hooks/truncator.py +21 -17
  29. mcp_bridge/notifications.py +151 -0
  30. mcp_bridge/prompts/__init__.py +3 -1
  31. mcp_bridge/prompts/dewey.py +30 -20
  32. mcp_bridge/prompts/explore.py +46 -8
  33. mcp_bridge/prompts/multimodal.py +24 -3
  34. mcp_bridge/prompts/planner.py +222 -0
  35. mcp_bridge/prompts/stravinsky.py +107 -28
  36. mcp_bridge/server.py +170 -10
  37. mcp_bridge/server_tools.py +554 -32
  38. mcp_bridge/tools/agent_manager.py +316 -106
  39. mcp_bridge/tools/background_tasks.py +2 -1
  40. mcp_bridge/tools/code_search.py +97 -11
  41. mcp_bridge/tools/lsp/__init__.py +7 -0
  42. mcp_bridge/tools/lsp/manager.py +448 -0
  43. mcp_bridge/tools/lsp/tools.py +637 -150
  44. mcp_bridge/tools/model_invoke.py +270 -47
  45. mcp_bridge/tools/semantic_search.py +2492 -0
  46. mcp_bridge/tools/templates.py +32 -18
  47. stravinsky-0.3.4.dist-info/METADATA +420 -0
  48. stravinsky-0.3.4.dist-info/RECORD +79 -0
  49. stravinsky-0.3.4.dist-info/entry_points.txt +5 -0
  50. mcp_bridge/native_hooks/edit_recovery.py +0 -46
  51. mcp_bridge/native_hooks/truncator.py +0 -23
  52. stravinsky-0.2.40.dist-info/METADATA +0 -204
  53. stravinsky-0.2.40.dist-info/RECORD +0 -57
  54. stravinsky-0.2.40.dist-info/entry_points.txt +0 -3
  55. /mcp_bridge/{native_hooks → hooks}/context.py +0 -0
  56. {stravinsky-0.2.40.dist-info → stravinsky-0.3.4.dist-info}/WHEEL +0 -0
@@ -11,6 +11,7 @@ import os
11
11
  import shutil
12
12
  import subprocess
13
13
  import signal
14
+ import time
14
15
  import uuid
15
16
  from dataclasses import asdict, dataclass, field
16
17
  from datetime import datetime
@@ -21,6 +22,85 @@ import logging
21
22
 
22
23
  logger = logging.getLogger(__name__)
23
24
 
25
+ # Model routing configuration
26
+ # Specialized agents call external models via MCP tools:
27
+ # explore/dewey/document_writer/multimodal → invoke_gemini(gemini-3-flash)
28
+ # frontend → invoke_gemini(gemini-3-pro-high)
29
+ # delphi → invoke_openai(gpt-5.2)
30
+ # Non-specialized coding tasks use Claude CLI with --model sonnet
31
+ AGENT_MODEL_ROUTING = {
32
+ # Specialized agents - no CLI model flag, they call invoke_* tools
33
+ "explore": None,
34
+ "dewey": None,
35
+ "document_writer": None,
36
+ "multimodal": None,
37
+ "frontend": None,
38
+ "delphi": None,
39
+ "research-lead": None, # Hierarchical orchestrator using gemini-3-flash
40
+ "implementation-lead": None, # Hierarchical orchestrator using haiku
41
+ # Planner uses Opus for superior reasoning about dependencies and parallelization
42
+ "planner": "opus",
43
+ # Default for unknown agent types (coding tasks) - use Sonnet 4.5
44
+ "_default": "sonnet",
45
+ }
46
+
47
+ # Cost tier classification (from oh-my-opencode pattern)
48
+ AGENT_COST_TIERS = {
49
+ "explore": "CHEAP", # Uses gemini-3-flash
50
+ "dewey": "CHEAP", # Uses gemini-3-flash
51
+ "document_writer": "CHEAP", # Uses gemini-3-flash
52
+ "multimodal": "CHEAP", # Uses gemini-3-flash
53
+ "research-lead": "CHEAP", # Uses gemini-3-flash
54
+ "implementation-lead": "CHEAP", # Uses haiku
55
+ "frontend": "MEDIUM", # Uses gemini-3-pro-high
56
+ "delphi": "EXPENSIVE", # Uses gpt-5.2 (OpenAI GPT)
57
+ "planner": "EXPENSIVE", # Uses Claude Opus 4.5
58
+ "_default": "EXPENSIVE", # Claude Sonnet 4.5 via CLI
59
+ }
60
+
61
+ # Display model names for output formatting (user-visible)
62
+ AGENT_DISPLAY_MODELS = {
63
+ "explore": "gemini-3-flash",
64
+ "dewey": "gemini-3-flash",
65
+ "document_writer": "gemini-3-flash",
66
+ "multimodal": "gemini-3-flash",
67
+ "research-lead": "gemini-3-flash",
68
+ "implementation-lead": "haiku",
69
+ "frontend": "gemini-3-pro-high",
70
+ "delphi": "gpt-5.2",
71
+ "planner": "opus-4.5",
72
+ "_default": "sonnet-4.5",
73
+ }
74
+
75
+ # Cost tier emoji indicators for visual differentiation
76
+ # Colors indicate cost: 🟢 cheap/free, 🔵 medium, 🟣 expensive (GPT), 🟠 Claude
77
+ COST_TIER_EMOJI = {
78
+ "CHEAP": "🟢", # Free/cheap models (gemini-3-flash, haiku)
79
+ "MEDIUM": "🔵", # Medium cost (gemini-3-pro-high)
80
+ "EXPENSIVE": "🟣", # Expensive models (gpt-5.2, opus)
81
+ }
82
+
83
+ # Model family indicators
84
+ MODEL_FAMILY_EMOJI = {
85
+ "gemini-3-flash": "🟢",
86
+ "gemini-3-pro-high": "🔵",
87
+ "haiku": "🟢",
88
+ "sonnet-4.5": "🟠",
89
+ "opus-4.5": "🟣",
90
+ "gpt-5.2": "🟣",
91
+ }
92
+
93
+
94
+ def get_agent_emoji(agent_type: str) -> str:
95
+ """Get the colored emoji indicator for an agent based on its cost tier."""
96
+ cost_tier = AGENT_COST_TIERS.get(agent_type, AGENT_COST_TIERS["_default"])
97
+ return COST_TIER_EMOJI.get(cost_tier, "⚪")
98
+
99
+
100
+ def get_model_emoji(model_name: str) -> str:
101
+ """Get the colored emoji indicator for a model."""
102
+ return MODEL_FAMILY_EMOJI.get(model_name, "⚪")
103
+
24
104
 
25
105
  @dataclass
26
106
  class AgentTask:
@@ -86,7 +166,7 @@ class AgentManager:
86
166
 
87
167
  # In-memory tracking for running processes
88
168
  self._processes: Dict[str, subprocess.Popen] = {}
89
- self._notification_queue: Dict[str, List[AgentTask]] = {}
169
+ self._notification_queue: Dict[str, List[Dict[str, Any]]] = {}
90
170
 
91
171
  def _load_tasks(self) -> Dict[str, Any]:
92
172
  """Load tasks from persistent storage."""
@@ -155,7 +235,9 @@ class AgentManager:
155
235
  Returns:
156
236
  Task ID for tracking
157
237
  """
158
- task_id = f"agent_{uuid.uuid4().hex[:8]}"
238
+ import uuid as uuid_module # Local import for MCP context
239
+
240
+ task_id = f"agent_{uuid_module.uuid4().hex[:8]}"
159
241
 
160
242
  task = AgentTask(
161
243
  id=task_id,
@@ -220,12 +302,20 @@ class AgentManager:
220
302
  full_prompt,
221
303
  "--output-format",
222
304
  "text",
305
+ "--dangerously-skip-permissions", # Critical: bypass permission prompts
223
306
  ]
224
307
 
225
- # NOTE: We intentionally do NOT pass --model to Claude CLI
226
- # The agent_configs have Stravinsky MCP model names (gemini-3-pro-low, gpt-5.2)
227
- # which Claude CLI doesn't recognize. Agents use Claude's default model
228
- # and can invoke Stravinsky MCP tools (invoke_gemini, invoke_openai) if needed.
308
+ # Model routing:
309
+ # - Specialized agents (explore/dewey/etc): None = use CLI default, they call invoke_*
310
+ # - Unknown agent types (coding tasks): Use Sonnet 4.5
311
+ if agent_type in AGENT_MODEL_ROUTING:
312
+ cli_model = AGENT_MODEL_ROUTING[agent_type] # None for specialized
313
+ else:
314
+ cli_model = AGENT_MODEL_ROUTING.get("_default", "sonnet")
315
+
316
+ if cli_model:
317
+ cmd.extend(["--model", cli_model])
318
+ logger.info(f"[AgentManager] Using --model {cli_model} for {agent_type} agent")
229
319
 
230
320
  # Add system prompt file if we have one
231
321
  if system_prompt:
@@ -240,6 +330,7 @@ class AgentManager:
240
330
  # (Previously used file handle which was closed before process finished)
241
331
  process = subprocess.Popen(
242
332
  cmd,
333
+ stdin=subprocess.DEVNULL, # Critical: prevent stdin blocking
243
334
  stdout=subprocess.PIPE,
244
335
  stderr=subprocess.PIPE,
245
336
  text=True,
@@ -416,20 +507,28 @@ class AgentManager:
416
507
  start = datetime.now()
417
508
  while (datetime.now() - start).total_seconds() < timeout:
418
509
  task = self.get_task(task_id)
419
- if task["status"] != "running":
510
+ if not task or task["status"] != "running":
420
511
  break
421
- asyncio.sleep(0.5)
512
+ time.sleep(0.5)
513
+
514
+ # Refresh task state after potential blocking wait
515
+ if not task:
516
+ return f"Task {task_id} not found."
422
517
 
423
518
  status = task["status"]
424
519
  description = task.get("description", "")
425
520
  agent_type = task.get("agent_type", "unknown")
426
521
 
522
+ # Get cost-tier emoji for visual differentiation
523
+ cost_emoji = get_agent_emoji(agent_type)
524
+ display_model = AGENT_DISPLAY_MODELS.get(agent_type, AGENT_DISPLAY_MODELS["_default"])
525
+
427
526
  if status == "completed":
428
527
  result = task.get("result", "(no output)")
429
- return f"""✅ Agent Task Completed
528
+ return f"""{cost_emoji} ✅ Agent Task Completed
430
529
 
431
530
  **Task ID**: {task_id}
432
- **Agent**: {agent_type}
531
+ **Agent**: {agent_type}:{display_model}
433
532
  **Description**: {description}
434
533
 
435
534
  **Result**:
@@ -437,29 +536,29 @@ class AgentManager:
437
536
 
438
537
  elif status == "failed":
439
538
  error = task.get("error", "(no error details)")
440
- return f"""❌ Agent Task Failed
539
+ return f"""{cost_emoji} ❌ Agent Task Failed
441
540
 
442
541
  **Task ID**: {task_id}
443
- **Agent**: {agent_type}
542
+ **Agent**: {agent_type}:{display_model}
444
543
  **Description**: {description}
445
544
 
446
545
  **Error**:
447
546
  {error}"""
448
547
 
449
548
  elif status == "cancelled":
450
- return f"""⚠️ Agent Task Cancelled
549
+ return f"""{cost_emoji} ⚠️ Agent Task Cancelled
451
550
 
452
551
  **Task ID**: {task_id}
453
- **Agent**: {agent_type}
552
+ **Agent**: {agent_type}:{display_model}
454
553
  **Description**: {description}"""
455
554
 
456
555
  else: # pending or running
457
556
  pid = task.get("pid", "N/A")
458
557
  started = task.get("started_at", "N/A")
459
- return f"""⏳ Agent Task Running
558
+ return f"""{cost_emoji} ⏳ Agent Task Running
460
559
 
461
560
  **Task ID**: {task_id}
462
- **Agent**: {agent_type}
561
+ **Agent**: {agent_type}:{display_model}
463
562
  **Description**: {description}
464
563
  **PID**: {pid}
465
564
  **Started**: {started}
@@ -535,10 +634,14 @@ Use `agent_output` with block=true to wait for completion."""
535
634
  "cancelled": "⚠️",
536
635
  }.get(status, "❓")
537
636
 
538
- result = f"""{status_emoji} **Agent Progress**
637
+ # Get cost-tier emoji for visual differentiation
638
+ cost_emoji = get_agent_emoji(agent_type)
639
+ display_model = AGENT_DISPLAY_MODELS.get(agent_type, AGENT_DISPLAY_MODELS["_default"])
640
+
641
+ result = f"""{cost_emoji} {status_emoji} **Agent Progress**
539
642
 
540
643
  **Task ID**: {task_id}
541
- **Agent**: {agent_type}
644
+ **Agent**: {agent_type}:{display_model}
542
645
  **Description**: {description}
543
646
  **Status**: {status}
544
647
  """
@@ -583,6 +686,7 @@ async def agent_spawn(
583
686
  model: str = "gemini-3-flash",
584
687
  thinking_budget: int = 0,
585
688
  timeout: int = 300,
689
+ blocking: bool = False,
586
690
  ) -> str:
587
691
  """
588
692
  Spawn a background agent.
@@ -594,95 +698,191 @@ async def agent_spawn(
594
698
  model: Model to use (gemini-3-flash, gemini-2.0-flash, claude)
595
699
  thinking_budget: Reserved reasoning tokens
596
700
  timeout: Execution timeout in seconds
701
+ blocking: If True, wait for completion and return result directly (use for delphi)
597
702
 
598
703
  Returns:
599
- Task ID and instructions
704
+ Task ID and instructions, or full result if blocking=True
600
705
  """
601
706
  manager = get_manager()
602
707
 
603
708
  # Map agent types to system prompts
709
+ # ALL agents use invoke_gemini or invoke_openai - NOT Claude directly
710
+ # explore/dewey/document_writer/multimodal/frontend → gemini-3-flash
711
+ # delphi → openai gpt-5.2
604
712
  system_prompts = {
605
- "explore": "You are a codebase exploration specialist. Find files, patterns, and answer 'where is X?' questions efficiently.",
606
- "dewey": "You are a documentation and research specialist. Find implementation examples, official docs, and provide evidence-based answers.",
607
- "frontend": """You are a Senior Frontend Architect & Avant-Garde UI Designer with 15+ years experience.
608
-
609
- OPERATIONAL DIRECTIVES:
610
- - Follow instructions. Execute immediately. No fluff.
611
- - Output First: Prioritize code and visual solutions.
612
-
613
- DESIGN PHILOSOPHY - "INTENTIONAL MINIMALISM":
614
- - Anti-Generic: Reject standard "bootstrapped" layouts. If it looks like a template, it's wrong.
615
- - Bespoke layouts, asymmetry, distinctive typography.
616
- - Before placing any element, calculate its purpose. No purpose = delete it.
617
-
618
- FRONTEND CODING STANDARDS:
619
- - Library Discipline: If a UI library (Shadcn, Radix, MUI) is detected, YOU MUST USE IT.
620
- - Do NOT build custom components if the library provides them.
621
- - Stack: Modern (React/Vue/Svelte), Tailwind/Custom CSS, semantic HTML5.
622
- - Focus on micro-interactions, perfect spacing, "invisible" UX.
623
-
624
- RESPONSE FORMAT:
625
- 1. Rationale: (1 sentence on why elements were placed there)
626
- 2. The Code.
627
-
628
- ULTRATHINK MODE (when user says "ULTRATHINK" or "think harder"):
629
- 1. Deep Reasoning Chain: Detailed breakdown of architectural and design decisions
630
- 2. Edge Case Analysis: What could go wrong and how we prevented it
631
- 3. The Code: Optimized, bespoke, production-ready, utilizing existing libraries""",
632
- "delphi": "You are a strategic advisor. Provide architecture guidance, debugging assistance, and code review.",
633
- "document_writer": """You are a Technical Documentation Specialist. Your expertise is creating clear, comprehensive documentation.
634
-
635
- DOCUMENT TYPES YOU EXCEL AT:
636
- - README files with proper structure
637
- - API documentation with examples
638
- - Architecture decision records (ADRs)
639
- - User guides and tutorials
640
- - Inline code documentation
641
-
642
- DOCUMENTATION PRINCIPLES:
643
- - Audience-first: Know who's reading and what they need
644
- - Progressive disclosure: Overview Details → Edge cases
645
- - Examples over explanations: Show, don't just tell
646
- - Keep it DRY: Reference rather than repeat
647
- - Version awareness: Note when behavior differs across versions
648
-
649
- RESPONSE FORMAT:
650
- 1. Document type and target audience identified
651
- 2. The documentation, properly formatted in markdown""",
652
- "multimodal": """You interpret media files that cannot be read as plain text.
653
-
654
- Your job: examine the attached file and extract ONLY what was requested.
655
-
656
- CAPABILITIES:
657
- - PDFs: extract text, structure, tables, data from specific sections
658
- - Images: describe layouts, UI elements, text, diagrams, charts
659
- - Diagrams: explain relationships, flows, architecture depicted
660
- - Screenshots: analyze UI/UX, identify components, extract text
661
-
662
- HOW YOU WORK:
663
- 1. Receive a file path and a goal describing what to extract
664
- 2. Read and analyze the file deeply using Gemini's vision capabilities
665
- 3. Return ONLY the relevant extracted information
666
- 4. The main agent never processes the raw file - you save context tokens
667
-
668
- RESPONSE RULES:
669
- - Return extracted information directly, no preamble
670
- - If info not found, state clearly what's missing
671
- - Be thorough on the goal, concise on everything else""",
713
+ "explore": """You are a codebase exploration specialist. Find files, patterns, and answer 'where is X?' questions.
714
+
715
+ MODEL ROUTING (MANDATORY):
716
+ You MUST use invoke_gemini with model="gemini-3-flash" for ALL analysis and reasoning.
717
+ Use Claude's native tools (Read, Grep, Glob) ONLY for file access, then pass content to invoke_gemini.
718
+
719
+ WORKFLOW:
720
+ 1. Use Read/Grep/Glob to get file contents
721
+ 2. Call invoke_gemini(prompt="Analyze this: <content>", model="gemini-3-flash", agent_context={"agent_type": "explore"}) for analysis
722
+ 3. Return the Gemini response""",
723
+ "dewey": """You are a documentation and research specialist. Find implementation examples and official docs.
724
+
725
+ MODEL ROUTING (MANDATORY):
726
+ You MUST use invoke_gemini with model="gemini-3-flash" for ALL analysis, summarization, and reasoning.
727
+
728
+ WORKFLOW:
729
+ 1. Gather information using available tools
730
+ 2. Call invoke_gemini(prompt="<task>", model="gemini-3-flash", agent_context={"agent_type": "dewey"}) for processing
731
+ 3. Return the Gemini response""",
732
+ "frontend": """You are a Senior Frontend Architect & UI Designer.
733
+
734
+ MODEL ROUTING (MANDATORY):
735
+ You MUST use invoke_gemini with model="gemini-3-pro-high" for ALL code generation and design work.
736
+
737
+ DESIGN PHILOSOPHY:
738
+ - Anti-Generic: Reject standard layouts. Bespoke, asymmetric, distinctive.
739
+ - Library Discipline: Use existing UI libraries (Shadcn, Radix, MUI) if detected.
740
+ - Stack: React/Vue/Svelte, Tailwind/Custom CSS, semantic HTML5.
741
+
742
+ WORKFLOW:
743
+ 1. Analyze requirements
744
+ 2. Call invoke_gemini(prompt="Generate frontend code for: <task>", model="gemini-3-pro-high", agent_context={"agent_type": "frontend"})
745
+ 3. Return the code""",
746
+ "delphi": """You are a strategic technical advisor for architecture and hard debugging.
747
+
748
+ MODEL ROUTING (MANDATORY):
749
+ You MUST use invoke_openai with model="gpt-5.2" for ALL strategic advice and analysis.
750
+
751
+ WORKFLOW:
752
+ 1. Gather context about the problem
753
+ 2. Call invoke_openai(prompt="<problem description>", model="gpt-5.2", agent_context={"agent_type": "delphi"})
754
+ 3. Return the GPT response""",
755
+ "document_writer": """You are a Technical Documentation Specialist.
756
+
757
+ MODEL ROUTING (MANDATORY):
758
+ You MUST use invoke_gemini with model="gemini-3-flash" for ALL documentation generation.
759
+
760
+ DOCUMENT TYPES: README, API docs, ADRs, user guides, inline docs.
761
+
762
+ WORKFLOW:
763
+ 1. Gather context about what to document
764
+ 2. Call invoke_gemini(prompt="Write documentation for: <topic>", model="gemini-3-flash", agent_context={"agent_type": "document_writer"})
765
+ 3. Return the documentation""",
766
+ "multimodal": """You interpret media files (PDFs, images, diagrams, screenshots).
767
+
768
+ MODEL ROUTING (MANDATORY):
769
+ You MUST use invoke_gemini with model="gemini-3-flash" for ALL visual analysis.
770
+
771
+ WORKFLOW:
772
+ 1. Receive file path and extraction goal
773
+ 2. Call invoke_gemini(prompt="Analyze this file: <path>. Extract: <goal>", model="gemini-3-flash", agent_context={"agent_type": "multimodal"})
774
+ 3. Return extracted information only""",
775
+ "planner": """You are a pre-implementation planning specialist. You analyze requests and produce structured implementation plans BEFORE any code changes begin.
776
+
777
+ PURPOSE:
778
+ - Analyze requests and produce actionable implementation plans
779
+ - Identify dependencies and parallelization opportunities
780
+ - Enable efficient parallel execution by the orchestrator
781
+ - Prevent wasted effort through upfront planning
782
+
783
+ METHODOLOGY:
784
+ 1. EXPLORE FIRST: Spawn explore agents IN PARALLEL to understand the codebase
785
+ 2. DECOMPOSE: Break request into atomic, single-purpose tasks
786
+ 3. ANALYZE DEPENDENCIES: What blocks what? What can run in parallel?
787
+ 4. ASSIGN AGENTS: Map each task to the right specialist (explore/dewey/frontend/delphi)
788
+ 5. OUTPUT STRUCTURED PLAN: Use the required format below
789
+
790
+ REQUIRED OUTPUT FORMAT:
791
+ ```
792
+ ## PLAN: [Brief title]
793
+
794
+ ### ANALYSIS
795
+ - **Request**: [One sentence summary]
796
+ - **Scope**: [What's in/out of scope]
797
+ - **Risk Level**: [Low/Medium/High]
798
+
799
+ ### EXECUTION PHASES
800
+
801
+ #### Phase 1: [Name] (PARALLEL)
802
+ | Task | Agent | Files | Est |
803
+ |------|-------|-------|-----|
804
+ | [description] | explore | file.py | S/M/L |
805
+
806
+ #### Phase 2: [Name] (SEQUENTIAL after Phase 1)
807
+ | Task | Agent | Files | Est |
808
+ |------|-------|-------|-----|
809
+
810
+ ### AGENT SPAWN COMMANDS
811
+ ```python
812
+ # Phase 1 - Fire all in parallel
813
+ agent_spawn(prompt="...", agent_type="explore", description="...")
814
+ ```
815
+ ```
816
+
817
+ CONSTRAINTS:
818
+ - You ONLY plan. You NEVER execute code changes.
819
+ - Every task must have a clear agent assignment
820
+ - Parallel phases must be truly independent
821
+ - Include ready-to-use agent_spawn commands""",
822
+ "research-lead": """You coordinate research tasks by spawning explore and dewey agents in parallel.
823
+
824
+ ## Your Role
825
+ 1. Receive research objective from Stravinsky
826
+ 2. Decompose into parallel search tasks
827
+ 3. Spawn explore/dewey agents for each task
828
+ 4. Collect and SYNTHESIZE results
829
+ 5. Return structured findings (not raw outputs)
830
+
831
+ ## Output Format
832
+ Always return a Research Brief:
833
+ ```json
834
+ {
835
+ "objective": "Original research goal",
836
+ "findings": [
837
+ {"source": "agent_id", "summary": "Key finding", "confidence": "high/medium/low"},
838
+ ...
839
+ ],
840
+ "synthesis": "Combined analysis of all findings",
841
+ "gaps": ["Information we couldn't find"],
842
+ "recommendations": ["Suggested next steps"]
843
+ }
844
+ ```
845
+
846
+ MODEL ROUTING:
847
+ Use invoke_gemini with model="gemini-3-flash" for ALL synthesis work.
848
+ """,
849
+ "implementation-lead": """You coordinate implementation based on research findings.
850
+
851
+ ## Your Role
852
+ 1. Receive Research Brief from Stravinsky
853
+ 2. Create implementation plan
854
+ 3. Delegate to specialists:
855
+ - frontend: UI/visual work
856
+ - debugger: Fix failures
857
+ - code-reviewer: Quality checks
858
+ 4. Verify with lsp_diagnostics
859
+ 5. Return Implementation Report
860
+
861
+ ## Output Format
862
+ ```json
863
+ {
864
+ "objective": "What was implemented",
865
+ "files_changed": ["path/to/file.py"],
866
+ "tests_status": "pass/fail/skipped",
867
+ "diagnostics": "clean/warnings/errors",
868
+ "blockers": ["Issues preventing completion"]
869
+ }
870
+ ```
871
+
872
+ ## Escalation Rules
873
+ - After 2 failed attempts → spawn debugger
874
+ - After debugger fails → escalate to Stravinsky with context
875
+ - NEVER call delphi directly
876
+ """,
672
877
  }
673
878
 
674
879
  system_prompt = system_prompts.get(agent_type, None)
675
880
 
676
- # NOTE: All agents run via Claude CLI using Claude's default model.
677
- # The agent_configs below are kept for documentation purposes only.
678
- # Agents can invoke Stravinsky MCP tools (invoke_gemini, invoke_openai)
679
- # within their prompts if they need to use other models.
680
- #
681
- # Agent model preferences (for reference - NOT passed to Claude CLI):
682
- # - stravinsky: Claude Opus 4.5 (orchestration)
683
- # - delphi: GPT-5.2 (strategic advice) - use invoke_openai
684
- # - frontend: Gemini Pro High (UI/UX) - use invoke_gemini with thinking_budget
685
- # - explore, dewey, document_writer, multimodal: Gemini Flash (fast) - use invoke_gemini
881
+ # Model routing (MANDATORY - enforced in system prompts):
882
+ # - explore, dewey, document_writer, multimodal invoke_gemini(gemini-3-flash)
883
+ # - frontend invoke_gemini(gemini-3-pro-high)
884
+ # - delphi invoke_openai(gpt-5.2)
885
+ # - Unknown agent types (coding tasks) → Claude CLI --model sonnet
686
886
 
687
887
  # Get token store for authentication
688
888
  from ..auth.token_store import TokenStore
@@ -700,16 +900,20 @@ RESPONSE RULES:
700
900
  timeout=timeout,
701
901
  )
702
902
 
703
- return f"""🚀 Background agent spawned successfully.
903
+ # Get display model and cost tier emoji for concise output
904
+ display_model = AGENT_DISPLAY_MODELS.get(agent_type, AGENT_DISPLAY_MODELS["_default"])
905
+ cost_emoji = get_agent_emoji(agent_type)
906
+ short_desc = (description or prompt[:50]).strip()
704
907
 
705
- **Task ID**: {task_id}
706
- **Agent Type**: {agent_type}
707
- **Description**: {description or prompt[:50]}
908
+ # If blocking mode (recommended for delphi), wait for completion
909
+ if blocking:
910
+ result = manager.get_output(task_id, block=True, timeout=timeout)
911
+ return f"{cost_emoji} {agent_type}:{display_model}('{short_desc}') [BLOCKING]\n\n{result}"
708
912
 
709
- The agent is now running. Use:
710
- - `agent_progress(task_id="{task_id}")` to monitor real-time progress
711
- - `agent_output(task_id="{task_id}")` to get final result
712
- - `agent_cancel(task_id="{task_id}")` to stop the agent"""
913
+ # Enhanced format: cost_emoji agent:model('description') status_emoji
914
+ # 🟢 explore:gemini-3-flash('Find auth...')
915
+ return f"""{cost_emoji} {agent_type}:{display_model}('{short_desc}')
916
+ task_id={task_id}"""
713
917
 
714
918
 
715
919
  async def agent_output(task_id: str, block: bool = False) -> str:
@@ -799,7 +1003,7 @@ async def agent_list() -> str:
799
1003
  if not tasks:
800
1004
  return "No background agent tasks found."
801
1005
 
802
- lines = ["**Background Agent Tasks**", ""]
1006
+ lines = []
803
1007
 
804
1008
  for t in sorted(tasks, key=lambda x: x.get("created_at", ""), reverse=True):
805
1009
  status_emoji = {
@@ -810,8 +1014,14 @@ async def agent_list() -> str:
810
1014
  "cancelled": "⚠️",
811
1015
  }.get(t["status"], "❓")
812
1016
 
1017
+ agent_type = t.get("agent_type", "unknown")
1018
+ display_model = AGENT_DISPLAY_MODELS.get(agent_type, AGENT_DISPLAY_MODELS["_default"])
1019
+ cost_emoji = get_agent_emoji(agent_type)
813
1020
  desc = t.get("description", t.get("prompt", "")[:40])
814
- lines.append(f"- {status_emoji} [{t['id']}] {t['agent_type']}: {desc}")
1021
+ # Concise format: cost_emoji status agent:model('desc') id=xxx
1022
+ lines.append(
1023
+ f"{cost_emoji} {status_emoji} {agent_type}:{display_model}('{desc}') id={t['id']}"
1024
+ )
815
1025
 
816
1026
  return "\n".join(lines)
817
1027
 
@@ -61,7 +61,8 @@ class BackgroundManager:
61
61
  json.dump(tasks, f, indent=2)
62
62
 
63
63
  def create_task(self, prompt: str, model: str) -> str:
64
- task_id = str(uuid.uuid4())[:8]
64
+ import uuid as uuid_module # Local import for MCP context
65
+ task_id = str(uuid_module.uuid4())[:8]
65
66
  task = BackgroundTask(
66
67
  id=task_id,
67
68
  prompt=prompt,