list_dir
Scan directories to list files and subfolders, optionally with recursive searching and ignored file filtering.
Instructions
Lists files and directories in the given directory (optionally with recursion). Returns a JSON object with the names of directories and files within the given directory.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| relative_path | Yes | The relative path to the directory to list; pass "." to scan the project root. | |
| recursive | Yes | Whether to scan subdirectories recursively. | |
| skip_ignored_files | No | Whether to skip files and directories that are ignored. | |
| max_answer_chars | No | If the output is longer than this number of characters, no content will be returned. -1 means the default value from the config will be used. Don't adjust unless there is really no other way to get the content required for the task. |
Implementation Reference
- src/serena/tools/file_tools.py:85-123 (handler)The handler function for the 'list_dir' tool. It lists files and directories in a given relative path, optionally recursively, skipping ignored files, and returns a JSON object with directories and files.class ListDirTool(Tool): """ Lists files and directories in the given directory (optionally with recursion). """ def apply(self, relative_path: str, recursive: bool, skip_ignored_files: bool = False, max_answer_chars: int = -1) -> str: """ Lists files and directories in the given directory (optionally with recursion). :param relative_path: the relative path to the directory to list; pass "." to scan the project root :param recursive: whether to scan subdirectories recursively :param skip_ignored_files: whether to skip files and directories that are ignored :param max_answer_chars: if the output is longer than this number of characters, no content will be returned. -1 means the default value from the config will be used. Don't adjust unless there is really no other way to get the content required for the task. :return: a JSON object with the names of directories and files within the given directory """ # Check if the directory exists before validation if not self.project.relative_path_exists(relative_path): error_info = { "error": f"Directory not found: {relative_path}", "project_root": self.get_project_root(), "hint": "Check if the path is correct relative to the project root", } return self._to_json(error_info) self.project.validate_relative_path(relative_path, require_not_ignored=skip_ignored_files) dirs, files = scan_directory( os.path.join(self.get_project_root(), relative_path), relative_to=self.get_project_root(), recursive=recursive, is_ignored_dir=self.project.is_ignored_path if skip_ignored_files else None, is_ignored_file=self.project.is_ignored_path if skip_ignored_files else None, ) result = self._to_json({"dirs": dirs, "files": files}) return self._limit_length(result, max_answer_chars)
- src/serena/tools/tools_base.py:118-128 (registration)The get_name_from_cls method derives the tool name 'list_dir' from the class name 'ListDirTool' by removing 'Tool' suffix and converting to snake_case.@classmethod def get_name_from_cls(cls) -> str: name = cls.__name__ if name.endswith("Tool"): name = name[:-4] # convert to snake_case name = "".join(["_" + c.lower() if c.isupper() else c for c in name]).lstrip("_") return name def get_name(self) -> str: return self.get_name_from_cls()
- src/serena/tools/tools_base.py:359-367 (registration)ToolRegistry.__init__ automatically discovers all subclasses of Tool in serena.tools packages and registers ListDirTool as 'list_dir'.for cls in iter_subclasses(Tool): if not any(cls.__module__.startswith(pkg) for pkg in tool_packages): continue is_optional = issubclass(cls, ToolMarkerOptional) name = cls.get_name_from_cls() if name in self._tool_dict: raise ValueError(f"Duplicate tool name found: {name}. Tool classes must have unique names.") self._tool_dict[name] = RegisteredTool(tool_class=cls, is_optional=is_optional, tool_name=name)
- Derives the input schema and description for the MCP tool from the apply method's signature and docstring using func_metadata.def get_apply_fn_metadata_from_cls(cls) -> FuncMetadata: """Get the metadata for the apply method from the class (static metadata). Needed for creating MCP tools in a separate process without running into serialization issues. """ # First try to get from __dict__ to handle dynamic docstring changes if "apply" in cls.__dict__: apply_fn = cls.__dict__["apply"] else: # Fall back to getattr for inherited methods apply_fn = getattr(cls, "apply", None) if apply_fn is None: raise AttributeError(f"apply method not defined in {cls}. Did you forget to implement it?") return func_metadata(apply_fn, skip_names=["self", "cls"])
- src/serena/tools/__init__.py:2-4 (registration)__init__.py imports file_tools making ListDirTool available for discovery by ToolRegistry.from .tools_base import * from .file_tools import * from .symbol_tools import *