shotgun-sh 0.2.6.dev1__py3-none-any.whl → 0.2.17__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 (127) hide show
  1. shotgun/agents/agent_manager.py +694 -73
  2. shotgun/agents/common.py +69 -70
  3. shotgun/agents/config/constants.py +0 -6
  4. shotgun/agents/config/manager.py +70 -35
  5. shotgun/agents/config/models.py +41 -1
  6. shotgun/agents/config/provider.py +33 -5
  7. shotgun/agents/context_analyzer/__init__.py +28 -0
  8. shotgun/agents/context_analyzer/analyzer.py +471 -0
  9. shotgun/agents/context_analyzer/constants.py +9 -0
  10. shotgun/agents/context_analyzer/formatter.py +115 -0
  11. shotgun/agents/context_analyzer/models.py +212 -0
  12. shotgun/agents/conversation_history.py +125 -2
  13. shotgun/agents/conversation_manager.py +57 -19
  14. shotgun/agents/export.py +6 -7
  15. shotgun/agents/history/compaction.py +9 -4
  16. shotgun/agents/history/context_extraction.py +93 -6
  17. shotgun/agents/history/history_processors.py +113 -5
  18. shotgun/agents/history/token_counting/anthropic.py +39 -3
  19. shotgun/agents/history/token_counting/base.py +14 -3
  20. shotgun/agents/history/token_counting/openai.py +11 -1
  21. shotgun/agents/history/token_counting/sentencepiece_counter.py +8 -0
  22. shotgun/agents/history/token_counting/tokenizer_cache.py +3 -1
  23. shotgun/agents/history/token_counting/utils.py +0 -3
  24. shotgun/agents/models.py +50 -2
  25. shotgun/agents/plan.py +6 -7
  26. shotgun/agents/research.py +7 -8
  27. shotgun/agents/specify.py +6 -7
  28. shotgun/agents/tasks.py +6 -7
  29. shotgun/agents/tools/__init__.py +0 -2
  30. shotgun/agents/tools/codebase/codebase_shell.py +6 -0
  31. shotgun/agents/tools/codebase/directory_lister.py +6 -0
  32. shotgun/agents/tools/codebase/file_read.py +11 -2
  33. shotgun/agents/tools/codebase/query_graph.py +6 -0
  34. shotgun/agents/tools/codebase/retrieve_code.py +6 -0
  35. shotgun/agents/tools/file_management.py +82 -16
  36. shotgun/agents/tools/registry.py +217 -0
  37. shotgun/agents/tools/web_search/__init__.py +8 -8
  38. shotgun/agents/tools/web_search/anthropic.py +8 -2
  39. shotgun/agents/tools/web_search/gemini.py +7 -1
  40. shotgun/agents/tools/web_search/openai.py +7 -1
  41. shotgun/agents/tools/web_search/utils.py +2 -2
  42. shotgun/agents/usage_manager.py +16 -11
  43. shotgun/api_endpoints.py +7 -3
  44. shotgun/build_constants.py +3 -3
  45. shotgun/cli/clear.py +53 -0
  46. shotgun/cli/compact.py +186 -0
  47. shotgun/cli/config.py +8 -5
  48. shotgun/cli/context.py +111 -0
  49. shotgun/cli/export.py +1 -1
  50. shotgun/cli/feedback.py +4 -2
  51. shotgun/cli/models.py +1 -0
  52. shotgun/cli/plan.py +1 -1
  53. shotgun/cli/research.py +1 -1
  54. shotgun/cli/specify.py +1 -1
  55. shotgun/cli/tasks.py +1 -1
  56. shotgun/cli/update.py +16 -2
  57. shotgun/codebase/core/change_detector.py +5 -3
  58. shotgun/codebase/core/code_retrieval.py +4 -2
  59. shotgun/codebase/core/ingestor.py +10 -8
  60. shotgun/codebase/core/manager.py +13 -4
  61. shotgun/codebase/core/nl_query.py +1 -1
  62. shotgun/exceptions.py +32 -0
  63. shotgun/logging_config.py +18 -27
  64. shotgun/main.py +73 -11
  65. shotgun/posthog_telemetry.py +37 -28
  66. shotgun/prompts/agents/export.j2 +18 -1
  67. shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +5 -1
  68. shotgun/prompts/agents/partials/interactive_mode.j2 +24 -7
  69. shotgun/prompts/agents/plan.j2 +1 -1
  70. shotgun/prompts/agents/research.j2 +1 -1
  71. shotgun/prompts/agents/specify.j2 +270 -3
  72. shotgun/prompts/agents/tasks.j2 +1 -1
  73. shotgun/sentry_telemetry.py +163 -16
  74. shotgun/settings.py +238 -0
  75. shotgun/telemetry.py +18 -33
  76. shotgun/tui/app.py +243 -43
  77. shotgun/tui/commands/__init__.py +1 -1
  78. shotgun/tui/components/context_indicator.py +179 -0
  79. shotgun/tui/components/mode_indicator.py +70 -0
  80. shotgun/tui/components/status_bar.py +48 -0
  81. shotgun/tui/containers.py +91 -0
  82. shotgun/tui/dependencies.py +39 -0
  83. shotgun/tui/protocols.py +45 -0
  84. shotgun/tui/screens/chat/__init__.py +5 -0
  85. shotgun/tui/screens/chat/chat.tcss +54 -0
  86. shotgun/tui/screens/chat/chat_screen.py +1254 -0
  87. shotgun/tui/screens/chat/codebase_index_prompt_screen.py +64 -0
  88. shotgun/tui/screens/chat/codebase_index_selection.py +12 -0
  89. shotgun/tui/screens/chat/help_text.py +40 -0
  90. shotgun/tui/screens/chat/prompt_history.py +48 -0
  91. shotgun/tui/screens/chat.tcss +11 -0
  92. shotgun/tui/screens/chat_screen/command_providers.py +78 -2
  93. shotgun/tui/screens/chat_screen/history/__init__.py +22 -0
  94. shotgun/tui/screens/chat_screen/history/agent_response.py +66 -0
  95. shotgun/tui/screens/chat_screen/history/chat_history.py +115 -0
  96. shotgun/tui/screens/chat_screen/history/formatters.py +115 -0
  97. shotgun/tui/screens/chat_screen/history/partial_response.py +43 -0
  98. shotgun/tui/screens/chat_screen/history/user_question.py +42 -0
  99. shotgun/tui/screens/confirmation_dialog.py +151 -0
  100. shotgun/tui/screens/feedback.py +4 -4
  101. shotgun/tui/screens/github_issue.py +102 -0
  102. shotgun/tui/screens/model_picker.py +49 -24
  103. shotgun/tui/screens/onboarding.py +431 -0
  104. shotgun/tui/screens/pipx_migration.py +153 -0
  105. shotgun/tui/screens/provider_config.py +50 -27
  106. shotgun/tui/screens/shotgun_auth.py +2 -2
  107. shotgun/tui/screens/welcome.py +23 -12
  108. shotgun/tui/services/__init__.py +5 -0
  109. shotgun/tui/services/conversation_service.py +184 -0
  110. shotgun/tui/state/__init__.py +7 -0
  111. shotgun/tui/state/processing_state.py +185 -0
  112. shotgun/tui/utils/mode_progress.py +14 -7
  113. shotgun/tui/widgets/__init__.py +5 -0
  114. shotgun/tui/widgets/widget_coordinator.py +263 -0
  115. shotgun/utils/file_system_utils.py +22 -2
  116. shotgun/utils/marketing.py +110 -0
  117. shotgun/utils/update_checker.py +69 -14
  118. shotgun_sh-0.2.17.dist-info/METADATA +465 -0
  119. shotgun_sh-0.2.17.dist-info/RECORD +194 -0
  120. {shotgun_sh-0.2.6.dev1.dist-info → shotgun_sh-0.2.17.dist-info}/entry_points.txt +1 -0
  121. {shotgun_sh-0.2.6.dev1.dist-info → shotgun_sh-0.2.17.dist-info}/licenses/LICENSE +1 -1
  122. shotgun/agents/tools/user_interaction.py +0 -37
  123. shotgun/tui/screens/chat.py +0 -804
  124. shotgun/tui/screens/chat_screen/history.py +0 -401
  125. shotgun_sh-0.2.6.dev1.dist-info/METADATA +0 -467
  126. shotgun_sh-0.2.6.dev1.dist-info/RECORD +0 -156
  127. {shotgun_sh-0.2.6.dev1.dist-info → shotgun_sh-0.2.17.dist-info}/WHEEL +0 -0
shotgun/logging_config.py CHANGED
@@ -2,12 +2,16 @@
2
2
 
3
3
  import logging
4
4
  import logging.handlers
5
- import os
6
5
  import sys
6
+ from datetime import datetime, timezone
7
7
  from pathlib import Path
8
8
 
9
+ from shotgun.settings import settings
9
10
  from shotgun.utils.env_utils import is_truthy
10
11
 
12
+ # Generate a single timestamp for this run to be used across all loggers
13
+ _RUN_TIMESTAMP = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
14
+
11
15
 
12
16
  def get_log_directory() -> Path:
13
17
  """Get the log directory path, creating it if necessary.
@@ -66,21 +70,16 @@ def setup_logger(
66
70
  logger = logging.getLogger(name)
67
71
 
68
72
  # Check if we already have a file handler
69
- has_file_handler = any(
70
- isinstance(h, logging.handlers.TimedRotatingFileHandler)
71
- for h in logger.handlers
72
- )
73
+ has_file_handler = any(isinstance(h, logging.FileHandler) for h in logger.handlers)
73
74
 
74
75
  # If we already have a file handler, just return the logger
75
76
  if has_file_handler:
76
77
  return logger
77
78
 
78
- # Get log level from environment variable, default to INFO
79
- env_level = os.getenv("SHOTGUN_LOG_LEVEL", "INFO").upper()
80
- if env_level not in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]:
81
- env_level = "INFO"
79
+ # Get log level from settings (already validated and uppercased)
80
+ log_level = settings.logging.log_level
82
81
 
83
- logger.setLevel(getattr(logging, env_level))
82
+ logger.setLevel(getattr(logging, log_level))
84
83
 
85
84
  # Default format string
86
85
  if format_string is None:
@@ -102,13 +101,13 @@ def setup_logger(
102
101
  # Check if console logging is enabled (default: off)
103
102
  # Force console logging OFF if Logfire is enabled in dev build
104
103
  console_logging_enabled = (
105
- is_truthy(os.getenv("LOGGING_TO_CONSOLE", "false")) and not is_logfire_dev_build
104
+ settings.logging.logging_to_console and not is_logfire_dev_build
106
105
  )
107
106
 
108
107
  if console_logging_enabled:
109
108
  # Create console handler
110
109
  console_handler = logging.StreamHandler(sys.stdout)
111
- console_handler.setLevel(getattr(logging, env_level))
110
+ console_handler.setLevel(getattr(logging, log_level))
112
111
 
113
112
  # Use colored formatter for console
114
113
  console_formatter = ColoredFormatter(format_string, datefmt="%H:%M:%S")
@@ -118,26 +117,21 @@ def setup_logger(
118
117
  logger.addHandler(console_handler)
119
118
 
120
119
  # Check if file logging is enabled (default: on)
121
- file_logging_enabled = is_truthy(os.getenv("LOGGING_TO_FILE", "true"))
120
+ file_logging_enabled = settings.logging.logging_to_file
122
121
 
123
122
  if file_logging_enabled:
124
123
  try:
125
- # Create file handler with rotation
124
+ # Create file handler with ISO8601 timestamp for each run
126
125
  log_dir = get_log_directory()
127
- log_file = log_dir / "shotgun.log"
126
+ log_file = log_dir / f"shotgun-{_RUN_TIMESTAMP}.log"
128
127
 
129
- # Use TimedRotatingFileHandler - rotates daily and keeps 7 days of logs
130
- file_handler = logging.handlers.TimedRotatingFileHandler(
128
+ # Use regular FileHandler - each run gets its own isolated log file
129
+ file_handler = logging.FileHandler(
131
130
  filename=log_file,
132
- when="midnight", # Rotate at midnight
133
- interval=1, # Every 1 day
134
- backupCount=7, # Keep 7 days of logs
135
131
  encoding="utf-8",
136
132
  )
137
133
 
138
- # Also set max file size (10MB) using RotatingFileHandler as fallback
139
- # Note: We'll use TimedRotatingFileHandler which handles both time and size
140
- file_handler.setLevel(getattr(logging, env_level))
134
+ file_handler.setLevel(getattr(logging, log_level))
141
135
 
142
136
  # Use standard formatter for file (no colors)
143
137
  file_formatter = logging.Formatter(
@@ -191,10 +185,7 @@ def get_logger(name: str) -> logging.Logger:
191
185
  logger = logging.getLogger(name)
192
186
 
193
187
  # Check if we have a file handler already
194
- has_file_handler = any(
195
- isinstance(h, logging.handlers.TimedRotatingFileHandler)
196
- for h in logger.handlers
197
- )
188
+ has_file_handler = any(isinstance(h, logging.FileHandler) for h in logger.handlers)
198
189
 
199
190
  # If no file handler, set up the logger (will add file handler)
200
191
  if not has_file_handler:
shotgun/main.py CHANGED
@@ -23,8 +23,11 @@ from dotenv import load_dotenv
23
23
  from shotgun import __version__
24
24
  from shotgun.agents.config import get_config_manager
25
25
  from shotgun.cli import (
26
+ clear,
26
27
  codebase,
28
+ compact,
27
29
  config,
30
+ context,
28
31
  export,
29
32
  feedback,
30
33
  plan,
@@ -53,8 +56,10 @@ logger.debug("Logfire observability enabled: %s", _logfire_enabled)
53
56
 
54
57
  # Initialize configuration
55
58
  try:
59
+ import asyncio
60
+
56
61
  config_manager = get_config_manager()
57
- config_manager.load() # Ensure config is loaded at startup
62
+ asyncio.run(config_manager.load()) # Ensure config is loaded at startup
58
63
  except Exception as e:
59
64
  logger.debug("Configuration initialization warning: %s", e)
60
65
 
@@ -78,6 +83,9 @@ app.add_typer(config.app, name="config", help="Manage Shotgun configuration")
78
83
  app.add_typer(
79
84
  codebase.app, name="codebase", help="Manage and query code knowledge graphs"
80
85
  )
86
+ app.add_typer(context.app, name="context", help="Analyze conversation context usage")
87
+ app.add_typer(compact.app, name="compact", help="Compact conversation history")
88
+ app.add_typer(clear.app, name="clear", help="Clear conversation history")
81
89
  app.add_typer(research.app, name="research", help="Perform research with agentic loops")
82
90
  app.add_typer(plan.app, name="plan", help="Generate structured plans")
83
91
  app.add_typer(specify.app, name="specify", help="Generate comprehensive specifications")
@@ -125,6 +133,41 @@ def main(
125
133
  help="Continue previous TUI conversation",
126
134
  ),
127
135
  ] = False,
136
+ web: Annotated[
137
+ bool,
138
+ typer.Option(
139
+ "--web",
140
+ help="Serve TUI as web application",
141
+ ),
142
+ ] = False,
143
+ port: Annotated[
144
+ int,
145
+ typer.Option(
146
+ "--port",
147
+ help="Port for web server (only used with --web)",
148
+ ),
149
+ ] = 8000,
150
+ host: Annotated[
151
+ str,
152
+ typer.Option(
153
+ "--host",
154
+ help="Host address for web server (only used with --web)",
155
+ ),
156
+ ] = "localhost",
157
+ public_url: Annotated[
158
+ str | None,
159
+ typer.Option(
160
+ "--public-url",
161
+ help="Public URL if behind proxy (only used with --web)",
162
+ ),
163
+ ] = None,
164
+ force_reindex: Annotated[
165
+ bool,
166
+ typer.Option(
167
+ "--force-reindex",
168
+ help="Force re-indexing of codebase (ignores existing index)",
169
+ ),
170
+ ] = False,
128
171
  ) -> None:
129
172
  """Shotgun - AI-powered CLI tool."""
130
173
  logger.debug("Starting shotgun CLI application")
@@ -134,16 +177,35 @@ def main(
134
177
  perform_auto_update_async(no_update_check=no_update_check)
135
178
 
136
179
  if ctx.invoked_subcommand is None and not ctx.resilient_parsing:
137
- logger.debug("Launching shotgun TUI application")
138
- try:
139
- tui_app.run(
140
- no_update_check=no_update_check, continue_session=continue_session
141
- )
142
- finally:
143
- # Ensure PostHog is shut down cleanly even if TUI exits unexpectedly
144
- from shotgun.posthog_telemetry import shutdown
145
-
146
- shutdown()
180
+ if web:
181
+ logger.debug("Launching shotgun TUI as web application")
182
+ try:
183
+ tui_app.serve(
184
+ host=host,
185
+ port=port,
186
+ public_url=public_url,
187
+ no_update_check=no_update_check,
188
+ continue_session=continue_session,
189
+ force_reindex=force_reindex,
190
+ )
191
+ finally:
192
+ # Ensure PostHog is shut down cleanly even if server exits unexpectedly
193
+ from shotgun.posthog_telemetry import shutdown
194
+
195
+ shutdown()
196
+ else:
197
+ logger.debug("Launching shotgun TUI application")
198
+ try:
199
+ tui_app.run(
200
+ no_update_check=no_update_check,
201
+ continue_session=continue_session,
202
+ force_reindex=force_reindex,
203
+ )
204
+ finally:
205
+ # Ensure PostHog is shut down cleanly even if TUI exits unexpectedly
206
+ from shotgun.posthog_telemetry import shutdown
207
+
208
+ shutdown()
147
209
  raise typer.Exit()
148
210
 
149
211
  # For CLI commands, register PostHog shutdown handler
@@ -10,6 +10,7 @@ from shotgun import __version__
10
10
  from shotgun.agents.config import get_config_manager
11
11
  from shotgun.agents.conversation_manager import ConversationManager
12
12
  from shotgun.logging_config import get_early_logger
13
+ from shotgun.settings import settings
13
14
 
14
15
  # Use early logger to prevent automatic StreamHandler creation
15
16
  logger = get_early_logger(__name__)
@@ -17,6 +18,9 @@ logger = get_early_logger(__name__)
17
18
  # Global PostHog client instance
18
19
  _posthog_client = None
19
20
 
21
+ # Cache the shotgun instance ID to avoid async calls during event tracking
22
+ _shotgun_instance_id: str | None = None
23
+
20
24
 
21
25
  def setup_posthog_observability() -> bool:
22
26
  """Set up PostHog analytics for usage tracking.
@@ -24,7 +28,7 @@ def setup_posthog_observability() -> bool:
24
28
  Returns:
25
29
  True if PostHog was successfully set up, False otherwise
26
30
  """
27
- global _posthog_client
31
+ global _posthog_client, _shotgun_instance_id
28
32
 
29
33
  try:
30
34
  # Check if PostHog is already initialized
@@ -32,10 +36,15 @@ def setup_posthog_observability() -> bool:
32
36
  logger.debug("PostHog is already initialized, skipping")
33
37
  return True
34
38
 
35
- # Hardcoded PostHog configuration
36
- api_key = "phc_KKnChzZUKeNqZDOTJ6soCBWNQSx3vjiULdwTR9H5Mcr"
39
+ # Get API key from settings (handles build constants + env vars automatically)
40
+ api_key = settings.telemetry.posthog_api_key
41
+
42
+ # If no API key is available, skip PostHog initialization
43
+ if not api_key:
44
+ logger.debug("No PostHog API key available, skipping initialization")
45
+ return False
37
46
 
38
- logger.debug("Using hardcoded PostHog configuration")
47
+ logger.debug("Using PostHog API key from settings")
39
48
 
40
49
  # Determine environment based on version
41
50
  # Dev versions contain "dev", "rc", "alpha", or "beta"
@@ -51,29 +60,20 @@ def setup_posthog_observability() -> bool:
51
60
  # Store the client for later use
52
61
  _posthog_client = posthog
53
62
 
54
- # Set user context with anonymous shotgun instance ID from config
63
+ # Cache the shotgun instance ID for later use (avoids async issues)
55
64
  try:
56
- config_manager = get_config_manager()
57
- shotgun_instance_id = config_manager.get_shotgun_instance_id()
58
-
59
- # Identify the user in PostHog
60
- posthog.identify( # type: ignore[attr-defined]
61
- distinct_id=shotgun_instance_id,
62
- properties={
63
- "version": __version__,
64
- "environment": environment,
65
- },
66
- )
65
+ import asyncio
67
66
 
68
- # Set default properties for all events
69
- posthog.disabled = False
70
- posthog.personal_api_key = None # Not needed for event tracking
67
+ config_manager = get_config_manager()
68
+ _shotgun_instance_id = asyncio.run(config_manager.get_shotgun_instance_id())
71
69
 
72
70
  logger.debug(
73
- "PostHog user identified with anonymous ID: %s", shotgun_instance_id
71
+ "PostHog initialized with shotgun instance ID: %s",
72
+ _shotgun_instance_id,
74
73
  )
75
74
  except Exception as e:
76
- logger.warning("Failed to set user context: %s", e)
75
+ logger.warning("Failed to load shotgun instance ID: %s", e)
76
+ # Continue anyway - we'll try to get it during event tracking
77
77
 
78
78
  logger.debug(
79
79
  "PostHog analytics configured successfully (environment: %s, version: %s)",
@@ -94,16 +94,19 @@ def track_event(event_name: str, properties: dict[str, Any] | None = None) -> No
94
94
  event_name: Name of the event to track
95
95
  properties: Optional properties to include with the event
96
96
  """
97
- global _posthog_client
97
+ global _posthog_client, _shotgun_instance_id
98
98
 
99
99
  if _posthog_client is None:
100
100
  logger.debug("PostHog not initialized, skipping event: %s", event_name)
101
101
  return
102
102
 
103
103
  try:
104
- # Get shotgun instance ID for tracking
105
- config_manager = get_config_manager()
106
- shotgun_instance_id = config_manager.get_shotgun_instance_id()
104
+ # Use cached instance ID (loaded during setup)
105
+ if _shotgun_instance_id is None:
106
+ logger.warning(
107
+ "Shotgun instance ID not available, skipping event: %s", event_name
108
+ )
109
+ return
107
110
 
108
111
  # Add version and environment to properties
109
112
  if properties is None:
@@ -118,7 +121,7 @@ def track_event(event_name: str, properties: dict[str, Any] | None = None) -> No
118
121
 
119
122
  # Track the event using PostHog's capture method
120
123
  _posthog_client.capture(
121
- distinct_id=shotgun_instance_id, event=event_name, properties=properties
124
+ distinct_id=_shotgun_instance_id, event=event_name, properties=properties
122
125
  )
123
126
  logger.debug("Tracked PostHog event: %s", event_name)
124
127
  except Exception as e:
@@ -162,10 +165,16 @@ def submit_feedback_survey(feedback: Feedback) -> None:
162
165
  logger.debug("PostHog not initialized, skipping feedback survey")
163
166
  return
164
167
 
168
+ import asyncio
169
+
165
170
  config_manager = get_config_manager()
166
- config = config_manager.load()
171
+ config = asyncio.run(config_manager.load())
167
172
  conversation_manager = ConversationManager()
168
- conversation = conversation_manager.load()
173
+ conversation = None
174
+ try:
175
+ conversation = asyncio.run(conversation_manager.load())
176
+ except Exception as e:
177
+ logger.debug(f"Failed to load conversation history: {e}")
169
178
  last_10_messages = []
170
179
  if conversation is not None:
171
180
  last_10_messages = conversation.get_agent_messages()[:10]
@@ -124,6 +124,7 @@ content_tasks = read_file('tasks.md') # Read implementation details
124
124
  - `plan.md` - Extract development approach and stages
125
125
  - `tasks.md` - Understand implementation tasks and structure
126
126
  2. **Map content to agents.md standard sections**:
127
+ - **Research, Specifications, and Planning**: ALWAYS include this section first. Check which pipeline files exist in `.shotgun/` (research.md, specification.md, plan.md, tasks.md) and list only the ones that exist. If none exist, omit this section.
127
128
  - **Project Overview**: Brief description and key technologies from specification.md
128
129
  - **Dev Environment Setup**: Installation, dependencies, dev server commands
129
130
  - **Code Style Guidelines**: Coding conventions and patterns from research.md
@@ -170,6 +171,14 @@ For additional specialized exports (only if specifically requested):
170
171
  <CORRECT_CONTENT_TEMPLATE>
171
172
  # Agents.md - [Project Name]
172
173
 
174
+ ## Research, Specifications, and Planning
175
+
176
+ The `.shotgun/` folder contains background research, specifications, and implementation planning files. Refer to these files for additional context:
177
+ - `research.md` - Codebase analysis and research findings
178
+ - `specification.md` - Project requirements and specifications
179
+ - `plan.md` - Development plan and implementation approach
180
+ - `tasks.md` - Task breakdown and implementation progress
181
+
173
182
  ## Project Overview
174
183
  - Brief description of what the project does
175
184
  - Key technologies and frameworks used
@@ -253,6 +262,14 @@ This project is about [making assumptions without reading files]...
253
262
  <GOOD_CONTENT_EXAMPLE>
254
263
  # Agents.md - E-commerce API Project
255
264
 
265
+ ## Research, Specifications, and Planning
266
+
267
+ The `.shotgun/` folder contains background research, specifications, and implementation planning files. Refer to these files for additional context:
268
+ - `research.md` - Codebase analysis and research findings
269
+ - `specification.md` - Project requirements and specifications
270
+ - `plan.md` - Development plan and implementation approach
271
+ - `tasks.md` - Task breakdown and implementation progress
272
+
256
273
  ## Project Overview
257
274
  - REST API for product catalog management with authentication
258
275
  - Built with Python/FastAPI for high performance async operations
@@ -316,7 +333,7 @@ This project is about [making assumptions without reading files]...
316
333
  USER INTERACTION - CLARIFY EXPORT REQUIREMENTS:
317
334
 
318
335
  - ALWAYS ask clarifying questions when export requirements are unclear
319
- - Use ask_user tool to gather specific details about:
336
+ - Use clarifying questions to gather specific details about:
320
337
  - Target format and file type preferences
321
338
  - Intended use case and audience for the export
322
339
  - Specific content sections to include/exclude from files
@@ -7,7 +7,11 @@ Your extensive expertise spans, among other things:
7
7
  ## KEY RULES
8
8
 
9
9
  {% if interactive_mode %}
10
- 0. Always ask CLARIFYING QUESTIONS if the user's request is ambiguous or lacks sufficient detail. Do not make assumptions about what the user wants.
10
+ 0. Always ask CLARIFYING QUESTIONS using structured output before doing work.
11
+ - Return your response with the clarifying_questions field populated
12
+ - Do not make assumptions about what the user wants, get a clear understanding first.
13
+ - Questions should be clear, specific, and answerable
14
+ - Do not ask too many questions that might overwhelm the user; prioritize the most important ones.
11
15
  {% endif %}
12
16
  1. Above all, prefer using tools to do the work and NEVER respond with text.
13
17
  2. IMPORTANT: Always ask for review and go ahead to move forward after using write_file().
@@ -6,20 +6,37 @@
6
6
  {% if interactive_mode -%}
7
7
  IMPORTANT: USER INTERACTION IS ENABLED (interactive mode).
8
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.
11
- - AFTER USING write_artifact_section(), ALWAYS USE ask_user() TO REVIEW AND ACCEPT THE ARTIFACT SECTION YOU'VE WORKED ON BEFORE PROCEEDING TO THE NEXT SECTION.
9
+ ## Structured Output Format
10
+
11
+ You must return responses using this structured format:
12
+
13
+ ```json
14
+ {
15
+ "response": "Your main response text here",
16
+ "clarifying_questions": ["Question 1?", "Question 2?"] // Optional, only when needed
17
+ }
18
+ ```
19
+
20
+ ## When to Use Clarifying Questions
21
+
22
+ - BEFORE GETTING TO WORK: If the user's request is ambiguous, use clarifying_questions to ask what they want
23
+ - DURING WORK: After using write_file(), you can suggest that the user review it and ask any clarifying questions with clarifying_questions
12
24
  - Don't assume - ask for confirmation of your understanding
13
- - When in doubt about any aspect of the goal, ASK before proceeding
25
+ - When in doubt about any aspect of the goal, include clarifying_questions
26
+
27
+ ## Important Notes
28
+
29
+ - If you don't need to ask questions, set clarifying_questions to null or omit it
30
+ - Keep response field concise - a paragraph at most for user communication
31
+ - Questions should be clear, specific, and independently answerable
32
+ - Don't ask multiple questions in one string - use separate array items
14
33
 
15
34
  {% else -%}
16
35
 
17
36
  IMPORTANT: USER INTERACTION IS DISABLED (non-interactive mode).
18
- - You cannot ask clarifying questions using ask_user tool
37
+ - You cannot ask clarifying questions (clarifying_questions will be ignored)
19
38
  - Make reasonable assumptions based on best practices
20
39
  - Use sensible defaults when information is missing
21
- - Make reasonable assumptions based on industry best practices
22
- - Use sensible defaults when specific details are not provided
23
40
  - When in doubt, make reasonable assumptions and proceed with best practices
24
41
  {% endif %}
25
42
 
@@ -118,7 +118,7 @@ USER INTERACTION - REDUCE UNCERTAINTY:
118
118
  - FIRST read `research.md` and `specification.md` before asking ANY questions
119
119
  - ONLY ask clarifying questions AFTER reading the context files
120
120
  - Questions should be about gaps not covered in research/specification
121
- - Use ask_user tool to gather specific details about:
121
+ - Use clarifying questions to gather specific details about:
122
122
  - Information not found in the context files
123
123
  - Clarifications on ambiguous specifications
124
124
  - Priorities when multiple options exist
@@ -39,7 +39,7 @@ For research tasks:
39
39
  ## RESEARCH PRINCIPLES
40
40
 
41
41
  {% if interactive_mode -%}
42
- - CRITICAL: BEFORE RUNNING ANY SEARCH TOOL, ASK THE USER FOR APPROVAL USING ask_user(). FINISH THE QUESTION WITH ASKING FOR A GO AHEAD.
42
+ - CRITICAL: BEFORE RUNNING ANY SEARCH TOOL, ASK THE USER FOR APPROVAL using clarifying questions. Include what you plan to search for and ask if they want you to proceed.
43
43
  {% endif -%}
44
44
  - Build upon existing research rather than starting from scratch
45
45
  - Focus on practical, actionable information over theoretical concepts