deepagents-cli 0.0.3__py3-none-any.whl → 0.0.4__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 deepagents-cli might be problematic. Click here for more details.

Files changed (41) hide show
  1. deepagents_cli/__init__.py +5 -0
  2. deepagents_cli/__main__.py +6 -0
  3. deepagents_cli/agent.py +267 -0
  4. deepagents_cli/cli.py +13 -0
  5. deepagents_cli/commands.py +86 -0
  6. deepagents_cli/config.py +138 -0
  7. deepagents_cli/execution.py +644 -0
  8. deepagents_cli/file_ops.py +347 -0
  9. deepagents_cli/input.py +249 -0
  10. deepagents_cli/main.py +217 -0
  11. deepagents_cli/py.typed +0 -0
  12. deepagents_cli/tools.py +140 -0
  13. deepagents_cli/ui.py +455 -0
  14. deepagents_cli-0.0.4.dist-info/METADATA +18 -0
  15. deepagents_cli-0.0.4.dist-info/RECORD +18 -0
  16. deepagents_cli-0.0.4.dist-info/entry_points.txt +3 -0
  17. deepagents_cli-0.0.4.dist-info/top_level.txt +1 -0
  18. deepagents/__init__.py +0 -7
  19. deepagents/cli.py +0 -567
  20. deepagents/default_agent_prompt.md +0 -64
  21. deepagents/graph.py +0 -144
  22. deepagents/memory/__init__.py +0 -17
  23. deepagents/memory/backends/__init__.py +0 -15
  24. deepagents/memory/backends/composite.py +0 -250
  25. deepagents/memory/backends/filesystem.py +0 -330
  26. deepagents/memory/backends/state.py +0 -206
  27. deepagents/memory/backends/store.py +0 -351
  28. deepagents/memory/backends/utils.py +0 -319
  29. deepagents/memory/protocol.py +0 -164
  30. deepagents/middleware/__init__.py +0 -13
  31. deepagents/middleware/agent_memory.py +0 -207
  32. deepagents/middleware/filesystem.py +0 -615
  33. deepagents/middleware/patch_tool_calls.py +0 -44
  34. deepagents/middleware/subagents.py +0 -481
  35. deepagents/pretty_cli.py +0 -289
  36. deepagents_cli-0.0.3.dist-info/METADATA +0 -551
  37. deepagents_cli-0.0.3.dist-info/RECORD +0 -24
  38. deepagents_cli-0.0.3.dist-info/entry_points.txt +0 -2
  39. deepagents_cli-0.0.3.dist-info/licenses/LICENSE +0 -21
  40. deepagents_cli-0.0.3.dist-info/top_level.txt +0 -1
  41. {deepagents_cli-0.0.3.dist-info → deepagents_cli-0.0.4.dist-info}/WHEEL +0 -0
deepagents/cli.py DELETED
@@ -1,567 +0,0 @@
1
- #!/usr/bin/env python3
2
- import argparse
3
- import asyncio
4
- import os
5
- import subprocess
6
- import platform
7
- import requests
8
- from typing import Dict, Any, Union, Literal
9
- from pathlib import Path
10
-
11
- from tavily import TavilyClient
12
- from deepagents import create_deep_agent
13
- from langgraph.checkpoint.memory import InMemorySaver
14
- from langchain.agents.middleware import ShellToolMiddleware, HostExecutionPolicy
15
-
16
- from rich.console import Console
17
- from rich.markdown import Markdown
18
- from rich.panel import Panel
19
- from rich.spinner import Spinner
20
- from deepagents.memory.backends.filesystem import FilesystemBackend
21
- from deepagents.memory.backends import CompositeBackend
22
- from deepagents.middleware.agent_memory import AgentMemoryMiddleware
23
- from pathlib import Path
24
- import shutil
25
- from rich import box
26
-
27
- import dotenv
28
-
29
- dotenv.load_dotenv()
30
-
31
- COLORS = {
32
- "primary": "#10b981",
33
- "dim": "#6b7280",
34
- "user": "#ffffff",
35
- "agent": "#10b981",
36
- "thinking": "#34d399",
37
- "tool": "#fbbf24",
38
- }
39
-
40
- DEEP_AGENTS_ASCII = """
41
- ██████╗ ███████╗ ███████╗ ██████╗
42
- ██╔══██╗ ██╔════╝ ██╔════╝ ██╔══██╗
43
- ██║ ██║ █████╗ █████╗ ██████╔╝
44
- ██║ ██║ ██╔══╝ ██╔══╝ ██╔═══╝
45
- ██████╔╝ ███████╗ ███████╗ ██║
46
- ╚═════╝ ╚══════╝ ╚══════╝ ╚═╝
47
-
48
- █████╗ ██████╗ ███████╗ ███╗ ██╗ ████████╗ ███████╗
49
- ██╔══██╗ ██╔════╝ ██╔════╝ ████╗ ██║ ╚══██╔══╝ ██╔════╝
50
- ███████║ ██║ ███╗ █████╗ ██╔██╗ ██║ ██║ ███████╗
51
- ██╔══██║ ██║ ██║ ██╔══╝ ██║╚██╗██║ ██║ ╚════██║
52
- ██║ ██║ ╚██████╔╝ ███████╗ ██║ ╚████║ ██║ ███████║
53
- ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═══╝ ╚═╝ ╚══════╝
54
- """
55
-
56
- console = Console()
57
-
58
- tavily_client = TavilyClient(api_key=os.environ.get("TAVILY_API_KEY")) if os.environ.get("TAVILY_API_KEY") else None
59
-
60
-
61
- def http_request(
62
- url: str,
63
- method: str = "GET",
64
- headers: Dict[str, str] = None,
65
- data: Union[str, Dict] = None,
66
- params: Dict[str, str] = None,
67
- timeout: int = 30,
68
- ) -> Dict[str, Any]:
69
- """
70
- Make HTTP requests to APIs and web services.
71
-
72
- Args:
73
- url: Target URL
74
- method: HTTP method (GET, POST, PUT, DELETE, etc.)
75
- headers: HTTP headers to include
76
- data: Request body data (string or dict)
77
- params: URL query parameters
78
- timeout: Request timeout in seconds
79
-
80
- Returns:
81
- Dictionary with response data including status, headers, and content
82
- """
83
- try:
84
- kwargs = {"url": url, "method": method.upper(), "timeout": timeout}
85
-
86
- if headers:
87
- kwargs["headers"] = headers
88
- if params:
89
- kwargs["params"] = params
90
- if data:
91
- if isinstance(data, dict):
92
- kwargs["json"] = data
93
- else:
94
- kwargs["data"] = data
95
-
96
- response = requests.request(**kwargs)
97
-
98
- try:
99
- content = response.json()
100
- except:
101
- content = response.text
102
-
103
- return {
104
- "success": response.status_code < 400,
105
- "status_code": response.status_code,
106
- "headers": dict(response.headers),
107
- "content": content,
108
- "url": response.url,
109
- }
110
-
111
- except requests.exceptions.Timeout:
112
- return {
113
- "success": False,
114
- "status_code": 0,
115
- "headers": {},
116
- "content": f"Request timed out after {timeout} seconds",
117
- "url": url,
118
- }
119
- except requests.exceptions.RequestException as e:
120
- return {
121
- "success": False,
122
- "status_code": 0,
123
- "headers": {},
124
- "content": f"Request error: {str(e)}",
125
- "url": url,
126
- }
127
- except Exception as e:
128
- return {
129
- "success": False,
130
- "status_code": 0,
131
- "headers": {},
132
- "content": f"Error making request: {str(e)}",
133
- "url": url,
134
- }
135
-
136
-
137
- def web_search(
138
- query: str,
139
- max_results: int = 5,
140
- topic: Literal["general", "news", "finance"] = "general",
141
- include_raw_content: bool = False,
142
- ):
143
- """Search the web using Tavily for programming-related information."""
144
- if tavily_client is None:
145
- return {
146
- "error": "Tavily API key not configured. Please set TAVILY_API_KEY environment variable.",
147
- "query": query
148
- }
149
-
150
- try:
151
- search_docs = tavily_client.search(
152
- query,
153
- max_results=max_results,
154
- include_raw_content=include_raw_content,
155
- topic=topic,
156
- )
157
- return search_docs
158
- except Exception as e:
159
- return {
160
- "error": f"Web search error: {str(e)}",
161
- "query": query
162
- }
163
-
164
-
165
- def get_default_coding_instructions() -> str:
166
- """Get the default coding agent instructions.
167
-
168
- These are the immutable base instructions that cannot be modified by the agent.
169
- Long-term memory (agent.md) is handled separately by the middleware.
170
- """
171
- default_prompt_path = Path(__file__).parent / "default_agent_prompt.md"
172
- return default_prompt_path.read_text()
173
-
174
-
175
- config = {"recursion_limit": 1000}
176
-
177
- MAX_ARG_LENGTH = 150
178
-
179
-
180
- def truncate_value(value: str, max_length: int = MAX_ARG_LENGTH) -> str:
181
- """Truncate a string value if it exceeds max_length."""
182
- if len(value) > max_length:
183
- return value[:max_length] + "..."
184
- return value
185
-
186
-
187
- def execute_task(user_input: str, agent, assistant_id: str | None):
188
- """Execute any task by passing it directly to the AI agent."""
189
- console.print()
190
-
191
- config = {
192
- "configurable": {"thread_id": "main"},
193
- "metadata": {"assistant_id": assistant_id} if assistant_id else {}
194
- }
195
-
196
- has_responded = False
197
- current_text = ""
198
- printed_tool_calls_after_text = False
199
-
200
- status = console.status(f"[bold {COLORS['thinking']}]Agent is thinking...", spinner="dots")
201
- status.start()
202
- spinner_active = True
203
-
204
- tool_icons = {
205
- "read_file": "📖",
206
- "write_file": "✏️",
207
- "edit_file": "✂️",
208
- "ls": "📁",
209
- "glob": "🔍",
210
- "grep": "🔎",
211
- "shell": "⚡",
212
- "web_search": "🌐",
213
- "http_request": "🌍",
214
- "task": "🤖",
215
- "write_todos": "📋",
216
- }
217
-
218
- for _, chunk in agent.stream(
219
- {"messages": [{"role": "user", "content": user_input}]},
220
- stream_mode="updates",
221
- subgraphs=True,
222
- config=config,
223
- durability="exit",
224
- ):
225
- chunk_data = list(chunk.values())[0]
226
- if not chunk_data or "messages" not in chunk_data:
227
- continue
228
-
229
- last_message = chunk_data["messages"][-1]
230
- message_role = getattr(last_message, "type", None)
231
- message_content = getattr(last_message, "content", None)
232
-
233
- # Skip tool results
234
- if message_role == "tool":
235
- continue
236
-
237
- # Handle AI messages
238
- if message_role == "ai":
239
- # First, extract and display text content
240
- text_content = ""
241
-
242
- if isinstance(message_content, str):
243
- text_content = message_content
244
- elif isinstance(message_content, list):
245
- for block in message_content:
246
- if isinstance(block, dict) and block.get("type") == "text":
247
- text_content = block.get("text", "")
248
- break
249
-
250
- if text_content.strip():
251
- if spinner_active:
252
- status.stop()
253
- spinner_active = False
254
-
255
- if not has_responded:
256
- console.print("... ", style=COLORS["agent"], end="", markup=False)
257
- has_responded = True
258
- printed_tool_calls_after_text = False
259
-
260
- if text_content != current_text:
261
- new_text = text_content[len(current_text):]
262
- console.print(new_text, style=COLORS["agent"], end="", markup=False)
263
- current_text = text_content
264
- printed_tool_calls_after_text = False
265
-
266
- # Then, handle tool calls from tool_calls attribute
267
- tool_calls = getattr(last_message, "tool_calls", None)
268
- if tool_calls:
269
- # If we've printed text, ensure tool calls go on new line
270
- if has_responded and current_text and not printed_tool_calls_after_text:
271
- console.print()
272
- printed_tool_calls_after_text = True
273
-
274
- for tool_call in tool_calls:
275
- tool_name = tool_call.get("name", "unknown")
276
- tool_args = tool_call.get("args", {})
277
-
278
- icon = tool_icons.get(tool_name, "🔧")
279
- args_str = ", ".join(
280
- f"{k}={truncate_value(str(v), 50)}" for k, v in tool_args.items()
281
- )
282
-
283
- if spinner_active:
284
- status.stop()
285
- console.print(f" {icon} {tool_name}({args_str})", style=f"dim {COLORS['tool']}")
286
- if spinner_active:
287
- status.start()
288
-
289
- # Handle tool calls from content blocks (alternative format) - only if not already handled
290
- elif isinstance(message_content, list):
291
- has_tool_use = False
292
- for block in message_content:
293
- if isinstance(block, dict) and block.get("type") == "tool_use":
294
- has_tool_use = True
295
- break
296
-
297
- if has_tool_use:
298
- # If we've printed text, ensure tool calls go on new line
299
- if has_responded and current_text and not printed_tool_calls_after_text:
300
- console.print()
301
- printed_tool_calls_after_text = True
302
-
303
- for block in message_content:
304
- if isinstance(block, dict) and block.get("type") == "tool_use":
305
- tool_name = block.get("name", "unknown")
306
- tool_input = block.get("input", {})
307
-
308
- icon = tool_icons.get(tool_name, "🔧")
309
- args = ", ".join(
310
- f"{k}={truncate_value(str(v), 50)}" for k, v in tool_input.items()
311
- )
312
-
313
- if spinner_active:
314
- status.stop()
315
- console.print(f" {icon} {tool_name}({args})", style=f"dim {COLORS['tool']}")
316
- if spinner_active:
317
- status.start()
318
-
319
- if spinner_active:
320
- status.stop()
321
-
322
- if has_responded:
323
- console.print()
324
- console.print()
325
-
326
-
327
- async def simple_cli(agent, assistant_id: str | None):
328
- """Main CLI loop."""
329
- console.clear()
330
- console.print(DEEP_AGENTS_ASCII, style=f"bold {COLORS['primary']}")
331
- console.print()
332
-
333
- if tavily_client is None:
334
- console.print(f"[yellow]⚠ Web search disabled:[/yellow] TAVILY_API_KEY not found.", style=COLORS["dim"])
335
- console.print(f" To enable web search, set your Tavily API key:", style=COLORS["dim"])
336
- console.print(f" export TAVILY_API_KEY=your_api_key_here", style=COLORS["dim"])
337
- console.print(f" Or add it to your .env file. Get your key at: https://tavily.com", style=COLORS["dim"])
338
- console.print()
339
-
340
- console.print("... Ready to code! What would you like to build?", style=COLORS["agent"])
341
- console.print()
342
- console.print(f" Tip: Type 'quit' to exit", style=f"dim {COLORS['dim']}")
343
- console.print()
344
-
345
- while True:
346
- try:
347
- console.print(f"> ", style=COLORS["user"], end="")
348
- user_input = input().strip()
349
- except EOFError:
350
- break
351
- except KeyboardInterrupt:
352
- console.print()
353
- break
354
-
355
- if not user_input:
356
- continue
357
-
358
- if user_input.lower() in ["quit", "exit", "q"]:
359
- console.print(f"\nGoodbye!", style=COLORS["primary"])
360
- break
361
-
362
- execute_task(user_input, agent, assistant_id)
363
-
364
-
365
- def list_agents():
366
- """List all available agents."""
367
- agents_dir = Path.home() / ".deepagents"
368
-
369
- if not agents_dir.exists() or not any(agents_dir.iterdir()):
370
- console.print("[yellow]No agents found.[/yellow]")
371
- console.print(f"[dim]Agents will be created in ~/.deepagents/ when you first use them.[/dim]", style=COLORS["dim"])
372
- return
373
-
374
- console.print(f"\n[bold]Available Agents:[/bold]\n", style=COLORS["primary"])
375
-
376
- for agent_path in sorted(agents_dir.iterdir()):
377
- if agent_path.is_dir():
378
- agent_name = agent_path.name
379
- agent_md = agent_path / "agent.md"
380
-
381
- if agent_md.exists():
382
- console.print(f" • [bold]{agent_name}[/bold]", style=COLORS["primary"])
383
- console.print(f" {agent_path}", style=COLORS["dim"])
384
- else:
385
- console.print(f" • [bold]{agent_name}[/bold] [dim](incomplete)[/dim]", style=COLORS["tool"])
386
- console.print(f" {agent_path}", style=COLORS["dim"])
387
-
388
- console.print()
389
-
390
-
391
- def reset_agent(agent_name: str, source_agent: str = None):
392
- """Reset an agent to default or copy from another agent."""
393
- agents_dir = Path.home() / ".deepagents"
394
- agent_dir = agents_dir / agent_name
395
-
396
- if source_agent:
397
- source_dir = agents_dir / source_agent
398
- source_md = source_dir / "agent.md"
399
-
400
- if not source_md.exists():
401
- console.print(f"[bold red]Error:[/bold red] Source agent '{source_agent}' not found or has no agent.md")
402
- return
403
-
404
- source_content = source_md.read_text()
405
- action_desc = f"contents of agent '{source_agent}'"
406
- else:
407
- source_content = get_default_coding_instructions()
408
- action_desc = "default"
409
-
410
- if agent_dir.exists():
411
- shutil.rmtree(agent_dir)
412
- console.print(f"Removed existing agent directory: {agent_dir}", style=COLORS["tool"])
413
-
414
- agent_dir.mkdir(parents=True, exist_ok=True)
415
- agent_md = agent_dir / "agent.md"
416
- agent_md.write_text(source_content)
417
-
418
- console.print(f"✓ Agent '{agent_name}' reset to {action_desc}", style=COLORS["primary"])
419
- console.print(f"Location: {agent_dir}\n", style=COLORS["dim"])
420
-
421
-
422
- def show_help():
423
- """Show help information."""
424
- console.print()
425
- console.print(DEEP_AGENTS_ASCII, style=f"bold {COLORS['primary']}")
426
- console.print()
427
-
428
- console.print("[bold]Usage:[/bold]", style=COLORS["primary"])
429
- console.print(" deepagents [--agent NAME] Start interactive session")
430
- console.print(" deepagents list List all available agents")
431
- console.print(" deepagents reset --agent AGENT Reset agent to default prompt")
432
- console.print(" deepagents reset --agent AGENT --target SOURCE Reset agent to copy of another agent")
433
- console.print(" deepagents help Show this help message")
434
- console.print()
435
-
436
- console.print("[bold]Examples:[/bold]", style=COLORS["primary"])
437
- console.print(" deepagents # Start with default agent", style=COLORS["dim"])
438
- console.print(" deepagents --agent mybot # Start with agent named 'mybot'", style=COLORS["dim"])
439
- console.print(" deepagents list # List all agents", style=COLORS["dim"])
440
- console.print(" deepagents reset --agent mybot # Reset mybot to default", style=COLORS["dim"])
441
- console.print(" deepagents reset --agent mybot --target other # Reset mybot to copy of 'other' agent", style=COLORS["dim"])
442
- console.print()
443
-
444
- console.print("[bold]Long-term Memory:[/bold]", style=COLORS["primary"])
445
- console.print(" By default, long-term memory is ENABLED using agent name 'agent'.", style=COLORS["dim"])
446
- console.print(" Memory includes:", style=COLORS["dim"])
447
- console.print(" - Persistent agent.md file with your instructions", style=COLORS["dim"])
448
- console.print(" - /memories/ folder for storing context across sessions", style=COLORS["dim"])
449
- console.print()
450
-
451
- console.print("[bold]Agent Storage:[/bold]", style=COLORS["primary"])
452
- console.print(" Agents are stored in: ~/.deepagents/AGENT_NAME/", style=COLORS["dim"])
453
- console.print(" Each agent has an agent.md file containing its prompt", style=COLORS["dim"])
454
- console.print()
455
-
456
- console.print("[bold]Interactive Commands:[/bold]", style=COLORS["primary"])
457
- console.print(" quit, exit, q Exit the session", style=COLORS["dim"])
458
- console.print()
459
-
460
-
461
- def parse_args():
462
- """Parse command line arguments."""
463
- parser = argparse.ArgumentParser(
464
- description="DeepAgents - AI Coding Assistant",
465
- formatter_class=argparse.RawDescriptionHelpFormatter,
466
- add_help=False,
467
- )
468
-
469
- subparsers = parser.add_subparsers(dest="command", help="Command to run")
470
-
471
- # List command
472
- subparsers.add_parser("list", help="List all available agents")
473
-
474
- # Help command
475
- subparsers.add_parser("help", help="Show help information")
476
-
477
- # Reset command
478
- reset_parser = subparsers.add_parser("reset", help="Reset an agent")
479
- reset_parser.add_argument("--agent", required=True, help="Name of agent to reset")
480
- reset_parser.add_argument("--target", dest="source_agent", help="Copy prompt from another agent")
481
-
482
- # Default interactive mode
483
- parser.add_argument(
484
- "--agent",
485
- default="agent",
486
- help="Agent identifier for separate memory stores (default: agent).",
487
- )
488
-
489
- return parser.parse_args()
490
-
491
-
492
- async def main(assistant_id: str):
493
- """Main entry point."""
494
-
495
- # Create agent with conditional tools
496
- tools = [http_request]
497
- if tavily_client is not None:
498
- tools.append(web_search)
499
-
500
- shell_middleware = ShellToolMiddleware(
501
- workspace_root=os.getcwd(),
502
- execution_policy=HostExecutionPolicy()
503
- )
504
-
505
- # For long-term memory, point to ~/.deepagents/AGENT_NAME/ with /memories/ prefix
506
- agent_dir = Path.home() / ".deepagents" / assistant_id
507
- agent_dir.mkdir(parents=True, exist_ok=True)
508
- agent_md = agent_dir / "agent.md"
509
- if not agent_md.exists():
510
- source_content = get_default_coding_instructions()
511
- agent_md.write_text(source_content)
512
-
513
- # Long-term backend - rooted at agent directory
514
- # This handles both /memories/ files and /agent.md
515
- long_term_backend = FilesystemBackend(root_dir=agent_dir, virtual_mode=True)
516
-
517
- # Composite backend: current working directory for default, agent directory for /memories/
518
- backend = CompositeBackend(
519
- default=FilesystemBackend(),
520
- routes={"/memories/": long_term_backend}
521
- )
522
-
523
- # Use the same backend for agent memory middleware
524
- agent_middleware = [AgentMemoryMiddleware(backend=long_term_backend, memory_path="/memories/"), shell_middleware]
525
- system_prompt = f"""### Current Working Directory
526
-
527
- The filesystem backend is currently operating in: `{Path.cwd()}`"""
528
-
529
- agent = create_deep_agent(
530
- system_prompt=system_prompt,
531
- tools=tools,
532
- memory_backend=backend,
533
- middleware=agent_middleware,
534
- ).with_config(config)
535
-
536
- agent.checkpointer = InMemorySaver()
537
-
538
- try:
539
- await simple_cli(agent, assistant_id)
540
- except KeyboardInterrupt:
541
- console.print(f"\n\nGoodbye!", style=COLORS["primary"])
542
- except Exception as e:
543
- console.print(f"\n[bold red]❌ Error:[/bold red] {e}\n")
544
-
545
-
546
- def cli_main():
547
- """Entry point for console script."""
548
- args = parse_args()
549
-
550
- if args.command == "help":
551
- show_help()
552
- elif args.command == "list":
553
- list_agents()
554
- elif args.command == "reset":
555
- reset_agent(args.agent, args.source_agent)
556
- else:
557
- if not os.environ.get("ANTHROPIC_API_KEY"):
558
- console.print("[bold red]Error:[/bold red] ANTHROPIC_API_KEY environment variable is not set.")
559
- console.print("Please set your Anthropic API key:")
560
- console.print(" export ANTHROPIC_API_KEY=your_api_key_here")
561
- console.print("\nOr add it to your .env file.")
562
- return
563
- asyncio.run(main(args.agent))
564
-
565
-
566
- if __name__ == "__main__":
567
- cli_main()
@@ -1,64 +0,0 @@
1
- You are an AI assistant that helps users with various tasks including coding, research, and analysis.
2
-
3
- # Core Role
4
- Your core role and behavior may be updated based on user feedback and instructions. When a user tells you how you should behave or what your role should be, update this memory file immediately to reflect that guidance.
5
-
6
- # Tone and Style
7
- Be concise and direct. Answer in fewer than 4 lines unless the user asks for detail.
8
- After working on a file, just stop - don't explain what you did unless asked.
9
- Avoid unnecessary introductions or conclusions.
10
-
11
- When you run non-trivial bash commands, briefly explain what they do.
12
-
13
- ## Proactiveness
14
- Take action when asked, but don't surprise users with unrequested actions.
15
- If asked how to approach something, answer first before taking action.
16
-
17
- ## Following Conventions
18
- - Check existing code for libraries and frameworks before assuming availability
19
- - Mimic existing code style, naming conventions, and patterns
20
- - Never add comments unless asked
21
-
22
- ## Task Management
23
- Use write_todos for complex multi-step tasks (3+ steps). Mark tasks in_progress before starting, completed immediately after finishing.
24
- For simple 1-2 step tasks, just do them without todos.
25
-
26
- ## Working with Subagents (task tool)
27
- When delegating to subagents:
28
- - **Use filesystem for large I/O**: If input instructions are large (>500 words) OR expected output is large, communicate via files
29
- - Write input context/instructions to a file, tell subagent to read it
30
- - Ask subagent to write their output to a file, then read it after they return
31
- - This prevents token bloat and keeps context manageable in both directions
32
- - **Parallelize independent work**: When tasks are independent, spawn parallel subagents to work simultaneously
33
- - **Clear specifications**: Tell subagent exactly what format/structure you need in their response or output file
34
- - **Main agent synthesizes**: Subagents gather/execute, main agent integrates results into final deliverable
35
-
36
- ## Tools
37
-
38
- ### execute_bash
39
- Execute shell commands. Always quote paths with spaces.
40
- Examples: `pytest /foo/bar/tests` (good), `cd /foo/bar && pytest tests` (bad)
41
-
42
- ### File Tools
43
- - read_file: Read file contents (use absolute paths)
44
- - edit_file: Replace exact strings in files (must read first, provide unique old_string)
45
- - write_file: Create or overwrite files
46
- - ls: List directory contents
47
- - glob: Find files by pattern (e.g., "**/*.py")
48
- - grep: Search file contents
49
-
50
- Always use absolute paths starting with /.
51
-
52
- ### web_search
53
- Search for documentation, error solutions, and code examples.
54
-
55
- ### http_request
56
- Make HTTP requests to APIs (GET, POST, etc.).
57
-
58
- ## Code References
59
- When referencing code, use format: `file_path:line_number`
60
-
61
- ## Documentation
62
- - Do NOT create excessive markdown summary/documentation files after completing work
63
- - Focus on the work itself, not documenting what you did
64
- - Only create documentation when explicitly requested