Skip to content

How Deep Agents Manages Files with Built-in Filesystem Tools

When I first started building AI agents, I kept running into the same problem: agents would work fine during a conversation, but they couldn’t persist anything. Every session started from scratch, and complex multi-step workflows were impossible because there was no way to save state or read existing project files.

Then I discovered Deep Agents has filesystem tools built right in. Let me show you how they work.

The Problem with Stateless Agents

Most agent frameworks treat files as an afterthought. You pass context through conversation memory, which works for simple tasks but breaks down quickly:

  • Large codebases: You can’t read an entire project into context
  • Generated outputs: Where do agents save their work?
  • Multi-session workflows: How do you resume work later?
  • Collaboration: How do multiple agents share state?

Deep Agents solves this with FilesystemMiddleware and a set of dedicated file tools.

Getting Started with Filesystem Tools

First, let’s see what tools are available:

Available Filesystem Tools
- read_file : Read file contents (with pagination)
- write_file : Create or overwrite files
- edit_file : Make targeted edits to existing files
- ls : List directory contents
- glob : Pattern-based file discovery
- grep : Content search within files

The middleware is applied automatically when you create a Deep Agent:

graph.py
from deepagents import create_agent, FilesystemMiddleware
agent = create_agent(
model="openai/gpt-4",
middlewares=[FilesystemMiddleware()]
)

Backend Options: Memory vs. Disk

Deep Agents supports multiple backend types for filesystem operations:

backend_options.py
from deepagents import StateBackend, FilesystemBackend
# Option 1: In-memory (default)
# Files are passed via invoke() and kept in state
backend = StateBackend()
# Option 2: Real filesystem access
# Agents can read/write actual files on disk
backend = FilesystemBackend(base_path="/projects/my-app")
# Option 3: Custom backend
# Implement BackendProtocol for your own storage

I started with StateBackend for testing, then switched to FilesystemBackend for production. The in-memory backend is great for isolated agent runs where you want explicit control over what files the agent can access.

Reading Files: The Foundation

The read_file tool is more sophisticated than a simple cat command:

read_example.py
# Agent can read files with pagination for large files
result = agent.invoke({
"messages": [
{"role": "user", "content": "Read the first 50 lines of src/main.py"}
]
})

What I found useful is the pagination support. When working with large files:

Large file handling
User: Read the config file at /etc/app/settings.yaml
Agent: I'll read the config file for you.
[Uses read_file with pagination to avoid context overflow]
The file contains database settings, API keys, and feature flags...

The agent automatically handles pagination when needed, preventing context window exhaustion.

Writing Files: Saving Agent Output

The write_file tool creates or overwrites files:

write_example.py
result = agent.invoke({
"messages": [
{"role": "user", "content": "Create a new file at output/summary.md with a project overview"}
]
})

I use this constantly for:

  • Generated documentation: Agents write README files
  • Code generation: Agents create new modules
  • Report output: Research agents save findings

Editing Files: Precise Modifications

This is where things get interesting. The edit_file tool makes targeted changes without rewriting entire files:

edit_example.py
result = agent.invoke({
"messages": [
{"role": "user", "content": "Update the version number in package.json from 1.0.0 to 1.1.0"}
]
})

The agent will:

  1. Read the file to find the exact location
  2. Make a surgical edit to just that line
  3. Preserve everything else

I initially tried having agents rewrite entire files for every change, but that was error-prone. The edit tool maintains file integrity and reduces the chance of unintended modifications.

Discovery Tools: ls, glob, grep

These three tools help agents navigate codebases:

ls - List directory contents:

ls_example.py
result = agent.invoke({
"messages": [
{"role": "user", "content": "What files are in the src/components directory?"}
]
})

glob - Pattern-based discovery:

glob_example.py
result = agent.invoke({
"messages": [
{"role": "user", "content": "Find all Python test files in the project"}
]
})
# Agent uses glob: **/*_test.py or **/test_*.py

grep - Content search:

grep_example.py
result = agent.invoke({
"messages": [
{"role": "user", "content": "Find where the API_KEY variable is used"}
]
})
# Agent uses grep to search file contents

A Real Workflow Example

Let me show you how these tools work together. I wanted an agent to analyze a codebase and create documentation:

doc_workflow.py
from deepagents import create_agent
agent = create_agent(
model="openai/gpt-4",
backend=FilesystemBackend(base_path="/my-project")
)
result = agent.invoke({
"messages": [
{"role": "user", "content": """
Analyze this project and create comprehensive documentation:
1. List all Python files using glob
2. Read the main entry points
3. Find all function definitions
4. Create a README.md with installation and usage
5. Create a docs/API.md for any API endpoints
"""}
]
})

The agent’s execution flow looked like this:

Agent execution trace
1. glob: **/*.py -> Found 23 Python files
2. ls: src/ -> Identified main modules
3. read_file: src/main.py -> Found entry point
4. grep: "def " -> Found 47 function definitions
5. read_file: src/api.py -> Analyzed API endpoints
6. write_file: README.md -> Created documentation
7. edit_file: README.md -> Added missing section

Notice the last step: the agent wrote the README, then realized it missed a section and used edit_file to add it. This is the kind of iterative workflow that filesystem tools enable.

Best Practices I Learned

After using these tools extensively, here are my recommendations:

1. Use specialized tools over shell commands

The Deep Agents documentation explicitly recommends this:

Use specialized tools over shell equivalents when available (e.g., read_file over cat, edit_file over sed)

The specialized tools have better error handling, pagination, and integration with the agent’s state.

2. Paginate large file reads

pagination_example.py
# BAD: Read entire 10MB log file at once
result = agent.invoke({
"messages": [{"role": "user", "content": "Read /var/log/app.log"}]
})
# BETTER: Agent reads in chunks
result = agent.invoke({
"messages": [{"role": "user", "content": "Read the last 100 lines of /var/log/app.log"}]
})

3. Choose the right backend

BackendUse Case
StateBackendTesting, isolated runs, explicit file control
FilesystemBackendProduction, real project work, persistent storage
CustomS3, databases, version control systems

4. Let agents discover before acting

I’ve found the best results when I let agents use ls and glob to explore before making changes:

discovery_first.py
result = agent.invoke({
"messages": [
{"role": "user", "content": "First explore the project structure, then add type hints to all Python files"}
]
})

Integration with Sub-Agents

Filesystem tools are also available to sub-agents through the middleware:

subagent_example.py
from deepagents import create_agent, FilesystemMiddleware
agent = create_agent(
model="openai/gpt-4",
middlewares=[FilesystemMiddleware(backend=FilesystemBackend())],
sub_agents=["researcher", "coder"] # Both inherit filesystem access
)

This enables coordinated workflows where one agent researches and another writes code, both working with the same files.

Sandbox Support

For running shell commands safely, Deep Agents provides sandbox capabilities:

sandbox_example.py
# If backend implements SandboxBackendProtocol,
# agents can use the 'execute' tool for shell commands
result = agent.invoke({
"messages": [
{"role": "user", "content": "Run the tests and save the output to test-results.txt"}
]
})

This is separate from filesystem tools but complementary - useful when you need git operations, package management, or test runners.

Common Pitfalls

I made these mistakes so you don’t have to:

Pitfall 1: Forgetting the backend

missing_backend.py
# WRONG: No backend specified, filesystem tools won't work
agent = create_agent(model="openai/gpt-4")
# CORRECT: Explicitly configure filesystem access
agent = create_agent(
model="openai/gpt-4",
middlewares=[FilesystemMiddleware(backend=FilesystemBackend())]
)

Pitfall 2: Assuming write permissions

With FilesystemBackend, the agent has the same permissions as the process running it. On production systems, consider:

  • Running with limited user permissions
  • Setting base_path to a sandboxed directory
  • Using StateBackend with explicit file control

Pitfall 3: Not handling errors

File operations can fail. Good agent prompts include error handling:

error_handling.py
result = agent.invoke({
"messages": [
{"role": "user", "content": """
Read the config file at /etc/app/config.yaml.
If it doesn't exist, create a default configuration.
"""}
]
})

When to Use Filesystem Tools

Filesystem tools shine in these scenarios:

  1. Coding agents - Read existing code, make edits, create new files
  2. Research agents - Save findings, generate reports, maintain context
  3. Data pipelines - Process files, transform data, write outputs
  4. Documentation - Analyze codebases, generate docs
  5. Multi-agent coordination - Share state via files

They’re less useful for:

  • Simple Q&A tasks
  • Stateless operations
  • Pure reasoning tasks without persistence needs

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments