Skip to main content

read_file

Read the contents of a file from the workspace.

Parameters

path
string
required
Path to the file, relative to workspace root or absolute. Accepts alternative keys: file, filepath, file_path, filename.

Returns

result
string
File contents as UTF-8 string, or an error message prefixed with "Error: ".

Behavior

  • Resolves relative paths against the workspace root
  • Validates path stays within workspace boundaries
  • Rejects files larger than 1 MB
  • Returns canonical error messages for missing files

Examples

{
  "path": "src/config.ts"
}

Implementation Details

From voice-tools.ts:236-272:
async function readFile(
  args: Record<string, unknown>,
  workspaceRoot: string
): Promise<string> {
  const path = extractStringArg(args, [
    "path",
    "file",
    "filepath",
    "file_path",
    "filename",
  ]);
  if (!path) {
    return "Error: Missing required parameter 'path'";
  }

  const resolved = await resolvePath(path, workspaceRoot);
  if (!resolved) {
    return "Error: Path escapes workspace root";
  }

  if (!existsSync(resolved)) {
    return `Error: File not found at '${path}'`;
  }

  try {
    const s = statSync(resolved);
    if (s.size > MAX_FILE_BYTES) {
      return `Error: File exceeds 1MB limit (${s.size} bytes)`;
    }
    return readFileSync(resolved, "utf8");
  } catch (err) {
    return `Error: Failed to read file: ${String(err)}`;
  }
}

write_file

Create a new file or overwrite an existing file with the provided content.
This tool is disabled in safe mode. Attempting to use it will return an error.

Parameters

path
string
required
Path to the file, relative to workspace root or absolute. Accepts alternative keys: file, filepath, file_path, filename.
content
string
required
UTF-8 content to write to the file.

Returns

result
string
Success message with byte count, or an error message prefixed with "Error: ".

Behavior

  • Creates parent directories automatically using mkdir -p semantics
  • Overwrites existing files without warning
  • Validates path stays within workspace boundaries
  • Returns error if safe mode is enabled

Examples

{
  "path": "src/config.ts",
  "content": "export const API_KEY = 'sk-test';\n"
}

Implementation Details

From voice-tools.ts:274-316:
async function writeFile(
  args: Record<string, unknown>,
  workspaceRoot: string,
  safeMode: boolean
): Promise<string> {
  if (safeMode) {
    return "Error: write_file is disabled in safe mode";
  }

  const path = extractStringArg(args, [
    "path",
    "file",
    "filepath",
    "file_path",
    "filename",
  ]);
  if (!path) {
    return "Error: Missing required parameter 'path'";
  }

  const content = args.content;
  if (typeof content !== "string") {
    return "Error: Missing required parameter 'content'";
  }

  const resolved = await resolvePath(path, workspaceRoot);
  if (!resolved) {
    return "Error: Path escapes workspace root";
  }

  try {
    mkdirSync(dirname(resolved), { recursive: true });
    const data = Buffer.from(content, "utf8");
    writeFileSync(resolved, data);
    return `Successfully wrote ${data.byteLength} bytes to ${path}`;
  } catch (err) {
    return `Error: Failed to write file: ${String(err)}`;
  }
}

edit_file

Make a targeted edit to an existing file using find-and-replace.
This tool is disabled in safe mode. Attempting to use it will return an error.

Parameters

path
string
required
Path to the file, relative to workspace root or absolute. Accepts alternative keys: file, filepath, file_path, filename.
old_text
string
required
Exact text to find in the file. Accepts alternative keys: oldText, find. Must match exactly once.
new_text
string
required
Replacement text. Accepts alternative keys: newText, replace.

Returns

result
string
Success message, or an error message prefixed with "Error: ".

Behavior

  • Requires exact match of old_text (case-sensitive)
  • Rejects ambiguous edits if old_text appears multiple times
  • Returns error if old_text is not found
  • Atomic operation: writes only if validation passes

Examples

{
  "path": "src/config.ts",
  "old_text": "timeout: 5000",
  "new_text": "timeout: 10000"
}

Implementation Details

From voice-tools.ts:318-373:
async function editFile(
  args: Record<string, unknown>,
  workspaceRoot: string,
  safeMode: boolean
): Promise<string> {
  if (safeMode) {
    return "Error: edit_file is disabled in safe mode";
  }

  const path = extractStringArg(args, [
    "path",
    "file",
    "filepath",
    "file_path",
    "filename",
  ]);
  if (!path) {
    return "Error: Missing required parameter 'path'";
  }

  const oldText = extractStringArg(args, ["old_text", "oldText", "find"]);
  if (!oldText) {
    return "Error: Missing required parameter 'old_text'";
  }

  const newText = extractStringArg(args, ["new_text", "newText", "replace"]);
  if (!newText) {
    return "Error: Missing required parameter 'new_text'";
  }

  const resolved = await resolvePath(path, workspaceRoot);
  if (!resolved) {
    return "Error: Path escapes workspace root";
  }

  try {
    const content = readFileSync(resolved, "utf8");
    const occurrences = content.split(oldText).length - 1;
    if (occurrences === 0) {
      return "Error: old_text not found in file";
    }
    if (occurrences > 1) {
      return `Error: old_text found ${occurrences} times (ambiguous edit)`;
    }

    const updated = content.replace(oldText, newText);
    writeFileSync(resolved, updated, "utf8");
    return `Successfully edited ${path}`;
  } catch (err) {
    return `Error: Failed to edit file: ${String(err)}`;
  }
}

Best Practices

Prefer edit_file over write_file when making small modifications. This preserves file history and reduces risk of data loss.
// Good: Targeted edit
{
  "path": "package.json",
  "old_text": "\"version\": \"1.0.0\"",
  "new_text": "\"version\": \"1.1.0\""
}
Make old_text unique to avoid ambiguity errors. Include surrounding context if needed.
// Bad: Ambiguous
{
  "old_text": "const x = 1;"
}

// Good: Unique context
{
  "old_text": "// Config\nconst x = 1;"
}
Always check for "Error: " prefix in results:
const result = await executeVoiceTool("read_file", args, workspace);
if (result.startsWith("Error: ")) {
  console.error("Tool failed:", result);
  return;
}
// Use result...

Bash

Execute shell commands for complex file operations

Search

Find files before reading or editing them

Build docs developers (and LLMs) love