Read in Portuguese / Leia em Portugues
atomwrite
Atomic file operations for LLM agents -- one CLI, zero corruption
What Is It
- A single Rust binary that handles every file operation an LLM agent needs
- Read, write, edit, search, replace, diff, copy, move, delete, transform, scope, backup, rollback, apply -- all in one tool
- Every write is atomic: tempfile, fsync, rename, fsync directory
- Every response is NDJSON: one JSON object per line, machine-readable by default
- Every file gets a BLAKE3 checksum: detect drift, verify integrity, enable optimistic locking
Why
- LLM agents juggle dozens of shell commands to manipulate files
- A single power failure or crash mid-write corrupts the file
- Parsing unstructured CLI output wastes tokens and causes hallucinations
- Agents need checksums to detect concurrent edits but rarely compute them
- atomwrite solves all four problems with one
cargo install
Superpowers
Atomic Writes
- Uses tempfile + fsync + rename + directory fsync on every write
- Guarantees all-or-nothing: the file is never left half-written
- Survives power loss, OOM kills, and SIGKILL
NDJSON Output
- stdout is ALWAYS structured JSON, one object per line
- Every object carries a
"type"discriminator field - Agents parse output without regex or brittle text scraping
- Errors also emit JSON with
error: trueon stdout
BLAKE3 Checksums
- Every
readandwriteresponse includes a BLAKE3 hash - Use
--expect-checksumfor optimistic locking on concurrent edits - Detect state drift before applying changes
Parallel Search
- Built on the ripgrep engine for file content search
- Respects
.gitignoreautomatically - Returns structured matches with file, line, column, and context
AST-Aware Transforms
- Structural search and rewrite powered by ast-grep
- Covers 306 programming languages
- Refactor code by syntax tree, not fragile regex
Grammatical Scoping
- Select AST categories like comments, functions, classes, and strings
- Apply actions: delete, uppercase, lowercase, titlecase, squeeze, or replace
- Covers Rust, Python, JavaScript, TypeScript, and Go with prepared queries
- Use
--patternfor custom AST patterns beyond the built-in queries
Batch Operations
- Execute write, replace, delete, edit, hash, move, and copy operations from an NDJSON manifest
- Use
--transactionfor all-or-nothing execution with automatic rollback - All operations in a batch share the same atomic guarantees
- Use
backupandrollbackcommands for manual snapshot and restore workflows - One CLI call replaces hundreds of individual tool invocations
Quick Start
# Write a file atomically from stdin
|
# Read it back with checksum
# Search across a directory
# Replace text with atomic writes
# Evaluate math and unit conversions
Installation
From crates.io
From source
Shell Completions
# Bash
# Zsh
# Fish
Usage
- All output goes to stdout as NDJSON
- All logs go to stderr (only with
--verbose) - Use
--workspace <DIR>to restrict operations to a project root - Use
--dry-runbefore destructive operations - Use
--expect-checksum <HASH>for optimistic locking - Use
--lang <LOCALE>to override the display language (en, pt-BR) - Pipe stdin for
writeandbatchcommands
Commands
read
- Read one or more files with metadata, size, permissions, and BLAKE3 checksum
- Use
--statto skip file content and return only metadata
write
- Create or overwrite a file atomically from stdin
- Returns the BLAKE3 checksum of the written content
- Use
--line-ending lf|crlf|cr|autoto normalize line endings (default: auto preserves original)
|
edit
- Surgically edit a file by line number, text marker, or exact match
- Supports insert, replace, and delete operations
- Use
--expect-checksumto prevent concurrent edit conflicts - Use
--fuzzy auto|off|aggressivefor fuzzy text matching - Use
--line-ending lf|crlf|cr|autoto normalize line endings - Use
--multito apply multiple edits via NDJSON stdin in a single atomic write
|
search
- Search file contents in parallel using the ripgrep engine
- Returns structured matches with file, line, column, and context
- Exits with code 1 when zero matches are found (not an error)
- Use
--context Nfor surrounding context lines - Use
--max-count Nto limit matches per file - Use
--invertto show lines without a match - Use
--sort pathto sort results by file path
replace
- Replace text across files with atomic writes
- Supports regex patterns and literal strings
- Use
--dry-runto preview changes
hash
- Calculate BLAKE3 checksums for one or more files
delete
- Delete files with optional backup before removal
- Use
--backupto create a.bakcopy first
count
- Count lines in files or count files by extension in a directory
diff
- Compare two files with unified, stat, or changes-only output
move
- Move or rename files atomically
- Falls back to copy+delete for cross-device moves
copy
- Copy files with BLAKE3 checksum verification after copy
list
- List project file structure with metadata
- Respects
.gitignoreby default
extract
- Extract fields from NDJSON input or text columns from stdin
|
calc
- Evaluate math expressions and unit conversions
- Powered by fend for arbitrary-precision arithmetic
regex
- Generate regex patterns from example strings
- Powered by grex for automatic inference
transform
- Structural AST search and rewrite powered by ast-grep
- Covers 306 programming languages
- Use
--rewriteto apply transformations
batch
- Execute multiple operations from an NDJSON manifest on stdin
- Supports write, replace, delete, edit, hash, move, and copy operations
- Use
--transactionfor all-or-nothing execution with automatic rollback
|
|
scope
- Grammatical scoping: select AST categories and apply actions
- Use
--queryfor prepared queries (fn, comments, strings, struct, etc.) - Use
--patternfor custom AST patterns - Use
--deleteto remove matched content or--action upper|lower|titlecase|squeeze - Covers Rust, Python, JavaScript, TypeScript, and Go
backup
- Create timestamped backups of files with BLAKE3 checksums
- Use
--retention Nto control how many backups to keep
rollback
- Restore a file from a previous backup
- Use
--verifyto check BLAKE3 checksum after restoration
apply
- Apply a patch from stdin (unified diff, SEARCH/REPLACE blocks, or full file replacement)
- Auto-detects patch format or use
--formatto specify
|
|
completions
- Generate shell completion scripts for bash, zsh, fish, elvish, or PowerShell
Environment Variables
NO_COLOR: disable colored output when set to any valueRUST_LOG: control log verbosity (e.g.,RUST_LOG=debug)ATOMWRITE_LANG: override locale for translated messages (e.g.,en,pt-BR)
Exit Codes
0: success1: no matches found (search, not an error)4: file not found13: permission denied28: disk full (no space left on device)30: quota exceeded65: invalid input (bad arguments or malformed data)73: cross-device rename (filesystem boundary)74: I/O error78: configuration invalid82: state drift (checksum mismatch, optimistic lock failed)126: workspace jail violated (path escapes workspace)127: symlink blocked (symlink target outside workspace)85: FIFO detected (named pipe cannot be atomically written)86: device file detected (block or character device)128: file immutable (cannot modify)130: interrupted by SIGINT141: broken pipe (SIGPIPE)143: terminated by SIGTERM255: internal error
Error Handling
- All errors emit a JSON object on stdout with
error: true - Error fields:
code,exit,message,path,error_class,retryable,suggestion - Error classes:
permanent,transient,conflict,precondition_failed - Transient and conflict errors set
retryable: true - The
suggestionfield provides actionable recovery guidance for agents
Performance
- Single static binary with zero runtime dependencies
- Release builds use LTO, single codegen unit, and symbol stripping
- Memory-mapped file reads via
memmap2for large files - Parallel search via rayon and the ripgrep engine
- Typical file operation latency: under 5 ms for small files
Troubleshooting FAQ
atomwrite write hangs with no output
- Ensure you are piping content to stdin
writereads from stdin and waits for EOF- Example:
echo "content" | atomwrite write file.txt
search returns exit code 1
- Exit code 1 means zero matches were found
- This is expected behavior, not an error
- Check the pattern and target path
cross-device rename fails with exit 73
- The source and destination are on different filesystems
- atomwrite falls back to copy+delete for
moveacross devices - Use
copyfollowed bydeleteas an alternative
checksum mismatch with exit 82
- Another process modified the file between read and write
- Re-read the file to get the current checksum
- Retry the operation with the updated
--expect-checksum
workspace jail violated with exit 126
- The target path resolves outside the
--workspaceboundary - Verify the path does not contain
..traversals or symlinks escaping the workspace
Architecture
- See ARCHITECTURE.md for module map, data flow, and design decisions
Contributing
- See CONTRIBUTING.md for development setup and guidelines
Security
- See SECURITY.md for vulnerability reporting
Changelog
- See CHANGELOG.md for release history
License
- Licensed under MIT OR Apache-2.0
- See LICENSE-MIT and LICENSE-APACHE for details