shotgun-sh 0.3.3.dev1__py3-none-any.whl → 0.4.0.dev1__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 (58) hide show
  1. shotgun/agents/agent_manager.py +191 -23
  2. shotgun/agents/common.py +78 -77
  3. shotgun/agents/config/manager.py +42 -1
  4. shotgun/agents/config/models.py +16 -0
  5. shotgun/agents/conversation/history/file_content_deduplication.py +66 -43
  6. shotgun/agents/export.py +12 -13
  7. shotgun/agents/models.py +66 -1
  8. shotgun/agents/plan.py +12 -13
  9. shotgun/agents/research.py +13 -10
  10. shotgun/agents/router/__init__.py +47 -0
  11. shotgun/agents/router/models.py +376 -0
  12. shotgun/agents/router/router.py +185 -0
  13. shotgun/agents/router/tools/__init__.py +18 -0
  14. shotgun/agents/router/tools/delegation_tools.py +503 -0
  15. shotgun/agents/router/tools/plan_tools.py +322 -0
  16. shotgun/agents/specify.py +12 -13
  17. shotgun/agents/tasks.py +12 -13
  18. shotgun/agents/tools/file_management.py +49 -1
  19. shotgun/agents/tools/registry.py +2 -0
  20. shotgun/agents/tools/web_search/__init__.py +1 -2
  21. shotgun/agents/tools/web_search/gemini.py +1 -3
  22. shotgun/codebase/core/change_detector.py +1 -1
  23. shotgun/codebase/core/ingestor.py +1 -1
  24. shotgun/codebase/core/manager.py +1 -1
  25. shotgun/prompts/agents/export.j2 +2 -0
  26. shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +5 -10
  27. shotgun/prompts/agents/partials/router_delegation_mode.j2 +36 -0
  28. shotgun/prompts/agents/plan.j2 +24 -12
  29. shotgun/prompts/agents/research.j2 +70 -31
  30. shotgun/prompts/agents/router.j2 +440 -0
  31. shotgun/prompts/agents/specify.j2 +39 -16
  32. shotgun/prompts/agents/state/system_state.j2 +15 -6
  33. shotgun/prompts/agents/tasks.j2 +58 -34
  34. shotgun/tui/app.py +5 -6
  35. shotgun/tui/components/mode_indicator.py +120 -25
  36. shotgun/tui/components/status_bar.py +2 -2
  37. shotgun/tui/dependencies.py +64 -9
  38. shotgun/tui/protocols.py +37 -0
  39. shotgun/tui/screens/chat/chat.tcss +9 -1
  40. shotgun/tui/screens/chat/chat_screen.py +643 -11
  41. shotgun/tui/screens/chat_screen/command_providers.py +0 -87
  42. shotgun/tui/screens/chat_screen/history/agent_response.py +7 -3
  43. shotgun/tui/screens/chat_screen/history/chat_history.py +12 -0
  44. shotgun/tui/screens/chat_screen/history/formatters.py +53 -15
  45. shotgun/tui/screens/chat_screen/history/partial_response.py +11 -1
  46. shotgun/tui/screens/chat_screen/messages.py +219 -0
  47. shotgun/tui/screens/onboarding.py +30 -26
  48. shotgun/tui/utils/mode_progress.py +20 -86
  49. shotgun/tui/widgets/__init__.py +2 -1
  50. shotgun/tui/widgets/approval_widget.py +152 -0
  51. shotgun/tui/widgets/cascade_confirmation_widget.py +203 -0
  52. shotgun/tui/widgets/plan_panel.py +129 -0
  53. shotgun/tui/widgets/step_checkpoint_widget.py +180 -0
  54. {shotgun_sh-0.3.3.dev1.dist-info → shotgun_sh-0.4.0.dev1.dist-info}/METADATA +3 -3
  55. {shotgun_sh-0.3.3.dev1.dist-info → shotgun_sh-0.4.0.dev1.dist-info}/RECORD +58 -45
  56. {shotgun_sh-0.3.3.dev1.dist-info → shotgun_sh-0.4.0.dev1.dist-info}/WHEEL +0 -0
  57. {shotgun_sh-0.3.3.dev1.dist-info → shotgun_sh-0.4.0.dev1.dist-info}/entry_points.txt +0 -0
  58. {shotgun_sh-0.3.3.dev1.dist-info → shotgun_sh-0.4.0.dev1.dist-info}/licenses/LICENSE +0 -0
@@ -1,26 +1,46 @@
1
1
  You are an experienced Specification Analyst.
2
2
 
3
- Your job is to help the user create comprehensive software specifications for their projects and maintain the specification.md file.
4
-
5
- Transform requirements into detailed, actionable specifications that development teams can implement.
3
+ Your job is to help the user create software specifications and maintain the specification.md file.
6
4
 
7
5
  {% include 'agents/partials/common_agent_system_prompt.j2' %}
8
6
 
9
- ## YOUR SCOPE AND HANDOFFS
7
+ ## CRITICAL: START MINIMAL, ASK QUESTIONS
10
8
 
11
- You are the **Specification agent**. Your files are `specification.md` and `.shotgun/contracts/*` - these are the ONLY files you can write to.
9
+ **DO NOT write a comprehensive spec on the first pass.**
10
+
11
+ Instead:
12
+ 1. **Write the bare minimum** - A skeleton spec with just the essentials
13
+ 2. **Ask clarifying questions** - What's unclear? What decisions need user input?
14
+ 3. **Iterate** - Expand the spec based on user answers
12
15
 
13
- When your specification is complete, suggest the next step:
14
- "I've completed the specification. Use **Shift+Tab** to switch to the plan agent to create an implementation plan based on this specification."
16
+ **Your first response should:**
17
+ - Create a minimal spec outline (TLDR + 2-3 key sections)
18
+ - List 2-4 clarifying questions in `clarifying_questions`
19
+ - NOT try to cover everything
15
20
 
16
- If the user asks you to edit other files, redirect them helpfully:
17
- - For research.md: "I can't edit research.md - that's handled by the research agent. Use **Shift+Tab** to switch to that agent and it can edit that file for you."
18
- - For plan.md: "I can't edit plan.md - that's handled by the plan agent. Use **Shift+Tab** to switch to that agent and it can edit that file for you."
19
- - For tasks.md: "I can't edit tasks.md - that's handled by the tasks agent. Use **Shift+Tab** to switch to that agent and it can edit that file for you."
21
+ **Example first response:**
22
+ ```
23
+ I've created a minimal specification outline for the evaluation system.
24
+
25
+ Before I expand it, I have a few questions:
26
+ 1. Should the evaluation run as a CLI command or as part of CI/CD?
27
+ 2. What scoring scale do you prefer (1-5, 1-10, pass/fail)?
28
+ 3. Should results be stored persistently or just printed?
29
+ ```
20
30
 
21
- NEVER offer to do work outside your scope:
22
- - Don't offer to write research, plans, or tasks - redirect the user to the appropriate agent
23
- - Don't offer to implement code - you are not a coding agent
31
+ **DO NOT:**
32
+ - Write 8 detailed sections on the first pass
33
+ - Invent requirements the user didn't ask for
34
+ - ❌ Create comprehensive documentation without asking what's needed
35
+ - ❌ Front-load all possible features
36
+
37
+ **The user will tell you what to expand.** Start small.
38
+
39
+ {% include 'agents/partials/router_delegation_mode.j2' %}
40
+
41
+ ## YOUR SCOPE
42
+
43
+ You are the **Specification agent**. Your files are `specification.md` and `.shotgun/contracts/*` - these are the ONLY files you can write to.
24
44
 
25
45
  ## MEMORY MANAGEMENT PROTOCOL
26
46
 
@@ -50,6 +70,8 @@ specification.md is your prose documentation file. It should contain:
50
70
  - Configuration requirements described (e.g., "App needs database URL and API key in environment")
51
71
  - Testing strategies and acceptance criteria
52
72
  - References to contract files (e.g., "See contracts/user_models.py for User type definition")
73
+ - **IMPORTANT**: Only reference contract files that you have ALREADY created using `write_file()`
74
+ - Never reference contract files that don't exist - create them first, then reference them
53
75
 
54
76
  **DO NOT INCLUDE in specification.md:**
55
77
  - Code blocks, type definitions, or function signatures (those go in contracts/)
@@ -355,8 +377,9 @@ For specification tasks:
355
377
  2. **Check research**: Read `research.md` if it exists to understand technical context and findings
356
378
  3. **Analyze requirements**: Understand the functional and non-functional requirements
357
379
  4. **Define specifications**: Create detailed technical and functional specifications
358
- 5. **Write TLDR section**: Start specification.md with a TLDR section summarizing key points, major features, and any key concerns
359
- 6. **Structure documentation**: Use `write_file("specification.md", content)` to save comprehensive specifications
380
+ 5. **Create contract files FIRST**: If your spec will reference contract files, create them with `write_file("contracts/filename.ext", content)` BEFORE writing specification.md
381
+ 6. **Write TLDR section**: Start specification.md with a TLDR section summarizing key points, major features, and any key concerns
382
+ 7. **Structure documentation**: Use `write_file("specification.md", content)` to save comprehensive specifications - only reference contract files you've already created
360
383
 
361
384
  ## SPECIFICATION PRINCIPLES
362
385
 
@@ -4,6 +4,20 @@ Your training data may be old. The current date and time is: {{ current_datetime
4
4
 
5
5
  {% include 'agents/state/codebase/codebase_graphs_available.j2' %}
6
6
 
7
+ {% if execution_plan %}
8
+ ## Current Execution Plan
9
+
10
+ {{ execution_plan }}
11
+
12
+ {% if pending_approval %}
13
+ **⚠️ PLAN AWAITING USER APPROVAL**
14
+
15
+ The plan above requires user approval before execution can begin.
16
+ You MUST call `final_result` now to present this plan to the user.
17
+ Do NOT attempt to delegate to any sub-agents until the user approves.
18
+ {% endif %}
19
+
20
+ {% endif %}
7
21
  ## Available Files
8
22
 
9
23
  {% if existing_files %}
@@ -14,12 +28,7 @@ Your working files are:
14
28
  - `{{ file }}`
15
29
  {% endfor %}
16
30
  {% else %}
17
- No files currently exist in your allowed directories. You can create:
18
- - `research.md` - Research findings and analysis
19
- - `plan.md` - Project plans and roadmaps
20
- - `tasks.md` - Task lists and management
21
- - `specification.md` - Technical specifications
22
- - `exports/` folder - For exported documents
31
+ No research or planning documents exist yet. Refer to your agent-specific instructions above for which files you can create.
23
32
  {% endif %}
24
33
 
25
34
  {% if markdown_toc %}
@@ -4,21 +4,33 @@ Your job is to help create and manage actionable tasks for software projects and
4
4
 
5
5
  {% include 'agents/partials/common_agent_system_prompt.j2' %}
6
6
 
7
- ## YOUR SCOPE AND HANDOFFS
7
+ ## CRITICAL: CREATE MINIMAL TASKS, ASK QUESTIONS
8
8
 
9
- You are the **Tasks agent**. Your file is `tasks.md` - this is the ONLY file you can write to.
9
+ **DO NOT generate a comprehensive task list on the first pass.**
10
+
11
+ Instead:
12
+ 1. **Create only essential tasks** - The minimum to start work
13
+ 2. **Ask clarifying questions** - What's the priority? What can wait?
14
+ 3. **Iterate** - Add tasks based on user feedback
15
+
16
+ **Your first response should:**
17
+ - Generate 3-5 high-priority tasks max
18
+ - Ask if these are the right starting tasks
19
+ - Identify what decisions affect task breakdown
20
+
21
+ **DO NOT:**
22
+ - ❌ Generate 20 tasks when 5 would start the work
23
+ - ❌ Create tasks for every edge case
24
+ - ❌ Add "nice to have" tasks without asking
25
+ - ❌ Break simple work into many tiny tasks
10
26
 
11
- When your tasks are complete, suggest the next step:
12
- "I've created the task list in tasks.md. You can now take these tasks to a coding agent like Claude Code, Cursor, or Windsurf to implement them."
27
+ **The user will tell you what to add.** Start with essentials.
13
28
 
14
- If the user asks you to edit other files, redirect them helpfully:
15
- - For research.md: "I can't edit research.md - that's handled by the research agent. Use **Shift+Tab** to switch to that agent and it can edit that file for you."
16
- - For specification.md or contracts: "I can't edit specification.md - that's handled by the specification agent. Use **Shift+Tab** to switch to that agent and it can edit that file for you."
17
- - For plan.md: "I can't edit plan.md - that's handled by the plan agent. Use **Shift+Tab** to switch to that agent and it can edit that file for you."
29
+ {% include 'agents/partials/router_delegation_mode.j2' %}
18
30
 
19
- NEVER offer to do work outside your scope:
20
- - Don't offer to write research, specifications, or plans - redirect the user to the appropriate agent
21
- - Don't offer to implement code - you are not a coding agent
31
+ ## YOUR SCOPE
32
+
33
+ You are the **Tasks agent**. Your file is `tasks.md` - this is the ONLY file you can write to.
22
34
 
23
35
  ## MEMORY MANAGEMENT PROTOCOL
24
36
 
@@ -27,9 +39,9 @@ NEVER offer to do work outside your scope:
27
39
  - This is your persistent memory store - ALWAYS load it first
28
40
  - Compress content regularly to stay within context limits
29
41
  - Keep your file updated as you work - it's your memory across sessions
30
- - Archive completed tasks to a compressed section at the bottom
42
+ - Keep completed tasks marked with `[X]` for reference
31
43
  - Consolidate similar or duplicate tasks when compressing
32
- - Maintain structure: Active Tasks Backlog Archived (compressed)
44
+ - Maintain structure: Stages with numbered tasks (Stage 1, Stage 2, etc.)
33
45
 
34
46
  ## AI AGENT PIPELINE AWARENESS
35
47
 
@@ -56,9 +68,10 @@ Example task format:
56
68
  For task management:
57
69
  1. **Load existing tasks**: ALWAYS first use `read_file("tasks.md")` to see what tasks already exist (if the file exists)
58
70
  2. **Review context**: Read `plan.md` and `specification.md` if they exist to understand project context
59
- 3. **Analyze requirements**: Understand the current situation and user's task requirements
60
- 4. **Create structured tasks**: Use `write_file("tasks.md", content)` to save organized tasks
61
- 5. **Build incrementally**: Update and refine tasks based on new information
71
+ 3. **Verify paths exist**: Check the "Available Files" list in your System Status to see what files exist in `.shotgun/`. If a path doesn't exist, tasks must CREATE it, not modify files within it.
72
+ 4. **Analyze requirements**: Understand the current situation and user's task requirements
73
+ 5. **Create structured tasks**: Use `write_file("tasks.md", content)` to save organized tasks
74
+ 6. **Build incrementally**: Update and refine tasks based on new information
62
75
 
63
76
  ## TASK FORMAT
64
77
 
@@ -69,33 +82,36 @@ For task management:
69
82
 
70
83
  ## TASK FILE STRUCTURE
71
84
 
72
- Start tasks.md with these instructions:
85
+ **CRITICAL**: Start tasks.md with instructions for AI coding agents, then organize tasks by stages. Do NOT include "In Progress", "Done", or "Blocked" sections - the checkboxes handle completion tracking.
86
+
73
87
  ```markdown
74
88
  # Task Management
75
89
 
76
- ## Instructions
77
- - Mark tasks as complete by replacing `[ ]` with `[X]`
78
- - Tasks without an `[X]` are not finished yet
79
- ```
90
+ ## Instructions for AI Coding Agents
80
91
 
81
- Then organize tasks into logical sections:
82
- ```markdown
83
- ## Backlog
84
- - [ ] Task description with clear action
85
- - [ ] Another specific task to complete
92
+ When working on these tasks:
93
+ 1. Focus on ONE stage at a time, completing all tasks in that stage before moving to the next
94
+ 2. Mark each task complete by replacing `[ ]` with `[X]` as you finish it
95
+ 3. Do NOT modify any other content in this file unless explicitly instructed by the user
96
+ 4. Tasks without an `[X]` are not finished yet
86
97
 
87
- ## In Progress
88
- - [ ] Currently working on this task
89
- - [ ] Task being actively developed
98
+ ---
90
99
 
91
- ## Done
92
- - [X] Completed task for reference
93
- - [X] Another finished task
100
+ ### Stage 1: [Stage Name]
101
+ - [ ] Task description with clear action
102
+ - [ ] Another specific task to complete
94
103
 
95
- ## Blocked
96
- - [ ] Task waiting on dependency (blocked by: reason)
104
+ ### Stage 2: [Stage Name]
105
+ - [ ] Task in the next stage
106
+ - [ ] Another task in this stage
97
107
  ```
98
108
 
109
+ **IMPORTANT**:
110
+ - Group related tasks under numbered stages (Stage 1, Stage 2, etc.)
111
+ - Do NOT create separate "In Progress", "Done", or "Blocked" sections
112
+ - The `[ ]` / `[X]` checkboxes are the ONLY mechanism for tracking completion
113
+ - Each stage should be completable independently before moving to the next
114
+
99
115
  ## TASK CREATION PRINCIPLES
100
116
 
101
117
  - **ALWAYS use checkbox format `[ ]` for every task**
@@ -145,6 +161,14 @@ INTEGRATION WITH RESEARCH & PLAN:
145
161
  - Create validation/testing tasks for success criteria from plan
146
162
  - Break down high-level plan steps into granular, executable tasks
147
163
 
164
+ PATH VERIFICATION (CRITICAL):
165
+ - Before generating tasks that reference specific file paths in `.shotgun/`, check the "Available Files" list in your System Status
166
+ - If specification.md references files under `.shotgun/contracts/` that don't appear in "Available Files", DO NOT generate tasks for those files
167
+ - The Specification agent is responsible for creating contract files, not downstream coding agents
168
+ - Tasks should reference files that EXIST or will be created in the project codebase (src/, tests/, etc.), not in `.shotgun/`
169
+ - Only generate tasks for `.shotgun/` files if they appear in the "Available Files" list and the task is about modifying them
170
+ - Do NOT generate tasks referencing `.shotgun/contracts/*` files unless those files already exist
171
+
148
172
  IMPORTANT RULES:
149
173
  - Make at most 1 tasks file write per request
150
174
  - Always base tasks on available research and plan when relevant
shotgun/tui/app.py CHANGED
@@ -13,6 +13,7 @@ from shotgun.agents.config import (
13
13
  from shotgun.agents.models import AgentType
14
14
  from shotgun.logging_config import get_logger
15
15
  from shotgun.tui.containers import TUIContainer
16
+ from shotgun.tui.dependencies import create_default_router_deps
16
17
  from shotgun.tui.screens.splash import SplashScreen
17
18
  from shotgun.utils.file_system_utils import (
18
19
  ensure_shotgun_directory_exists,
@@ -166,13 +167,11 @@ class ShotgunApp(App[None]):
166
167
  return
167
168
 
168
169
  # Create ChatScreen with all dependencies injected from container
169
- # Get the default agent mode (RESEARCH)
170
- agent_mode = AgentType.RESEARCH
170
+ # Get the default agent mode (ROUTER)
171
+ agent_mode = AgentType.ROUTER
171
172
 
172
- # Create AgentDeps asynchronously (get_provider_model is now async)
173
- from shotgun.tui.dependencies import create_default_tui_deps
174
-
175
- agent_deps = await create_default_tui_deps()
173
+ # Create RouterDeps asynchronously (get_provider_model is now async)
174
+ agent_deps = await create_default_router_deps()
176
175
 
177
176
  # Create AgentManager with async initialization
178
177
  agent_manager = AgentManager(deps=agent_deps, initial_type=agent_mode)
@@ -1,20 +1,68 @@
1
1
  """Widget to display the current agent mode."""
2
2
 
3
+ from enum import StrEnum
4
+
3
5
  from textual.widget import Widget
4
6
 
5
7
  from shotgun.agents.models import AgentType
6
- from shotgun.tui.protocols import QAStateProvider
8
+ from shotgun.agents.router.models import RouterMode
9
+ from shotgun.tui.protocols import (
10
+ ActiveSubAgentProvider,
11
+ QAStateProvider,
12
+ RouterModeProvider,
13
+ )
7
14
  from shotgun.tui.utils.mode_progress import PlaceholderHints
8
15
 
9
16
 
17
+ class RouterModeCssClass(StrEnum):
18
+ """CSS class names for router mode styling."""
19
+
20
+ PLANNING = "mode-planning"
21
+ DRAFTING = "mode-drafting"
22
+
23
+
24
+ # Shared display name mapping for agent types
25
+ AGENT_DISPLAY_NAMES: dict[AgentType, str] = {
26
+ AgentType.RESEARCH: "Research",
27
+ AgentType.SPECIFY: "Specify",
28
+ AgentType.PLAN: "Planning",
29
+ AgentType.TASKS: "Tasks",
30
+ AgentType.EXPORT: "Export",
31
+ }
32
+
33
+ # Mode descriptions for legacy agent display
34
+ AGENT_DESCRIPTIONS: dict[AgentType, str] = {
35
+ AgentType.RESEARCH: "Research topics with web search and synthesize findings",
36
+ AgentType.PLAN: "Create comprehensive, actionable plans with milestones",
37
+ AgentType.TASKS: "Generate specific, actionable tasks from research and plans",
38
+ AgentType.SPECIFY: "Create detailed specifications and requirements documents",
39
+ AgentType.EXPORT: "Export artifacts and findings to various formats",
40
+ }
41
+
42
+
10
43
  class ModeIndicator(Widget):
11
- """Widget to display the current agent mode."""
44
+ """Widget to display the current agent mode.
45
+
46
+ For router mode, displays:
47
+ - Idle: "📋 Planning mode" or "✍️ Drafting mode"
48
+ - During execution: "📋 Planning → Research" format
49
+
50
+ For legacy agents, displays the agent name and description.
51
+ """
12
52
 
13
53
  DEFAULT_CSS = """
14
54
  ModeIndicator {
15
55
  text-wrap: wrap;
16
56
  padding-left: 1;
17
57
  }
58
+
59
+ ModeIndicator.mode-planning {
60
+ /* Planning mode styling - blue/cyan accent */
61
+ }
62
+
63
+ ModeIndicator.mode-drafting {
64
+ /* Drafting mode styling - green accent */
65
+ }
18
66
  """
19
67
 
20
68
  def __init__(self, mode: AgentType) -> None:
@@ -29,41 +77,88 @@ class ModeIndicator(Widget):
29
77
 
30
78
  def render(self) -> str:
31
79
  """Render the mode indicator."""
32
- # Check if in Q&A mode first
80
+ # Check if in Q&A mode first - takes priority
33
81
  if isinstance(self.screen, QAStateProvider) and self.screen.qa_mode:
34
82
  return (
35
83
  "[bold $text-accent]Q&A mode[/]"
36
84
  "[$foreground-muted] (Answer the clarifying questions or ESC to cancel)[/]"
37
85
  )
38
86
 
39
- mode_display = {
40
- AgentType.RESEARCH: "Research",
41
- AgentType.PLAN: "Planning",
42
- AgentType.TASKS: "Tasks",
43
- AgentType.SPECIFY: "Specify",
44
- AgentType.EXPORT: "Export",
45
- }
46
- mode_description = {
47
- AgentType.RESEARCH: (
48
- "Research topics with web search and synthesize findings"
49
- ),
50
- AgentType.PLAN: "Create comprehensive, actionable plans with milestones",
51
- AgentType.TASKS: (
52
- "Generate specific, actionable tasks from research and plans"
53
- ),
54
- AgentType.SPECIFY: (
55
- "Create detailed specifications and requirements documents"
56
- ),
57
- AgentType.EXPORT: "Export artifacts and findings to various formats",
58
- }
87
+ # Router mode display
88
+ if self.mode == AgentType.ROUTER:
89
+ return self._render_router_mode()
59
90
 
60
- mode_title = mode_display.get(self.mode, self.mode.value.title())
61
- description = mode_description.get(self.mode, "")
91
+ # Legacy agent mode display
92
+ return self._render_legacy_mode()
93
+
94
+ def _render_router_mode(self) -> str:
95
+ """Render the router mode indicator.
96
+
97
+ Shows:
98
+ - "📋 Planning mode" or "✍️ Drafting mode" when idle
99
+ - "📋 Planning → Research" format when sub-agent is executing
100
+ """
101
+ # Get router mode from screen
102
+ router_mode: str | None = None
103
+ if isinstance(self.screen, RouterModeProvider):
104
+ router_mode = self.screen.router_mode
105
+
106
+ # Get active sub-agent from screen
107
+ active_sub_agent: AgentType | None = None
108
+ if isinstance(self.screen, ActiveSubAgentProvider):
109
+ sub_agent_str = self.screen.active_sub_agent
110
+ if sub_agent_str:
111
+ # Convert string back to AgentType enum
112
+ try:
113
+ active_sub_agent = AgentType(sub_agent_str)
114
+ except ValueError:
115
+ pass
116
+
117
+ # Determine mode display using RouterMode enum
118
+ if router_mode == RouterMode.DRAFTING.value:
119
+ icon = "✍️"
120
+ mode_name = "Drafting"
121
+ description = "Auto-execute without confirmation"
122
+ css_class = RouterModeCssClass.DRAFTING
123
+ else:
124
+ # Default to planning mode
125
+ icon = "📋"
126
+ mode_name = "Planning"
127
+ description = "Review plans before execution"
128
+ css_class = RouterModeCssClass.PLANNING
129
+
130
+ # Update CSS class for styling
131
+ self.set_classes(css_class)
132
+
133
+ # Add sub-agent suffix if executing
134
+ if active_sub_agent:
135
+ # Use shared display name mapping
136
+ sub_agent_name = AGENT_DISPLAY_NAMES.get(
137
+ active_sub_agent, active_sub_agent.value.title()
138
+ )
139
+ return f"[bold $text-accent]{icon} {mode_name} → {sub_agent_name}[/]"
140
+
141
+ return (
142
+ f"[bold $text-accent]{icon} {mode_name} mode[/]"
143
+ f"[$foreground-muted] ({description})[/]"
144
+ )
145
+
146
+ def _render_legacy_mode(self) -> str:
147
+ """Render the legacy agent mode indicator.
148
+
149
+ Shows the agent name with description and content status.
150
+ """
151
+ mode_title = AGENT_DISPLAY_NAMES.get(self.mode, self.mode.value.title())
152
+ description = AGENT_DESCRIPTIONS.get(self.mode, "")
62
153
 
63
154
  # Check if mode has content
64
155
  has_content = self.progress_checker.has_mode_content(self.mode)
65
156
  status_icon = " ✓" if has_content else ""
66
157
 
158
+ # Clear any router mode CSS classes
159
+ self.remove_class(RouterModeCssClass.PLANNING)
160
+ self.remove_class(RouterModeCssClass.DRAFTING)
161
+
67
162
  return (
68
163
  f"[bold $text-accent]{mode_title}{status_icon} mode[/]"
69
164
  f"[$foreground-muted] ({description})[/]"
@@ -37,12 +37,12 @@ class StatusBar(Widget):
37
37
  return (
38
38
  "[$foreground-muted][bold $text]esc[/] to stop • "
39
39
  "[bold $text]enter[/] to send • [bold $text]ctrl+j[/] for newline • "
40
- "[bold $text]ctrl+p[/] command palette • [bold $text]shift+tab[/] cycle modes • "
40
+ "[bold $text]ctrl+p[/] command palette • [bold $text]shift+tab[/] toggle mode • "
41
41
  "/help for commands[/]"
42
42
  )
43
43
  else:
44
44
  return (
45
45
  "[$foreground-muted][bold $text]enter[/] to send • "
46
46
  "[bold $text]ctrl+j[/] for newline • [bold $text]ctrl+p[/] command palette • "
47
- "[bold $text]shift+tab[/] cycle modes • /help for commands[/]"
47
+ "[bold $text]shift+tab[/] toggle mode • /help for commands[/]"
48
48
  )
@@ -1,13 +1,44 @@
1
1
  """Dependency creation utilities for TUI components."""
2
2
 
3
+ from typing import Any
4
+
3
5
  from pydantic_ai import RunContext
4
6
 
5
- from shotgun.agents.config import get_provider_model
7
+ from shotgun.agents.config import get_config_manager, get_provider_model
8
+ from shotgun.agents.config.models import ModelConfig
6
9
  from shotgun.agents.models import AgentDeps
10
+ from shotgun.agents.router.models import RouterDeps, RouterMode
11
+ from shotgun.codebase.service import CodebaseService
7
12
  from shotgun.tui.filtered_codebase_service import FilteredCodebaseService
8
13
  from shotgun.utils import get_shotgun_home
9
14
 
10
15
 
16
+ async def _get_tui_config() -> tuple[ModelConfig, CodebaseService]:
17
+ """Get common TUI configuration components.
18
+
19
+ Returns:
20
+ Tuple of (model_config, codebase_service) for TUI deps.
21
+ """
22
+ model_config = await get_provider_model()
23
+ storage_dir = get_shotgun_home() / "codebases"
24
+ codebase_service = FilteredCodebaseService(storage_dir)
25
+ return model_config, codebase_service
26
+
27
+
28
+ def _placeholder_system_prompt_fn(ctx: RunContext[Any]) -> str:
29
+ """Placeholder system prompt that should never be called.
30
+
31
+ Agents provide their own system_prompt_fn via their create functions.
32
+ This placeholder exists only to satisfy the AgentDeps requirement.
33
+
34
+ Raises:
35
+ RuntimeError: Always, as this should never be invoked.
36
+ """
37
+ raise RuntimeError(
38
+ "This should not be called - agents provide their own system_prompt_fn"
39
+ )
40
+
41
+
11
42
  async def create_default_tui_deps() -> AgentDeps:
12
43
  """Create default AgentDeps for TUI components.
13
44
 
@@ -21,14 +52,7 @@ async def create_default_tui_deps() -> AgentDeps:
21
52
  Returns:
22
53
  Configured AgentDeps instance ready for TUI use.
23
54
  """
24
- model_config = await get_provider_model()
25
- storage_dir = get_shotgun_home() / "codebases"
26
- codebase_service = FilteredCodebaseService(storage_dir)
27
-
28
- def _placeholder_system_prompt_fn(ctx: RunContext[AgentDeps]) -> str:
29
- raise RuntimeError(
30
- "This should not be called - agents provide their own system_prompt_fn"
31
- )
55
+ model_config, codebase_service = await _get_tui_config()
32
56
 
33
57
  return AgentDeps(
34
58
  interactive_mode=True,
@@ -37,3 +61,34 @@ async def create_default_tui_deps() -> AgentDeps:
37
61
  codebase_service=codebase_service,
38
62
  system_prompt_fn=_placeholder_system_prompt_fn,
39
63
  )
64
+
65
+
66
+ async def create_default_router_deps() -> RouterDeps:
67
+ """Create default RouterDeps for TUI components with router mode.
68
+
69
+ This creates a RouterDeps configuration suitable for interactive
70
+ TUI usage with:
71
+ - Router mode loaded from config (default: PLANNING)
72
+ - Interactive mode enabled
73
+ - TUI context flag set
74
+ - Filtered codebase service (restricted to CWD)
75
+ - Placeholder system prompt (router provides its own)
76
+
77
+ Returns:
78
+ Configured RouterDeps instance ready for TUI use.
79
+ """
80
+ model_config, codebase_service = await _get_tui_config()
81
+
82
+ # Load router mode from config (default to PLANNING)
83
+ config_manager = get_config_manager()
84
+ config = await config_manager.load()
85
+ router_mode = RouterMode(config.router_mode)
86
+
87
+ return RouterDeps(
88
+ interactive_mode=True,
89
+ is_tui_context=True,
90
+ llm_model=model_config,
91
+ codebase_service=codebase_service,
92
+ system_prompt_fn=_placeholder_system_prompt_fn,
93
+ router_mode=router_mode,
94
+ )
shotgun/tui/protocols.py CHANGED
@@ -43,3 +43,40 @@ class ProcessingStateProvider(Protocol):
43
43
  True if an agent is processing, False otherwise.
44
44
  """
45
45
  ...
46
+
47
+
48
+ @runtime_checkable
49
+ class RouterModeProvider(Protocol):
50
+ """Protocol for screens that provide router mode state.
51
+
52
+ This protocol allows components to check the current router mode
53
+ (Planning or Drafting) without importing the concrete ChatScreen class.
54
+ """
55
+
56
+ @property
57
+ def router_mode(self) -> str | None:
58
+ """The current router mode.
59
+
60
+ Returns:
61
+ 'planning' or 'drafting' if in router mode, None otherwise.
62
+ """
63
+ ...
64
+
65
+
66
+ @runtime_checkable
67
+ class ActiveSubAgentProvider(Protocol):
68
+ """Protocol for screens that provide active sub-agent state.
69
+
70
+ This protocol allows components to check which sub-agent is currently
71
+ executing during router delegation without importing ChatScreen.
72
+ """
73
+
74
+ @property
75
+ def active_sub_agent(self) -> str | None:
76
+ """The currently executing sub-agent type.
77
+
78
+ Returns:
79
+ The sub-agent type string (e.g., 'research', 'specify') if
80
+ a sub-agent is executing, None if idle.
81
+ """
82
+ ...
@@ -16,11 +16,19 @@ ModeIndicator {
16
16
  height: auto;
17
17
  }
18
18
 
19
+ ModeIndicator.mode-planning {
20
+ /* Blue/cyan accent for planning mode */
21
+ }
22
+
23
+ ModeIndicator.mode-drafting {
24
+ /* Green accent for drafting mode */
25
+ }
26
+
19
27
  #footer {
20
28
  dock: bottom;
21
29
  height: auto;
22
30
  padding: 1 1 1 2;
23
- max-height: 14;
31
+ max-height: 24;
24
32
  }
25
33
 
26
34
  #window {