stravinsky 0.2.11__tar.gz → 0.2.62__tar.gz
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.
- {stravinsky-0.2.11 → stravinsky-0.2.62}/.github/workflows/publish.yml +3 -4
- stravinsky-0.2.62/.mcp.json +8 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_0de66569.out +117 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_0de66569.system +10 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_2ef2b305.out +142 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_2ef2b305.system +9 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_32fc606b.out +123 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_32fc606b.system +10 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_4943202a.out +112 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_4943202a.system +10 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_4ed6ec7a.out +132 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_4ed6ec7a.system +9 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_622ae68b.out +119 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_622ae68b.system +10 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_6731b838.out +278 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_6731b838.system +10 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_6c1ebe08.out +345 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_6c1ebe08.system +9 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_6c536f2d.out +103 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_6c536f2d.system +10 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_6ecde4ed.out +76 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_6ecde4ed.system +9 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_6f6687f1.out +388 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_6f6687f1.system +10 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_85449406.out +13 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_85449406.system +9 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_940fbc06.out +170 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_940fbc06.system +10 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_adc99d05.out +128 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_adc99d05.system +10 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_b3c09833.out +124 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_b3c09833.system +10 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_cdd28e91.system +10 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_e7637527.out +353 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_e7637527.system +9 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_fee89a04.out +81 -0
- stravinsky-0.2.62/.stravinsky/agents/agent_fee89a04.system +10 -0
- stravinsky-0.2.62/.stravinsky/agents.json +290 -0
- stravinsky-0.2.62/ARCHITECTURE.md +1133 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/CLAUDE.md +6 -1
- stravinsky-0.2.62/INSTALL.md +484 -0
- stravinsky-0.2.62/PKG-INFO +284 -0
- stravinsky-0.2.62/README.md +252 -0
- stravinsky-0.2.62/docs/AGENTS.md +282 -0
- stravinsky-0.2.62/docs/AGENT_WORKFLOW.md +974 -0
- stravinsky-0.2.62/docs/INSTALL.md +370 -0
- stravinsky-0.2.62/docs/QUICKSTART.md +127 -0
- stravinsky-0.2.62/docs/README.md +79 -0
- stravinsky-0.2.62/docs/TROUBLESHOOTING.md +382 -0
- stravinsky-0.2.62/docs/USAGE.md +460 -0
- stravinsky-0.2.62/docs/architecture_workflow.md +79 -0
- stravinsky-0.2.62/docs/remediation_plan.md +38 -0
- stravinsky-0.2.62/logs/.1c0e2f6784d083818216ed08579b248b799c8d86-audit.json +25 -0
- stravinsky-0.2.62/logs/.270de9f01be3c37438e0ae9542f6c146c85078ae-audit.json +25 -0
- stravinsky-0.2.62/logs/application-2026-01-03.log +45 -0
- stravinsky-0.2.62/logs/application-2026-01-04.log +232 -0
- stravinsky-0.2.62/logs/application-2026-01-05.log +111 -0
- stravinsky-0.2.62/logs/error-2026-01-03.log +3 -0
- stravinsky-0.2.62/logs/error-2026-01-04.log +24 -0
- stravinsky-0.2.62/logs/error-2026-01-05.log +8 -0
- stravinsky-0.2.62/mcp_bridge/__init__.py +1 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/auth/cli.py +84 -46
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/auth/oauth.py +88 -63
- stravinsky-0.2.62/mcp_bridge/auth/token_refresh.py +130 -0
- stravinsky-0.2.62/mcp_bridge/cli/__init__.py +5 -0
- stravinsky-0.2.62/mcp_bridge/cli/session_report.py +585 -0
- stravinsky-0.2.62/mcp_bridge/hooks/__init__.py +78 -0
- stravinsky-0.2.62/mcp_bridge/hooks/agent_reminder.py +61 -0
- stravinsky-0.2.62/mcp_bridge/hooks/auto_slash_command.py +186 -0
- stravinsky-0.2.62/mcp_bridge/hooks/comment_checker.py +136 -0
- stravinsky-0.2.62/mcp_bridge/hooks/context_monitor.py +58 -0
- stravinsky-0.2.62/mcp_bridge/hooks/empty_message_sanitizer.py +240 -0
- stravinsky-0.2.62/mcp_bridge/hooks/git_noninteractive.py +89 -0
- stravinsky-0.2.62/mcp_bridge/hooks/keyword_detector.py +152 -0
- stravinsky-0.2.62/mcp_bridge/hooks/manager.py +146 -0
- stravinsky-0.2.62/mcp_bridge/hooks/parallel_enforcer.py +127 -0
- stravinsky-0.2.62/mcp_bridge/hooks/pre_compact.py +234 -0
- stravinsky-0.2.62/mcp_bridge/hooks/preemptive_compaction.py +231 -0
- stravinsky-0.2.62/mcp_bridge/hooks/rules_injector.py +507 -0
- stravinsky-0.2.62/mcp_bridge/hooks/session_idle.py +116 -0
- stravinsky-0.2.62/mcp_bridge/hooks/session_notifier.py +125 -0
- stravinsky-0.2.62/mcp_bridge/hooks/session_recovery.py +186 -0
- stravinsky-0.2.62/mcp_bridge/hooks/task_validator.py +73 -0
- stravinsky-0.2.62/mcp_bridge/hooks/tmux_manager.py +141 -0
- stravinsky-0.2.62/mcp_bridge/hooks/todo_enforcer.py +75 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/prompts/__init__.py +3 -1
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/prompts/delphi.py +3 -2
- stravinsky-0.2.62/mcp_bridge/prompts/dewey.py +277 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/prompts/explore.py +46 -8
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/prompts/multimodal.py +24 -3
- stravinsky-0.2.62/mcp_bridge/prompts/planner.py +222 -0
- stravinsky-0.2.62/mcp_bridge/prompts/stravinsky.py +739 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/server.py +319 -65
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/server_tools.py +181 -33
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/tools/__init__.py +2 -1
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/tools/agent_manager.py +439 -284
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/tools/background_tasks.py +2 -1
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/tools/code_search.py +59 -1
- stravinsky-0.2.62/mcp_bridge/tools/model_invoke.py +986 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/tools/skill_loader.py +51 -47
- stravinsky-0.2.62/mcp_bridge/tools/task_runner.py +141 -0
- stravinsky-0.2.62/mcp_bridge/tools/templates.py +189 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/pyproject.toml +2 -1
- stravinsky-0.2.62/repro_spawn.py +29 -0
- stravinsky-0.2.62/run-mcp.sh +3 -0
- stravinsky-0.2.62/tests/conftest.py +8 -0
- stravinsky-0.2.62/tests/test_new_hooks.py +316 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/uv.lock +1 -1
- stravinsky-0.2.11/.mcp.json +0 -3
- stravinsky-0.2.11/.stravinsky/agents/agent_9b9fd4f0.log +0 -0
- stravinsky-0.2.11/.stravinsky/agents/agent_9b9fd4f0.out +0 -1
- stravinsky-0.2.11/.stravinsky/agents.json +0 -1
- stravinsky-0.2.11/PKG-INFO +0 -210
- stravinsky-0.2.11/README.md +0 -178
- stravinsky-0.2.11/mcp_bridge/__init__.py +0 -1
- stravinsky-0.2.11/mcp_bridge/hooks/__init__.py +0 -28
- stravinsky-0.2.11/mcp_bridge/hooks/manager.py +0 -77
- stravinsky-0.2.11/mcp_bridge/native_hooks/context.py +0 -38
- stravinsky-0.2.11/mcp_bridge/native_hooks/edit_recovery.py +0 -46
- stravinsky-0.2.11/mcp_bridge/native_hooks/truncator.py +0 -23
- stravinsky-0.2.11/mcp_bridge/prompts/dewey.py +0 -183
- stravinsky-0.2.11/mcp_bridge/prompts/stravinsky.py +0 -345
- stravinsky-0.2.11/mcp_bridge/tools/model_invoke.py +0 -297
- stravinsky-0.2.11/mcp_bridge/tools/task_runner.py +0 -97
- stravinsky-0.2.11/mcp_bridge/tools/templates.py +0 -94
- {stravinsky-0.2.11 → stravinsky-0.2.62}/.gitignore +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/assets/logo.png +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/assets/logo.png.txt +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/assets/logo_small.png +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/error.log +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/install_native_hooks.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/auth/__init__.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/auth/openai_oauth.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/auth/token_store.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/config/__init__.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/config/hooks.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/hooks/budget_optimizer.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/hooks/compaction.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/hooks/directory_context.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/hooks/edit_recovery.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/hooks/truncator.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/prompts/document_writer.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/prompts/frontend.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/tools/continuous_loop.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/tools/init.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/tools/lsp/__init__.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/tools/lsp/tools.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/tools/project_context.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/tools/session_manager.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/mcp_bridge/utils/__init__.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/stdout_handshake_auditor.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/tests/manual_test_hooks.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/tests/test_hooks.py +0 -0
- {stravinsky-0.2.11 → stravinsky-0.2.62}/verify_tools.py +0 -0
|
@@ -10,7 +10,6 @@ jobs:
|
|
|
10
10
|
build-and-publish:
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
12
|
permissions:
|
|
13
|
-
id-token: write # Required for trusted publishing
|
|
14
13
|
contents: read
|
|
15
14
|
|
|
16
15
|
steps:
|
|
@@ -33,6 +32,6 @@ jobs:
|
|
|
33
32
|
- name: Publish to PyPI
|
|
34
33
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
35
34
|
with:
|
|
36
|
-
#
|
|
37
|
-
|
|
38
|
-
password: ${{ secrets.
|
|
35
|
+
# Disable OIDC trusted publishing - use API token instead
|
|
36
|
+
attestations: false
|
|
37
|
+
password: ${{ secrets.PYPY_API_TOKEN }}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
I have the complete picture now. Here's the comprehensive summary:
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Claude Code Hooks Structure in Stravinsky - Complete Analysis
|
|
6
|
+
|
|
7
|
+
### 1. Hook Files Location
|
|
8
|
+
|
|
9
|
+
**Native hooks directory:** `/Users/davidandrews/PycharmProjects/stravinsky/mcp_bridge/native_hooks/`
|
|
10
|
+
- `context.py` - UserPromptSubmit hook (injects README/CLAUDE.md context)
|
|
11
|
+
- `edit_recovery.py` - PostToolUse for Edit error recovery
|
|
12
|
+
- `stravinsky_mode.py` - PreToolUse to block native tools in orchestrator mode
|
|
13
|
+
- `todo_delegation.py` - PostToolUse for TodoWrite parallel enforcement
|
|
14
|
+
- `truncator.py` - PostToolUse for response truncation
|
|
15
|
+
|
|
16
|
+
### 2. Configuration Format (`.claude/settings.json`)
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"hooks": {
|
|
21
|
+
"PreToolUse": [
|
|
22
|
+
{
|
|
23
|
+
"matcher": "Read,Search,Grep,Bash,Edit,MultiEdit",
|
|
24
|
+
"hooks": [
|
|
25
|
+
{
|
|
26
|
+
"type": "command",
|
|
27
|
+
"command": "python3 /absolute/path/to/hook.py"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"UserPromptSubmit": [
|
|
33
|
+
{
|
|
34
|
+
"matcher": "*",
|
|
35
|
+
"hooks": [
|
|
36
|
+
{
|
|
37
|
+
"type": "command",
|
|
38
|
+
"command": "python3 /absolute/path/to/context.py"
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"PostToolUse": [
|
|
44
|
+
{
|
|
45
|
+
"matcher": "*",
|
|
46
|
+
"hooks": [...]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"matcher": "TodoWrite",
|
|
50
|
+
"hooks": [...]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Key configuration properties:**
|
|
58
|
+
- `matcher`: Tool names (comma-separated) or `"*"` for all
|
|
59
|
+
- `type`: `"command"` for shell commands
|
|
60
|
+
- `command`: Full command to execute
|
|
61
|
+
|
|
62
|
+
### 3. UserPromptSubmit Hook Pattern (context.py)
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import os
|
|
66
|
+
import sys
|
|
67
|
+
import json
|
|
68
|
+
from pathlib import Path
|
|
69
|
+
|
|
70
|
+
def main():
|
|
71
|
+
# 1. Read JSON input from stdin
|
|
72
|
+
try:
|
|
73
|
+
data = json.load(sys.stdin)
|
|
74
|
+
prompt = data.get("prompt", "")
|
|
75
|
+
except Exception:
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
# 2. Get working directory from env
|
|
79
|
+
cwd = Path(os.environ.get("CLAUDE_CWD", "."))
|
|
80
|
+
|
|
81
|
+
# 3. Load context or modify prompt
|
|
82
|
+
new_prompt = f"[CONTEXT]\n{context}\n\n[USER PROMPT]\n{prompt}"
|
|
83
|
+
|
|
84
|
+
# 4. Output modified prompt to stdout
|
|
85
|
+
print(new_prompt)
|
|
86
|
+
|
|
87
|
+
if __name__ == "__main__":
|
|
88
|
+
main()
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 4. Environment Variables Available
|
|
92
|
+
- `CLAUDE_CWD` - Current working directory
|
|
93
|
+
- `CLAUDE_SESSION_ID` - Session ID
|
|
94
|
+
- `CLAUDE_TOOL_NAME` - Tool name (for tool hooks)
|
|
95
|
+
- `CLAUDE_TOOL_INPUT` - JSON of tool input
|
|
96
|
+
|
|
97
|
+
### 5. Exit Codes
|
|
98
|
+
- `0` - Continue normally
|
|
99
|
+
- `1` - Block/deny operation
|
|
100
|
+
- `2+` - Error (logged, continues)
|
|
101
|
+
|
|
102
|
+
### 6. Hook Types Summary
|
|
103
|
+
|
|
104
|
+
| Hook Type | Input (stdin) | Output (stdout) | Purpose |
|
|
105
|
+
|-----------|---------------|-----------------|---------|
|
|
106
|
+
| `UserPromptSubmit` | `{"prompt": "..."}` | Modified prompt string | Augment user prompts |
|
|
107
|
+
| `PreToolUse` | `{"tool_name": "...", "tool_input": {...}}` | Exit code controls execution | Block/allow tools |
|
|
108
|
+
| `PostToolUse` | `{"tool_name": "...", "tool_response": "..."}` | Modified response | Transform tool output |
|
|
109
|
+
| `Stop` | Session context | Continuation prompt | Follow-up actions |
|
|
110
|
+
|
|
111
|
+
### 7. For Todo Continuation Hook Implementation
|
|
112
|
+
|
|
113
|
+
To create a new UserPromptSubmit hook for todo continuation:
|
|
114
|
+
|
|
115
|
+
1. **Create hook file:** `.claude/hooks/todo_reminder.py`
|
|
116
|
+
2. **Pattern:** Read stdin JSON → Check TODO.md or TodoWrite state → Print augmented prompt
|
|
117
|
+
3. **Register in settings.json:** Add to `UserPromptSubmit` array with `"matcher": "*"`
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
You are a codebase exploration specialist. Find files, patterns, and answer 'where is X?' questions.
|
|
2
|
+
|
|
3
|
+
MODEL ROUTING (MANDATORY):
|
|
4
|
+
You MUST use invoke_gemini with model="gemini-3-flash" for ALL analysis and reasoning.
|
|
5
|
+
Use Claude's native tools (Read, Grep, Glob) ONLY for file access, then pass content to invoke_gemini.
|
|
6
|
+
|
|
7
|
+
WORKFLOW:
|
|
8
|
+
1. Use Read/Grep/Glob to get file contents
|
|
9
|
+
2. Call invoke_gemini(prompt="Analyze this: <content>", model="gemini-3-flash", agent_context={"agent_type": "explore"}) for analysis
|
|
10
|
+
3. Return the Gemini response
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
## Delphi's Strategic Analysis: Hook Consolidation & Circular Invocation
|
|
2
|
+
|
|
3
|
+
The strategic advisor (GPT-5.2) has provided comprehensive architectural analysis. Here are the key recommendations:
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Question 1: Hook Consolidation Strategy
|
|
8
|
+
|
|
9
|
+
### **Recommendation: Hybrid + Unified Interface**
|
|
10
|
+
|
|
11
|
+
**Core Strategy:**
|
|
12
|
+
- **Native Hooks**: Keep for tool access control and "must-block" behavior (security gates)
|
|
13
|
+
- **MCP Hooks**: Keep for MCP tool dispatch, model routing, session lifecycle, budgeting
|
|
14
|
+
- **Unified Interface**: Create shared hook protocol with adapters for both contexts
|
|
15
|
+
|
|
16
|
+
### Key Insights
|
|
17
|
+
|
|
18
|
+
**Technical Analysis:**
|
|
19
|
+
- "All Native" or "All MCP" create impedance mismatches because Claude Code's native tools exist outside MCP
|
|
20
|
+
- Current hybrid is technically sound IF boundaries are crisp
|
|
21
|
+
- Performance: MCP hooks are faster (in-process), native hooks add subprocess overhead
|
|
22
|
+
|
|
23
|
+
**Security Layering:**
|
|
24
|
+
- **Native**: Hard gates (deny/allow) for Claude Code tools + pre-execution redaction
|
|
25
|
+
- **MCP**: Soft/hard gates for MCP tools + model invocation policy, quotas, logging
|
|
26
|
+
- This layered approach provides defense in depth
|
|
27
|
+
|
|
28
|
+
**Industry Pattern:**
|
|
29
|
+
Matches production agentic CLI designs:
|
|
30
|
+
- Native = enforcement boundary (closest to execution)
|
|
31
|
+
- MCP = orchestration layer (rich lifecycle management)
|
|
32
|
+
|
|
33
|
+
### Actionable Migration Path
|
|
34
|
+
|
|
35
|
+
1. **Define canonical event model**: `ToolEvent`, `ModelInvokeEvent`, `SessionEvent`
|
|
36
|
+
2. **Wrap existing native hooks** with compatibility shim
|
|
37
|
+
3. **Port MCP hooks tier-by-tier** into unified form (lowest risk first)
|
|
38
|
+
4. **Single source of truth** for policies (allow/deny lists, budgets) consumed by both contexts
|
|
39
|
+
|
|
40
|
+
### Success Metrics
|
|
41
|
+
- % of hook logic shared vs duplicated
|
|
42
|
+
- Hook-induced latency (p50/p95)
|
|
43
|
+
- Incident rate for "unexpected block" / "policy mismatch" bugs
|
|
44
|
+
- Trace completeness (native + MCP share `trace_id`)
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Question 2: Circular Invocation Pattern
|
|
49
|
+
|
|
50
|
+
### **Recommendation: Keep Current (Option D) + Add Local Model Proxy**
|
|
51
|
+
|
|
52
|
+
**Core Strategy:**
|
|
53
|
+
Decouple model transport without losing Claude Code's tool ecosystem:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
Claude Code (main)
|
|
57
|
+
↓
|
|
58
|
+
Stravinsky MCP Server
|
|
59
|
+
↓
|
|
60
|
+
agent_spawn → Claude CLI process (agent)
|
|
61
|
+
↓
|
|
62
|
+
Agent invokes tools (Read/Grep/Bash) + invoke_gemini
|
|
63
|
+
↓
|
|
64
|
+
MCP invoke_gemini → LOCAL MODEL PROXY (Unix socket/HTTP)
|
|
65
|
+
↓
|
|
66
|
+
Model Proxy → Google Antigravity / OpenAI API
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Key Benefits
|
|
70
|
+
|
|
71
|
+
**Performance:**
|
|
72
|
+
- Breaks tight "agent → MCP stdio → provider" coupling
|
|
73
|
+
- Scales concurrency independent of MCP's stdio constraints
|
|
74
|
+
- Moves heavy provider I/O out of MCP event loop
|
|
75
|
+
|
|
76
|
+
**Security:**
|
|
77
|
+
- Keeps centralized auth/token management
|
|
78
|
+
- Enables per-provider circuit breakers and rate limits
|
|
79
|
+
- Maintains audit logging with unified trace IDs
|
|
80
|
+
|
|
81
|
+
**Flexibility:**
|
|
82
|
+
- Hybrid routing: model-only tasks can use proxy directly (no subprocess)
|
|
83
|
+
- Tasks needing tools still use `agent_spawn` with full Claude Code access
|
|
84
|
+
|
|
85
|
+
### Failure Mode Analysis
|
|
86
|
+
|
|
87
|
+
**Current Risks:**
|
|
88
|
+
- Head-of-line blocking on single MCP stdio transport
|
|
89
|
+
- Re-entrancy contention with many concurrent agents
|
|
90
|
+
- Cascade failures from provider rate limits
|
|
91
|
+
- Zombie agents outliving orchestrator
|
|
92
|
+
|
|
93
|
+
**Mitigations:**
|
|
94
|
+
- Circuit breaker per provider
|
|
95
|
+
- Queue + concurrency limits
|
|
96
|
+
- Agent cancellation propagation
|
|
97
|
+
- Persistent task ledger for resumable state
|
|
98
|
+
|
|
99
|
+
### Migration Path
|
|
100
|
+
|
|
101
|
+
1. **Implement model proxy** with same request/response schema as current `invoke_*`
|
|
102
|
+
2. **Switch MCP tools** to proxy-backed implementation (transparent change)
|
|
103
|
+
3. **Add trace ID propagation** from Claude → agent → proxy
|
|
104
|
+
4. **Optional: Add hybrid routing** for model-only tasks (Python worker calling proxy directly)
|
|
105
|
+
|
|
106
|
+
### Success Metrics
|
|
107
|
+
- End-to-end `invoke_*` latency (p50/p95) under N concurrent agents
|
|
108
|
+
- MCP protocol stability (fewer hangs/timeouts)
|
|
109
|
+
- Provider error rate and retry amplification
|
|
110
|
+
- Reduction in spawned Claude processes for model-only work
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Long-Term Vision (5 Years)
|
|
115
|
+
|
|
116
|
+
**Hook System:**
|
|
117
|
+
- Unified interface enables porting to alternative frontends (other IDEs)
|
|
118
|
+
- New hook types added without duplicating semantics
|
|
119
|
+
- Positions Stravinsky as "policy + orchestration layer" vs tightly coupled to one mechanism
|
|
120
|
+
|
|
121
|
+
**Model Architecture:**
|
|
122
|
+
- Local proxy enables multiple frontends beyond Claude Code
|
|
123
|
+
- Improved caching (prompt/result memoization)
|
|
124
|
+
- Single telemetry point for all model interactions
|
|
125
|
+
- Simpler adoption of new providers/models
|
|
126
|
+
|
|
127
|
+
**Ecosystem Compatibility:**
|
|
128
|
+
- MCP evolution (multi-client, richer transport) can be absorbed independently
|
|
129
|
+
- Claude Code hook API changes minimized through unified hook spec
|
|
130
|
+
- New use cases: team policy packs, per-project budgets, trace replay, offline simulation
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Next Steps
|
|
135
|
+
|
|
136
|
+
The advisor offers to create an actionable design document with:
|
|
137
|
+
- Module structure aligned with `mcp_bridge/hooks/` and `mcp_bridge/native_hooks/`
|
|
138
|
+
- Event schemas for unified hook interface
|
|
139
|
+
- Ordering rules and tier semantics
|
|
140
|
+
- Minimal incremental milestone plan
|
|
141
|
+
|
|
142
|
+
Would you like me to proceed with creating this design document?
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
You are a strategic technical advisor for architecture and hard debugging.
|
|
2
|
+
|
|
3
|
+
MODEL ROUTING (MANDATORY):
|
|
4
|
+
You MUST use invoke_openai with model="gpt-5.2" for ALL strategic advice and analysis.
|
|
5
|
+
|
|
6
|
+
WORKFLOW:
|
|
7
|
+
1. Gather context about the problem
|
|
8
|
+
2. Call invoke_openai(prompt="<problem description>", model="gpt-5.2", agent_context={"agent_type": "delphi"})
|
|
9
|
+
3. Return the GPT response
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
Perfect! Based on my exploration of the Stravinsky codebase, here's a comprehensive analysis of how agents invoke Gemini and OpenAI:
|
|
2
|
+
|
|
3
|
+
## 📋 Summary: Agent Model Invocation in Stravinsky
|
|
4
|
+
|
|
5
|
+
### 1. **Agent Spawn Implementation**
|
|
6
|
+
|
|
7
|
+
The `agent_spawn()` function in `mcp_bridge/tools/agent_manager.py` is the core mechanism:
|
|
8
|
+
|
|
9
|
+
- **Entry Point**: `agent_spawn(prompt, agent_type, description, model, thinking_budget, timeout)`
|
|
10
|
+
- **Returns**: Task ID for tracking
|
|
11
|
+
- **Execution**: Spawns Claude CLI subprocess with `claude -p <prompt> --dangerously-skip-permissions`
|
|
12
|
+
- **Storage**: Tasks stored in `.stravinsky/agents/` directory
|
|
13
|
+
|
|
14
|
+
### 2. **Model Routing Architecture**
|
|
15
|
+
|
|
16
|
+
**Key Innovation**: Specialized agents DON'T use Claude directly - they're instructed via system prompts to call `invoke_gemini` or `invoke_openai`:
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
AGENT_MODEL_ROUTING = {
|
|
20
|
+
"explore": None, # No CLI model - uses invoke_gemini
|
|
21
|
+
"dewey": None, # No CLI model - uses invoke_gemini
|
|
22
|
+
"document_writer": None, # No CLI model - uses invoke_gemini
|
|
23
|
+
"multimodal": None, # No CLI model - uses invoke_gemini
|
|
24
|
+
"frontend": None, # No CLI model - uses invoke_gemini
|
|
25
|
+
"delphi": None, # No CLI model - uses invoke_openai
|
|
26
|
+
"planner": "opus", # Direct Claude Opus via CLI
|
|
27
|
+
"_default": "sonnet", # Direct Claude Sonnet via CLI
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 3. **System Prompt Enforcement**
|
|
32
|
+
|
|
33
|
+
Each agent type gets a mandatory system prompt that enforces model routing:
|
|
34
|
+
|
|
35
|
+
**Example - Explore Agent** (lines 656-665):
|
|
36
|
+
```
|
|
37
|
+
You MUST use invoke_gemini with model="gemini-3-flash" for ALL analysis and reasoning.
|
|
38
|
+
Use Claude's native tools (Read, Grep, Glob) ONLY for file access, then pass content to invoke_gemini.
|
|
39
|
+
|
|
40
|
+
WORKFLOW:
|
|
41
|
+
1. Use Read/Grep/Glob to get file contents
|
|
42
|
+
2. Call invoke_gemini(prompt="Analyze this: <content>", model="gemini-3-flash") for analysis
|
|
43
|
+
3. Return the Gemini response
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Example - Delphi Agent** (lines 692-696):
|
|
47
|
+
```
|
|
48
|
+
You MUST use invoke_openai with model="gpt-5.2" for ALL strategic advice and analysis.
|
|
49
|
+
|
|
50
|
+
WORKFLOW:
|
|
51
|
+
1. Gather context about the problem
|
|
52
|
+
2. Call invoke_openai(prompt="<problem description>", model="gpt-5.2")
|
|
53
|
+
3. Return the GPT response
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 4. **invoke_gemini Implementation**
|
|
57
|
+
|
|
58
|
+
Located in `mcp_bridge/tools/model_invoke.py`:
|
|
59
|
+
|
|
60
|
+
- **OAuth Flow**: Uses TokenStore with automatic refresh
|
|
61
|
+
- **API**: Calls Google Antigravity API (`/v1internal:generateContent`)
|
|
62
|
+
- **Features**: Session persistence for thinking cache, endpoint fallback, retry logic
|
|
63
|
+
- **Thinking Support**: Supports `thinking_budget` parameter for extended reasoning
|
|
64
|
+
|
|
65
|
+
### 5. **invoke_openai Implementation**
|
|
66
|
+
|
|
67
|
+
Also in `model_invoke.py`:
|
|
68
|
+
|
|
69
|
+
- **OAuth Flow**: Uses OpenAI ChatGPT OAuth tokens
|
|
70
|
+
- **API**: Calls `chatgpt.com/backend-api/codex/responses` (SSE streaming)
|
|
71
|
+
- **Features**: JWT account ID extraction, Codex instructions fetching from GitHub
|
|
72
|
+
- **Streaming**: Parses SSE events for `response.output_text.delta`
|
|
73
|
+
|
|
74
|
+
### 6. **Output and Logging Structure**
|
|
75
|
+
|
|
76
|
+
For each spawned agent task:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
.stravinsky/agents/
|
|
80
|
+
├── agent_abc123.out # stdout - final response from agent
|
|
81
|
+
├── agent_abc123.log # stderr - errors/warnings
|
|
82
|
+
└── agent_abc123.system # system prompt file (if custom)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Key logging points**:
|
|
86
|
+
- Line 248: "Spawning Claude CLI agent {task_id} ({agent_type})"
|
|
87
|
+
- Line 316: "Agent {task_id} completed successfully"
|
|
88
|
+
- Line 327: "Agent {task_id} failed: {error_msg}"
|
|
89
|
+
|
|
90
|
+
### 7. **Agent Context & Metadata**
|
|
91
|
+
|
|
92
|
+
The `AgentTask` dataclass tracks:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
@dataclass
|
|
96
|
+
class AgentTask:
|
|
97
|
+
id: str # Task identifier (e.g., "agent_abc123")
|
|
98
|
+
prompt: str # Full task prompt
|
|
99
|
+
agent_type: str # explore, dewey, delphi, etc.
|
|
100
|
+
description: str # Short display description
|
|
101
|
+
status: str # pending/running/completed/failed/cancelled
|
|
102
|
+
created_at: str # ISO timestamp
|
|
103
|
+
started_at: Optional[str] # When execution began
|
|
104
|
+
completed_at: Optional[str] # When finished
|
|
105
|
+
result: Optional[str] # Final output
|
|
106
|
+
error: Optional[str] # Error message if failed
|
|
107
|
+
pid: Optional[int] # Process ID for cancellation
|
|
108
|
+
timeout: int = 300 # Max execution time
|
|
109
|
+
parent_session_id: Optional[str] # For notifications
|
|
110
|
+
progress: Optional[Dict] # Real-time progress tracking
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 8. **Key Architectural Patterns**
|
|
114
|
+
|
|
115
|
+
✅ **Separation of Concerns**: Claude CLI handles tool access, external models (Gemini/GPT) handle reasoning
|
|
116
|
+
✅ **Cost Optimization**: Cheap models (gemini-3-flash) for exploration, expensive models (gpt-5.2) for strategy
|
|
117
|
+
✅ **Non-Blocking**: All agents run in background threads, allowing parallel execution
|
|
118
|
+
✅ **Persistence**: Task state survives process restarts via JSON storage
|
|
119
|
+
✅ **Zombie Detection**: Progress tracking checks if PIDs still exist (line 541-555)
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
**Bottom Line**: Stravinsky agents are Claude CLI subprocesses that are **instructed via system prompts** to delegate their actual reasoning to Gemini or OpenAI by calling `invoke_gemini`/`invoke_openai` MCP tools. This creates a multi-model orchestration layer where Claude manages tool usage while specialized models handle domain-specific reasoning.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
You are a codebase exploration specialist. Find files, patterns, and answer 'where is X?' questions.
|
|
2
|
+
|
|
3
|
+
MODEL ROUTING (MANDATORY):
|
|
4
|
+
You MUST use invoke_gemini with model="gemini-3-flash" for ALL analysis and reasoning.
|
|
5
|
+
Use Claude's native tools (Read, Grep, Glob) ONLY for file access, then pass content to invoke_gemini.
|
|
6
|
+
|
|
7
|
+
WORKFLOW:
|
|
8
|
+
1. Use Read/Grep/Glob to get file contents
|
|
9
|
+
2. Call invoke_gemini(prompt="Analyze this: <content>", model="gemini-3-flash") for analysis
|
|
10
|
+
3. Return the Gemini response
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
The Gemini calls aren't working. Let me analyze this directly based on the code I've read:
|
|
2
|
+
|
|
3
|
+
## Analysis: Delegation and Parallel Execution in Stravinsky
|
|
4
|
+
|
|
5
|
+
Based on my examination of the codebase, here's what I found:
|
|
6
|
+
|
|
7
|
+
### 1. **`run_in_background` Parameter - Documentation Error**
|
|
8
|
+
|
|
9
|
+
**Finding**: `run_in_background=true` appears in hook instructions but is **NOT implemented** in either the native Task tool or the MCP agent_spawn tool.
|
|
10
|
+
|
|
11
|
+
**Evidence**:
|
|
12
|
+
- `.claude/hooks/todo_delegation.py` (line 69-70): Shows example using `run_in_background=true`
|
|
13
|
+
- `.claude/hooks/parallel_execution.py` (line 82, 95-97): Shows example using `run_in_background=true`
|
|
14
|
+
- `mcp_bridge/tools/agent_manager.py` (line 646): agent_spawn has `blocking` parameter (default False), NOT `run_in_background`
|
|
15
|
+
- Native Task tool: No `run_in_background` parameter exists in Claude Code's Task tool
|
|
16
|
+
|
|
17
|
+
**Conclusion**: This is a **documentation inconsistency**. The hooks are providing incorrect example syntax.
|
|
18
|
+
|
|
19
|
+
### 2. **Two Parallel Delegation Systems**
|
|
20
|
+
|
|
21
|
+
The codebase has **TWO separate delegation mechanisms**:
|
|
22
|
+
|
|
23
|
+
#### A. **Native Claude Code System** (Task tool)
|
|
24
|
+
- **Where**: Used in `.claude/agents/stravinsky.md` orchestrator
|
|
25
|
+
- **Tool**: Native `Task(subagent_type="explore", prompt="...", description="...")`
|
|
26
|
+
- **Behavior**: Blocking by default - returns results directly in function response
|
|
27
|
+
- **No async mode**: Task tool is synchronous, no background execution
|
|
28
|
+
- **Usage**: Stravinsky orchestrator delegates to explore/dewey/code-reviewer/debugger/frontend
|
|
29
|
+
|
|
30
|
+
#### B. **Stravinsky MCP System** (agent_spawn)
|
|
31
|
+
- **Where**: `mcp_bridge/tools/agent_manager.py`
|
|
32
|
+
- **Tool**: `agent_spawn(prompt="...", agent_type="explore", blocking=False)`
|
|
33
|
+
- **Behavior**:
|
|
34
|
+
- `blocking=False` (default): Returns task_id immediately, async execution
|
|
35
|
+
- `blocking=True`: Waits for completion, returns full result
|
|
36
|
+
- **Collection**: Use `agent_output(task_id, block=True)` to retrieve results
|
|
37
|
+
- **Usage**: MCP tools for when native subagents need to spawn their own background work
|
|
38
|
+
|
|
39
|
+
### 3. **Stravinsky Mode Flow**
|
|
40
|
+
|
|
41
|
+
**Activation**:
|
|
42
|
+
1. User invokes `/stravinsky` skill
|
|
43
|
+
2. `parallel_execution.py` (UserPromptSubmit hook) detects invocation
|
|
44
|
+
3. Creates `~/.stravinsky_mode` marker file
|
|
45
|
+
4. Injects parallel execution instructions into prompt
|
|
46
|
+
|
|
47
|
+
**Enforcement**:
|
|
48
|
+
1. `stravinsky_mode.py` (PreToolUse hook) checks for marker file
|
|
49
|
+
2. Blocks Read/Grep/Bash/Edit/MultiEdit with exit code 2
|
|
50
|
+
3. Forces delegation to Task tool instead
|
|
51
|
+
|
|
52
|
+
**Post-TodoWrite**:
|
|
53
|
+
1. `todo_delegation.py` (PostToolUse hook) fires after TodoWrite
|
|
54
|
+
2. Counts pending todos
|
|
55
|
+
3. If 2+ pending and stravinsky mode active: exit code 2 (HARD BLOCK)
|
|
56
|
+
4. If 2+ pending and mode inactive: exit code 1 (WARNING)
|
|
57
|
+
|
|
58
|
+
### 4. **Gaps and Inconsistencies**
|
|
59
|
+
|
|
60
|
+
**Critical Issues**:
|
|
61
|
+
|
|
62
|
+
1. **Invalid Parameter**: Hooks instruct `run_in_background=true` but this parameter doesn't exist
|
|
63
|
+
- Should be removed or corrected to match actual API
|
|
64
|
+
|
|
65
|
+
2. **Mixed Metaphors**:
|
|
66
|
+
- Hooks say "Task tool" but show agent_spawn examples
|
|
67
|
+
- `.claude/agents/stravinsky.md` uses Task tool (blocking)
|
|
68
|
+
- `mcp_bridge/hooks/parallel_enforcer.py` uses agent_spawn (async)
|
|
69
|
+
|
|
70
|
+
3. **No True Parallel Task Execution**:
|
|
71
|
+
- Native Task tool is synchronous/blocking
|
|
72
|
+
- Can call multiple Task tools in one response, but they execute sequentially
|
|
73
|
+
- True parallelism only available via agent_spawn MCP tool
|
|
74
|
+
|
|
75
|
+
4. **Marker File Brittleness**:
|
|
76
|
+
- `~/.stravinsky_mode` file persists across sessions
|
|
77
|
+
- No automatic cleanup on task completion
|
|
78
|
+
- Can leak into unrelated Claude sessions
|
|
79
|
+
- Race conditions if multiple Claude instances run
|
|
80
|
+
|
|
81
|
+
5. **Documentation Mismatch**:
|
|
82
|
+
- Stravinsky agent says "Task tool returns results directly - no manual collection needed"
|
|
83
|
+
- This is correct but contradicts the async/parallel narrative in hooks
|
|
84
|
+
- Hooks imply background execution but Task tool is synchronous
|
|
85
|
+
|
|
86
|
+
### 5. **Correct Patterns**
|
|
87
|
+
|
|
88
|
+
**For Native Subagents (stravinsky orchestrator)**:
|
|
89
|
+
```python
|
|
90
|
+
# Multiple Task calls in ONE response = sequential but batched
|
|
91
|
+
Task(subagent_type="explore", prompt="Find X", description="Find X")
|
|
92
|
+
Task(subagent_type="dewey", prompt="Research Y", description="Research Y")
|
|
93
|
+
# Results returned immediately in function responses
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**For MCP-based Async Delegation**:
|
|
97
|
+
```python
|
|
98
|
+
# True parallel execution
|
|
99
|
+
agent_spawn(prompt="Task 1", agent_type="explore", description="Task 1") # Returns task_id
|
|
100
|
+
agent_spawn(prompt="Task 2", agent_type="dewey", description="Task 2") # Returns task_id
|
|
101
|
+
# Later collect results:
|
|
102
|
+
agent_output(task_id_1, block=True)
|
|
103
|
+
agent_output(task_id_2, block=True)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 6. **Recommendations**
|
|
107
|
+
|
|
108
|
+
1. **Fix hook examples**: Remove `run_in_background=true` or replace with correct syntax
|
|
109
|
+
2. **Clarify delegation**: Document when to use Task vs agent_spawn
|
|
110
|
+
3. **Cleanup marker file**: Add automatic removal of `~/.stravinsky_mode` on session end
|
|
111
|
+
4. **Unify terminology**: Either "blocking/async" or "foreground/background", not both
|
|
112
|
+
5. **Add validation**: Hook should validate that Task tool calls are valid syntax
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
You are a codebase exploration specialist. Find files, patterns, and answer 'where is X?' questions.
|
|
2
|
+
|
|
3
|
+
MODEL ROUTING (MANDATORY):
|
|
4
|
+
You MUST use invoke_gemini with model="gemini-3-flash" for ALL analysis and reasoning.
|
|
5
|
+
Use Claude's native tools (Read, Grep, Glob) ONLY for file access, then pass content to invoke_gemini.
|
|
6
|
+
|
|
7
|
+
WORKFLOW:
|
|
8
|
+
1. Use Read/Grep/Glob to get file contents
|
|
9
|
+
2. Call invoke_gemini(prompt="Analyze this: <content>", model="gemini-3-flash", agent_context={"agent_type": "explore"}) for analysis
|
|
10
|
+
3. Return the Gemini response
|