# How the File-Picker Agent in Codebuff Identifies and Selects Relevant Files

> Discover how the Codebuff file-picker agent efficiently identifies and selects relevant files. Learn about its process of file discovery, path parsing, and content reading.

- Repository: [Codebuff/codebuff](https://github.com/CodebuffAI/codebuff)
- Tags: internals
- Published: 2026-03-09

---

**The file-picker agent in Codebuff delegates file discovery to a specialized File-Lister sub-agent, parses the returned paths, deduplicates them using a Set, and then reads the actual file contents using the `read_files` tool.**

The file-picker agent in Codebuff serves as an intelligent entry point for locating relevant code within a repository. Unlike traditional file search tools that rely solely on pattern matching, this agent leverages a sub-agent architecture to understand semantic context and return the most pertinent files. According to the Codebuff source code, the implementation resides primarily in [`agents/file-explorer/file-picker.ts`](https://github.com/CodebuffAI/codebuff/blob/main/agents/file-explorer/file-picker.ts) and orchestrates a multi-step discovery pipeline.

## Architecture Overview of the File-Picker Agent

The File-Picker operates as a **secret agent** that does not read code directly. Instead, it implements a *discover-then-read* pattern by spawning specialized sub-agents in parallel. The agent uses the generic `spawn_agents` tool to invoke either `file-lister` (default mode) or `file-lister-max` (max mode), depending on the configuration. This architecture separates the concerns of file discovery from file reading, allowing each sub-agent to optimize for its specific task.

## Step-by-Step File Selection Process

### 1. Agent Initialization via `createFilePicker`

The process begins in [`agents/file-explorer/file-picker.ts`](https://github.com/CodebuffAI/codebuff/blob/main/agents/file-explorer/file-picker.ts) with the `createFilePicker` function. This factory function builds a secret-agent definition that configures the Gemini model and defines the input schema (`prompt` plus optional `directories`). Crucially, it declares which sub-agents can be spawned:

- **Default mode**: Spawns `file-lister` (returns up to 12 files)
- **Max mode**: Spawns `file-lister-max` (returns up to 20 files)

```typescript
export const createFilePicker = (mode: 'default' | 'max'): Omit<SecretAgentDefinition, 'id'> => {
  const isMax = mode === 'max';
  // ...
  spawnableAgents: isMax ? ['file-lister-max'] : ['file-lister'],
  // ...
};

```

### 2. Spawning the File-Lister Sub-Agent

When the File-Picker executes, it yields control to either `handleStepsDefault` or `handleStepsMax`. These generator functions yield a `spawn_agents` call that instructs the runtime to execute the File-Lister sub-agent. The payload includes the original user prompt and any parameters such as target directories.

According to lines 71-80 of [`file-picker.ts`](https://github.com/CodebuffAI/codebuff/blob/main/file-picker.ts), the spawn call looks like this:

```typescript
const handleStepsDefault: SecretAgentDefinition['handleSteps'] = function* ({
  prompt,
  params,
}) {
  const { toolResult: fileListerResults } = yield {
    toolName: 'spawn_agents',
    input: {
      agents: [{ agent_type: 'file-lister', prompt, params }],
    },
  };
  // ...
};

```

### 3. Directory Tree Analysis by the Sub-Agent

The spawned File-Lister (defined in [`agents/file-explorer/file-lister.ts`](https://github.com/CodebuffAI/codebuff/blob/main/agents/file-explorer/file-lister.ts)) performs the actual discovery. It calls the `read_subtree` tool to obtain the directory structure, analyzes it against the provided prompt, and returns a list of relevant file paths—one per line. The default variant returns up to 12 paths, while the max variant in [`file-lister-max.ts`](https://github.com/CodebuffAI/codebuff/blob/main/file-lister-max.ts) returns up to 20.

### 4. Parsing and Deduplicating Results

Once the sub-agent completes, the File-Picker processes the results using `extractSpawnResults` and `extractLastMessageText`. These functions parse the sub-agent’s JSON output, locate the final assistant message, and extract the text containing file paths.

As implemented in lines 84-102 and 108-120 of [`file-picker.ts`](https://github.com/CodebuffAI/codebuff/blob/main/file-picker.ts), the agent splits the text on newlines and stores paths in a `Set<string>` to eliminate duplicates:

```typescript
function extractLastMessageText(agentOutput: any): string | null {
  if (agentOutput?.type === 'lastMessage' && Array.isArray(agentOutput.value)) {
    for (let i = agentOutput.value.length - 1; i >= 0; i--) {
      const msg = agentOutput.value[i];
      if (msg.role === 'assistant' && Array.isArray(msg.content)) {
        for (const part of msg.content) {
          if (part.type === 'text') return part.text;
        }
      }
    }
  }
  return null;
}

```

### 5. Reading File Contents

With the deduplicated list of paths, the File-Picker yields the `read_files` tool to fetch the actual content. After the files are read, it yields a `STEP` marker to signal completion of the workflow.

```typescript
yield {
  toolName: 'read_files',
  input: { paths: Array.from(allPaths) },
};

```

## Key Implementation Details

The **secret agent** pattern distinguishes the File-Picker from standard tools. Rather than accessing the filesystem directly, it orchestrates other agents through the `spawn_agents` tool defined in [`common/src/tools/params/tool/spawn-agents.ts`](https://github.com/CodebuffAI/codebuff/blob/main/common/src/tools/params/tool/spawn-agents.ts). This tool validates that the requested `agent_type` refers to a real agent rather than a tool, and normalizes the payload so sub-agents receive `prompt` and `params` as top-level fields.

The runtime transformation logic in [`sdk/src/impl/llm.ts`](https://github.com/CodebuffAI/codebuff/blob/main/sdk/src/impl/llm.ts) handles the conversion of direct agent calls into `spawn_agents` invocations when necessary, ensuring the File-Picker can operate seamlessly within the broader Codebuff ecosystem.

## Practical Usage Example

To leverage the file-picker agent in Codebuff, invoke it with a descriptive prompt and optional directory constraints:

```typescript
// Client invocation to find authentication-related files
await runAgent({
  agent_type: 'file-picker',
  prompt: 'Find all files that handle authentication',
  params: { directories: ['src/auth', 'src/user'] }, // Optional narrowing
});

```

The runtime translates this into a `spawn_agents` request for the underlying `file-lister`, manages the parsing and deduplication logic, and returns the full source content of the identified files—eliminating the need for manual file management.

## Summary

- The file-picker agent in Codebuff operates as a **secret agent** that orchestrates file discovery rather than performing it directly.
- It spawns either `file-lister` (12 files) or `file-lister-max` (20 files) sub-agents using the `spawn_agents` tool defined in [`common/src/tools/params/tool/spawn-agents.ts`](https://github.com/CodebuffAI/codebuff/blob/main/common/src/tools/params/tool/spawn-agents.ts).
- The sub-agent analyzes directory trees via `read_subtree` and returns relevant paths, which the File-Picker deduplicates using a `Set<string>`.
- Finally, the agent fetches actual file contents via the `read_files` tool, completing the discover-then-read workflow.

## Frequently Asked Questions

### What is the difference between the default and max modes in the file-picker agent?

The default mode spawns a `file-lister` sub-agent that returns up to 12 relevant files, while the max mode spawns `file-lister-max` to return up to 20 files. The `createFilePicker` function in [`agents/file-explorer/file-picker.ts`](https://github.com/CodebuffAI/codebuff/blob/main/agents/file-explorer/file-picker.ts) configures the appropriate spawnable agent based on the mode parameter, allowing users to balance between precision and comprehensiveness.

### How does the file-picker agent handle duplicate file paths?

After parsing the sub-agent's output using `extractLastMessageText` and `extractSpawnResults`, the File-Picker splits the returned text on newlines and stores each path in a `Set<string>`. This data structure automatically eliminates duplicates. The deduplication logic appears in lines 108-120 of [`agents/file-explorer/file-picker.ts`](https://github.com/CodebuffAI/codebuff/blob/main/agents/file-explorer/file-picker.ts), ensuring that the final `read_files` call only fetches unique content.

### Why does the file-picker agent use a sub-agent instead of reading files directly?

The File-Picker implements a **secret agent** pattern that separates discovery from retrieval. By spawning a specialized File-Lister sub-agent, the system leverages distinct optimization strategies for each phase: the sub-agent focuses on semantic relevance and directory tree analysis via `read_subtree`, while the File-Picker handles orchestration, deduplication, and content retrieval. This architecture, defined in [`agents/file-explorer/file-picker.ts`](https://github.com/CodebuffAI/codebuff/blob/main/agents/file-explorer/file-picker.ts), promotes modularity and allows independent scaling of discovery logic.

### What tools does the file-picker agent use to complete its task?

The agent relies on three primary tools: `spawn_agents` (defined in [`common/src/tools/params/tool/spawn-agents.ts`](https://github.com/CodebuffAI/codebuff/blob/main/common/src/tools/params/tool/spawn-agents.ts)) to invoke File-Lister sub-agents, `read_subtree` (used by the sub-agent to scan directories), and `read_files` (to fetch final content). The `spawn_agents` tool validates agent types and normalizes payloads, while the File-Picker's internal functions like `extractLastMessageText` handle the parsing of sub-agent responses.