Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

First rewrite

The three-step flow agents and humans both use.

1. Preview

recast 'OldName' 'NewName' src/

Output:

--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1 +1 @@
-fn OldName() {}
+fn NewName() {}
recast: 1 file(s) would change, 1 match(es) across 8 scanned.

No writes happen until you pass --apply.

2. Apply

recast --apply 'OldName' 'NewName' src/

Output:

recast: applying 1 file(s), 1 match(es).

Under the hood: every file is staged in a sibling .recast.tmp.N (written + fsync’d), then renamed into place via a per-file original → .recast.bak.N / temp → original swap. A failure at any step reverse-renames every committed file from its backup, leaving the tree bit-identical to the pre-image. See Safety guarantees.

3. Re-run

recast --apply 'OldName' 'NewName' src/
# recast: match-count guard violated: found 0, required at least 1
# exit 2

The second run finds nothing to match, and by default that is a guard violation — the same answer you get for a mistyped pattern, because the two are indistinguishable from the outside.

For a retry loop in CI or from an LLM agent, say so explicitly:

recast --apply --at-least 0 'OldName' 'NewName' src/
# recast: already applied; no changes needed.
# exit 0

If the pattern is non-convergent (e.g. 'a' -> 'aa'), recast refuses before writing anything, with a non_convergent_replacement, non_convergent_context, or non_convergent_script error depending on why. See Safety guarantees.