Build your own Claude Code
Reading the world·15 min

Glob

0 / 1
# grade this stage (from your course directory)
npx theinference test --stage glob --watch

view reads one path you already know. Glob answers the question before that: which paths exist? Give it a pattern like src/** or **/*.ts and it walks the sandbox tree and returns every relative path that matches, sorted. This is how the model finds the file it's looking for without you spoon-feeding it the layout — and "sorted" is what makes the result deterministic enough to grade.

gitignore-style wildcards
*    → any run of characters except "/"   (one path segment)
**   → any characters including "/"        (crosses directories)
?    → exactly one non-"/" character

src/**       matches  src/a.ts, src/lib/b.ts   (everything under src/)
**/*.ts      matches  a.ts, src/lib/b.ts       (every .ts, any depth)

What to build

Your task

Implement Tools.glob

Implement Tools.glob(pattern) in src/tools.ts:

  • Compile pattern to a regex anchored with ^…$ over the relative path: * → [^/]*, ** → .* (consuming a trailing / so src/** also matches src/a.ts), ? → [^/], and escape regex metacharacters.
  • Recursively walk the sandbox root. For each file, compute its path relative to the root and keep it if the regex matches.
  • Return the matching relative paths sorted, one per line.

The program.ts glob subcommand builds a sandbox from case.files and prints tools.glob(case.pattern).

src/tools.ts
glob(pattern: string): ToolOutput {
  // 1. compile pattern -> anchored RegExp (* -> [^/]*, ** -> .*, ? -> [^/])
  // 2. walk the sandbox root; for each FILE, test the RELATIVE path
  // 3. return matches sorted, one per line
}
Match the relative path, never the absolute one

The sandbox lives in a temp dir like /tmp/cc-task-XYZ/src/a.ts, but the pattern src/** is written against the tree root. Always test relative(root, full) — i.e. src/a.ts — not the absolute path, or src/** will silently match nothing. This is also why the output is reproducible: relative paths don't leak the random temp prefix into the graded result.

Recurse into directories, but only emit files

Directories are how you reach the files, not results in their own right. Walk into every subdirectory, but only push a path when it's a file. With case.files of src/a.ts, src/b.js, README.md, the pattern src/** yields exactly src/a.ts and src/b.js — README.md is at the root, outside src/, so it's excluded.

How it's graded

Process mode. The harness runs npx tsx program.ts glob fixtures/case.json and compares the printed JSON to fixtures/expected.json. Sort order is part of the contract: {"content":"src/a.ts\nsrc/b.js"} must come out in that exact order. An unsorted walk that happens to match the same set still fails the byte diff — the lexical .sort() is what makes the result deterministic across filesystems.