sourcebot 0.1.0__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 (110) hide show
  1. sourcebot/__init__.py +9 -0
  2. sourcebot/__main__.py +17 -0
  3. sourcebot/bus/__init__.py +4 -0
  4. sourcebot/bus/channel_adapter.py +21 -0
  5. sourcebot/bus/event_bus.py +15 -0
  6. sourcebot/bus/message_models.py +33 -0
  7. sourcebot/bus/outbound_dispatcher.py +15 -0
  8. sourcebot/bus/session_manager.py +20 -0
  9. sourcebot/cli/commands/core/__init__.py +3 -0
  10. sourcebot/cli/commands/core/command_line.py +26 -0
  11. sourcebot/cli/commands/init_commands/__init__.py +3 -0
  12. sourcebot/cli/commands/init_commands/init_global_config.py +30 -0
  13. sourcebot/cli/commands/init_commands/init_workspace_config.py +18 -0
  14. sourcebot/cli/commands/run_commands/__init__.py +3 -0
  15. sourcebot/cli/commands/run_commands/command_line_tool.py +345 -0
  16. sourcebot/cli/commands/run_commands/safe_runner.py +47 -0
  17. sourcebot/cli/main.py +28 -0
  18. sourcebot/config/__init__.py +15 -0
  19. sourcebot/config/base.py +13 -0
  20. sourcebot/config/config_manager.py +367 -0
  21. sourcebot/config/exceptions.py +4 -0
  22. sourcebot/config/global_config.py +55 -0
  23. sourcebot/config/provider_config.py +62 -0
  24. sourcebot/config/workspace_config.py +106 -0
  25. sourcebot/context/__init__.py +5 -0
  26. sourcebot/context/context_builder.py +78 -0
  27. sourcebot/context/identity.py +19 -0
  28. sourcebot/context/message_builder.py +154 -0
  29. sourcebot/context/skill/__init__.py +7 -0
  30. sourcebot/context/skill/skill.py +11 -0
  31. sourcebot/context/skill/skill_context.py +10 -0
  32. sourcebot/context/skill/skill_loader.py +57 -0
  33. sourcebot/context/skill/skill_metadata.py +27 -0
  34. sourcebot/context/skill/skill_requirements.py +25 -0
  35. sourcebot/context/skill/skill_summary.py +31 -0
  36. sourcebot/conversation/__init__.py +2 -0
  37. sourcebot/conversation/service.py +191 -0
  38. sourcebot/docker_sandbox/__init__.py +3 -0
  39. sourcebot/docker_sandbox/docker_sandbox.py +113 -0
  40. sourcebot/llm/__init__.py +3 -0
  41. sourcebot/llm/anthropic/__init__.py +2 -0
  42. sourcebot/llm/anthropic/adapter.py +30 -0
  43. sourcebot/llm/anthropic/anthropic_llm_client.py +38 -0
  44. sourcebot/llm/anthropic/converter.py +59 -0
  45. sourcebot/llm/core/adapter.py +16 -0
  46. sourcebot/llm/core/client.py +16 -0
  47. sourcebot/llm/core/delta.py +12 -0
  48. sourcebot/llm/core/message.py +53 -0
  49. sourcebot/llm/core/message_converter.py +33 -0
  50. sourcebot/llm/core/response.py +30 -0
  51. sourcebot/llm/core/tool.py +7 -0
  52. sourcebot/llm/core/tool_converter.py +30 -0
  53. sourcebot/llm/core/tool_delta_aggregator.py +38 -0
  54. sourcebot/llm/llm_client_factory.py +13 -0
  55. sourcebot/llm/openai/__init__.py +2 -0
  56. sourcebot/llm/openai/adapter.py +27 -0
  57. sourcebot/llm/openai/converter.py +53 -0
  58. sourcebot/llm/openai/openai_llm_client.py +47 -0
  59. sourcebot/logging/__init__.py +3 -0
  60. sourcebot/logging/setup.py +33 -0
  61. sourcebot/memory/__init__.py +5 -0
  62. sourcebot/memory/file_store.py +23 -0
  63. sourcebot/memory/llm_consolidator.py +79 -0
  64. sourcebot/memory/service.py +116 -0
  65. sourcebot/memory/window_policy.py +36 -0
  66. sourcebot/prompt/__init__.py +4 -0
  67. sourcebot/prompt/deeomposer_prompt.py +420 -0
  68. sourcebot/prompt/identity_prompt.py +98 -0
  69. sourcebot/prompt/subagent_prompt.py +25 -0
  70. sourcebot/runtime/__init__.py +3 -0
  71. sourcebot/runtime/agent/__init__.py +3 -0
  72. sourcebot/runtime/agent/agent.py +130 -0
  73. sourcebot/runtime/agent/agent_factory.py +83 -0
  74. sourcebot/runtime/dag/planner/__init__.py +3 -0
  75. sourcebot/runtime/dag/planner/dag_planner.py +26 -0
  76. sourcebot/runtime/dag/planner/execution_scheduler.py +35 -0
  77. sourcebot/runtime/dag/planner/parallelism_optimizer.py +44 -0
  78. sourcebot/runtime/dag/planner/task_decomposer.py +37 -0
  79. sourcebot/runtime/dag/scheduler/__init__.py +3 -0
  80. sourcebot/runtime/dag/scheduler/dag_scheduler.py +319 -0
  81. sourcebot/runtime/dag/scheduler/retry_policy.py +27 -0
  82. sourcebot/runtime/dag/scheduler/run_store.py +58 -0
  83. sourcebot/runtime/dag/scheduler/state_store.py +40 -0
  84. sourcebot/runtime/dag/scheduler/task_graph.py +29 -0
  85. sourcebot/runtime/init_system.py +182 -0
  86. sourcebot/runtime/tool_executor.py +30 -0
  87. sourcebot/security/policy.py +23 -0
  88. sourcebot/session/__init__.py +4 -0
  89. sourcebot/session/jsonl_repository.py +142 -0
  90. sourcebot/session/repository.py +19 -0
  91. sourcebot/session/service.py +44 -0
  92. sourcebot/session/session.py +53 -0
  93. sourcebot/storage/__init__.py +3 -0
  94. sourcebot/storage/rules_loader.py +72 -0
  95. sourcebot/storage/skill_storage.py +51 -0
  96. sourcebot/tools/__init__.py +7 -0
  97. sourcebot/tools/base.py +182 -0
  98. sourcebot/tools/registry.py +81 -0
  99. sourcebot/tools/rule_detail.py +70 -0
  100. sourcebot/tools/rule_list.py +57 -0
  101. sourcebot/tools/shell.py +93 -0
  102. sourcebot/tools/skill_detail.py +61 -0
  103. sourcebot/tools/skill_list.py +68 -0
  104. sourcebot/utils/__init__.py +2 -0
  105. sourcebot/utils/output.py +79 -0
  106. sourcebot-0.1.0.dist-info/METADATA +318 -0
  107. sourcebot-0.1.0.dist-info/RECORD +110 -0
  108. sourcebot-0.1.0.dist-info/WHEEL +5 -0
  109. sourcebot-0.1.0.dist-info/entry_points.txt +2 -0
  110. sourcebot-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,5 @@
1
+ from sourcebot.memory.file_store import FileMemoryStore
2
+ from sourcebot.memory.service import MemoryService
3
+ from sourcebot.memory.llm_consolidator import LLMConsolidator
4
+ from sourcebot.memory.window_policy import WindowMemoryPolicy
5
+ __all__ = ["FileMemoryStore", "MemoryService", "LLMConsolidator", "WindowMemoryPolicy"]
@@ -0,0 +1,23 @@
1
+ # sourcebot/memory/file_store.py
2
+ from pathlib import Path
3
+
4
+
5
+ class FileMemoryStore:
6
+ def __init__(self, workspace: Path):
7
+ self.memory_dir = workspace / "memory"
8
+ self.memory_file = self.memory_dir / "MEMORY.md"
9
+ self.history_file = self.memory_dir / "HISTORY.md"
10
+
11
+ self.memory_dir.mkdir(parents=True, exist_ok=True)
12
+
13
+ def read_long_term(self) -> str:
14
+ if self.memory_file.exists():
15
+ return self.memory_file.read_text(encoding="utf-8")
16
+ return ""
17
+
18
+ def write_long_term(self, content: str) -> None:
19
+ self.memory_file.write_text(content, encoding="utf-8")
20
+
21
+ def append_history(self, entry: str) -> None:
22
+ with open(self.history_file, "a", encoding="utf-8") as f:
23
+ f.write(entry.rstrip() + "\n\n")
@@ -0,0 +1,79 @@
1
+ # sourcebot/memory/llm_consolidator.py
2
+
3
+ import logging
4
+ logger = logging.getLogger(__name__)
5
+ from sourcebot.llm.core.message import Message
6
+ class LLMConsolidator:
7
+ def __init__(
8
+ self,
9
+ llm
10
+ ):
11
+ self.llm = llm
12
+
13
+ async def consolidate(self, current_memory: str, lines: list[str]):
14
+ """
15
+ Returns:
16
+ (history_entry, updated_memory)
17
+ or None if skipped
18
+ """
19
+
20
+ if not lines:
21
+ return None
22
+
23
+ conversation_chunk = "\n".join(lines)
24
+
25
+ prompt = f"""
26
+ You are a memory consolidation engine.
27
+
28
+ Current long-term memory:
29
+ -------------------------
30
+ {current_memory}
31
+
32
+ New conversation chunk:
33
+ -------------------------
34
+ {conversation_chunk}
35
+
36
+ Task:
37
+ 1. Extract important facts, preferences, decisions, architecture insights.
38
+ 2. Merge them into long-term memory.
39
+ 3. Avoid duplication.
40
+ 4. Return TWO SECTIONS:
41
+
42
+ === HISTORY_ENTRY ===
43
+ Short 1-2 paragraph summary of what happened.
44
+
45
+ === UPDATED_MEMORY ===
46
+ Full updated long-term memory document.
47
+ """
48
+ response = await self.conversation_summary(prompt)
49
+
50
+ if "=== HISTORY_ENTRY ===" not in response:
51
+ logger.warning("Consolidation format invalid.")
52
+ return None
53
+
54
+ try:
55
+ history = response.split("=== HISTORY_ENTRY ===")[1] \
56
+ .split("=== UPDATED_MEMORY ===")[0] \
57
+ .strip()
58
+
59
+ updated = response.split("=== UPDATED_MEMORY ===")[1].strip()
60
+
61
+ return history, updated
62
+
63
+ except Exception:
64
+ logger.exception("Failed to parse consolidation result.")
65
+ return None
66
+
67
+ async def conversation_summary(
68
+ self,
69
+ prompt: str,
70
+ ) -> str:
71
+ messages = [
72
+ Message(role = "system", content = "You are a memory consolidation engine."),
73
+ Message(role = "user", content = prompt),
74
+ ]
75
+ response = await self.llm.complete(
76
+ messages,
77
+ tools = None,
78
+ )
79
+ return response.content
@@ -0,0 +1,116 @@
1
+ # sourcebot/memory/service.py
2
+ import logging
3
+
4
+ logger = logging.getLogger(__name__)
5
+
6
+
7
+ class MemoryService:
8
+
9
+ def __init__(self, store, policy, consolidator):
10
+ self.store = store
11
+ self.policy = policy
12
+ self.consolidator = consolidator
13
+
14
+ self._consolidating: set[str] = set()
15
+
16
+
17
+ async def maybe_consolidate(
18
+ self,
19
+ session,
20
+ memory_window: int = 50,
21
+ ):
22
+ """
23
+ Decide whether consolidation should run.
24
+ """
25
+
26
+ if len(session.messages) <= memory_window:
27
+ return
28
+
29
+ if session.key in self._consolidating:
30
+ return
31
+
32
+ self._consolidating.add(session.key)
33
+
34
+ async def _task():
35
+ try:
36
+ await self.consolidate(session, memory_window)
37
+ finally:
38
+ self._consolidating.discard(session.key)
39
+
40
+
41
+ await _task()
42
+
43
+
44
+ # The actual compression logic is executed.
45
+
46
+ async def consolidate(
47
+ self,
48
+ session,
49
+ memory_window = 50,
50
+ archive_all = True,
51
+ ):
52
+
53
+ old_messages, new_last = self.policy.select_messages(
54
+ session.messages,
55
+ session.last_consolidated,
56
+ memory_window,
57
+ archive_all,
58
+ )
59
+ if not old_messages:
60
+ return
61
+
62
+ lines = []
63
+ for m in old_messages:
64
+ if not m.content:
65
+ continue
66
+
67
+ tools_used = m.metadata.get("tools_used", [])
68
+
69
+ tools = (
70
+ f" [tools: {', '.join(tools_used)}]"
71
+ if tools_used
72
+ else ""
73
+ )
74
+
75
+ ts = m.metadata.get("timestamp", "?")
76
+
77
+ lines.append(
78
+ f"[{ts[:16]}] "
79
+ f"{m.role.upper()}{tools}: {m.content}"
80
+ )
81
+
82
+ current_memory = self.store.read_long_term()
83
+
84
+ result = await self.consolidator.consolidate(
85
+ current_memory,
86
+ lines,
87
+ )
88
+ if not result:
89
+ logger.warning("Memory consolidation skipped.")
90
+ return
91
+
92
+ history_entry, memory_update = result
93
+ self.store.append_history(history_entry)
94
+
95
+ if memory_update != current_memory:
96
+ self.store.write_long_term(memory_update)
97
+ session.last_consolidated = new_last
98
+
99
+
100
+
101
+ # /new Dedicated mandatory archiving
102
+ async def consolidate_archived(
103
+ self,
104
+ session_key: str,
105
+ archived_messages: list[dict],
106
+ ):
107
+ """
108
+ Used by /new command to archive everything.
109
+ """
110
+ from sourcebot.session import Session
111
+ temp = Session(key = session_key)
112
+ temp.messages = archived_messages
113
+ await self.consolidate(
114
+ temp,
115
+ archive_all = True,
116
+ )
@@ -0,0 +1,36 @@
1
+ # sourcebot/memory/window_policy.py
2
+ from sourcebot.llm.core.message import Message
3
+ class WindowMemoryPolicy:
4
+ """
5
+ A simple strategy based on window size:
6
+ - Retain the most recent `memory_window` messages
7
+ - Compress the rest
8
+ """
9
+
10
+ def select_messages(
11
+ self,
12
+ messages: list[Message],
13
+ last_consolidated: int,
14
+ memory_window: int,
15
+ archive_all: bool,
16
+ ):
17
+ total = len(messages)
18
+
19
+ if total <= last_consolidated:
20
+ return [], last_consolidated
21
+
22
+ if archive_all:
23
+ old_messages = messages[last_consolidated:]
24
+ return old_messages, total
25
+
26
+ keep_from = max(total - memory_window, 0)
27
+
28
+ start = last_consolidated
29
+ end = min(keep_from, total)
30
+
31
+ if start >= end:
32
+ return [], last_consolidated
33
+
34
+ old_messages = messages[start:end]
35
+
36
+ return old_messages, end
@@ -0,0 +1,4 @@
1
+ from sourcebot.prompt.deeomposer_prompt import DECOMPOSER_PROMPT
2
+ from sourcebot.prompt.subagent_prompt import SUBAGENT_PROMPT
3
+ from sourcebot.prompt.identity_prompt import IDENTITY_PROMPT
4
+ __all__ = ["DECOMPOSER_PROMPT", "SUBAGENT_PROMPT", "IDENTITY_PROMPT"]
@@ -0,0 +1,420 @@
1
+ # sourcebot/prompt/decomposer_prompt.py
2
+
3
+ DECOMPOSER_PROMPT = """You are an advanced software engineering planning agent.
4
+
5
+ Your role is to transform a high-level user request into a structured execution plan
6
+ that can be executed by multiple autonomous agents in parallel.
7
+
8
+ The system executing your plan is a distributed AI engineering runtime similar to:
9
+
10
+ - Devin
11
+ - OpenAI DeepResearch
12
+ - Autonomous IDE agents
13
+
14
+ Your plan must be optimized for reliability, parallel execution, and fault recovery.
15
+
16
+
17
+ --------------------------------------------------
18
+ PRIMARY OBJECTIVE
19
+ --------------------------------------------------
20
+
21
+ Convert the user request into a Directed Acyclic Graph (DAG) of tasks.
22
+
23
+ Each task must be:
24
+
25
+ - atomic
26
+ - independently executable
27
+ - deterministic
28
+ - testable
29
+
30
+
31
+ --------------------------------------------------
32
+ AVAILABLE RULES AND SKILLS
33
+ --------------------------------------------------
34
+
35
+ The following rules and skills are available to guide task execution:
36
+
37
+ {rules}
38
+
39
+ Available skills for agents:
40
+ {skills_summary}
41
+
42
+ --------------------------------------------------
43
+ PLANNING PRINCIPLES
44
+ --------------------------------------------------
45
+
46
+ Follow these principles strictly.
47
+
48
+ 1. ATOMIC TASKS
49
+
50
+ Each task should perform exactly ONE concrete action.
51
+
52
+ Good examples:
53
+
54
+ - locate authentication module
55
+ - implement rate limiting middleware
56
+ - write unit tests for login handler
57
+ - run pytest for authentication module
58
+
59
+ Bad examples:
60
+
61
+ - analyze system
62
+ - improve architecture
63
+ - fix bugs
64
+ - refactor code
65
+
66
+
67
+ 2. PARALLEL EXECUTION
68
+
69
+ Maximize tasks that can run in parallel.
70
+
71
+ Avoid unnecessary dependencies.
72
+
73
+ Only add dependencies when strictly required.
74
+
75
+
76
+ 3. DAG STRUCTURE
77
+
78
+ The output must form a Directed Acyclic Graph.
79
+
80
+ Each task should specify its dependencies explicitly.
81
+
82
+ Use task IDs to define dependencies.
83
+
84
+
85
+ 4. ENGINEERING ACTIONS
86
+
87
+ Tasks should correspond to real engineering operations such as:
88
+
89
+ - searching code
90
+ - modifying files
91
+ - implementing features
92
+ - writing tests
93
+ - running tests
94
+ - verifying behavior
95
+
96
+
97
+ 5. REPOSITORY AWARENESS
98
+
99
+ The system has access to:
100
+
101
+ - repository semantic index
102
+ - code search
103
+ - file editor
104
+ - test runner
105
+ - sandbox execution environment
106
+
107
+ Therefore tasks may include:
108
+
109
+ - search repository
110
+ - inspect implementation
111
+ - modify specific files
112
+ - run tests
113
+
114
+
115
+ 6. FAILURE TOLERANCE
116
+
117
+ Your plan must tolerate failures.
118
+
119
+ When possible:
120
+
121
+ - isolate risky tasks
122
+ - ensure later tasks can retry safely
123
+ - avoid cascading failures
124
+
125
+
126
+ 7. RETRY STRATEGY
127
+
128
+ Some tasks may fail due to:
129
+
130
+ - syntax errors
131
+ - failing tests
132
+ - runtime issues
133
+
134
+ For tasks that involve execution or testing:
135
+
136
+ - include retry-friendly structure
137
+ - ensure fixes can be applied without rerunning the entire plan
138
+
139
+
140
+ --------------------------------------------------
141
+ TASK DESIGN RULES
142
+ --------------------------------------------------
143
+
144
+ Each task must include the following fields:
145
+
146
+ id
147
+ title
148
+ description
149
+ depends_on
150
+ parallelizable
151
+ retryable
152
+ context
153
+
154
+
155
+ Field definitions:
156
+
157
+
158
+ id
159
+
160
+ Unique task identifier.
161
+
162
+ Example:
163
+
164
+ task_1
165
+ task_2
166
+
167
+
168
+ title
169
+
170
+ Short summary of the task.
171
+
172
+
173
+ description
174
+
175
+ Detailed description of the action that the execution agent must perform.
176
+
177
+
178
+ depends_on
179
+
180
+ List of task IDs that must complete before this task runs.
181
+
182
+ Example:
183
+
184
+ []
185
+
186
+ or
187
+
188
+ ["task_1"]
189
+
190
+
191
+ parallelizable
192
+
193
+ Boolean value.
194
+
195
+ true → task can run in parallel with others
196
+ false → task must run sequentially
197
+
198
+
199
+ retryable
200
+
201
+ Boolean value.
202
+
203
+ true → task can be safely retried
204
+ false → retry may cause inconsistent state
205
+
206
+
207
+ context
208
+
209
+ Object containing task-specific execution context with the following structure:
210
+
211
+ {{
212
+ "rules": [
213
+ "List of specific rules from the global ruleset that apply to this task",
214
+ "Each rule should be directly relevant to the task's execution"
215
+ ],
216
+ "skills": [
217
+ "List of specific skills needed to execute this task",
218
+ "Skills should be selected from the available skills_sum"
219
+ ],
220
+ "environment": {{
221
+ "required_tools": ["List of tools needed", "e.g., python", "go", "docker"],
222
+ "working_dir": "Suggested working directory if applicable",
223
+ "env_vars": {{
224
+ "KEY": "Environment variables needed"
225
+ }}
226
+ }},
227
+ "inherited_context": {{
228
+ "project_type": "Type of project (e.g., go_module, python_package)",
229
+ "quality_standards": ["List of quality standards to apply"],
230
+ "critical_files": ["Files that are critical to this task"]
231
+ }}
232
+ }}
233
+
234
+ When selecting rules and skills:
235
+ - Choose rules that directly constrain or guide the task execution
236
+ - Select skills that are essential for completing the task
237
+ - Include only the most relevant items, not everything from the global list
238
+
239
+
240
+ --------------------------------------------------
241
+ SELF VALIDATION
242
+ --------------------------------------------------
243
+
244
+ Before returning the plan, validate the following:
245
+
246
+ 1. The plan must not contain cycles.
247
+
248
+ 2. Tasks should be atomic.
249
+
250
+ 3. Parallelizable tasks should not depend on each other unnecessarily.
251
+
252
+ 4. Tasks that modify the same files should generally not run in parallel.
253
+
254
+ 5. Execution tasks should depend on implementation tasks.
255
+
256
+ 6. Testing tasks should depend on code changes.
257
+
258
+ 7. Each task must have appropriate rules and skills assigned in its context.
259
+
260
+ 8. The assigned rules and skills must be relevant to the task description.
261
+
262
+
263
+ --------------------------------------------------
264
+ PLAN OPTIMIZATION
265
+ --------------------------------------------------
266
+
267
+ You should optimize the plan for:
268
+
269
+ - minimal execution time
270
+ - maximal parallelism
271
+ - safe retry
272
+ - deterministic behavior
273
+
274
+
275
+ --------------------------------------------------
276
+ OUTPUT FORMAT
277
+ --------------------------------------------------
278
+
279
+ Return ONLY valid JSON.
280
+
281
+ Do not include explanations.
282
+
283
+ The JSON must follow this structure:
284
+
285
+ {{
286
+ "tasks": [
287
+ {{
288
+ "id": "task_1",
289
+ "title": "Locate authentication module",
290
+ "description": "Search the repository to identify files responsible for authentication logic",
291
+ "depends_on": [],
292
+ "parallelizable": true,
293
+ "retryable": true,
294
+ "context": {{
295
+ "rules": ["Always use semantic search for code location", "Document found files"],
296
+ "skills": ["code_search", "file_system"],
297
+ "environment": {{
298
+ "required_tools": ["git"],
299
+ "working_dir": "/repo"
300
+ }},
301
+ "inherited_context": {{
302
+ "project_type": "web_application",
303
+ "critical_files": ["auth.py", "routes.py"]
304
+ }}
305
+ }}
306
+ }},
307
+ {{
308
+ "id": "task_2",
309
+ "title": "Inspect login endpoint",
310
+ "description": "Locate the login endpoint implementation and analyze how authentication is handled",
311
+ "depends_on": ["task_1"],
312
+ "parallelizable": false,
313
+ "retryable": true,
314
+ "context": {{
315
+ "rules": ["Analyze code for security vulnerabilities", "Document authentication flow"],
316
+ "skills": ["code_analysis", "security_review"],
317
+ "environment": {{
318
+ "required_tools": ["python"],
319
+ "working_dir": "/repo"
320
+ }},
321
+ "inherited_context": {{
322
+ "project_type": "web_application",
323
+ "quality_standards": ["security_review_required"]
324
+ }}
325
+ }}
326
+ }}
327
+ ]
328
+ }}
329
+
330
+
331
+ --------------------------------------------------
332
+ EXAMPLE PLAN
333
+ --------------------------------------------------
334
+
335
+ User request:
336
+
337
+ "Add rate limiting to the login endpoint"
338
+
339
+
340
+ Available rules:
341
+ - "Always add tests for new functionality"
342
+ - "Use built-in framework middleware when available"
343
+ - "Document all API changes"
344
+
345
+ Available skills:
346
+ - code_search: Search and locate code files
347
+ - file_editor: Create and modify files
348
+ - test_runner: Execute test suites
349
+ - middleware_implementer: Add middleware to web frameworks
350
+
351
+ Example output:
352
+
353
+ {{
354
+ "tasks": [
355
+ {{
356
+ "id": "task_1",
357
+ "title": "Locate authentication module",
358
+ "description": "Search the repository to identify files responsible for authentication logic",
359
+ "depends_on": [],
360
+ "parallelizable": true,
361
+ "retryable": true,
362
+ "context": {{
363
+ "rules": ["Use built-in framework middleware when available"],
364
+ "skills": ["code_search"],
365
+ "environment": {{
366
+ "required_tools": ["git"],
367
+ "working_dir": "/repo"
368
+ }},
369
+ "inherited_context": {{
370
+ "project_type": "web_application",
371
+ "critical_files": ["auth.py", "routes.py"]
372
+ }}
373
+ }}
374
+ }},
375
+ {{
376
+ "id": "task_2",
377
+ "title": "Implement rate limiting middleware",
378
+ "description": "Add middleware to limit repeated login attempts using the framework's built-in rate limiting",
379
+ "depends_on": ["task_1"],
380
+ "parallelizable": false,
381
+ "retryable": true,
382
+ "context": {{
383
+ "rules": ["Always add tests for new functionality", "Document all API changes"],
384
+ "skills": ["file_editor", "middleware_implementer"],
385
+ "environment": {{
386
+ "required_tools": ["python", "flask"],
387
+ "working_dir": "/repo",
388
+ "env_vars": {{
389
+ "RATE_LIMIT": "5/minute"
390
+ }}
391
+ }},
392
+ "inherited_context": {{
393
+ "project_type": "flask_application",
394
+ "quality_standards": ["test_coverage_required"]
395
+ }}
396
+ }}
397
+ }},
398
+ {{
399
+ "id": "task_3",
400
+ "title": "Write tests for rate limiting",
401
+ "description": "Create unit tests verifying login rate limiting behavior with multiple failed attempts",
402
+ "depends_on": ["task_2"],
403
+ "parallelizable": true,
404
+ "retryable": true,
405
+ "context": {{
406
+ "rules": ["Always add tests for new functionality"],
407
+ "skills": ["test_runner"],
408
+ "environment": {{
409
+ "required_tools": ["python", "pytest"],
410
+ "working_dir": "/repo/tests"
411
+ }},
412
+ "inherited_context": {{
413
+ "project_type": "flask_application",
414
+ "critical_files": ["test_auth.py"]
415
+ }}
416
+ }}
417
+ }}
418
+ ]
419
+ }}
420
+ """