Skip to main content

File Editing

BOR reads, writes, and surgically patches files like a coding agent. This is what powers “build a real project”, “fix the bug in my repo”, and “write a script that…”. File tools live in server/protocol/handlers/file.js.

Reading

ToolPurpose
read_fileRead a file. Relative paths resolve against the project root; absolute paths are allowed. device:/ maps to your home folder, bor:/ to BOR-created files.
read_file_in_chunksRead a large file by chunk.
read_batchRead several files at once.
list_filesList a directory.
search_filesSearch file contents (regex).
list_code_definition_namesList top-level code definitions in a file/folder.
Reads are unrestricted — BOR can read any path the Node process can read.

Writing

ToolPurpose
write_file / write_to_fileCreate or fully replace a file.
replace_in_fileSurgically patch a file with SEARCH/REPLACE blocks.
delete_fileRemove a file.

write_file

The file content rides in the tag body (CDATA-safe). BOR streams it into a live editor card in the bubble — one card per file. For a multi-file project, you watch each file fill in and finalize separately.

replace_in_file (surgical edits)

For targeted changes, BOR reads the file, then patches it with a diff of SEARCH/REPLACE blocks:
------- SEARCH
const a = 1;
=======
const a = 2;
+++++++ REPLACE
The applier matches the SEARCH text exactly (with a line-trimmed fallback) and swaps in the REPLACE text. If the SEARCH text isn’t found, BOR is told to re-read the latest file and make the search match exactly — it won’t blindly overwrite.

Where files go

The default destination follows the .bor artifact policy (see Storage):
  • New projects → .bor/workspaces/<slug>/
  • Individual scripts → .bor/files/<slug>.<ext>
  • Images / downloads / reports / exports / scratch → the matching .bor/ subfolder
…unless you name a path or reference an existing project at a path BOR already knows. BOR always announces where it wrote.

Write protection

server/protocol/paths.js refuses writes to the OS source tree (server/, shell/, node_modules/, .git/, lockfiles) and to absolute paths outside $HOME (except /tmp, /var/folders). Narrow carve-outs let the AI write a theme’s user-extras.css and theme assets. This keeps BOR from damaging its own source while leaving you free.

Robust parsing

File content can contain anything — <, >, even ]]> or stray markup from a confused model. BOR’s parser is hardened so this never corrupts a write:
  • It anchors on the tool’s own close tag, not on the (fragile) CDATA delimiter — so a malformed CDATA close can’t make one file swallow the next.
  • It accepts content with embedded ]]> or no CDATA at all.
  • It strips BOR’s internal turn-structure tags (<tool_results> etc.) if a weak model hallucinates them into file content — they never land on disk.
This is why “build me a 6-file app” reliably writes six correct, separate files even on smaller models. See The protocol.

Use cases

  • “Write a Python script that renames my photos by date.” → one file in .bor/files/, run it.
  • “Fix the off-by-one in /Users/me/app/src/list.ts.”read_file, then replace_in_file in place.
  • “Scaffold a Next.js dashboard.” → a real project in .bor/workspaces/, then run it and preview it.
  • “Refactor this module.” → read, surgically patch, re-read to verify.