shotgun-sh 0.1.0.dev22__py3-none-any.whl → 0.1.0.dev24__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.

Files changed (56) hide show
  1. shotgun/agents/agent_manager.py +95 -15
  2. shotgun/agents/common.py +143 -25
  3. shotgun/agents/conversation_history.py +56 -0
  4. shotgun/agents/conversation_manager.py +105 -0
  5. shotgun/agents/export.py +5 -2
  6. shotgun/agents/models.py +16 -7
  7. shotgun/agents/plan.py +2 -1
  8. shotgun/agents/research.py +2 -1
  9. shotgun/agents/specify.py +2 -1
  10. shotgun/agents/tasks.py +5 -2
  11. shotgun/agents/tools/file_management.py +67 -2
  12. shotgun/codebase/core/ingestor.py +1 -1
  13. shotgun/codebase/core/manager.py +106 -4
  14. shotgun/codebase/models.py +4 -0
  15. shotgun/codebase/service.py +60 -2
  16. shotgun/main.py +9 -1
  17. shotgun/prompts/agents/export.j2 +14 -11
  18. shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +6 -9
  19. shotgun/prompts/agents/plan.j2 +9 -13
  20. shotgun/prompts/agents/research.j2 +11 -14
  21. shotgun/prompts/agents/specify.j2 +9 -12
  22. shotgun/prompts/agents/state/system_state.j2 +27 -5
  23. shotgun/prompts/agents/tasks.j2 +12 -12
  24. shotgun/sdk/codebase.py +26 -2
  25. shotgun/sdk/services.py +0 -14
  26. shotgun/tui/app.py +9 -4
  27. shotgun/tui/screens/chat.py +80 -19
  28. shotgun/tui/screens/chat_screen/command_providers.py +1 -1
  29. shotgun/tui/screens/chat_screen/history.py +6 -0
  30. shotgun/tui/utils/mode_progress.py +111 -78
  31. {shotgun_sh-0.1.0.dev22.dist-info → shotgun_sh-0.1.0.dev24.dist-info}/METADATA +8 -9
  32. {shotgun_sh-0.1.0.dev22.dist-info → shotgun_sh-0.1.0.dev24.dist-info}/RECORD +35 -54
  33. shotgun/agents/artifact_state.py +0 -58
  34. shotgun/agents/tools/artifact_management.py +0 -481
  35. shotgun/artifacts/__init__.py +0 -17
  36. shotgun/artifacts/exceptions.py +0 -89
  37. shotgun/artifacts/manager.py +0 -530
  38. shotgun/artifacts/models.py +0 -334
  39. shotgun/artifacts/service.py +0 -463
  40. shotgun/artifacts/templates/__init__.py +0 -10
  41. shotgun/artifacts/templates/loader.py +0 -252
  42. shotgun/artifacts/templates/models.py +0 -136
  43. shotgun/artifacts/templates/plan/delivery_and_release_plan.yaml +0 -66
  44. shotgun/artifacts/templates/research/market_research.yaml +0 -585
  45. shotgun/artifacts/templates/research/sdk_comparison.yaml +0 -257
  46. shotgun/artifacts/templates/specify/prd.yaml +0 -331
  47. shotgun/artifacts/templates/specify/product_spec.yaml +0 -301
  48. shotgun/artifacts/utils.py +0 -76
  49. shotgun/prompts/agents/partials/artifact_system.j2 +0 -32
  50. shotgun/prompts/agents/state/artifact_templates_available.j2 +0 -20
  51. shotgun/prompts/agents/state/existing_artifacts_available.j2 +0 -25
  52. shotgun/sdk/artifact_models.py +0 -186
  53. shotgun/sdk/artifacts.py +0 -448
  54. {shotgun_sh-0.1.0.dev22.dist-info → shotgun_sh-0.1.0.dev24.dist-info}/WHEEL +0 -0
  55. {shotgun_sh-0.1.0.dev22.dist-info → shotgun_sh-0.1.0.dev24.dist-info}/entry_points.txt +0 -0
  56. {shotgun_sh-0.1.0.dev22.dist-info → shotgun_sh-0.1.0.dev24.dist-info}/licenses/LICENSE +0 -0
shotgun/agents/tasks.py CHANGED
@@ -19,7 +19,7 @@ from .common import (
19
19
  create_usage_limits,
20
20
  run_agent,
21
21
  )
22
- from .models import AgentDeps, AgentRuntimeOptions
22
+ from .models import AgentDeps, AgentRuntimeOptions, AgentType
23
23
 
24
24
  logger = get_logger(__name__)
25
25
 
@@ -41,7 +41,10 @@ def create_tasks_agent(
41
41
  system_prompt_fn = partial(build_agent_system_prompt, "tasks")
42
42
 
43
43
  agent, deps = create_base_agent(
44
- system_prompt_fn, agent_runtime_options, provider=provider
44
+ system_prompt_fn,
45
+ agent_runtime_options,
46
+ provider=provider,
47
+ agent_mode=AgentType.TASKS,
45
48
  )
46
49
  return agent, deps
47
50
 
@@ -8,12 +8,76 @@ from typing import Literal
8
8
 
9
9
  from pydantic_ai import RunContext
10
10
 
11
- from shotgun.agents.models import AgentDeps, FileOperationType
11
+ from shotgun.agents.models import AgentDeps, AgentType, FileOperationType
12
12
  from shotgun.logging_config import get_logger
13
13
  from shotgun.utils.file_system_utils import get_shotgun_base_path
14
14
 
15
15
  logger = get_logger(__name__)
16
16
 
17
+ # Map agent modes to their allowed directories/files (in workflow order)
18
+ AGENT_DIRECTORIES = {
19
+ AgentType.RESEARCH: "research.md",
20
+ AgentType.SPECIFY: "specification.md",
21
+ AgentType.PLAN: "plan.md",
22
+ AgentType.TASKS: "tasks.md",
23
+ AgentType.EXPORT: "exports/",
24
+ }
25
+
26
+
27
+ def _validate_agent_scoped_path(filename: str, agent_mode: AgentType | None) -> Path:
28
+ """Validate and resolve a file path within the agent's scoped directory.
29
+
30
+ Args:
31
+ filename: Relative filename
32
+ agent_mode: The current agent mode
33
+
34
+ Returns:
35
+ Absolute path to the file within the agent's scoped directory
36
+
37
+ Raises:
38
+ ValueError: If the path attempts to access files outside the agent's scope
39
+ """
40
+ base_path = get_shotgun_base_path()
41
+
42
+ if agent_mode and agent_mode in AGENT_DIRECTORIES:
43
+ # For export mode, allow writing to any file in exports/ directory
44
+ if agent_mode == AgentType.EXPORT:
45
+ # Ensure the filename starts with exports/ or is being written to exports/
46
+ if not filename.startswith("exports/"):
47
+ filename = f"exports/{filename}"
48
+ full_path = (base_path / filename).resolve()
49
+
50
+ # Ensure it's within .shotgun/exports/
51
+ exports_dir = base_path / "exports"
52
+ try:
53
+ full_path.relative_to(exports_dir.resolve())
54
+ except ValueError as e:
55
+ raise ValueError(
56
+ f"Export agent can only write to exports/ directory. Path '{filename}' is not allowed"
57
+ ) from e
58
+ else:
59
+ # For other agents, only allow writing to their specific file
60
+ allowed_file = AGENT_DIRECTORIES[agent_mode]
61
+ if filename != allowed_file:
62
+ raise ValueError(
63
+ f"{agent_mode.value.capitalize()} agent can only write to '{allowed_file}'. "
64
+ f"Attempted to write to '{filename}'"
65
+ )
66
+ full_path = (base_path / filename).resolve()
67
+ else:
68
+ # No agent mode specified, fall back to old validation
69
+ full_path = (base_path / filename).resolve()
70
+
71
+ # Ensure the resolved path is within the .shotgun directory
72
+ try:
73
+ full_path.relative_to(base_path.resolve())
74
+ except ValueError as e:
75
+ raise ValueError(
76
+ f"Access denied: Path '{filename}' is outside .shotgun directory"
77
+ ) from e
78
+
79
+ return full_path
80
+
17
81
 
18
82
  def _validate_shotgun_path(filename: str) -> Path:
19
83
  """Validate and resolve a file path within the .shotgun directory.
@@ -99,7 +163,8 @@ async def write_file(
99
163
  raise ValueError(f"Invalid mode '{mode}'. Use 'w' for write or 'a' for append")
100
164
 
101
165
  try:
102
- file_path = _validate_shotgun_path(filename)
166
+ # Use agent-scoped validation for write operations
167
+ file_path = _validate_agent_scoped_path(filename, ctx.deps.agent_mode)
103
168
 
104
169
  # Determine operation type
105
170
  if mode == "a":
@@ -54,7 +54,7 @@ class Ingestor:
54
54
 
55
55
  # Node tables
56
56
  node_schemas = [
57
- "CREATE NODE TABLE Project(name STRING PRIMARY KEY, repo_path STRING, graph_id STRING, created_at INT64, updated_at INT64, schema_version STRING, build_options STRING, node_count INT64, relationship_count INT64, stats_updated_at INT64, status STRING, current_operation_id STRING, last_operation STRING)",
57
+ "CREATE NODE TABLE Project(name STRING PRIMARY KEY, repo_path STRING, graph_id STRING, created_at INT64, updated_at INT64, schema_version STRING, build_options STRING, node_count INT64, relationship_count INT64, stats_updated_at INT64, status STRING, current_operation_id STRING, last_operation STRING, indexed_from_cwds STRING)",
58
58
  "CREATE NODE TABLE Package(qualified_name STRING PRIMARY KEY, name STRING, path STRING)",
59
59
  "CREATE NODE TABLE Folder(path STRING PRIMARY KEY, name STRING)",
60
60
  "CREATE NODE TABLE File(path STRING PRIMARY KEY, name STRING, extension STRING)",
@@ -252,6 +252,7 @@ class CodebaseGraphManager:
252
252
  name: str,
253
253
  languages: list[str] | None,
254
254
  exclude_patterns: list[str] | None,
255
+ indexed_from_cwd: str | None = None,
255
256
  ) -> None:
256
257
  """Initialize the graph database and create initial metadata.
257
258
 
@@ -294,7 +295,8 @@ class CodebaseGraphManager:
294
295
  last_operation: $last_operation,
295
296
  node_count: 0,
296
297
  relationship_count: 0,
297
- stats_updated_at: $stats_updated_at
298
+ stats_updated_at: $stats_updated_at,
299
+ indexed_from_cwds: $indexed_from_cwds
298
300
  })
299
301
  """,
300
302
  {
@@ -311,6 +313,9 @@ class CodebaseGraphManager:
311
313
  "current_operation_id": None,
312
314
  "last_operation": None,
313
315
  "stats_updated_at": int(time.time()),
316
+ "indexed_from_cwds": json.dumps(
317
+ [indexed_from_cwd] if indexed_from_cwd else []
318
+ ),
314
319
  },
315
320
  )
316
321
 
@@ -323,6 +328,7 @@ class CodebaseGraphManager:
323
328
  name: str | None = None,
324
329
  languages: list[str] | None = None,
325
330
  exclude_patterns: list[str] | None = None,
331
+ indexed_from_cwd: str | None = None,
326
332
  ) -> CodebaseGraph:
327
333
  """Build a new code knowledge graph.
328
334
 
@@ -397,7 +403,8 @@ class CodebaseGraphManager:
397
403
  created_at: $created_at,
398
404
  updated_at: $updated_at,
399
405
  schema_version: $schema_version,
400
- build_options: $build_options
406
+ build_options: $build_options,
407
+ indexed_from_cwds: $indexed_from_cwds
401
408
  })
402
409
  """,
403
410
  {
@@ -410,6 +417,9 @@ class CodebaseGraphManager:
410
417
  "build_options": json.dumps(
411
418
  {"languages": languages, "exclude_patterns": exclude_patterns}
412
419
  ),
420
+ "indexed_from_cwds": json.dumps(
421
+ [indexed_from_cwd] if indexed_from_cwd else []
422
+ ),
413
423
  },
414
424
  )
415
425
 
@@ -475,6 +485,7 @@ class CodebaseGraphManager:
475
485
  status=GraphStatus.READY,
476
486
  last_operation=None,
477
487
  current_operation_id=None,
488
+ indexed_from_cwds=[indexed_from_cwd] if indexed_from_cwd else [],
478
489
  )
479
490
 
480
491
  # Update status to READY
@@ -1145,6 +1156,15 @@ class CodebaseGraphManager:
1145
1156
  logger.debug(f"Failed to parse last operation stats: {e}")
1146
1157
  last_operation = None
1147
1158
 
1159
+ # Parse indexed_from_cwds - handle backward compatibility
1160
+ indexed_from_cwds_json = project.get("indexed_from_cwds", "[]")
1161
+ try:
1162
+ indexed_from_cwds = (
1163
+ json.loads(indexed_from_cwds_json) if indexed_from_cwds_json else []
1164
+ )
1165
+ except (json.JSONDecodeError, TypeError):
1166
+ indexed_from_cwds = []
1167
+
1148
1168
  return CodebaseGraph(
1149
1169
  graph_id=graph_id,
1150
1170
  repo_path=project.get("repo_path", ""),
@@ -1165,6 +1185,7 @@ class CodebaseGraphManager:
1165
1185
  status=status,
1166
1186
  last_operation=last_operation,
1167
1187
  current_operation_id=project.get("current_operation_id"),
1188
+ indexed_from_cwds=indexed_from_cwds,
1168
1189
  )
1169
1190
  except Exception as e:
1170
1191
  logger.error(
@@ -1190,6 +1211,83 @@ class CodebaseGraphManager:
1190
1211
 
1191
1212
  return sorted(graphs, key=lambda g: g.updated_at, reverse=True)
1192
1213
 
1214
+ async def add_cwd_access(self, graph_id: str, cwd: str | None = None) -> None:
1215
+ """Add a working directory to a graph's access list.
1216
+
1217
+ Args:
1218
+ graph_id: Graph ID to update
1219
+ cwd: Working directory to add. If None, uses current working directory.
1220
+ """
1221
+ from pathlib import Path
1222
+
1223
+ if cwd is None:
1224
+ cwd = str(Path.cwd().resolve())
1225
+ else:
1226
+ cwd = str(Path(cwd).resolve())
1227
+
1228
+ # Get current graph
1229
+ graph = await self.get_graph(graph_id)
1230
+ if not graph:
1231
+ raise ValueError(f"Graph {graph_id} not found")
1232
+
1233
+ # Get current list
1234
+ current_cwds = graph.indexed_from_cwds.copy()
1235
+
1236
+ # Add new CWD if not already present
1237
+ if cwd not in current_cwds:
1238
+ current_cwds.append(cwd)
1239
+
1240
+ # Update in database
1241
+ await self._execute_query(
1242
+ graph_id,
1243
+ """
1244
+ MATCH (p:Project {graph_id: $graph_id})
1245
+ SET p.indexed_from_cwds = $indexed_from_cwds
1246
+ """,
1247
+ {
1248
+ "graph_id": graph_id,
1249
+ "indexed_from_cwds": json.dumps(current_cwds),
1250
+ },
1251
+ )
1252
+ logger.info(f"Added CWD access for {cwd} to graph {graph_id}")
1253
+
1254
+ async def remove_cwd_access(self, graph_id: str, cwd: str) -> None:
1255
+ """Remove a working directory from a graph's access list.
1256
+
1257
+ Args:
1258
+ graph_id: Graph ID to update
1259
+ cwd: Working directory to remove
1260
+ """
1261
+ from pathlib import Path
1262
+
1263
+ cwd = str(Path(cwd).resolve())
1264
+
1265
+ # Get current graph
1266
+ graph = await self.get_graph(graph_id)
1267
+ if not graph:
1268
+ raise ValueError(f"Graph {graph_id} not found")
1269
+
1270
+ # Get current list
1271
+ current_cwds = graph.indexed_from_cwds.copy()
1272
+
1273
+ # Remove CWD if present
1274
+ if cwd in current_cwds:
1275
+ current_cwds.remove(cwd)
1276
+
1277
+ # Update in database
1278
+ await self._execute_query(
1279
+ graph_id,
1280
+ """
1281
+ MATCH (p:Project {graph_id: $graph_id})
1282
+ SET p.indexed_from_cwds = $indexed_from_cwds
1283
+ """,
1284
+ {
1285
+ "graph_id": graph_id,
1286
+ "indexed_from_cwds": json.dumps(current_cwds),
1287
+ },
1288
+ )
1289
+ logger.info(f"Removed CWD access for {cwd} from graph {graph_id}")
1290
+
1193
1291
  async def delete_graph(self, graph_id: str) -> None:
1194
1292
  """Delete a graph.
1195
1293
 
@@ -1365,6 +1463,7 @@ class CodebaseGraphManager:
1365
1463
  name: str,
1366
1464
  languages: list[str] | None,
1367
1465
  exclude_patterns: list[str] | None,
1466
+ indexed_from_cwd: str | None = None,
1368
1467
  ) -> CodebaseGraph:
1369
1468
  """Internal implementation of graph building (runs in background)."""
1370
1469
  operation_id = str(uuid.uuid4())
@@ -1388,7 +1487,7 @@ class CodebaseGraphManager:
1388
1487
 
1389
1488
  # Do the actual build work
1390
1489
  graph = await self._do_build_graph(
1391
- graph_id, repo_path, name, languages, exclude_patterns
1490
+ graph_id, repo_path, name, languages, exclude_patterns, indexed_from_cwd
1392
1491
  )
1393
1492
 
1394
1493
  # Update operation stats
@@ -1436,6 +1535,7 @@ class CodebaseGraphManager:
1436
1535
  name: str,
1437
1536
  languages: list[str] | None,
1438
1537
  exclude_patterns: list[str] | None,
1538
+ indexed_from_cwd: str | None = None,
1439
1539
  ) -> CodebaseGraph:
1440
1540
  """Execute the actual graph building logic (extracted from original build_graph)."""
1441
1541
  # The database and Project node already exist from _initialize_graph_metadata
@@ -1515,6 +1615,7 @@ class CodebaseGraphManager:
1515
1615
  name: str | None = None,
1516
1616
  languages: list[str] | None = None,
1517
1617
  exclude_patterns: list[str] | None = None,
1618
+ indexed_from_cwd: str | None = None,
1518
1619
  ) -> str:
1519
1620
  """Start building a new code knowledge graph asynchronously.
1520
1621
 
@@ -1547,12 +1648,13 @@ class CodebaseGraphManager:
1547
1648
  name=name,
1548
1649
  languages=languages,
1549
1650
  exclude_patterns=exclude_patterns,
1651
+ indexed_from_cwd=indexed_from_cwd,
1550
1652
  )
1551
1653
 
1552
1654
  # Start the build operation in background
1553
1655
  task = asyncio.create_task(
1554
1656
  self._build_graph_impl(
1555
- graph_id, repo_path, name, languages, exclude_patterns
1657
+ graph_id, repo_path, name, languages, exclude_patterns, indexed_from_cwd
1556
1658
  )
1557
1659
  )
1558
1660
  self._operations[graph_id] = task
@@ -73,6 +73,10 @@ class CodebaseGraph(BaseModel):
73
73
  current_operation_id: str | None = Field(
74
74
  None, description="ID of current in-progress operation"
75
75
  )
76
+ indexed_from_cwds: list[str] = Field(
77
+ default_factory=list,
78
+ description="List of working directories from which this graph is accessible. Empty list means globally accessible.",
79
+ )
76
80
 
77
81
 
78
82
  class QueryResult(BaseModel):
@@ -36,17 +36,57 @@ class CodebaseService:
36
36
  """
37
37
  return await self.manager.list_graphs()
38
38
 
39
- async def create_graph(self, repo_path: str | Path, name: str) -> CodebaseGraph:
39
+ async def list_graphs_for_directory(
40
+ self, directory: Path | str | None = None
41
+ ) -> list[CodebaseGraph]:
42
+ """List graphs that match a specific directory.
43
+
44
+ Args:
45
+ directory: Directory to filter by. If None, uses current working directory.
46
+
47
+ Returns:
48
+ List of CodebaseGraph objects accessible from the specified directory
49
+ """
50
+ from pathlib import Path
51
+
52
+ if directory is None:
53
+ directory = Path.cwd()
54
+ elif isinstance(directory, str):
55
+ directory = Path(directory)
56
+
57
+ # Resolve to absolute path for comparison
58
+ target_path = str(directory.resolve())
59
+
60
+ # Get all graphs and filter by those accessible from this directory
61
+ all_graphs = await self.manager.list_graphs()
62
+ filtered_graphs = []
63
+
64
+ for graph in all_graphs:
65
+ # If indexed_from_cwds is empty, it's globally accessible (backward compatibility)
66
+ if not graph.indexed_from_cwds:
67
+ filtered_graphs.append(graph)
68
+ # Otherwise, check if current directory is in the allowed list
69
+ elif target_path in graph.indexed_from_cwds:
70
+ filtered_graphs.append(graph)
71
+
72
+ return filtered_graphs
73
+
74
+ async def create_graph(
75
+ self, repo_path: str | Path, name: str, indexed_from_cwd: str | None = None
76
+ ) -> CodebaseGraph:
40
77
  """Create and index a new graph from a repository.
41
78
 
42
79
  Args:
43
80
  repo_path: Path to the repository to index
44
81
  name: Human-readable name for the graph
82
+ indexed_from_cwd: Working directory from which indexing was initiated
45
83
 
46
84
  Returns:
47
85
  The created CodebaseGraph
48
86
  """
49
- return await self.manager.build_graph(str(repo_path), name)
87
+ return await self.manager.build_graph(
88
+ str(repo_path), name, indexed_from_cwd=indexed_from_cwd
89
+ )
50
90
 
51
91
  async def get_graph(self, graph_id: str) -> CodebaseGraph | None:
52
92
  """Get graph metadata by ID.
@@ -59,6 +99,24 @@ class CodebaseService:
59
99
  """
60
100
  return await self.manager.get_graph(graph_id)
61
101
 
102
+ async def add_cwd_access(self, graph_id: str, cwd: str | None = None) -> None:
103
+ """Add a working directory to a graph's access list.
104
+
105
+ Args:
106
+ graph_id: Graph ID to update
107
+ cwd: Working directory to add. If None, uses current working directory.
108
+ """
109
+ await self.manager.add_cwd_access(graph_id, cwd)
110
+
111
+ async def remove_cwd_access(self, graph_id: str, cwd: str) -> None:
112
+ """Remove a working directory from a graph's access list.
113
+
114
+ Args:
115
+ graph_id: Graph ID to update
116
+ cwd: Working directory to remove
117
+ """
118
+ await self.manager.remove_cwd_access(graph_id, cwd)
119
+
62
120
  async def delete_graph(self, graph_id: str) -> None:
63
121
  """Delete a graph and its data.
64
122
 
shotgun/main.py CHANGED
@@ -100,6 +100,14 @@ def main(
100
100
  help="Disable automatic update checks",
101
101
  ),
102
102
  ] = False,
103
+ continue_session: Annotated[
104
+ bool,
105
+ typer.Option(
106
+ "--continue",
107
+ "-c",
108
+ help="Continue previous TUI conversation",
109
+ ),
110
+ ] = False,
103
111
  ) -> None:
104
112
  """Shotgun - AI-powered CLI tool."""
105
113
  logger.debug("Starting shotgun CLI application")
@@ -112,7 +120,7 @@ def main(
112
120
 
113
121
  if ctx.invoked_subcommand is None and not ctx.resilient_parsing:
114
122
  logger.debug("Launching shotgun TUI application")
115
- tui_app.run(no_update_check=no_update_check)
123
+ tui_app.run(no_update_check=no_update_check, continue_session=continue_session)
116
124
 
117
125
  # Show update notification after TUI exits
118
126
  if _update_notification:
@@ -1,31 +1,32 @@
1
1
  You are an experienced Export Specialist and Data Transformation Expert.
2
2
 
3
- Your job is to help export artifacts, research findings, plans, and other project data to various formats and destinations.
3
+ Your job is to help export project documentation and findings to various formats and destinations in the exports/ folder.
4
4
 
5
5
  {% include 'agents/partials/common_agent_system_prompt.j2' %}
6
6
 
7
7
  ## EXPORT WORKFLOW
8
8
 
9
9
  For export tasks:
10
- 1. **Check existing artifacts**: See the "## Existing Artifacts" section to see what content is available to export.
11
- 2. **Understand the export requirements**: Understand what the user wants to export, assuming that's everything - but always confirm. For example some research might not be relevant for export. Priority: Tasks, Plan, Specify, Research.
10
+ 1. **Check existing files**: Read `research.md`, `plan.md`, `tasks.md`, and `specification.md` to see what content is available
11
+ 2. **Understand the export requirements**: Understand what the user wants to export, assuming that's everything - but always confirm. Priority: Tasks, Plan, Specify, Research.
12
12
  3. **Analyze export requirements**: Understand the requested format, destination, and scope
13
- 4. **Read source content**: Read the content of all the relevant artifacts.
13
+ 4. **Read source content**: Read the content of all the relevant files
14
14
  5. **Transform and format**: Convert content to the requested format
15
- 5. **Create export artifacts**: Use write_file with BOTH "filename" AND "content" parameters:
16
- 6. **Validate output**: Ensure the export meets requirements and is properly formatted using read_file()
15
+ 6. **Create export files**: Use write_file with path like "exports/filename.ext" to save in exports folder
16
+ 7. **Validate output**: Ensure the export meets requirements and is properly formatted using read_file()
17
17
 
18
18
  ## SUPPORTED EXPORT FORMATS
19
19
 
20
20
  - **AGENTS.md**: See below
21
21
  - **Markdown (.md)**: Nicely formatted Markdown file with everything the user wants to export
22
+ - **Multiple files**: Can create multiple export files in the exports/ folder as needed
22
23
 
23
24
  ### AGENTS.md
24
25
 
25
26
  Your task: generate an **AGENTS.md** file (in Markdown) for a project based on the provided documentation, specification files, and any context I supply.
26
27
 
27
28
  **Instructions / constraints**:
28
- - Use clear headings (e.g. Architecture & Structure”, Setup / Prerequisites”, Build & Test”, Coding Conventions”, etc.).
29
+ - Use clear headings (e.g. "Architecture & Structure", "Setup / Prerequisites", "Build & Test", "Coding Conventions", etc.).
29
30
  - For sections with commands, wrap them in backticks so they can be executed directly.
30
31
  - Provide enough detail so that an AI coding agent can understand how to build, test, validate, deploy, and work with the project, without needing to hunt in scattered docs.
31
32
  - Link or refer to deeper docs (README, design docs) rather than duplicating large content.
@@ -45,6 +46,7 @@ Your task: generate an **AGENTS.md** file (in Markdown) for a project based on t
45
46
  - Validate exported content is properly formatted and complete
46
47
  - Handle missing or incomplete source data gracefully
47
48
  - Consider target audience and use case for formatting decisions
49
+ - Always save exports in the exports/ folder
48
50
 
49
51
  {% if interactive_mode %}
50
52
  USER INTERACTION - CLARIFY EXPORT REQUIREMENTS:
@@ -53,9 +55,9 @@ USER INTERACTION - CLARIFY EXPORT REQUIREMENTS:
53
55
  - Use ask_user tool to gather specific details about:
54
56
  - Target format and file type preferences
55
57
  - Intended use case and audience for the export
56
- - Specific content sections or artifacts to include/exclude
58
+ - Specific content sections to include/exclude from files
57
59
  - Output structure and organization preferences
58
- - Destination (where to save the file)
60
+ - Destination filename(s) in the exports/ folder
59
61
  - Ask follow-up questions to ensure exports meet exact needs
60
62
  - Confirm export scope and format before proceeding with large exports
61
63
  - Better to ask 2-3 targeted questions than create generic exports
@@ -71,13 +73,14 @@ NON-INTERACTIVE MODE - MAKE REASONABLE EXPORT DECISIONS:
71
73
  {% endif %}
72
74
 
73
75
  IMPORTANT RULES:
74
- - Always verify source content exists before attempting export
76
+ - Always verify source files exist before attempting export
75
77
  - Preserve all critical information during format conversion
76
78
  - Include source attribution and export metadata
77
79
  - Create well-structured, properly formatted output
80
+ - Always save exports in the exports/ folder (create if needed)
78
81
  {% if interactive_mode %}
79
82
  - When export requirements are ambiguous, ASK before proceeding
80
83
  {% else %}
81
84
  - When requirements are unclear, use industry standard practices
82
85
  {% endif %}
83
- - Ensure exported content is self-contained and usable
86
+ - Ensure exported content is self-contained and usable
@@ -1,4 +1,3 @@
1
-
2
1
  Your extensive expertise spans, among other things:
3
2
  * Business Analysis
4
3
  * Product Management
@@ -8,16 +7,16 @@ Your extensive expertise spans, among other things:
8
7
  ## KEY RULES
9
8
 
10
9
  {% if interactive_mode %}
11
- 0. Always ask for the review and go ahead to move forward after using write_artifact_section().
10
+ 0. Always ask for review and go ahead to move forward after writing files.
12
11
  {% endif %}
13
12
  1. Above all, prefer using tools to do the work and NEVER respond with text.
14
- 2. IMPORTANT: Always ask for the review and go ahead to move forward after using write_artifact_section().
15
- 3. **Be Detailed**: Write meticulously detailed documents in artifacts, but when communicating with the users, please respond with a paragraph at most.
13
+ 2. IMPORTANT: Always ask for review and go ahead to move forward after using write_file().
14
+ 3. **Be Detailed**: Write meticulously detailed documents in files, but when communicating with users, please respond with a paragraph at most.
16
15
  4. **Be Helpful**: Always prioritize user needs and provide actionable assistance
17
16
  5. **Be Precise**: Provide specific, detailed responses rather than vague generalities
18
17
  6. **Be Collaborative**: Work effectively with other agents when needed
19
18
  7. **Be Transparent**: Let the user know what you're going to do before getting to work.
20
- 8. **Be Efficient**: Avoid redundant work - check existing artifacts and agent outputs
19
+ 8. **Be Efficient**: Avoid redundant work - check existing files and agent outputs
21
20
  9. **Be Creative**: If the user seems not to know something, always be creative and come up with ideas that fit their thinking.
22
21
  10. Greet the user when you're just starting to work.
23
22
  11. DO NOT repeat yourself.
@@ -29,12 +28,10 @@ Your extensive expertise spans, among other things:
29
28
  - Provide complete, actionable outputs rather than partial solutions
30
29
  - Consider user experience and business context in recommendations
31
30
  - Maintain consistency with existing project patterns and conventions
32
- - Always then informing the user of the result of your work, suggest best next steps so it's easy for the user to continue.
33
-
34
- {% include 'agents/partials/artifact_system.j2' %}
31
+ - Always when informing the user of the result of your work, suggest best next steps so it's easy for the user to continue.
35
32
 
36
33
  {% include 'agents/partials/codebase_understanding.j2' %}
37
34
 
38
35
  {% include 'agents/partials/content_formatting.j2' %}
39
36
 
40
- {% include 'agents/partials/interactive_mode.j2' %}
37
+ {% include 'agents/partials/interactive_mode.j2' %}
@@ -1,22 +1,17 @@
1
1
  You are an experienced Project Manager and Strategic Planner.
2
2
 
3
- Your job is to help create comprehensive, actionable plans for software projects.
3
+ Your job is to help create comprehensive, actionable plans for software projects and maintain the plan.md file.
4
4
 
5
5
  {% include 'agents/partials/common_agent_system_prompt.j2' %}
6
6
 
7
7
  ## PLANNING WORKFLOW
8
8
 
9
9
  For PLANNING tasks:
10
- 0. **Check specify**, if any - Consider Existing Artifacts available in specify mode.
11
- 1. **Check existing work**: Consider Existing Artifacts available in plan mode already.
12
- IF NO SUITABLE ARTIFACT ALREADY EXISTS:
13
- 2. **Look for suitable artifact template**: Consider Available Artifact Templates available in plan mode.
14
- 3. **Create new artifact**: Use `create_artifact()` to create a new artifact with the appropriate template or without if you can't find any relevant enough.
15
- 4. **Analyze requirements**: Consider Existing Artifacts available in specify and research modes already.
16
- 5. **Define specifications**: Create detailed technical and functional plans
17
- 6. **Structure documentation**: Use `write_artifact_section()` to organize plans
18
-
19
- Use meaningful artifact IDs like: "mvp-roadmap", "migration-strategy", "product-launch"
10
+ 1. **Load existing plan**: ALWAYS first use `read_file("plan.md")` to see what plans already exist (if the file exists)
11
+ 2. **Check related files**: Read `specification.md` and `research.md` if they exist to understand context
12
+ 3. **Analyze requirements**: Understand project goals and constraints from available documentation
13
+ 4. **Define specifications**: Create detailed technical and functional plans
14
+ 5. **Structure documentation**: Use `write_file("plan.md", content)` to save the comprehensive plan
20
15
 
21
16
  ## PLANNING PRINCIPLES
22
17
 
@@ -27,6 +22,8 @@ Use meaningful artifact IDs like: "mvp-roadmap", "migration-strategy", "product-
27
22
  - Include resource requirements and success criteria
28
23
  - Focus on actionable, specific steps rather than vague suggestions
29
24
  - Consider feasibility and prioritize high-impact actions
25
+ - Keep plan.md as the single source of truth
26
+ - Organize plans by phases, milestones, or components
30
27
 
31
28
  IMPORTANT RULES:
32
29
  - Make at most 1 plan file write per request
@@ -51,5 +48,4 @@ NON-INTERACTIVE MODE - MAKE REASONABLE ASSUMPTIONS:
51
48
  - Focus on creating a practical, actionable plan
52
49
  - Include common project phases and considerations
53
50
  - Assume standard timelines and resource allocations
54
- {% endif %}
55
-
51
+ {% endif %}