deepagents-cli 0.0.2__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.

deepagents/cli.py DELETED
@@ -1,588 +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 langgraph.types import Command, Interrupt
15
-
16
- from rich.console import Console
17
- from rich.markdown import Markdown
18
- from rich.panel import Panel
19
- from rich.syntax import Syntax
20
- from rich.text import Text
21
- from rich.live import Live
22
- from rich.spinner import Spinner
23
- from rich.prompt import Prompt
24
- import shutil
25
- from rich import box
26
-
27
- import dotenv
28
-
29
- dotenv.load_dotenv()
30
-
31
- console = Console()
32
-
33
- tavily_client = TavilyClient(api_key=os.environ.get("TAVILY_API_KEY")) if os.environ.get("TAVILY_API_KEY") else None
34
-
35
-
36
- def http_request(
37
- url: str,
38
- method: str = "GET",
39
- headers: Dict[str, str] = None,
40
- data: Union[str, Dict] = None,
41
- params: Dict[str, str] = None,
42
- timeout: int = 30,
43
- ) -> Dict[str, Any]:
44
- """
45
- Make HTTP requests to APIs and web services.
46
-
47
- Args:
48
- url: Target URL
49
- method: HTTP method (GET, POST, PUT, DELETE, etc.)
50
- headers: HTTP headers to include
51
- data: Request body data (string or dict)
52
- params: URL query parameters
53
- timeout: Request timeout in seconds
54
-
55
- Returns:
56
- Dictionary with response data including status, headers, and content
57
- """
58
- try:
59
- kwargs = {"url": url, "method": method.upper(), "timeout": timeout}
60
-
61
- if headers:
62
- kwargs["headers"] = headers
63
- if params:
64
- kwargs["params"] = params
65
- if data:
66
- if isinstance(data, dict):
67
- kwargs["json"] = data
68
- else:
69
- kwargs["data"] = data
70
-
71
- response = requests.request(**kwargs)
72
-
73
- try:
74
- content = response.json()
75
- except:
76
- content = response.text
77
-
78
- return {
79
- "success": response.status_code < 400,
80
- "status_code": response.status_code,
81
- "headers": dict(response.headers),
82
- "content": content,
83
- "url": response.url,
84
- }
85
-
86
- except requests.exceptions.Timeout:
87
- return {
88
- "success": False,
89
- "status_code": 0,
90
- "headers": {},
91
- "content": f"Request timed out after {timeout} seconds",
92
- "url": url,
93
- }
94
- except requests.exceptions.RequestException as e:
95
- return {
96
- "success": False,
97
- "status_code": 0,
98
- "headers": {},
99
- "content": f"Request error: {str(e)}",
100
- "url": url,
101
- }
102
- except Exception as e:
103
- return {
104
- "success": False,
105
- "status_code": 0,
106
- "headers": {},
107
- "content": f"Error making request: {str(e)}",
108
- "url": url,
109
- }
110
-
111
-
112
- def web_search(
113
- query: str,
114
- max_results: int = 5,
115
- topic: Literal["general", "news", "finance"] = "general",
116
- include_raw_content: bool = False,
117
- ):
118
- """Search the web using Tavily for programming-related information."""
119
- if tavily_client is None:
120
- return {
121
- "error": "Tavily API key not configured. Please set TAVILY_API_KEY environment variable.",
122
- "query": query
123
- }
124
-
125
- try:
126
- search_docs = tavily_client.search(
127
- query,
128
- max_results=max_results,
129
- include_raw_content=include_raw_content,
130
- topic=topic,
131
- )
132
- return search_docs
133
- except Exception as e:
134
- return {
135
- "error": f"Web search error: {str(e)}",
136
- "query": query
137
- }
138
-
139
-
140
- def get_default_coding_instructions(include_memory: bool = True) -> str:
141
- """Get the default coding agent instructions.
142
-
143
- Args:
144
- include_memory: If False, removes the Long-term Memory section from the prompt.
145
- """
146
- default_prompt_path = Path(__file__).parent / "default_agent_prompt.md"
147
- prompt = default_prompt_path.read_text()
148
-
149
- if not include_memory:
150
- # Remove the Long-term Memory section
151
- lines = prompt.split('\n')
152
- result_lines = []
153
- skip = False
154
-
155
- for line in lines:
156
- if line.strip() == "## Long-term Memory":
157
- skip = True
158
- continue
159
- if skip and line.startswith('##'):
160
- skip = False
161
- if not skip:
162
- result_lines.append(line)
163
-
164
- prompt = '\n'.join(result_lines).rstrip() + '\n'
165
-
166
- return prompt
167
-
168
-
169
- def get_coding_instructions(agent_name: str | None, long_term_memory: bool = False) -> str:
170
- """Get the coding agent instructions from file or create default.
171
-
172
- If agent_name is None or long_term_memory is False, returns default instructions without memory features.
173
- """
174
- if agent_name is None or not long_term_memory:
175
- return get_default_coding_instructions(include_memory=False)
176
-
177
- agent_dir = Path.home() / ".deepagents" / agent_name
178
- agent_prompt_file = agent_dir / "agent.md"
179
-
180
- if agent_prompt_file.exists():
181
- agent_memory_content = agent_prompt_file.read_text()
182
- else:
183
- agent_dir.mkdir(parents=True, exist_ok=True)
184
- default_prompt = get_default_coding_instructions(include_memory=True)
185
- agent_prompt_file.write_text(default_prompt)
186
- agent_memory_content = default_prompt
187
-
188
- return f"<agent_memory>\n{agent_memory_content}\n</agent_memory>"
189
-
190
-
191
- config = {"recursion_limit": 1000}
192
-
193
- # Constants for display truncation
194
- MAX_ARG_LENGTH = 200
195
- MAX_RESULT_LENGTH = 200
196
-
197
-
198
- def truncate_value(value: str, max_length: int = MAX_ARG_LENGTH) -> str:
199
- """Truncate a string value if it exceeds max_length."""
200
- if len(value) > max_length:
201
- return value[:max_length] + "..."
202
- return value
203
-
204
-
205
- def format_tool_args(tool_input: dict) -> str:
206
- """Format tool arguments for display, truncating long values."""
207
- if not tool_input:
208
- return ""
209
-
210
- args_parts = []
211
- for key, value in tool_input.items():
212
- value_str = str(value)
213
- value_str = truncate_value(value_str)
214
- args_parts.append(f"{key}={value_str}")
215
-
216
- return ", ".join(args_parts)
217
-
218
-
219
- def display_tool_call(tool_name: str, tool_input: dict):
220
- """Display a tool call with arguments, truncating long values."""
221
-
222
- tool_icons = {
223
- "read_file": "📖",
224
- "write_file": "✏️",
225
- "edit_file": "✂️",
226
- "ls": "📁",
227
- "glob": "🔍",
228
- "grep": "🔎",
229
- "shell": "⚡",
230
- "web_search": "🌐",
231
- "http_request": "🌍",
232
- "task": "🤖",
233
- "write_todos": "📋",
234
- }
235
-
236
- icon = tool_icons.get(tool_name, "🔧")
237
- args_str = format_tool_args(tool_input)
238
-
239
- # Display: icon tool_name(args)
240
- if args_str:
241
- console.print(f"[dim]{icon} {tool_name}({args_str})[/dim]")
242
- else:
243
- console.print(f"[dim]{icon} {tool_name}()[/dim]")
244
-
245
-
246
- def display_text_content(text: str):
247
- """Display text content with markdown rendering."""
248
- if text.strip():
249
- if "```" in text or "#" in text or "**" in text:
250
- md = Markdown(text)
251
- console.print(md)
252
- else:
253
- console.print(text, style="white")
254
-
255
-
256
- def extract_and_display_content(message_content):
257
- """Extract content from agent messages and display with rich formatting."""
258
- if isinstance(message_content, str):
259
- display_text_content(message_content)
260
- return
261
-
262
- if isinstance(message_content, list):
263
- for block in message_content:
264
- if isinstance(block, dict):
265
- if block.get("type") == "text" and "text" in block:
266
- display_text_content(block["text"])
267
- elif block.get("type") == "tool_use":
268
- tool_name = block.get("name", "unknown_tool")
269
- tool_input = block.get("input", {})
270
- display_tool_call(tool_name, tool_input)
271
- # Skip tool_result blocks - they're just noise
272
- elif block.get("type") == "tool_result":
273
- pass # Don't display tool results
274
-
275
-
276
- def execute_task(user_input: str, agent, agent_name: str | None):
277
- """Execute any task by passing it directly to the AI agent."""
278
- console.print()
279
-
280
- config = {"configurable": {"thread_id": "main", "agent_name": agent_name}} if agent_name else {"configurable": {"thread_id": "main"}}
281
-
282
- for _, chunk in agent.stream(
283
- {"messages": [{"role": "user", "content": user_input}]},
284
- stream_mode="updates",
285
- subgraphs=True,
286
- config=config,
287
- durability="exit",
288
- ):
289
- chunk = list(chunk.values())[0]
290
- if chunk is not None:
291
- # Check for interrupts
292
- if "__interrupt__" in chunk:
293
- result = chunk
294
- break
295
-
296
- # Normal message processing
297
- if "messages" in chunk and chunk["messages"]:
298
- last_message = chunk["messages"][-1]
299
-
300
- message_content = None
301
- message_role = getattr(last_message, "type", None)
302
- if isinstance(message_role, dict):
303
- message_role = last_message.get("role", "unknown")
304
-
305
- if hasattr(last_message, "content"):
306
- message_content = last_message.content
307
- elif isinstance(last_message, dict) and "content" in last_message:
308
- message_content = last_message["content"]
309
-
310
- if message_content:
311
- # Show tool calls with truncated args
312
- if message_role != "tool":
313
- if isinstance(message_content, list):
314
- for block in message_content:
315
- if isinstance(block, dict) and block.get("type") == "tool_use":
316
- tool_name = block.get("name", "unknown_tool")
317
- tool_input = block.get("input", {})
318
-
319
- tool_icons = {
320
- "read_file": "📖",
321
- "write_file": "✏️",
322
- "edit_file": "✂️",
323
- "ls": "📁",
324
- "glob": "🔍",
325
- "grep": "🔎",
326
- "shell": "⚡",
327
- "web_search": "🌐",
328
- "http_request": "🌍",
329
- "task": "🤖",
330
- "write_todos": "📋",
331
- }
332
-
333
- icon = tool_icons.get(tool_name, "🔧")
334
- args_str = format_tool_args(tool_input)
335
-
336
- if args_str:
337
- console.print(f"[dim]{icon} {tool_name}({args_str})[/dim]")
338
- else:
339
- console.print(f"[dim]{icon} {tool_name}()[/dim]")
340
-
341
- # Show tool results with truncation
342
- if message_role == "tool":
343
- result_str = str(message_content)
344
- result_str = truncate_value(result_str, MAX_RESULT_LENGTH)
345
- console.print(f"[dim] → {result_str}[/dim]")
346
-
347
- # Show text content
348
- if message_role != "tool":
349
- has_text_content = False
350
- if isinstance(message_content, str):
351
- has_text_content = True
352
- elif isinstance(message_content, list):
353
- for block in message_content:
354
- if isinstance(block, dict):
355
- if block.get("type") == "text" and block.get("text", "").strip():
356
- has_text_content = True
357
- break
358
-
359
- if has_text_content:
360
- extract_and_display_content(message_content)
361
- console.print()
362
-
363
- console.print()
364
-
365
-
366
- async def simple_cli(agent, agent_name: str | None):
367
- """Main CLI loop."""
368
- console.print()
369
- console.print(Panel.fit(
370
- "[bold cyan]DeepAgents[/bold cyan] [dim]|[/dim] AI Coding Assistant",
371
- border_style="cyan",
372
- box=box.DOUBLE
373
- ))
374
- console.print("[dim]Type 'quit' to exit[/dim]")
375
- console.print()
376
-
377
- while True:
378
- try:
379
- console.print("[bold green]❯[/bold green] ", end="")
380
- user_input = input().strip()
381
- except EOFError:
382
- break
383
-
384
- if not user_input:
385
- continue
386
-
387
- if user_input.lower() in ["quit", "exit", "q"]:
388
- console.print("\n[bold cyan]👋 Goodbye![/bold cyan]\n")
389
- break
390
-
391
-
392
-
393
- else:
394
- execute_task(user_input, agent, agent_name)
395
-
396
-
397
- def list_agents():
398
- """List all available agents."""
399
- agents_dir = Path.home() / ".deepagents"
400
-
401
- if not agents_dir.exists() or not any(agents_dir.iterdir()):
402
- console.print("[yellow]No agents found.[/yellow]")
403
- console.print("[dim]Agents will be created in ~/.deepagents/ when you first use them.[/dim]")
404
- return
405
-
406
- console.print("\n[bold cyan]Available Agents:[/bold cyan]\n")
407
-
408
- for agent_path in sorted(agents_dir.iterdir()):
409
- if agent_path.is_dir():
410
- agent_name = agent_path.name
411
- agent_md = agent_path / "agent.md"
412
-
413
- if agent_md.exists():
414
- console.print(f" [green]•[/green] [bold]{agent_name}[/bold]")
415
- console.print(f" [dim]{agent_path}[/dim]")
416
- else:
417
- console.print(f" [yellow]•[/yellow] [bold]{agent_name}[/bold] [dim](incomplete)[/dim]")
418
- console.print(f" [dim]{agent_path}[/dim]")
419
-
420
- console.print()
421
-
422
-
423
- def reset_agent(agent_name: str, source_agent: str = None):
424
- """Reset an agent to default or copy from another agent."""
425
- agents_dir = Path.home() / ".deepagents"
426
- agent_dir = agents_dir / agent_name
427
-
428
- if source_agent:
429
- source_dir = agents_dir / source_agent
430
- source_md = source_dir / "agent.md"
431
-
432
- if not source_md.exists():
433
- console.print(f"[bold red]Error:[/bold red] Source agent '{source_agent}' not found or has no agent.md")
434
- return
435
-
436
- source_content = source_md.read_text()
437
- action_desc = f"contents of agent '{source_agent}'"
438
- else:
439
- source_content = get_default_coding_instructions()
440
- action_desc = "default prompt"
441
-
442
- if agent_dir.exists():
443
- shutil.rmtree(agent_dir)
444
- console.print(f"[yellow]Removed existing agent directory:[/yellow] {agent_dir}")
445
-
446
- agent_dir.mkdir(parents=True, exist_ok=True)
447
- agent_md = agent_dir / "agent.md"
448
- agent_md.write_text(source_content)
449
-
450
- console.print(f"[bold green]✓[/bold green] Agent '{agent_name}' reset to {action_desc}")
451
- console.print(f"[dim]Location: {agent_dir}[/dim]\n")
452
-
453
-
454
- def show_help():
455
- """Show help information."""
456
- help_text = """
457
- [bold cyan]DeepAgents - AI Coding Assistant[/bold cyan]
458
-
459
- [bold]Usage:[/bold]
460
- deepagents [--agent NAME] [--no-memory] Start interactive session
461
- deepagents list List all available agents
462
- deepagents reset --agent AGENT Reset agent to default prompt
463
- deepagents reset --agent AGENT --target SOURCE Reset agent to copy of another agent
464
- deepagents help Show this help message
465
-
466
- [bold]Examples:[/bold]
467
- deepagents # Start with default agent (long-term memory enabled)
468
- deepagents --agent mybot # Start with agent named 'mybot'
469
- deepagents --no-memory # Start without long-term memory
470
- deepagents list # List all agents
471
- deepagents reset --agent mybot # Reset mybot to default
472
- deepagents reset --agent mybot --target other # Reset mybot to copy of 'other' agent
473
-
474
- [bold]Long-term Memory:[/bold]
475
- By default, long-term memory is ENABLED using agent name 'agent'.
476
- Memory includes:
477
- - Persistent agent.md file with your instructions
478
- - /memories/ folder for storing context across sessions
479
-
480
- Use --no-memory to disable these features.
481
- Note: --agent and --no-memory cannot be used together.
482
-
483
- [bold]Agent Storage:[/bold]
484
- Agents are stored in: ~/.deepagents/AGENT_NAME/
485
- Each agent has an agent.md file containing its prompt
486
-
487
- [bold]Interactive Commands:[/bold]
488
- quit, exit, q Exit the session
489
- help Show usage examples
490
- """
491
- console.print(help_text)
492
-
493
-
494
- def parse_args():
495
- """Parse command line arguments."""
496
- parser = argparse.ArgumentParser(
497
- description="DeepAgents - AI Coding Assistant",
498
- formatter_class=argparse.RawDescriptionHelpFormatter,
499
- add_help=False,
500
- )
501
-
502
- subparsers = parser.add_subparsers(dest="command", help="Command to run")
503
-
504
- # List command
505
- subparsers.add_parser("list", help="List all available agents")
506
-
507
- # Help command
508
- subparsers.add_parser("help", help="Show help information")
509
-
510
- # Reset command
511
- reset_parser = subparsers.add_parser("reset", help="Reset an agent")
512
- reset_parser.add_argument("--agent", required=True, help="Name of agent to reset")
513
- reset_parser.add_argument("--target", dest="source_agent", help="Copy prompt from another agent")
514
-
515
- # Default interactive mode
516
- parser.add_argument(
517
- "--agent",
518
- default="agent",
519
- help="Agent identifier for separate memory stores (default: agent).",
520
- )
521
-
522
- parser.add_argument(
523
- "--no-memory",
524
- action="store_true",
525
- help="Disable long-term memory features (no agent.md or /memories/ access).",
526
- )
527
-
528
- return parser.parse_args()
529
-
530
-
531
- async def main(agent_name: str, no_memory: bool):
532
- """Main entry point."""
533
- # Error if both --agent and --no-memory are specified
534
- if agent_name != "agent" and no_memory:
535
- console.print("[bold red]Error:[/bold red] Cannot use --agent with --no-memory flag.")
536
- console.print("Either specify --agent for memory-enabled mode, or use --no-memory for memory-disabled mode.")
537
- return
538
-
539
- # Disable long-term memory if --no-memory flag is set
540
- long_term_memory = not no_memory
541
-
542
- # If memory is disabled, set agent_name to None
543
- effective_agent_name = None if no_memory else agent_name
544
-
545
- # Create agent with conditional tools
546
- tools = [http_request]
547
- if tavily_client is not None:
548
- tools.append(web_search)
549
-
550
- agent = create_deep_agent(
551
- tools=tools,
552
- system_prompt=get_coding_instructions(effective_agent_name, long_term_memory=long_term_memory),
553
- use_local_filesystem=True,
554
- long_term_memory=long_term_memory,
555
- ).with_config(config)
556
-
557
- agent.checkpointer = InMemorySaver()
558
-
559
- try:
560
- await simple_cli(agent, effective_agent_name)
561
- except KeyboardInterrupt:
562
- console.print("\n\n[bold cyan]👋 Goodbye![/bold cyan]\n")
563
- except Exception as e:
564
- console.print(f"\n[bold red]❌ Error:[/bold red] {e}\n")
565
-
566
-
567
- def cli_main():
568
- """Entry point for console script."""
569
- args = parse_args()
570
-
571
- if args.command == "help":
572
- show_help()
573
- elif args.command == "list":
574
- list_agents()
575
- elif args.command == "reset":
576
- reset_agent(args.agent, args.source_agent)
577
- else:
578
- if not os.environ.get("ANTHROPIC_API_KEY"):
579
- console.print("[bold red]Error:[/bold red] ANTHROPIC_API_KEY environment variable is not set.")
580
- console.print("Please set your Anthropic API key:")
581
- console.print(" export ANTHROPIC_API_KEY=your_api_key_here")
582
- console.print("\nOr add it to your .env file.")
583
- return
584
- asyncio.run(main(args.agent, args.no_memory))
585
-
586
-
587
- if __name__ == "__main__":
588
- cli_main()
@@ -1,94 +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
65
-
66
- ## Long-term Memory
67
- You have access to a long-term memory system using the `/memories/` path prefix.
68
- Files stored in `/memories/` persist across sessions and are stored in your agent directory.
69
-
70
- Your system prompt is loaded from `/memories/agent.md` at startup. You can update your own instructions by editing this file.
71
-
72
- **When to update memories:**
73
- - **IMMEDIATELY when the user describes your role or how you should behave** (e.g., "you are a web researcher", "you are an expert in X")
74
- - **IMMEDIATELY when the user gives feedback on your work** - Before continuing, update memories to capture what was wrong and how to do it better
75
- - When the user explicitly asks you to remember something
76
- - When patterns or preferences emerge (coding styles, conventions, workflows)
77
- - After significant work where context would help in future sessions
78
-
79
- **Learning from feedback:**
80
- - When user says something is better/worse, capture WHY and encode it as a pattern
81
- - Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions
82
- - When user says "you should remember X" or "be careful about Y", treat this as HIGH PRIORITY - update memories IMMEDIATELY
83
- - Look for the underlying principle behind corrections, not just the specific mistake
84
- - If it's something you "should have remembered", identify where that instruction should live permanently
85
-
86
- **What to store where:**
87
- - **`/memories/agent.md`**: Update this to modify your core instructions and behavioral patterns
88
- - **Other `/memories/` files**: Use for project-specific context, reference information, or structured notes
89
- - If you create additional memory files, add references to them in `/memories/agent.md` so you remember to consult them
90
-
91
- The portion of your system prompt that comes from `/memories/agent.md` is marked with `<agent_memory>` tags so you can identify what instructions come from your persistent memory.
92
-
93
- Example: `edit_file('/memories/agent.md', ...)` to update your instructions
94
- Example: `write_file('/memories/project_context.md', ...)` for project-specific notes, then reference it in agent.md