adachsoft / directory-scanner-tool
Safe, configurable directory scanner tool for PHP and adachsoft/ai-tool-call integration
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Forks: 0
pkg:composer/adachsoft/directory-scanner-tool
Requires
- php: >=8.3
- adachsoft/ai-tool-call: ^1.0
- adachsoft/filesystem: ^1.0
- adachsoft/normalized-safe-path: ^0.1.0
Requires (Dev)
- adachsoft/php-code-style: ^0.2.1
- friendsofphp/php-cs-fixer: ^3.90
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.4
This package is not auto-updated.
Last update: 2025-12-02 02:48:22 UTC
README
Safe, configurable directory scanner tool for PHP projects, designed to integrate with the
adachsoft/ai-tool-call library and AI agents
(e.g. Google Gemini).
It exposes a single tool called directory_scanner that scans a configured base directory, applies
exclusions and depth/entry limits, and returns a flat list of file system entries with optional
metadata.
First public release is planned as v0.1.0. Version numbers are managed via Git tags / Packagist and follow Semantic Versioning.
Features
- Safe scanning strictly confined to a configured
basePath(no directory traversal above base path). - Support for excluded subpaths (e.g.
vendor,var/cache,.git). - Configurable maximum recursion depth (
maxAllowedDepth). - Configurable maximum number of returned entries (
maxEntries) with truncation indication. - Optional inclusion of additional metadata for each entry:
- file size (bytes),
- last modification time (ISO 8601 string),
- future‑ready fields for creation time and permissions.
- Flat, predictable result structure (
items+summary). - Ready‑to‑use SPI tool + factory for
adachsoft/ai-tool-call.
Requirements
- PHP 8.3 or higher
- Composer
The library depends on the following AdachSoft packages at runtime:
adachsoft/ai-tool-calladachsoft/filesystemadachsoft/normalized-safe-path
These are installed automatically when you require this package.
Installation
composer require adachsoft/directory-scanner-tool
Concepts and architecture
The core pieces of this library are:
DirectoryScannerTool– SPI tool implementation (AdachSoft\AiToolCall\SPI\ToolInterface) that is discovered and executed byadachsoft/ai-tool-call.DirectoryScannerToolFactory– factory used byAiToolCallFacadeBuilderto create configured tool instances based on aConfigMap.DirectoryScannerService/DirectoryScanRunner– services responsible for scanning the file system and collecting results.PathNormalizationHelper– usesadachsoft/normalized-safe-pathto ensure all paths stay inside the configuredbasePath.
You typically do not construct these objects manually. Instead, you plug the factory into
AiToolCallFacadeBuilder and configure the tool using a ConfigMap.
Configuration
The directory scanner is configured by the host application (not by the AI agent) via
DirectoryScannerToolFactory and ConfigMap.
Factory configuration (host application)
Example of wiring the tool with AiToolCallFacadeBuilder:
use AdachSoft\AiToolCall\PublicApi\Builder\AiToolCallFacadeBuilder;
use AdachSoft\AiToolCall\SPI\Collection\ConfigMap;
use AdachSoft\DirectoryScannerTool\DirectoryScannerToolFactory;
$factory = new DirectoryScannerToolFactory();
$facade = AiToolCallFacadeBuilder::new()
->withSpiFactories([$factory])
->withToolConfigs([
'directory_scanner' => new ConfigMap([
'basePath' => '/var/www/my-project',
'excludedPaths' => ['vendor', 'var/cache', '.git'],
'maxAllowedDepth' => 10,
'maxEntries' => 5000,
// Optional defaults for include_* flags when the agent does not specify them
'defaultIncludeSize' => false,
'defaultIncludeCreatedAt' => false,
'defaultIncludeModifiedAt' => false,
'defaultIncludePermissions' => false,
]),
])
->build();
Supported config keys
All config keys are passed as an array to ConfigMap for tool name directory_scanner:
basePath(string, required)- Absolute path that acts as the root of all scans.
- All agent‑provided paths are resolved relative to this base path.
excludedPaths(string[]|optional)- List of relative paths (from
basePath) that should be excluded from scanning. - Both the directory itself and all its descendants are excluded.
- List of relative paths (from
maxAllowedDepth(int, optional, default:10)- Maximum recursion depth allowed by the host application.
- The effective depth used for a given request is the minimum of this value and
the request‑level
max_depthparameter (see below).
maxEntries(int, optional, default:5000)- Maximum number of entries that will be returned from a single scan.
- If the limit is reached, scanning stops and
summary.truncated_by_max_entriesis set totrue.
defaultIncludeSize(bool, optional, default:false)defaultIncludeCreatedAt(bool, optional, default:false)defaultIncludeModifiedAt(bool, optional, default:false)defaultIncludePermissions(bool, optional, default:false)- Default values used when the agent omits corresponding request parameters.
Tool invocation (AI agent request)
Once the tool is registered, AI agents (or your own code) call it through the
AdachSoft\AiToolCall\PublicApi\AiToolCallFacade.
Request parameters
The directory_scanner tool exposes the following parameters schema (as seen in
DirectoryScannerTool::getDefinition()):
path(string, required)- Relative path to scan from
basePath(e.g..,src,src/Module). .means "start from the base path itself".
- Relative path to scan from
recursive(bool, default:false)- Whether nested directories should be scanned recursively.
max_depth(int|null, default:null)- Maximum recursion depth relative to the starting directory.
1means "only direct children".- The actual maximum depth used is
min(max_depth, config.maxAllowedDepth).
include_size(bool, default:false)- Whether to include file size in bytes (for files only).
include_created_at(bool, default:false)- Reserved for future use (creation time; currently may always be
nulldepending on filesystem).
- Reserved for future use (creation time; currently may always be
include_modified_at(bool, default:false)- Whether to include last modification time as an ISO 8601 string.
include_permissions(bool, default:false)- Reserved for future use (POSIX‑like permission string); may be
nullif unavailable.
- Reserved for future use (POSIX‑like permission string); may be
Example: calling the tool via Public API
use AdachSoft\AiToolCall\PublicApi\Dto\ToolCallRequestDto as PublicToolCallRequestDto;
$request = new PublicToolCallRequestDto(
toolName: 'directory_scanner',
parameters: [
'path' => '.',
'recursive' => true,
'max_depth' => 3,
'include_size' => true,
'include_modified_at' => true,
],
);
$result = $facade->callTool($request);
// $result->toolName === 'directory_scanner'
// $result->result is an array with keys 'items' and 'summary'
$items = $result->result['items'];
$summary = $result->result['summary'];
Response structure
The tool returns a structure containing two top‑level keys: items and summary.
items
items is a flat list of scan entries:
/**
* @var array<int, array{
* path: string,
* name: string,
* is_file: bool,
* is_directory: bool,
* size: int|null,
* created_at: string|null,
* modified_at: string|null,
* permissions: string|null,
* }> $items
*/
$items = $result->result['items'];
path– relative path from the configuredbasePath.name– basename of the entry (file or directory name).is_file–trueif the entry is a file.is_directory–trueif the entry is a directory.size– file size in bytes (only wheninclude_sizeistrueand the entry is a file).created_at– creation time as ISO 8601 string (may benull).modified_at– last modification time as ISO 8601 string (may benullif disabled).permissions– POSIX‑style permissions string (may benull).
summary
summary contains metadata about the scan:
/**
* @var array{
* base_path: string,
* requested_path: string,
* recursive: bool,
* requested_max_depth: int|null,
* effective_max_depth: int,
* actual_depth_reached: int,
* total_entries_found: int,
* returned_entries_count: int,
* truncated_by_max_entries: bool,
* } $summary
*/
$summary = $result->result['summary'];
base_path– the configured base path used for scanning.requested_path– thepathvalue from the request.recursive– whether recursive scanning was enabled for the request.requested_max_depth– rawmax_depthfrom the request (may benull).effective_max_depth– actual recursion depth limit used after applying config constraints.actual_depth_reached– deepest level reached during the scan.total_entries_found– total number of entries encountered (before truncation).returned_entries_count– number of entries actually returned initems.truncated_by_max_entries–trueif scanning was stopped becausemaxEntrieswas reached.
Error handling
The tool uses exceptions from adachsoft/ai-tool-call and its own domain exceptions to signal
problems:
InvalidToolCallException- Thrown when request parameters are invalid (e.g. wrong types, impossible options).
ToolExecutionException- Wraps domain and filesystem errors that occur during scanning.
- The original cause is available as the previous exception and usually contains a
DirectoryScannerToolExceptionwith a more detailed message.
DirectoryScannerDomainException- Used internally for invalid or unsafe path operations (e.g. attempts to escape
basePath).
- Used internally for invalid or unsafe path operations (e.g. attempts to escape
In typical adachsoft/ai-tool-call setups, these exceptions are translated into structured error
responses returned to the AI agent.
Development
To work on the library locally, install dev dependencies and run the checks:
composer install
# Run test suite
vendor/bin/phpunit
# Run static analysis
vendor/bin/phpstan analyse
# Run coding standards fixer (dry run or fix)
PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --dry-run
Versioning
This library follows Semantic Versioning. The first public release is planned
as v0.1.0 and will be published as a Git tag (and on Packagist). The composer.json file does
not contain an explicit version field; Composer reads version information from VCS tags.
License
This library is open‑source software licensed under the MIT License. See the LICENSE
file for full license text.
Author
- Arkadiusz Adach