Directory Tool¶
directory_tool inspects and manipulates directories: list a tree
view, create, copy, move, delete. For operating on a single file, see the
File Tool.
from langchain_mero_tools import make_directory_tool
directory_tool = make_directory_tool(ctx) # ctx=None for unrestricted access
Input schema¶
{
"operation": "list" | "create" | "copy" | "move" | "delete",
"path": str,
"destination_path": str | None, # required for copy/move
"glob": list[str] | None, # list only — filters files shown by "list"
"depth": int, # default 1; -1 = all (capped, see below)
"ignore": list[str] | None, # regex or plain substrings to skip
"include_hidden": bool # default False — dotfiles/dotdirs skipped otherwise
}
glob/depth/ignore/include_hidden only apply to list. copy,
move, and delete are always fully recursive — there's no way to
partially copy or delete a directory tree with this tool (use
File Tool for single-file granularity within a
directory).
Operations¶
| Operation | Required permission | What it does |
|---|---|---|
list |
READ |
Returns an ASCII tree view of the directory, respecting depth, glob, ignore, include_hidden. |
create |
WRITE |
Creates the directory (and any missing parents), exist_ok=True. |
copy |
WRITE (both source and destination_path) |
Recursively copies the directory tree (shutil.copytree, dirs_exist_ok=True). |
move |
WRITE (both source and destination_path) |
Recursively moves/renames the directory. |
delete |
DELETE |
Recursively deletes the directory and everything in it (shutil.rmtree). |
Examples¶
List a tree (default: one level deep, no hidden files)¶
List deeper, with hidden files, ignoring build artifacts¶
directory_tool.invoke({
"operation": "list",
"path": "./workspace",
"depth": 3,
"include_hidden": True,
"ignore": ["__pycache__", "node_modules", r"\.egg-info$"],
})
ignore entries are checked as both a regex (re.search) and a glob
(fnmatch) against the entry name — whichever matches first wins, so you
can freely mix plain substrings, glob patterns, and regex without prefixing
anything (unlike the stricter, explicitly-typed matching used for
allowed_commands/denied_commands — see
Security & Sandboxing
for why command matching is stricter than directory-listing matching).
List only certain file types¶
directory_tool.invoke({
"operation": "list",
"path": "./src",
"depth": -1, # all levels (capped — see below)
"glob": ["*.py"], # only show files matching one of these globs
})
Note: glob only filters files in the listing, not directories —
directories are always shown so you can still see the structure.
Create a directory¶
directory_tool.invoke({"operation": "create", "path": "./workspace/output/logs"})
# "Created directory './workspace/output/logs'."
Recursively copy, move, delete¶
directory_tool.invoke({
"operation": "copy",
"path": "./workspace/draft",
"destination_path": "./workspace/archive/draft",
})
directory_tool.invoke({
"operation": "move",
"path": "./workspace/draft",
"destination_path": "./workspace/final",
})
directory_tool.invoke({"operation": "delete", "path": "./workspace/temp"})
# "Deleted directory './workspace/temp' (recursive)."
delete requires Permission.DELETE specifically, same as
File Tool's delete.
Depth and output-size caps¶
Two hard caps protect against a huge/deep tree blowing up the agent's
context window, regardless of what depth is requested:
| Cap | Value | Behavior when hit |
|---|---|---|
| Max depth | 12 levels | depth=-1 (unlimited) or any depth > 12 is silently capped to 12, with a [depth capped to 12 to avoid excessive output] notice appended to the output. |
| Max entries | 2000 total | Once 2000 entries have been listed across the whole tree, listing stops with a [entry list truncated at 2000 entries] notice. |
Both notices appear directly in the tool's string output, so an agent (or you, reading the result) always knows if what it's looking at is partial.
Error responses¶
directory_tool.invoke({"operation": "list", "path": "not-a-directory.txt"})
# "Error: 'not-a-directory.txt' is not a directory or does not exist."
directory_tool.invoke({"operation": "delete", "path": "/"})
# "Denied: Path '/' is outside the allowed scope [...] for context '...'."
Notes and edge cases¶
- An empty directory listing returns the literal string
"(empty directory)"rather than an empty string. - Permission errors while walking a subdirectory (e.g. restrictive OS
permissions on a nested folder) are caught per-directory and shown as
[permission denied]in that branch of the tree, rather than failing the whole listing. createis idempotent — creating a directory that already exists succeeds silently (exist_ok=True), it doesn't error.
See also¶
- File Tool — single-file operations.
- Security & Sandboxing — how paths are
resolved against the
PathEntrymount table.