HOW-TO · RAG
How to Add File System Operations as Agent Tools
Target environment
Ubuntu 24.04 · Ollama 0.4.x
PREREQUISITES
Agent with tool use, Python os/pathlib, Python 3.10+
What this does
File system tools let agents read, write, list, and organize files on the local machine — enabling tasks like saving search results, reading configuration files, and generating reports.
Steps
- Create a read_file tool. Restrict to an allowed directory for security.
from langchain.tools import tool
import os
ALLOWED_DIR = os.path.expanduser("~/agent_workspace")
def safe_path(path: str) -> str:
full = os.path.abspath(os.path.join(ALLOWED_DIR, path))
if not full.startswith(ALLOWED_DIR):
raise PermissionError(f"Access denied: {path}")
return full
@tool
def read_file(path: str) -> str:
"""Read the contents of a file within the workspace."""
safe = safe_path(path)
if not os.path.exists(safe):
return f"Error: file not found: {path}"
with open(safe, "r") as f:
return f.read()
- Create a write_file tool.
@tool
def write_file(path: str, content: str) -> str:
"""Write content to a file within the workspace."""
safe = safe_path(path)
os.makedirs(os.path.dirname(safe), exist_ok=True)
with open(safe, "w") as f:
f.write(content)
return f"Written {len(content)} bytes to {path}"
- Create list_directory and file_info tools.
@tool
def list_directory(path: str = ".") -> str:
"""List files and directories in the workspace."""
safe = safe_path(path)
items = os.listdir(safe)
result = []
for item in sorted(items):
full = os.path.join(safe, item)
size = os.path.getsize(full) if os.path.isfile(full) else 0
kind = "📄" if os.path.isfile(full) else "📁"
result.append(f"{kind} {item} ({size} bytes)")
return "\n".join(result)
@tool
def file_info(path: str) -> str:
"""Get metadata about a file."""
safe = safe_path(path)
stat = os.stat(safe)
return f"Size: {stat.st_size} bytes\nModified: {stat.st_mtime}"
- Add a search-in-files tool.
@tool
def search_files(pattern: str, path: str = ".") -> str:
"""Search for text pattern in workspace files."""
safe = safe_path(path)
matches = []
for root, _, files in os.walk(safe):
for fname in files:
fpath = os.path.join(root, fname)
try:
with open(fpath) as f:
for i, line in enumerate(f, 1):
if pattern in line:
rel = os.path.relpath(fpath, ALLOWED_DIR)
matches.append(f"{rel}:{i}: {line.strip()[:100]}")
except (UnicodeDecodeError, PermissionError):
continue
return "\n".join(matches[:50]) or "No matches found."
- Register all file tools with the agent.
file_tools = [read_file, write_file, list_directory, file_info, search_files]
registry = ToolRegistry()
for t in file_tools:
registry.register(t)
Verification
python -c "
import os
p = os.path.abspath(os.path.join(os.path.expanduser('~'), 'test.txt'))
print(p.startswith(os.path.expanduser('~')))
# Expected: True
"
Common failures
- Path traversal vulnerability. A malicious
path = "../../etc/passwd"escapes the workspace. Always normalize withos.path.abspathand check the prefix. - Binary file read errors. Reading a binary file as text raises
UnicodeDecodeError. Detect binary files by extension or catch the exception. - Disk space exhaustion. The agent could write unlimited data. Implement a quota or max file size check before writing.
- Version mismatch - The installed package or runtime differs from the command shown; check the version first and rerun the smallest verification command.
- Local environment drift - Another service, virtual environment, model, or path is being used; print the active binary path and configuration before changing the guide steps.
Related guides
- How to Implement Secure File Operations for Agents
- How to Build Custom Tools for Agents