Skip to main content

File System Tools

Qwen Code provides a comprehensive suite of tools for interacting with the local file system. All file system tools operate within the workspace directory for security.

read_file

Tool Name: read_file Display Name: ReadFile Kind: Read Description: Reads and returns the content of a specified file. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), and PDF files.

Parameters

interface ReadFileParams {
  absolute_path: string;  // Required: Absolute path to file
  offset?: number;        // Optional: Starting line (0-based)
  limit?: number;         // Optional: Number of lines to read
}

Usage

// Read entire file
read_file({
  absolute_path: '/home/user/project/src/index.ts'
});

// Read specific lines
read_file({
  absolute_path: '/home/user/project/README.md',
  offset: 0,
  limit: 50
});

// Read image
read_file({
  absolute_path: '/home/user/project/logo.png'
});

Behavior

  • Text Files: Returns content as string with line numbers
  • Images: Returns base64-encoded data with MIME type
  • PDFs: Returns base64-encoded data
  • Binary Files: Returns error message
  • Large Files: Automatically truncates with indication
  • Missing Files: Returns error

Confirmation

No confirmation required (read-only operation).

Implementation

Location: packages/core/src/tools/read-file.ts
export class ReadFileTool extends BaseDeclarativeTool<
  ReadFileToolParams,
  ToolResult
> {
  static readonly Name = ToolNames.READ_FILE;

  constructor(private config: Config) {
    super(
      ReadFileTool.Name,
      ToolDisplayNames.READ_FILE,
      'Reads and returns the content of a specified file...',
      Kind.Read,
      { /* schema */ },
    );
  }

  protected override validateToolParamValues(
    params: ReadFileToolParams,
  ): string | null {
    // Validate absolute path
    if (!path.isAbsolute(params.absolute_path)) {
      return 'Path must be absolute';
    }

    // Validate within workspace
    if (!this.config.getWorkspaceContext()
        .isPathWithinWorkspace(params.absolute_path)) {
      return 'Path must be within workspace';
    }

    // Check .qwenignore
    if (this.config.getFileService()
        .shouldQwenIgnoreFile(params.absolute_path)) {
      return 'File is ignored by .qwenignore';
    }

    return null;
  }
}

write_file

Tool Name: write_file Display Name: WriteFile Kind: Edit Description: Writes content to a specified file. Creates the file and parent directories if they don’t exist. Overwrites existing files.

Parameters

interface WriteFileParams {
  file_path: string;  // Required: Absolute path to file
  content: string;    // Required: Content to write
}

Usage

// Create new file
write_file({
  file_path: '/home/user/project/src/new.ts',
  content: 'export const value = 42;'
});

// Overwrite existing file
write_file({
  file_path: '/home/user/project/README.md',
  content: '# Updated README\n\nNew content...'
});

Behavior

  • New Files: Creates file and parent directories
  • Existing Files: Overwrites completely
  • Encoding: Preserves existing BOM if present
  • Permissions: Respects file system permissions
  • User Modification: User can modify content before write

Confirmation

Yes. Shows a diff of changes and asks for user approval.

Implementation

Location: packages/core/src/tools/write-file.ts
export class WriteFileTool
  extends BaseDeclarativeTool<WriteFileToolParams, ToolResult>
  implements ModifiableDeclarativeTool<WriteFileToolParams>
{
  static readonly Name = ToolNames.WRITE_FILE;

  override async shouldConfirmExecute(
    signal: AbortSignal,
  ): Promise<ToolCallConfirmationDetails | false> {
    if (this.config.getApprovalMode() === ApprovalMode.AUTO_EDIT) {
      return false;
    }

    // Generate diff for confirmation
    const { originalContent, correctedContent } =
      await getCorrectedFileContent(
        this.config,
        this.params.file_path,
        this.params.content,
      );

    const fileDiff = Diff.createPatch(
      fileName,
      originalContent,
      correctedContent,
      'Current',
      'Proposed',
    );

    return {
      type: 'edit',
      title: `Confirm Write: ${fileName}`,
      fileDiff,
      originalContent,
      newContent: correctedContent,
    };
  }
}

edit

Tool Name: edit Display Name: Edit Kind: Edit Description: Replaces text within a file. By default requires unique match. Set replace_all for multiple replacements.

Parameters

interface EditParams {
  file_path: string;      // Required: Absolute path
  old_string: string;     // Required: Text to replace
  new_string: string;     // Required: Replacement text
  replace_all?: boolean;  // Optional: Replace all occurrences
}

Usage

// Single replacement (default)
edit({
  file_path: '/home/user/project/src/config.ts',
  old_string: `export const API_URL = 'http://localhost:3000';`,
  new_string: `export const API_URL = 'https://api.example.com';`,
});

// Multiple replacements
edit({
  file_path: '/home/user/project/src/utils.ts',
  old_string: 'oldFunction',
  new_string: 'newFunction',
  replace_all: true,
});

// Create new file (empty old_string)
edit({
  file_path: '/home/user/project/src/new.ts',
  old_string: '',
  new_string: 'export const value = 42;',
});

Behavior

  • Unique Match Required: By default, old_string must match exactly once
  • Replace All: Set replace_all: true for multiple matches
  • Context Required: Include sufficient context (3+ lines before/after)
  • Whitespace Sensitive: Preserves exact indentation and spacing
  • Line Ending Normalization: Handles CRLF/LF automatically
  • Self-Correction: May attempt to fix ambiguous matches

Confirmation

Yes. Shows a diff of the proposed changes.

Common Errors

// Error: old_string not found
edit({
  file_path: '/file.ts',
  old_string: 'function foo() {',  // No match
  new_string: 'function bar() {',
});
// Solution: Read file first to get exact text

// Error: Multiple matches without replace_all
edit({
  file_path: '/file.ts',
  old_string: 'const x = 1;',  // Matches 3 times
  new_string: 'const x = 2;',
});
// Solution: Add more context or use replace_all: true

// Error: File already exists
edit({
  file_path: '/existing.ts',
  old_string: '',  // Trying to create
  new_string: 'content',
});
// Solution: Use write_file or provide old_string

Implementation

Location: packages/core/src/tools/edit.ts
export class EditTool
  extends BaseDeclarativeTool<EditToolParams, ToolResult>
  implements ModifiableDeclarativeTool<EditToolParams>
{
  static readonly Name = ToolNames.EDIT;

  async execute(signal: AbortSignal): Promise<ToolResult> {
    const editData = await this.calculateEdit(this.params);

    if (editData.error) {
      return {
        llmContent: editData.error.raw,
        error: {
          message: editData.error.raw,
          type: editData.error.type,
        },
      };
    }

    // Apply replacement
    const newContent = applyReplacement(
      editData.currentContent,
      finalOldString,
      finalNewString,
      editData.isNewFile,
    );

    // Write file
    await this.config
      .getFileSystemService()
      .writeTextFile(this.params.file_path, newContent);

    return {
      llmContent: 'Successfully modified file',
      returnDisplay: { fileDiff, fileName, /* ... */ },
    };
  }
}

glob

Tool Name: glob Display Name: Glob Kind: Read Description: Finds files matching glob patterns, returning paths sorted by modification time (newest first).

Parameters

interface GlobParams {
  pattern: string;   // Required: Glob pattern
  path?: string;     // Optional: Directory to search
}

Usage

// Find all TypeScript files
glob({ pattern: '**/*.ts' });

// Find in specific directory
glob({
  pattern: '*.md',
  path: '/home/user/project/docs'
});

// Complex patterns
glob({ pattern: 'src/**/*.{ts,tsx}' });
glob({ pattern: '**/test/**/*.test.js' });

Patterns

  • * - Match any characters except /
  • ** - Match any characters including /
  • ? - Match single character
  • [abc] - Match any character in set
  • {js,ts} - Match any pattern in set
  • !pattern - Exclude pattern

Behavior

  • Sorting: Most recently modified first
  • Limit: Returns max 100 files
  • Respects Ignores: Follows .gitignore and .qwenignore
  • Absolute Paths: Always returns absolute paths

Confirmation

No confirmation required.

Implementation

Location: packages/core/src/tools/glob.ts
Tool Name: grep_search Display Name: Grep Kind: Read Description: Searches for regex patterns within file contents. Returns matching lines with file paths and line numbers.

Parameters

interface GrepParams {
  pattern: string;   // Required: Regex pattern
  path?: string;     // Optional: File or directory
  glob?: string;     // Optional: File filter pattern
  limit?: number;    // Optional: Max results
}

Usage

// Search for pattern
grep_search({
  pattern: 'function\\s+\\w+',
});

// Search in directory with filter
grep_search({
  pattern: 'TODO',
  path: 'src',
  glob: '*.ts',
});

// Limit results
grep_search({
  pattern: 'import',
  limit: 50,
});

// Complex regex
grep_search({
  pattern: 'class\\s+(\\w+)\\s+extends',
  glob: '**/*.{ts,tsx}',
});

Behavior

  • Engine: Uses ripgrep if available, falls back to JS implementation
  • Case Insensitive: By default
  • Respects Ignores: Follows .gitignore and .qwenignore
  • Line Context: Returns full matching lines
  • Performance: Very fast with ripgrep

Confirmation

No confirmation required.

Implementation

Location: packages/core/src/tools/grep.ts and ripGrep.ts

list_directory

Tool Name: list_directory Display Name: ListFiles Kind: Read Description: Lists files and subdirectories in a specified directory.

Parameters

interface ListDirectoryParams {
  path: string;                    // Required: Directory path
  ignore?: string[];               // Optional: Patterns to ignore
  respect_git_ignore?: boolean;    // Optional: Respect .gitignore
}

Usage

// List directory
list_directory({
  path: '/home/user/project/src'
});

// With ignore patterns
list_directory({
  path: '/home/user/project',
  ignore: ['*.log', 'node_modules', '.git'],
});

// Ignore .gitignore
list_directory({
  path: '/home/user/project',
  respect_git_ignore: false,
});

Behavior

  • Sorting: Directories first, then alphabetically
  • Type Indication: Shows [DIR] for directories
  • Respects Ignores: Follows ignore patterns by default

Confirmation

No confirmation required.

Implementation

Location: packages/core/src/tools/ls.ts

Security

All file system tools enforce security measures:

Path Validation

  1. Absolute Paths Required: All paths must be absolute
  2. Workspace Boundary: Paths must be within workspace
  3. Ignore Patterns: Respects .qwenignore and .gitignore
  4. Temp Directory Access: Limited temp directory access

Example Validation

protected override validateToolParamValues(
  params: FileToolParams,
): string | null {
  const filePath = params.path;

  // Check absolute
  if (!path.isAbsolute(filePath)) {
    return `Path must be absolute: ${filePath}`;
  }

  // Check workspace
  const workspaceContext = this.config.getWorkspaceContext();
  if (!workspaceContext.isPathWithinWorkspace(filePath)) {
    return `Path must be within workspace: ${filePath}`;
  }

  // Check ignore
  if (this.config.getFileService().shouldQwenIgnoreFile(filePath)) {
    return `Path is ignored: ${filePath}`;
  }

  return null;
}

Best Practices

  1. Read Before Edit: Always read files before editing
  2. Sufficient Context: Include 3+ lines of context in old_string
  3. Use Glob First: Use glob to find files before reading
  4. Limit Results: Use limits to prevent overwhelming context
  5. Validate Paths: Always use absolute paths
  6. Handle Errors: Check for error results

Next Steps