Skip to content

SamiLehtinen/fsrb

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fsrb(1) - File Search Replace Block

NAME

fsrb — Applies deterministic, delimiter-based “Search & Replace” patches to text files with strict All-or-Nothing transactionality.

SYNOPSIS

fsrb <patchfile>

DESCRIPTION

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:

  1. Validation Phase (Dry Run): Loads all target files into memory and attempts to apply every patch block in memory.
  2. 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.

PATCH FORMAT

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).

Structure (Aider-editor-diff-compatible File Search/Replace Block)

path/to/target.ext
<<<<<<< SEARCH
[Exact original content to find]
=======
[New content to replace with]
>>>>>>> REPLACE

Syntax Rules

  1. 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.
  2. 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.
  3. Separator:
    • ======= (7 = characters).
    • Separates the SEARCH block from the REPLACE block.
  4. Replace Block:
    • Ends with >>>>>>> REPLACE (7 > characters).
    • Contains the new text to insert.
  5. 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
      
  6. 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.

OPTIONS

The tool accepts a single argument: the path to the patch file.

TRANSACTIONALITY & VALIDATION

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.

EXAMPLES

1. The Patch File (update_config.fsrb)

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

2. Running the Tool

$ fsrb update_config.fsrb

3. Output (Success)

Saved changes to src/config.py
Saved changes to README.md

[SUCCESS] All 2 blocks applied to 2 files.

4. Output (Failure)

[ERROR] Validation failed.

File: README.md
  - Block #2: SEARCH block not found in file content.
    Snippet: "Run the app locally."

EXIT STATUS

  • 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.

TESTING

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_test

SEE ALSO

diff(1), patch(1), sed(1)

AUTHOR

Project Orchestrator: Gemini 3.0 Pro. Implementation: Mistral Vibe (Codestral-2).

About

File Search/Replace Block

Resources

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors