fsrb — Applies deterministic, delimiter-based “Search & Replace” patches to text files with strict All-or-Nothing transactionality.
fsrb <patchfile>
fsrb (File Search Replace Block) is a stateless utility designed to apply AI-generated code edits to local files. Unlike patch(1) or git-apply(1), fsrb ignores line numbers, relying instead on exact content matching within delimited blocks.
fsrb operates with strict Global Binary Transactionality using a two-pass workflow:
- Validation Phase (Dry Run): Loads all target files into memory and attempts to apply every patch block in memory.
- Commit Phase: Only if every block in every file applies successfully (exactly 1 match per block) does it write changes to disk.
If any block fails (0 matches or >1 matches), no files are modified. Validation errors are reported together so you can fix everything in one iteration.
The input <patchfile> is a standard text file containing one or more file sections. This format is designed to be easily generated by AI agents (Aider-editor-diff-compatible File Search/Replace Block).
path/to/target.ext
<<<<<<< SEARCH
[Exact original content to find]
=======
[New content to replace with]
>>>>>>> REPLACE
- File Header:
<path>- Must be on its own line.
- The path is relative to the current working directory.
- The header is only recognized if the next non-ignored line is
<<<<<<< SEARCH(blank lines are allowed). - Lines beginning with
#are treated as comments and ignored. - Lines beginning with triple backticks (
```), such as Markdown code fences, are ignored.
- Search Block:
- Starts with
<<<<<<< SEARCH(7<characters). - The delimiter marker lines (
<<<<<<< SEARCH,=======,>>>>>>> REPLACE) are recognized even if they have leading/trailing whitespace (the parser trims for delimiter detection). - Contains the exact text to find. Whitespace, indentation, and newlines must match the target file content exactly.
- Starts with
- Separator:
=======(7=characters).- Separates the SEARCH block from the REPLACE block.
- Replace Block:
- Ends with
>>>>>>> REPLACE(7>characters). - Contains the new text to insert.
- Ends with
- Escaping delimiter lines inside SEARCH/REPLACE content:
- If you need a literal line equal to a delimiter marker, prefix the line with a single backslash (
\) at the very start of the line. - The leading
\is removed during parsing and the literal delimiter text is included in the SEARCH/REPLACE content. - Example:
\<<<<<<< SEARCH \======= \>>>>>>> REPLACE
- If you need a literal line equal to a delimiter marker, prefix the line with a single backslash (
- Literal Matching (Regex Safety):
- The content inside the SEARCH block is treated as a literal string.
- Special characters (e.g.,
*,?,[]) are not treated as regex operators.
The tool accepts a single argument: the path to the patch file.
fsrb ensures code integrity through strict validation rules:
- File loading:
- If a referenced file does not exist, validation fails unless it is created by a CREATE operation (empty SEARCH + non-empty REPLACE).
- If a referenced file cannot be read, validation fails.
- Uniqueness check (per block):
- 0 matches: validation fails (search block not found).
- >1 matches: validation fails (ambiguous match).
- 1 match: valid; applied in-memory.
- Empty SEARCH block:
- Empty SEARCH + non-empty REPLACE is a CREATE operation: the file must not exist at validation time; the tool creates any missing parent directories and writes the REPLACE content.
- Empty SEARCH + empty REPLACE is invalid (no-op is not allowed).
- Empty REPLACE block:
- Non-empty SEARCH + empty REPLACE is a DELETE operation: the tool replaces the matched SEARCH with nothing; if the resulting file content becomes empty, the file is deleted.
- After deleting files, the tool may remove now-empty parent directories (best-effort), stopping at the first non-empty directory.
- All-or-nothing commit:
- If any validation error exists, no files are modified.
- If validation passes, all modified files are written using an atomic, rollback-safe commit strategy.
- Line endings:
- Matching is performed with normalized LF (
\n) in memory. - When writing back, the original file’s line-ending style is preserved.
- Matching is performed with normalized LF (
src/config.py
<<<<<<< SEARCH
DB_HOST = "localhost"
DB_PORT = 5432
=======
DB_HOST = env.get("DB_HOST", "127.0.0.1")
DB_PORT = int(env.get("DB_PORT", 5432))
>>>>>>> REPLACE
README.md
<<<<<<< SEARCH
Run the app locally.
=======
Run the app locally or via Docker.
>>>>>>> REPLACE
$ fsrb update_config.fsrbSaved changes to src/config.py
Saved changes to README.md
[SUCCESS] All 2 blocks applied to 2 files.
[ERROR] Validation failed.
File: README.md
- Block #2: SEARCH block not found in file content.
Snippet: "Run the app locally."
- 0: Success. All blocks in all files were applied.
- 1: Failure. One or more validation errors occurred (file not found, unreadable file, empty SEARCH, block not found, ambiguous match). No changes were applied.
The Rust implementation includes unit tests. No Cargo setup is required — compile and run with rustc --test:
rustc --test src/fsrb.rs -o /tmp/fsrb_test && /tmp/fsrb_testdiff(1), patch(1), sed(1)
Project Orchestrator: Gemini 3.0 Pro. Implementation: Mistral Vibe (Codestral-2).