Glob
Feature Definition
Section titled “Feature Definition”A glob capability lets the model discover files by path pattern without reading file contents first.
It is the fastest route from “there should be files shaped like X” to a concrete candidate set.
Typical glob calls:
**/*.rssrc/**/*.ts**/*test*.pypackages/*/src/**/tool/*.ts
Glob is often the first tool in a multi-step chain.
Standard chain:
- glob to find path candidates
- grep to filter by content
- read targeted ranges
- edit selected files
The challenge is not pattern matching itself.
The challenge is operational determinism and bounded output.
If glob returns unstable order, models produce flaky plans.
If glob returns unbounded results, context gets saturated by path spam.
If glob semantics are unclear, pattern expectations diverge between shell, Python, and ripgrep engines.
A production glob tool should therefore define:
- accepted pattern dialect
- path root and path normalization rules
- hidden-file behavior
- ignore behavior
- ordering behavior
- truncation behavior
- permission model
Another subtle challenge is trust boundaries.
Path globbing can walk large trees quickly, including symlinked or external directories, if boundaries are not enforced.
Reference implementations show three broad styles:
- Aider: user command expansion (
/add) with repo filtering - Codex: no first-class glob tool; composition with
list_dirandgrep_files - OpenCode: dedicated
globtool over ripgrep file enumeration
See Also
Section titled “See Also”- List for directory-shape discovery before pattern filtering.
- Grep for content-level filtering after path expansion.
- File Read for bounded inspection of the final file set.
Aider Implementation
Section titled “Aider Implementation”Aider at b9050e1d5faf8096eae7a46a9ecc05a86231384b
does not expose a model-callable glob tool.
Glob behavior appears in command handling,
primarily /add.
/add Flow and Glob Expansion
Section titled “/add Flow and Glob Expansion”Core flow lives in aider/commands.py:799-898.
cmd_add() parses arguments,
checks existing files and ignored files,
and then falls back to pattern matching via
glob_filtered_to_repo() when direct file resolution fails.
glob_filtered_to_repo() implementation:
commands.py:765-797.
Behavior sequence:
- ignore empty pattern (
:766-767) - absolute path case:
treat as exact path candidate (
:769-772) - relative pattern case:
run
Path(self.coder.root).glob(pattern)(:774) - catch parsing/attribute errors and return empty on failure (
:775-779) - expand directories recursively via
expand_subdir(:781-783) - convert to repo-relative paths when inside root (
:785-789) - if git repo exists,
filter against tracked file list (
:791-795) - return string paths (
:796-797)
Directory expansion helper is expand_subdir
in commands.py:1669-1678.
It yields:
- single file if input is a file
- recursive
rglob("*")file set if input is a directory
This means pattern-to-files can recurse deeply and include all files in matched directories.
cmd_add() then handles no-match behavior.
If no file matched and no wildcard characters are present,
Aider may ask to create the file (commands.py:838-844).
So /add is both discovery and onboarding.
Repository Filtering via Git Tracked Files
Section titled “Repository Filtering via Git Tracked Files”Aider narrows glob matches against tracked files when repository context exists.
Filtering point:
commands.py:792-795
Tracked set source:
aider/repo.py:get_tracked_files(:433-488)
get_tracked_files() includes:
- files from HEAD tree traversal when commit exists (
:448-477) - staged files from index entries (
:478-483) - ignore filtering before return (
:486)
Practical effect:
/addglob avoids flooding results with untracked build artifacts- command behavior remains repo-centric
- discovery aligns with what Aider can commit/manage
Edge caveat:
If user expects non-tracked files to appear, this filtering can look like missing matches.
Architectural Implication
Section titled “Architectural Implication”Aider’s glob behavior is command-scoped, not tool-scoped.
Consequences:
- model cannot autonomously issue typed glob calls
- glob semantics are coupled to
/addlogic and repository policy - output format is command feedback, not a stable tool payload contract
This is coherent with Aider’s overall architecture, where user commands and coder flows mediate most filesystem operations.
For tool-native systems, that same behavior generally needs extraction into a dedicated schema-driven tool.
Codex Implementation
Section titled “Codex Implementation”Codex at 4ab44e2c5cc54ed47e47a6729dfd8aa5a3dc2476
currently has no first-class glob tool
in core/src/tools/spec.rs.
No Dedicated Glob Tool
Section titled “No Dedicated Glob Tool”Tool registration in spec.rs:1499-1537
shows optional dynamic registration for:
apply_patchgrep_filesread_filelist_dir
No glob_files or equivalent path-pattern tool exists.
Therefore models must synthesize glob-like discovery using available primitives.
This is partly intentional:
- lower surface area
- fewer semantics to maintain
- richer composition through existing tools
But it also increases prompt complexity for simple “find paths by pattern” tasks.
list_dir as Primitive
Section titled “list_dir as Primitive”Codex list_dir is an experimental function tool.
Spec in spec.rs:1023-1067 defines:
dir_path(required, absolute)offset(1-indexed)limitdepth
Handler in handlers/list_dir.rs:1-330 provides:
- strict argument validation:
- offset > 0
- limit > 0
- depth > 0
- absolute
dir_path
- breadth-first traversal with depth cap
- deterministic sorting
- entry formatting with type markers
- pagination + “More than X entries found” sentinel
Useful constants:
MAX_ENTRY_LENGTH = 500- default
offset = 1 - default
limit = 25 - default
depth = 2
While not pattern matching,
list_dir can provide candidate tree structure
for follow-up filtering.
grep_files Include Glob Filter
Section titled “grep_files Include Glob Filter”grep_files spec (spec.rs:829-878) includes optional include glob.
Handler (handlers/grep_files.rs:109-152) invokes:
rg --files-with-matches --sortr=modified --regexp <pattern> --no-messages [--glob <include>] -- <path>
This gives glob behavior only in conjunction with content search.
Useful constants:
DEFAULT_LIMIT = 100MAX_LIMIT = 2000COMMAND_TIMEOUT = 30s
So Codex can simulate “glob plus content condition” but not raw pattern-only file matching.
Practical Result
Section titled “Practical Result”Codex supports glob-adjacent workflows, not glob-native workflows.
Typical model workaround:
list_dirfor rough path mapgrep_fileswith broad regex + include globread_fileon selected paths
This works, but has tradeoffs:
- more round trips than direct glob
- content regex required even for pure path search
- greater chance of false negatives when regex is too narrow
For OpenOxide,
a dedicated glob tool still adds value
even with list_dir and grep_files present.
OpenCode Implementation
Section titled “OpenCode Implementation”OpenCode at 7ed449974864361bad2c1f1405769fd2c2fcdf42
implements an explicit glob tool
in packages/opencode/src/tool/glob.ts:9-80.
Parameter Schema (Zod)
Section titled “Parameter Schema (Zod)”glob.ts schema:
pattern: stringrequiredpath?: stringoptional directory scope
The description text in glob.txt:1-6 emphasizes:
- fast file pattern matching at codebase scale
- output sorted by modification time
- using Task tool for open-ended multi-round discovery
- batching multiple searches when useful
This provides model guidance at prompt level, while code enforces runtime behavior.
Execution Flow
Section titled “Execution Flow”Exact call sequence in glob.ts:
- ask
globpermission up front (:21-29) - derive search root:
params.pathif provided- otherwise
Instance.directory(:31)
- resolve to absolute path (
:32) - enforce directory-boundary policy
with
assertExternalDirectory(..., { kind: "directory" })(:33) - initialize limit control:
limit = 100(:35)
- iterate ripgrep file stream via
Ripgrep.files(:38-42) - enforce truncation when >= limit (
:43-46) - convert each relative entry to absolute path (
:47) - query mtime with
Bun.file(full).stat()(:48-51) - sort descending by mtime (
:57) - render output:
- “No files found” if empty
- newline-separated absolute paths if matches
- truncation advisory footer if truncated (
:63-68)
- return metadata
{ count, truncated }(:73-76)
This is a compact but complete implementation.
Notable design choice:
permission is requested before directory resolution results are returned, so user can deny broad scans early.
Ripgrep Integration
Section titled “Ripgrep Integration”glob.ts delegates traversal to Ripgrep.files.
packages/opencode/src/file/ripgrep.ts:210-276
defines generator behavior.
Key details:
- command starts with
rg --files --glob=!.git/*(:220) - hidden files included by default unless
hidden === false(:222) - optional follow symlinks and max depth supported (
:221,:223) - caller globs appended as repeated
--glob=<pattern>(:224-227) - directory existence pre-check for clearer errors (
:230-238) - streamed line-by-line output parsing with
Unix and Windows line ending handling (
:260-266) - abort-signal checks before/during/after read loop (
:218,:254,:275)
Platform behavior:
- uses system
rgif available (:126-131) - otherwise downloads ripgrep
14.1.1per platform (:140-147) - extracts archive and sets executable bit on non-Windows (
:197)
This gives OpenCode predictable traversal capability across environments, without assuming ripgrep pre-install.
Glob tool inherits these properties automatically.
Output and Metadata
Section titled “Output and Metadata”Output content strategy is intentionally simple:
- list absolute file paths
- append truncation warning when cap hit
Metadata fields:
count: number returned (bounded by cap)truncated: boolean
Title field:
- relative path from worktree to search root (
glob.ts:72)
This makes UI display predictable and supports downstream logic without expensive parsing.
One subtle behavior:
mtime sort requires per-file stat call.
If stat fails,
mtime falls back to 0 (:51),
which pushes such files toward tail.
Pitfalls & Hard Lessons
Section titled “Pitfalls & Hard Lessons”Glob Dialect Drift
Section titled “Glob Dialect Drift”Glob syntax differs across engines.
Examples of divergence sources:
- Python
Path.glob - ripgrep
--glob - shell expansion rules
- gitignore-style wildmatch semantics
If prompt guidance assumes one dialect while runtime uses another, models may under-match or over-match.
Mitigation set:
- document accepted examples in tool description
- reject invalid patterns with explicit error messaging
- include returned root path in output
- include count + truncation metadata
For cross-tool consistency, OpenOxide should choose one canonical matcher backend for glob/list/grep include patterns.
Hidden File Expectations
Section titled “Hidden File Expectations”Teams differ on whether glob should include dotfiles.
OpenCode currently includes hidden files by default through ripgrep files generator.
Aider command behavior depends on Python traversal plus repo filtering.
Codex list_dir includes whatever filesystem traversal returns.
Without explicit contract, users and models infer different defaults.
Mitigation:
- add
include_hiddenparameter - default based on explicit policy, not backend accident
- echo hidden-file mode in result metadata
Recursive Patterns Can Explode
Section titled “Recursive Patterns Can Explode”Broad patterns like **/*
can produce enormous candidate sets.
Even when output is capped, traversal cost can be high, and user approval prompts may become noisy.
Mitigation patterns:
- hard result cap
- optional traversal depth cap
- stable ordering so truncation is reproducible
- advisory text prompting narrower patterns
OpenCode already caps at 100 and warns on truncation.
Codex list_dir uses offset/limit/depth for bounded traversal.
OpenOxide should combine both:
- traversal bound
- return bound
Path Normalization and Traversal
Section titled “Path Normalization and Traversal”Pattern search near workspace boundaries is a common security and correctness risk.
Risks:
- relative
..path escaping - symlink-driven traversal outside project
- mixed separator issues on Windows
Reference patterns:
- OpenCode uses
assertExternalDirectoryto ask explicit permission for external targets - Aider restricts many operations to repo root
and filters to tracked files in
/addflow - Codex list_dir requires absolute path and validates inputs
OpenOxide should canonicalize paths early and separate permissions for:
- path boundary crossing
- file enumeration itself
OpenOxide Blueprint
Section titled “OpenOxide Blueprint”Tool Contract
Section titled “Tool Contract”Introduce first-class glob_files tool.
Suggested schema:
pattern: Stringrequiredbase_path: Option<String>absolute root overridelimit: Option<usize>default 100, hard max 2000max_depth: Option<usize>optional traversal capinclude_hidden: booldefault falsefollow_symlinks: booldefault falsesort: "path" | "mtime_desc"defaultpath
Response shape:
paths: Vec<String>absolutecount_returnedcount_total_estimate(optional)truncatedbase_pathpatternelapsed_ms
Policy shape:
- permission kind
glob - separate permission kind
external_directorywhen root is outside workspace
Matcher Strategy
Section titled “Matcher Strategy”Use ripgrep-backed traversal as default, for consistency with grep/list tools.
Execution model:
- canonicalize base path
- validate directory exists
- enforce boundary policy
- build
rg --filesargs with glob filters - stream results with cancellation support
- apply limit and sorting
- return structured response + summary text
Validation behaviors:
- empty pattern -> model-facing error
- invalid pattern -> model-facing error with example
- nonexistent root -> typed
PathNotFound
Cross-platform considerations:
- normalize separators in output
- preserve absolute path representation per OS
- test line ending handling in streaming parser
Deterministic Ordering and Limits
Section titled “Deterministic Ordering and Limits”Determinism matters for reproducible agent behavior.
Recommended default ordering:
- lexicographic normalized path
Optional mode:
- mtime descending
If using mtime sort, stat failures should be tracked and surfaced, not silently ignored.
Limit behavior:
- hard cap from config
- request cap clamped to hard cap
truncatedtrue when more candidates existed
Pagination future extension:
offset_tokenover sorted result set- allows large result exploration without massive single responses
Crates
Section titled “Crates”Implementation options:
- ripgrep subprocess via
tokio::process - or
ignorecrate walker +globsetmatching
Recommended baseline:
- start with ripgrep subprocess for parity with grep stack
- add optional native walker later if needed
Support crates:
serde+schemarsfor schema typingthiserrorfor typed error responsestokiofor async execution and cancellationcaminoor existing absolute-path utility for normalization
Testing matrix:
- simple pattern
- recursive pattern
- hidden include/exclude
- symlink follow off/on
- external directory permission denied/approved
- truncation path with deterministic order
- Windows path separator behavior
- cancellation mid-stream
A dedicated glob tool is low conceptual complexity, but high leverage.
Done well, it reduces prompt ambiguity, shrinks unnecessary content search, and gives models a stable discovery primitive for large repositories.