NAME
Langertha::Raider::SearchTools - Internal search tools of raider: glob (files by name) and grep (files by content)
VERSION
version 0.504
SYNOPSIS
my $search = Langertha::Raider::SearchTools->new( root => '/some/project' );
my $server = $search->server; # MCP::Server with the tools glob and grep
say $search->glob({ pattern => 'lib/**/*.pm' });
say $search->grep({ pattern => 'sub \w+', output_mode => 'count' });
DESCRIPTION
Internal module. Its interface may change without notice.
The two search tools of raider, named and shaped after Claude Code's Glob and Grep (Langertha::Raider::ToolNames), confined to one directory the way Langertha::Raider::FileTools is: every path argument is resolved with realpath and must stay inside "root" (unless "confine" is off). Paths in the results are relative to "root", so they go straight into read_file.
Both tools see the same files. They walk the tree without following symbolic links, skip the version control directories (.git, .hg, .svn), look into hidden files and do not apply .gitignore: what is searched does not depend on which engine runs the search. Narrow a search with path and glob instead. Files over 10 MB and binary files (a NUL byte near the start) are skipped.
glob matches a pattern against the path below the search directory (* and ? stay within one path segment, ** crosses segments, [abc] and {a,b} as in a shell) and lists the matches, newest modification time first.
grep searches file contents with a regular expression, with the modes and options of Claude Code's tool. It runs ripgrep when there is one ("rg") and plain Perl otherwise; the output is the same. A type together with a glob is always searched by the Perl code, as ripgrep cannot take both filters at once. The pattern is a Perl regular expression in the Perl code and a Rust one in ripgrep -- stay with the common syntax (no look-around, no back-references).
root
Required. The directory the tools are confined to and the relative paths of the results are taken from. It must exist.
rg
Path of the ripgrep executable grep uses. Default: rg off PATH. Pass 0 to always use the Perl code (a test does, to be independent of the host), or a path to name the executable.
default_limit
How many results a call returns unless head_limit says otherwise (glob: files; grep: lines of content, files or counts). Default 250.
extra_roots
More directories a path may name besides "root" (the additional directories of ADR 0021). Results inside them are shown as absolute paths. One that does not exist is left out. A CodeRef returning the list (or an ArrayRef) is called on every call, so the roots can change while the tools are mounted (/reload).
confine
True by default: a path must stay inside "root" and the "extra_roots". False (or a CodeRef answering false, asked on every call) lets a search start anywhere -- the application does so in the Claude layout, where the permission gate asks before a search outside the root and the additional directories (ADR 0023). Results outside "root" are absolute paths; the walk still follows no symbolic link.
hider
Called without arguments at the start of every call. Returns undef, or code that is called with the real absolute path of each file a call would list or search and returns true for a file to leave out -- the application hides the files a permission rule refuses or asks about reading (ADR 0021). The result then ends with (N paths hidden by permission rules). While a hider is in force grep runs the Perl code, which applies it file by file.
server
The MCP::Server with the tools glob and grep, built once.
engine
my $engine = $search->engine; # 'ripgrep' or 'perl'
Which one "grep" runs for an ordinary search.
types
The names grep accepts as type, sorted.
glob
my $text = $search->glob({ pattern => '**/*.pm', path => 'lib' });
The files below path (default: "root") whose path below path matches pattern, one per line, newest modification time first, as paths relative to "root". At most "default_limit" are listed; the text says so when there are more. Croaks on a missing pattern, a pattern that leaves the search directory, and a path that does not exist, is not a directory or leaves the root (and the "extra_roots"). Files the "hider" hides are not listed; the text then ends with how many.
grep
my $text = $search->grep({
pattern => 'TODO',
path => 'lib', # directory or file; default: the root
glob => '*.pm', # only files matching it (any depth)
type => 'perl', # only files of this type
output_mode => 'content', # files_with_matches (default), content, count
'-i' => 1, # ignore case
'-n' => 1, # line numbers in content mode (default on)
'-B' => 1, '-A' => 2, '-C' => 3, # context lines; context is an alias of -C
multiline => 1, # the pattern may span lines, . matches a newline
head_limit => 50, offset => 0, # slice of the output
});
The files of path whose content matches pattern. files_with_matches lists the files, newest first; count gives path:N lines, the number of matching lines; content gives the matching lines as path:line:text and context lines as path-line-text, groups of lines apart from each other separated by --. head_limit (default "default_limit", 0 for no limit) and offset cut the lines of the output, and the text says when it was cut. Lines over 2000 characters are shortened. Croaks on an invalid option or pattern and a path that does not exist or leaves the root; a search without a match returns No matches found. Files the "hider" hides are not searched; the text then ends with how many.
SEE ALSO
SUPPORT
Issues
Please report bugs and feature requests at https://github.com/Getty/langertha-raider/issues.
IRC
Join #langertha on irc.perl.org or message Getty directly.
CONTRIBUTING
Contributions are welcome! Please fork the repository and submit a pull request.
AUTHOR
Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/
COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by Torsten Raudssus.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.