shotgun-sh 0.1.0.dev15__py3-none-any.whl → 0.1.0.dev16__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of shotgun-sh might be problematic. Click here for more details.

@@ -1,16 +1,30 @@
1
1
  """Agent manager for coordinating multiple AI agents with shared message history."""
2
2
 
3
+ import logging
4
+ from collections.abc import AsyncIterable
5
+ from dataclasses import dataclass, field
3
6
  from enum import Enum
4
- from typing import Any
7
+ from typing import Any, cast
5
8
 
6
9
  from pydantic_ai import (
7
10
  Agent,
8
11
  DeferredToolRequests,
9
12
  DeferredToolResults,
13
+ RunContext,
10
14
  UsageLimits,
11
15
  )
12
16
  from pydantic_ai.agent import AgentRunResult
13
- from pydantic_ai.messages import ModelMessage, ModelRequest
17
+ from pydantic_ai.messages import (
18
+ AgentStreamEvent,
19
+ FinalResultEvent,
20
+ ModelMessage,
21
+ ModelRequest,
22
+ ModelResponse,
23
+ ModelResponsePart,
24
+ PartDeltaEvent,
25
+ PartStartEvent,
26
+ ToolCallPartDelta,
27
+ )
14
28
  from textual.message import Message
15
29
  from textual.widget import Widget
16
30
 
@@ -18,8 +32,11 @@ from .history.compaction import apply_persistent_compaction
18
32
  from .models import AgentDeps, AgentRuntimeOptions, FileOperation
19
33
  from .plan import create_plan_agent
20
34
  from .research import create_research_agent
35
+ from .specify import create_specify_agent
21
36
  from .tasks import create_tasks_agent
22
37
 
38
+ logger = logging.getLogger(__name__)
39
+
23
40
 
24
41
  class AgentType(Enum):
25
42
  """Enumeration for available agent types (for Python < 3.11)."""
@@ -27,6 +44,7 @@ class AgentType(Enum):
27
44
  RESEARCH = "research"
28
45
  PLAN = "plan"
29
46
  TASKS = "tasks"
47
+ SPECIFY = "specify"
30
48
 
31
49
 
32
50
  class MessageHistoryUpdated(Message):
@@ -51,6 +69,25 @@ class MessageHistoryUpdated(Message):
51
69
  self.file_operations = file_operations or []
52
70
 
53
71
 
72
+ class PartialResponseMessage(Message):
73
+ """Event posted when a partial response is received."""
74
+
75
+ def __init__(self, message: ModelResponse | None, is_last: bool) -> None:
76
+ """Initialize the partial response message."""
77
+ super().__init__()
78
+ self.message = message
79
+ self.is_last = is_last
80
+
81
+
82
+ @dataclass(slots=True)
83
+ class _PartialStreamState:
84
+ """Tracks partial response parts while streaming a single agent run."""
85
+
86
+ parts: list[ModelResponsePart | ToolCallPartDelta] = field(default_factory=list)
87
+ latest_partial: ModelResponse | None = None
88
+ final_sent: bool = False
89
+
90
+
54
91
  class AgentManager(Widget):
55
92
  """Manages multiple agents with shared message history."""
56
93
 
@@ -65,6 +102,8 @@ class AgentManager(Widget):
65
102
  deps: Optional agent dependencies. If not provided, defaults to interactive mode.
66
103
  """
67
104
  super().__init__()
105
+ self.display = False
106
+
68
107
  # Use provided deps or create default with interactive mode
69
108
  self.deps = deps
70
109
 
@@ -80,14 +119,17 @@ class AgentManager(Widget):
80
119
  tasks=self.deps.tasks,
81
120
  )
82
121
 
83
- # Initialize all agents with the same deps
84
- self.research_agent, _ = create_research_agent(
122
+ # Initialize all agents and store their specific deps
123
+ self.research_agent, self.research_deps = create_research_agent(
124
+ agent_runtime_options=agent_runtime_options
125
+ )
126
+ self.plan_agent, self.plan_deps = create_plan_agent(
85
127
  agent_runtime_options=agent_runtime_options
86
128
  )
87
- self.plan_agent, _ = create_plan_agent(
129
+ self.tasks_agent, self.tasks_deps = create_tasks_agent(
88
130
  agent_runtime_options=agent_runtime_options
89
131
  )
90
- self.tasks_agent, _ = create_tasks_agent(
132
+ self.specify_agent, self.specify_deps = create_specify_agent(
91
133
  agent_runtime_options=agent_runtime_options
92
134
  )
93
135
 
@@ -98,6 +140,7 @@ class AgentManager(Widget):
98
140
  self.ui_message_history: list[ModelMessage] = []
99
141
  self.message_history: list[ModelMessage] = []
100
142
  self.recently_change_files: list[FileOperation] = []
143
+ self._stream_state: _PartialStreamState | None = None
101
144
 
102
145
  @property
103
146
  def current_agent(self) -> Agent[AgentDeps, str | DeferredToolRequests]:
@@ -123,9 +166,52 @@ class AgentManager(Widget):
123
166
  AgentType.RESEARCH: self.research_agent,
124
167
  AgentType.PLAN: self.plan_agent,
125
168
  AgentType.TASKS: self.tasks_agent,
169
+ AgentType.SPECIFY: self.specify_agent,
126
170
  }
127
171
  return agent_map[agent_type]
128
172
 
173
+ def _get_agent_deps(self, agent_type: AgentType) -> AgentDeps:
174
+ """Get agent-specific deps by type.
175
+
176
+ Args:
177
+ agent_type: The type of agent to retrieve deps for.
178
+
179
+ Returns:
180
+ The agent-specific dependencies.
181
+ """
182
+ deps_map = {
183
+ AgentType.RESEARCH: self.research_deps,
184
+ AgentType.PLAN: self.plan_deps,
185
+ AgentType.TASKS: self.tasks_deps,
186
+ AgentType.SPECIFY: self.specify_deps,
187
+ }
188
+ return deps_map[agent_type]
189
+
190
+ def _create_merged_deps(self, agent_type: AgentType) -> AgentDeps:
191
+ """Create merged dependencies combining shared and agent-specific deps.
192
+
193
+ This preserves the agent's system_prompt_fn while using shared runtime state.
194
+
195
+ Args:
196
+ agent_type: The type of agent to create merged deps for.
197
+
198
+ Returns:
199
+ Merged AgentDeps with agent-specific system_prompt_fn.
200
+ """
201
+ agent_deps = self._get_agent_deps(agent_type)
202
+
203
+ # Ensure shared deps is not None (should be guaranteed by __init__)
204
+ if self.deps is None:
205
+ raise ValueError("Shared deps is None - this should not happen")
206
+
207
+ # Create new deps with shared runtime state but agent's system_prompt_fn
208
+ # Use a copy of the shared deps and update the system_prompt_fn
209
+ merged_deps = self.deps.model_copy(
210
+ update={"system_prompt_fn": agent_deps.system_prompt_fn}
211
+ )
212
+
213
+ return merged_deps
214
+
129
215
  def set_agent(self, agent_type: AgentType) -> None:
130
216
  """Set the current active agent.
131
217
 
@@ -166,9 +252,9 @@ class AgentManager(Widget):
166
252
  Returns:
167
253
  The agent run result.
168
254
  """
169
- # Use manager's deps if not provided
255
+ # Use merged deps (shared state + agent-specific system prompt) if not provided
170
256
  if deps is None:
171
- deps = self.deps
257
+ deps = self._create_merged_deps(self._current_agent_type)
172
258
 
173
259
  # Ensure deps is not None
174
260
  if deps is None:
@@ -178,35 +264,168 @@ class AgentManager(Widget):
178
264
  self.ui_message_history.append(ModelRequest.user_text_prompt(prompt))
179
265
  self._post_messages_updated()
180
266
 
181
- # Run the agent with the shared message history
182
- result: AgentRunResult[
183
- str | DeferredToolRequests
184
- ] = await self.current_agent.run(
185
- prompt,
186
- deps=deps,
187
- usage_limits=usage_limits,
188
- message_history=self.message_history,
189
- deferred_tool_results=deferred_tool_results,
190
- **kwargs,
267
+ # Ensure system prompt is added to message history before running agent
268
+ from pydantic_ai.messages import SystemPromptPart
269
+
270
+ from shotgun.agents.common import add_system_prompt_message
271
+
272
+ # Start with persistent message history
273
+ message_history = self.message_history
274
+
275
+ # Check if the message history already has a system prompt
276
+ has_system_prompt = any(
277
+ hasattr(msg, "parts")
278
+ and any(isinstance(part, SystemPromptPart) for part in msg.parts)
279
+ for msg in message_history
280
+ )
281
+
282
+ # Always ensure we have a system prompt for the agent
283
+ # (compaction may remove it from persistent history, but agent needs it)
284
+ if not has_system_prompt:
285
+ message_history = await add_system_prompt_message(deps, message_history)
286
+
287
+ # Run the agent with streaming support (from origin/main)
288
+ self._stream_state = _PartialStreamState()
289
+
290
+ model_name = ""
291
+ if hasattr(deps, "llm_model") and deps.llm_model is not None:
292
+ model_name = deps.llm_model.name
293
+ is_gpt5 = ( # streaming is likely not supported for gpt5. It varies between keys.
294
+ "gpt-5" in model_name.lower()
191
295
  )
192
296
 
193
- # Update the shared message history with all messages from this run
297
+ try:
298
+ result: AgentRunResult[
299
+ str | DeferredToolRequests
300
+ ] = await self.current_agent.run(
301
+ prompt,
302
+ deps=deps,
303
+ usage_limits=usage_limits,
304
+ message_history=message_history,
305
+ deferred_tool_results=deferred_tool_results,
306
+ event_stream_handler=self._handle_event_stream if not is_gpt5 else None,
307
+ **kwargs,
308
+ )
309
+ finally:
310
+ # If the stream ended unexpectedly without a final result, clear accumulated state.
311
+ if self._stream_state is not None and not self._stream_state.final_sent:
312
+ partial_message = self._build_partial_response(self._stream_state.parts)
313
+ if partial_message is not None:
314
+ self._post_partial_message(partial_message, True)
315
+ self._stream_state = None
316
+
194
317
  self.ui_message_history = self.ui_message_history + [
195
318
  mes for mes in result.new_messages() if not isinstance(mes, ModelRequest)
196
319
  ]
197
320
 
198
321
  # Apply compaction to persistent message history to prevent cascading growth
199
- self.message_history = await apply_persistent_compaction(
200
- result.all_messages(), deps
201
- )
322
+ all_messages = result.all_messages()
323
+ self.message_history = await apply_persistent_compaction(all_messages, deps)
202
324
 
203
325
  # Log file operations summary if any files were modified
204
- self.recently_change_files = deps.file_tracker.operations.copy()
326
+ file_operations = deps.file_tracker.operations.copy()
327
+ self.recently_change_files = file_operations
205
328
 
206
- self._post_messages_updated(self.recently_change_files)
329
+ self._post_messages_updated(file_operations)
207
330
 
208
331
  return result
209
332
 
333
+ async def _handle_event_stream(
334
+ self,
335
+ _ctx: RunContext[AgentDeps],
336
+ stream: AsyncIterable[AgentStreamEvent],
337
+ ) -> None:
338
+ """Process streamed events and forward partial updates to the UI."""
339
+
340
+ state = self._stream_state
341
+ if state is None:
342
+ state = self._stream_state = _PartialStreamState()
343
+
344
+ partial_parts = state.parts
345
+
346
+ async for event in stream:
347
+ try:
348
+ if isinstance(event, PartStartEvent):
349
+ index = event.index
350
+ if index < len(partial_parts):
351
+ partial_parts[index] = event.part
352
+ elif index == len(partial_parts):
353
+ partial_parts.append(event.part)
354
+ else:
355
+ logger.warning(
356
+ "Received PartStartEvent with out-of-bounds index",
357
+ extra={"index": index, "current_len": len(partial_parts)},
358
+ )
359
+ partial_parts.append(event.part)
360
+
361
+ partial_message = self._build_partial_response(partial_parts)
362
+ if partial_message is not None:
363
+ state.latest_partial = partial_message
364
+ self._post_partial_message(partial_message, False)
365
+
366
+ elif isinstance(event, PartDeltaEvent):
367
+ index = event.index
368
+ if index >= len(partial_parts):
369
+ logger.warning(
370
+ "Received PartDeltaEvent before corresponding start event",
371
+ extra={"index": index, "current_len": len(partial_parts)},
372
+ )
373
+ continue
374
+
375
+ try:
376
+ updated_part = event.delta.apply(
377
+ cast(ModelResponsePart, partial_parts[index])
378
+ )
379
+ except Exception: # pragma: no cover - defensive logging
380
+ logger.exception(
381
+ "Failed to apply part delta", extra={"event": event}
382
+ )
383
+ continue
384
+
385
+ partial_parts[index] = updated_part
386
+
387
+ partial_message = self._build_partial_response(partial_parts)
388
+ if partial_message is not None:
389
+ state.latest_partial = partial_message
390
+ self._post_partial_message(partial_message, False)
391
+
392
+ elif isinstance(event, FinalResultEvent):
393
+ final_message = (
394
+ state.latest_partial
395
+ or self._build_partial_response(partial_parts)
396
+ )
397
+ self._post_partial_message(final_message, True)
398
+ state.latest_partial = None
399
+ state.final_sent = True
400
+ partial_parts.clear()
401
+ self._stream_state = None
402
+ break
403
+
404
+ # Ignore other AgentStreamEvent variants (e.g. tool call notifications) for partial UI updates.
405
+
406
+ except Exception: # pragma: no cover - defensive logging
407
+ logger.exception(
408
+ "Error while handling agent stream event", extra={"event": event}
409
+ )
410
+
411
+ def _build_partial_response(
412
+ self, parts: list[ModelResponsePart | ToolCallPartDelta]
413
+ ) -> ModelResponse | None:
414
+ """Create a `ModelResponse` from the currently streamed parts."""
415
+
416
+ completed_parts = [
417
+ part for part in parts if not isinstance(part, ToolCallPartDelta)
418
+ ]
419
+ if not completed_parts:
420
+ return None
421
+ return ModelResponse(parts=list(completed_parts))
422
+
423
+ def _post_partial_message(
424
+ self, message: ModelResponse | None, is_last: bool
425
+ ) -> None:
426
+ """Post a partial message to the UI."""
427
+ self.post_message(PartialResponseMessage(message, is_last))
428
+
210
429
  def _post_messages_updated(
211
430
  self, file_operations: list[FileOperation] | None = None
212
431
  ) -> None:
@@ -347,14 +347,13 @@ async def read_artifact_section(
347
347
 
348
348
  section = service.get_section(artifact_id, mode, section_number)
349
349
 
350
- # Return formatted content with title
351
- formatted_content = f"# {section.title}\n\n{section.content}"
350
+ # Return section content (already contains title header from file storage)
352
351
  logger.debug(
353
352
  "📄 Read section %d with %d characters",
354
353
  section_number,
355
354
  len(section.content),
356
355
  )
357
- return formatted_content
356
+ return section.content
358
357
 
359
358
  except Exception as e:
360
359
  error_msg = (
@@ -15,16 +15,16 @@ sections:
15
15
  instructions: |
16
16
  # What is a good research.overview section?
17
17
 
18
- Clarifies the technical need
19
- Establishes scope and constraints
20
- Aligns the team on evaluation criteria
21
- Sets realistic timeline for decision
18
+ * Clarifies the technical need
19
+ * Establishes scope and constraints
20
+ * Aligns the team on evaluation criteria
21
+ * Sets realistic timeline for decision
22
22
 
23
23
  # Questions to ask yourself:
24
- What problem are we trying to solve with this SDK/library?
25
- What happens if we make the wrong choice?
26
- What are our non-negotiable requirements?
27
- Is there anything specific to our tech stack that constrains choices?
24
+ * What problem are we trying to solve with this SDK/library?
25
+ * What happens if we make the wrong choice?
26
+ * What are our non-negotiable requirements?
27
+ * Is there anything specific to our tech stack that constrains choices?
28
28
 
29
29
  # Includes:
30
30
  Research Objective: [One clear sentence stating what SDK/library type we need and why]
@@ -50,36 +50,36 @@ sections:
50
50
 
51
51
  Define technical and business requirements that will guide the evaluation.
52
52
 
53
- Separates must-haves from nice-to-haves
54
- Includes both functional and non-functional requirements
55
- Considers team capabilities and constraints
53
+ * Separates must-haves from nice-to-haves
54
+ * Includes both functional and non-functional requirements
55
+ * Considers team capabilities and constraints
56
56
 
57
57
  # Questions to ask yourself:
58
- What features are absolutely essential vs. "would be nice"?
59
- What are our technical constraints (language, platform, licenses)?
60
- What are our resource constraints (budget, team expertise)?
58
+ * What features are absolutely essential vs. "would be nice"?
59
+ * What are our technical constraints (language, platform, licenses)?
60
+ * What are our resource constraints (budget, team expertise)?
61
61
 
62
62
  # Includes:
63
63
  ## Functional Requirements
64
64
  Essential Features:
65
- - [Core functionality needed]
66
- - [Integration requirements]
67
- - [Performance benchmarks]
65
+ * [Core functionality needed]
66
+ * [Integration requirements]
67
+ * [Performance benchmarks]
68
68
 
69
69
  Nice-to-Have Features:
70
- - [Additional capabilities]
71
- - [Future-proofing considerations]
70
+ * [Additional capabilities]
71
+ * [Future-proofing considerations]
72
72
 
73
73
  ## Non-Functional Requirements
74
74
  Technical Constraints:
75
- - Language/Platform: [e.g., Must support TypeScript]
76
- - Architecture: [e.g., Must work in serverless environment]
77
- - Performance: [e.g., < 50ms latency for operations]
75
+ * Language/Platform: [e.g., Must support TypeScript]
76
+ * Architecture: [e.g., Must work in serverless environment]
77
+ * Performance: [e.g., < 50ms latency for operations]
78
78
 
79
79
  Business Constraints:
80
- - License: [e.g., MIT or Apache 2.0 preferred]
81
- - Cost: [e.g., Free for commercial use or < $X/month]
82
- - Support: [e.g., Active community or paid support available]
80
+ * License: [e.g., MIT or Apache 2.0 preferred]
81
+ * Cost: [e.g., Free for commercial use or < $X/month]
82
+ * Support: [e.g., Active community or paid support available]
83
83
  depends_on:
84
84
  - "research.overview"
85
85
 
@@ -89,21 +89,21 @@ sections:
89
89
 
90
90
  Document the process and results of finding available options.
91
91
 
92
- Shows comprehensive search methodology
93
- Lists all viable candidates with brief descriptions
94
- Explains why certain options were excluded early
92
+ * Shows comprehensive search methodology
93
+ * Lists all viable candidates with brief descriptions
94
+ * Explains why certain options were excluded early
95
95
 
96
96
  # Questions to ask yourself:
97
- Where did we search? (GitHub, npm, package managers, forums)
98
- What keywords and criteria did we use?
99
- Are there any industry-standard or popular choices we're missing?
97
+ * Where did we search? (GitHub, npm, package managers, forums)
98
+ * What keywords and criteria did we use?
99
+ * Are there any industry-standard or popular choices we're missing?
100
100
 
101
101
  # Includes:
102
102
  ## Search Methodology
103
103
  Sources Consulted:
104
- - [Package registries searched]
105
- - [Community recommendations]
106
- - [Industry reports/comparisons referenced]
104
+ * [Package registries searched]
105
+ * [Community recommendations]
106
+ * [Industry reports/comparisons referenced]
107
107
 
108
108
  ## Initial Candidates
109
109
 
@@ -115,8 +115,8 @@ sections:
115
115
 
116
116
  ## Early Eliminations
117
117
  Excluded Options:
118
- - **[Library Name]**: [Reason for exclusion]
119
- - **[Library Name]**: [Critical missing feature or constraint violation]
118
+ * **[Library Name]**: [Reason for exclusion]
119
+ * **[Library Name]**: [Critical missing feature or constraint violation]
120
120
 
121
121
  depends_on:
122
122
  - "research.requirements"
@@ -127,23 +127,23 @@ sections:
127
127
 
128
128
  Deep technical analysis of the top candidates.
129
129
 
130
- Provides objective, measurable comparisons
131
- Includes code examples and API comparisons
132
- Evaluates developer experience and learning curve
130
+ * Provides objective, measurable comparisons
131
+ * Includes code examples and API comparisons
132
+ * Evaluates developer experience and learning curve
133
133
 
134
134
  # Questions to ask yourself:
135
- How easy is it to implement our use case in each option?
136
- What are the performance characteristics under our expected load?
137
- How well does each option integrate with our existing stack?
135
+ * How easy is it to implement our use case in each option?
136
+ * What are the performance characteristics under our expected load?
137
+ * How well does each option integrate with our existing stack?
138
138
 
139
139
  # Includes:
140
140
  ## Evaluated Options (Top 3-5 candidates)
141
141
 
142
142
  ### **Option A: [Name]**
143
143
  Technical Architecture:
144
- - Core design philosophy
145
- - Key abstractions and patterns
146
- - Dependencies and size
144
+ * Core design philosophy
145
+ * Key abstractions and patterns
146
+ * Dependencies and size
147
147
 
148
148
  Code Example:
149
149
  ```[language]
@@ -151,15 +151,15 @@ sections:
151
151
  ```
152
152
 
153
153
  Performance Metrics:
154
- - Benchmark results
155
- - Memory footprint
156
- - Bundle size impact
154
+ * Benchmark results
155
+ * Memory footprint
156
+ * Bundle size impact
157
157
 
158
158
  Developer Experience:
159
- - Setup complexity: [Rating]
160
- - Documentation quality: [Rating]
161
- - API design: [Rating]
162
- - Debugging tools: [Rating]
159
+ * Setup complexity: [Rating]
160
+ * Documentation quality: [Rating]
161
+ * API design: [Rating]
162
+ * Debugging tools: [Rating]
163
163
 
164
164
  [Repeat for each candidate]
165
165
 
@@ -172,21 +172,21 @@ sections:
172
172
 
173
173
  Side-by-side comparison of all evaluation criteria.
174
174
 
175
- Enables quick visual comparison
176
- Uses consistent scoring methodology
177
- Weights criteria by importance
175
+ * Enables quick visual comparison
176
+ * Uses consistent scoring methodology
177
+ * Weights criteria by importance
178
178
 
179
179
  # Questions to ask yourself:
180
- Are we comparing apples to apples?
181
- Is our scoring methodology clear and reproducible?
182
- Have we weighted criteria appropriately for our use case?
180
+ * Are we comparing apples to apples?
181
+ * Is our scoring methodology clear and reproducible?
182
+ * Have we weighted criteria appropriately for our use case?
183
183
 
184
184
  # Includes:
185
185
  ## Scoring Methodology
186
- - 🟢 Excellent (3 points): Exceeds requirements
187
- - 🟡 Good (2 points): Meets requirements
188
- - 🔴 Poor (1 point): Below requirements
189
- - ❌ Missing (0 points): Doesn't support
186
+ * 🟢 Excellent (3 points): Exceeds requirements
187
+ * 🟡 Good (2 points): Meets requirements
188
+ * 🔴 Poor (1 point): Below requirements
189
+ * ❌ Missing (0 points): Doesn't support
190
190
 
191
191
  ## Feature Comparison
192
192
 
@@ -215,14 +215,14 @@ sections:
215
215
 
216
216
  Clear recommendation with thorough justification.
217
217
 
218
- States the recommendation unambiguously
219
- Provides clear rationale tied to requirements
220
- Addresses concerns and mitigation strategies
218
+ * States the recommendation unambiguously
219
+ * Provides clear rationale tied to requirements
220
+ * Addresses concerns and mitigation strategies
221
221
 
222
222
  # Questions to ask yourself:
223
- Will stakeholders understand why we chose this option?
224
- Have we addressed all major concerns about our choice?
225
- Is our decision reversible if needed?
223
+ * Will stakeholders understand why we chose this option?
224
+ * Have we addressed all major concerns about our choice?
225
+ * Is our decision reversible if needed?
226
226
 
227
227
  # Includes:
228
228
  ## Recommendation
@@ -236,12 +236,12 @@ sections:
236
236
  ## Detailed Justification
237
237
 
238
238
  ### Why [Selected] Over [Alternative A]
239
- - [Specific technical advantage]
240
- - [Business consideration]
241
- - [Risk mitigation]
239
+ * [Specific technical advantage]
240
+ * [Business consideration]
241
+ * [Risk mitigation]
242
242
 
243
243
  ### Why [Selected] Over [Alternative B]
244
- - [Comparison points]
244
+ * [Comparison points]
245
245
 
246
246
  ## Risk Mitigation Plan
247
247
 
@@ -250,7 +250,7 @@ sections:
250
250
  | [Specific risk] | [How we'll address it] | [Team/Person] |
251
251
 
252
252
  ## Dissenting Opinions
253
- - [Any team concerns and how they were addressed]
253
+ * [Any team concerns and how they were addressed]
254
254
 
255
255
  depends_on:
256
256
  - "research.comparison_matrix"
@@ -1,6 +1,13 @@
1
+
2
+
3
+
4
+ !!! CRITICALLY IMPORTANT !!!
5
+
1
6
  {% if interactive_mode -%}
2
7
  IMPORTANT: USER INTERACTION IS ENABLED (interactive mode).
3
8
 
9
+ - BEFORE GETTING TO WORK, ALWAYS THINK WHAT YOU'RE GOING TO DO AND ask_user() TO ACCEPT WHAT YOU'RE GOING TO DO.
10
+ - ALWAYS USE ask_user TO REVIEW AND ACCEPT THE ARTIFACT SECTION YOU'VE WORKED ON BEFORE PROCEEDING TO THE NEXT SECTION.
4
11
  - Don't assume - ask for confirmation of your understanding
5
12
  - When in doubt about any aspect of the goal, ASK before proceeding
6
13
 
@@ -13,4 +20,6 @@ IMPORTANT: USER INTERACTION IS DISABLED (non-interactive mode).
13
20
  - Make reasonable assumptions based on industry best practices
14
21
  - Use sensible defaults when specific details are not provided
15
22
  - When in doubt, make reasonable assumptions and proceed with best practices
16
- {% endif %}
23
+ {% endif %}
24
+
25
+