docs.rs failed to build atomwrite-0.1.38
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build:
atomwrite-0.1.36
Read in Portuguese / Leia em Português
atomwrite
- Atomic file operations for LLM agents: one CLI, all-or-nothing writes
- Agent-readable summary: llms.txt and llms-full.txt
- Jump to: Installation, Quick Start, Global Flags, Commands, Configuration, Exit Codes
What Is It
- A single Rust binary that handles every file operation an LLM agent needs
- 47 subcommands (SSOT: clap
Commands/agent-surface), all listed with an example in Commands - 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
Installation
From crates.io
Slim and full builds
- Features:
core,ast,lang-rust,lang-ts,lang-py,lang-go,lang-full,watch,full(default =core+ast+lang-rust+lang-ts+lang-py;watchis opt-in;semantic-searchis always compiled) - Slim build (core only, 26,560,352 bytes measured on 2026-11-04, DERIVADO 26560352 / 1048576 = 25.33 MiB, above the local size-gate of 15 MiB):
cargo install --path . --locked --force --no-default-features --features core - Full/default build (AST languages, 71,084,440 bytes measured on 2026-11-04, DERIVADO 71084440 / 1048576 = 67.79 MiB):
cargo install --path . --locked --force - Build with
watch:cargo install --path . --locked --force --features watch(the default binary exits 78 onwatchwith a rebuild hint) - Slim build:
outlineandsparse outlineexit 78 with a rebuild hint (measured), andquery,scope,transformandwrite --syntax-checkhave stubs for the same case (read fromsrc/commands/*_stub.rsandsrc/syntax_check_stub.rs, the slim build was not executed to confirm) cargo xtask check-featureschecks thecoreandcore,watchsets- The features
i18n-cjk,i18n-rtl,i18n-europe,i18n-fullandslow-testsare placeholders or test switches: do not enable them - The 5-8 MB target of the product plan applies to the core profile, not to the default AST build: the measured core build (25.33 MiB) is above that target and above the 15 MiB gate
From source
Shell completions
# Bash
# Zsh
# Fish
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
# Set a value in a TOML file (preserves comments)
# Walk the AST of a Rust file (downloads the parser on first use, see Network And Privacy)
# Extract the outline of a Python file
# Real tree-sitter syntax check before writing (exit 88 on a syntax error)
|
# Report stale WAL sidecars and estimate the reclaim
# Reap terminal journals older than the threshold
What Is New In v0.1.38 (2026-11-04)
read --format rawstops at 24,000 bytes and prints one stderr line with the next--lines, because the Bash tool already cut the stream at 30,000 characters without saying so--allremoves the cap, and the raw path streams withBufReaderinstead of holding the file in memory--numberprintsN:text,--linesis repeatable with--rangeas an alias, and several windows and several files arrive in one call with==> path <==headers--symbol NAMEand--line N --enclosingselect by syntax tree, and--no-commentsdrops comment and blank lines before the window is countedsearch --format textwrites onepath:line:col:textper match under a byte cap, and a tree where every file was binary exits89 ALL_SKIPPED_BINARYinstead ofNO_MATCHESlist --format textwrites one path per line, andtotal_bytescounts files onlyoutline --format tsvwritesline<TAB>kind<TAB>namewith the path once, lists Markdown headings and setext sections, parses raw bytes, and publishesparse_errorswithfirst_error_lineoutlinereads a Markdown heading as asectionthat runs to the end of its own section, andread --symbol Partreturns that whole section with its sub-sectionsapplymatches whole lines, refuses a repeated SEARCH with exit65 MATCH_AMBIGUOUSunless--allis given, and refuses a block that lost=======or>>>>>>> REPLACEby naming its indexapply --showreturns the changed lines with their 1-based numbers, which removes the re-read that confirmed the swapapplyruns the syntax check before and after the swap and refuses only when the parse-error count rises, with--no-syntax-checkas the opt-outapply --format unifiedaccepts@@ ... @@and a bare@@, so a hunk without numbers matches by context and more than one match is refused with the line of each onediffreports 1-basedlineplusold_lineandnew_line, and--selectis honored on the terminal summarydeletepublishesbackups_kept,backup_bytesanddirs_leftwhen a backup or a leftover exists- The failure envelope carries
ok,codeandexit, anderror: trueleft it because it duplicatedok: falsepluscode, cost 13 bytes on every failure (179 to 166 bytes on the same path) and no caller branched on it alone - The lock targets the inode with
std::fs::File::try_lock, anddeletetakes the same lock before it hashes and unlinks delete -r <dir>owns the whole named tree, including hidden, ignored, linked, fifo, socket and device entries, and a link is never followedtarget_resolvedis always an array in invocation order, because a path may contain the comma that used to join several targetsread --format rawon a single target honors--max-filesizeand exits 65FILE_TOO_LARGEabove the ceiling- A file whose image signature is damaged fails
readwith exit 65INVALID_INPUTinstead of returning its bytes as text output.profile = "lean"drops the digests, the byte counts and the timing from a successful mutation record, which took oneapplyon a three-line file from 433 bytes to 196configlists 43 keys, andatomwrite commands --briefprints one line per subcommand in 5 020 bytes against 67 492 for the full tree- Pin agents to
^0.1.38. 47 subcommands (SSOT)
Read Expansion In v0.1.37 (2026-10-31)
readtakes one or more paths: explicit paths are read in argv order, and an operand carrying*,?or[is a pattern the binary expands itself against one level of its own directory- Pattern order is the
LC_ALL=Cshell order, taken from the encoded bytes of each name, so one code path sorts on all three targets, and only Linux was executed, while macOS and Windows stay unvalidated --format rawconcatenates every target with no header, no separator and no newline of its own, soatomwrite read --format raw '*.rs' | cmp - <(LC_ALL=C cat *.rs)exits 0 with an empty diff- The batch copies in 64 KiB blocks, so memory stays flat instead of holding the sum of every file, and
--timeout-secsstill cuts the copy with exit 124 because every block advances the cancel check - A target that fails prints one line on stderr and the run continues with the next one, and the final status is the semantic code of the first failure: 4 for a missing path, 13 for a permission, 126 outside the
--workspace read --format rawerrors now go to stderr and never to stdout, because that channel promised bytes and a JSON envelope there was the defect--lines,--line,--context,--head,--tail,--grep,--statand--verify-checksumneed a single target: naming several exits 65 with a message that names the flag**is out of scope: a pattern with**or with more than one separator exits 65 instead of matching something else in silence- The default NDJSON format is unchanged, and one target in
--format rawis byte-identical to 0.1.37 [profile.dev] opt-level = 1cut the dev-profile fuzzy cost from 18533 ms to 4232 ms on the same 15 MB corpus- Pin agents to
^0.1.37. 47 subcommands (SSOT)
What Is New In v0.1.37 (2026-10-31)
- Risk assessment now runs in every verb that writes:
edit,edit-loop,replace,case,transformandcodemodpublishrisk_assessmentwhen the payload matches a content-risk pattern, exactly aswritealready did. The size barriers stay out of these verbs on purpose, because they rewrite a region and a shorter result is the operation working - A grammar this host cannot provide is exit 69
GRAMMAR_UNAVAILABLEwith classprecondition_failed, never 255INTERNAL_ERROR.atomwrite doctorreports the newgrammar_cachecheck with how many of the 23 grammars the AST verbs can need are already cached write.content_risk_patternsis reachable withconfig getandconfig setas a list value, so the risk patterns are XDG configuration instead of a compiled literal (43 keys)log.fileandlog.rotationare accepted in the workspace scope too, and the[log]section of.atomwrite.tomlnow starts the log sink instead of being validated and discardedbatch --transactionpublishes one verdict: therollbackevent carriesok: falsewith thecodeandexitof the failure that caused it, and the transaction locks every target in path order before the snapshot--versionno longer appends-dirty, so an untracked file cannot change the string
What Is New In v0.1.37 (2026-10-15 draft)
- Full history lives in CHANGELOG.md, the upgrade steps live in docs/MIGRATION.md
- New
configverb (the 47th subcommand):config path|list|get|set|unset|doctorreads and writes 37 persistent tuning keys, see Configuration - New
extract-artifactverb: bounded signal from PDF, OOXML and image headers, never raw bytes - Global stream shaping:
--sort-by,--dedupe,--aggregate,--join,--diff-against,--redact,--normalize-encoding,--truncate-content,--max-output-bytes, see Global Flags - The terminal success event carries
ok: true(the per-item events of a stream, such asentryandmatch, do not), and a failing run ends in exactly one terminal event withok: false - Verbs that write take an explicit path (exit 2 without one), and the terminal event carries
target_resolvedandtarget_source: "argv" - Every terminal event also carries
workspace_source:argvwhen the root came from--workspace, andcwdwhen it came from the process working directory edit-loopis all-or-nothing: a pair with no match exits 65 and writes nothing, while--partialwrites the matches and exits 87; the checksum it reads under the lock is the write base, so a concurrent edit exits 82STATE_DRIFT- Atomic writes take an automatic advisory lock (waits up to 5 s, exit 83), and
search,write,editand the other stdin verbs obey SIGTERM, SIGHUP and the deadline (exit 143, 129, 124) watchleft the default feature set, and--versionprintsatomwrite 0.1.37 (<sha>) <target triple>inside a tracked checkout andatomwrite 0.1.37 (no-git) <target triple>outside one- Changes that can break a consumer:
- top-level JSON fields whose value was
nullare no longer emitted: test for an absent key, not fornull --max-output-bytesnow requires--allow-truncate, and each flag alone exits 2semantic-mergewith a conflict exits 84 (MERGE_CONFLICT), andapplywith a unified diff that does not match the file exits 65 and writes nothing- an invalid regex or glob exits 65, not 255, and
get,setanddelon an invalid TOML or JSON file exit 65 case,transform,scopeandcodemodcan exit 82 (STATE_DRIFT) when a file changed during the runsparse listapplies--includeand--exclude, andsearch.max_inflight_bytesstarts at 4 MiB- the Rust library API changed, see Library API
- top-level JSON fields whose value was
- Pin agents to
^0.1.37. 47 subcommands (SSOT). CLI + XDG only (no productATOMWRITE_*knobs; no product telemetry). Error envelopes always emit, with two deliberate exceptions: a broken pipe and a checksum divergence already published as onehash_verifyevent
Why
- LLM agents juggle dozens of shell commands to manipulate files
- A crash mid-write can corrupt a file written in place
- 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
Objectives
- Spend fewer tokens: one NDJSON object per call replaces the shell pipeline, and
commands --briefanswers in 5 020 bytes where the full tree costs 67 492 - Lower the financial cost, because the bill follows the tokens and the round trips, and one call replaces the several shell calls a file task needs
- Reduce errors with an atomic write and a BLAKE3 checksum on every response, so a stale or partial result is caught instead of assumed
- Reduce hallucinations with a
typediscriminator, a closed schema per verb and an exit code that names the failure - Reduce the time spent on each task, because the read, the search and the write run in one process instead of a chain of shell tools
- Reduce latency with local execution and no network on the file path, measured at medians of 5.6 ms on
readand 6.7 ms onwritefor small files - Multiply the speed of operations with
batch,edit-loop,replace,case,transformandcodemodsettling many files in one call - Cut the lead time between the request and the verified result, because the response already carries the checksum, the
target_resolvedand the next step - Make the agent faster, more effective and more assertive, since the exit code, the
codeand thesuggestionsay what to do next without a retry guess
Superpowers
Atomic Writes
- Uses tempfile + fsync + rename + directory fsync on every write
- A reader sees the old file or the new file, never a half-written one
- Durability is set by
write --durability full|fast|auto(defaultauto); a power cut was not simulated in the tests - Optional real syntax check via tree-sitter (
--syntax-checkflag onwrite, exit 88) - Optional WAL sidecar for crash recovery (
.atomwrite.journal.<target>.atomwrite.journal.json)
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 on stdout with
ok: falsepluscode,exit,messageandsuggestion
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
transformandcodemodrewrite by syntax tree through ast-grep 0.43, which supports 28 languages (measured: each of the 28 names is accepted,ziganderlangexit 65unsupported language)query,outlineand--syntax-checkusetree-sitter-language-pack1.22.1, whose manifest lists 372 languages (measured on 2026-10-31 against the manifest of that version)- Automatic language detection by file extension covers 23 languages (
src/syntax_check.rs);--language NAMEaccepts a parser that is already in the local cache - 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
Structured Config Editing
setwrites a value at a dotted path in TOML or JSON files (preserves comments viatoml_edit)getreads a value at a dotted path with auto-detected formatdelremoves a key (with--force-missingto treat missing keys as no-op success)caserenames identifiers inside files viaheck(snake, camel, pascal, kebab, screaming-snake)
Usage
- All output goes to stdout as NDJSON
- Logs go to stderr: warnings and errors always, info and debug with
-v/-vv - Always pass
--workspace <DIR>to restrict operations to a project root - Use
--dry-runbefore destructive operations - Use
--expect-checksum <HASH>for optimistic locking - Use
--locale <TAG>oratomwrite locale --set/locale --clearfor UI locale (en,pt-BR); NDJSON codes stay English - Configuration is CLI flags + XDG /
.atomwrite.tomlonly, see Configuration - Pipe stdin for
writeandbatchcommands - Agent-native stdout globals (all subcommands):
--select/--fields(CSV top-level keys),--filter KEY=VAL(repeatable AND),--limit N(long-only: there is no global-n, andreplaceowns short-n) - Error NDJSON always has
ok: falseand usuallymatch_count: parseexit/codefirst; success shaping via--filter/--limitnever drops error envelopes
Global Flags
- 33 flags are accepted before or after the subcommand (source:
atomwrite commands --include-globals); a hidden--jsonis also accepted and ignored because the output is always NDJSON - The short help
-hof a subcommand lists only that verb's own flags, and its footer line points toatomwrite --helpfor the 33 globals - Aliases:
--max-concurrencyfor-j/--threads,--timeoutfor--timeout-secs,--fieldsfor--select - Flags named like a global but local to one command (for example
search --max-filesize, 10 MiB by default) are listed inatomwrite <command> --help
| Flag | Default | What it does |
|---|---|---|
-v, --verbose |
off | raises log verbosity on stderr (-v info, -vv debug, -vvv trace) |
-q, --quiet |
off | lowers it (-q error, -qq off) |
--workspace <DIR> |
current directory | root of the path jail, always pass it |
--config <PATH> |
none | explicit .atomwrite.toml, fails if missing or malformed; replaces both files in config get and config list |
--color <WHEN> |
auto |
auto, always or never |
--no-color |
off | disables colored output |
--ready-file <PATH> |
none | writes the PID after the signal handlers are installed (test harness only) |
--no-gitignore |
off | does not respect .gitignore files |
--hidden |
off | includes hidden files and directories |
--follow-symlinks |
off | follows symbolic links |
-j, --threads <N> |
automatic | worker bound; omitted or 0 = the smaller of logical CPUs, 16 and the RAM cap; an explicit N is honoured, also above 16 |
--max-filesize <BYTES> |
1 GiB | rejects a larger file (read, edit, hash and write exit 65 FILE_TOO_LARGE), and on write it also bounds the stdin payload, so the flag names one ceiling and the payload and the target obey the same one; only search skips silently, with its own local 10 MiB limit counted in files_skipped |
--timeout-secs <N> |
120 | global deadline, 0 disables it, exit 124 with a cancelled event that has deadline_exceeded: true |
--no-progress |
off | disables NDJSON progress events on long operations |
--json-schema |
off | emits the JSON Schema of the command output and exits |
--print-schema [NAME] |
none | lists the 55 schema names, or emits one schema; an unknown name exits 65 |
--non-interactive |
off | declares agent-hosted execution: never prompts, never reads a confirmation from stdin |
--confirm-side-effect |
off | acknowledges a side effect where a command contract asks for it; on a verb that writes nothing it is rejected with exit 65 INVALID_INPUT instead of being a silent no-op |
--allow-truncate |
off | opts in to value truncation, required by --max-output-bytes |
--locale <TAG> |
resolved | en or pt-BR; precedence: this flag, the saved preference, the OS language, en |
--no-auto-heal |
off | skips the startup wal-heal pass (3600 s threshold, 100 ms budget) |
--select <KEYS> |
all keys | keeps only the listed top-level keys (CSV) |
--filter <KEY=VALUE> |
none | keeps events whose key equals the value (!= and == work; repeatable, AND); never drops an error envelope |
--limit <N> |
none | work budget: the target list is cut before the side effect and the walk stops at the record that reaches the cap, so --limit 1 touches exactly one target and a huge tree is not read to the end; and the terminal summary carries walker_stopped_early: true only when the walk was actually cut before the tree ended |
--sort-by <KEY> |
arrival order | sorts events by path-line, line-path or any key (buffers until the end) |
--dedupe <KEYS> |
off | drops events whose key tuple (CSV) was already seen |
--aggregate <KEY[:OP[:FIELD]]> |
off | groups buffered events by KEY; OP is count, sum, min or max |
--join <KEY:SUFFIX> |
off | reads the NDJSON table from stdin once (up to 16 MiB) and attaches the matching rows as a SUFFIX array to every data event that has KEY; events without KEY or without a match, failure events and the summary stay as they were; runs before --select, --filter and --limit (with --sort-by, --dedupe or --aggregate: after the sort, before the dedupe); exits 65 INVALID_INPUT for a TTY stdin, a table above 16 MiB, a line that is not a JSON object, a bad format, a KEY with no row holding a string value, or a command that already reads stdin (write, edit, edit-loop, apply, extract, batch without --file, hash --stdin, calc or regex reading stdin, diff with -) |
--truncate-content <KEY:LEN> |
off | cuts one string key to LEN characters |
--redact |
off | replaces secret-shaped values with [redacted] |
--normalize-encoding |
off | normalizes every string value to Unicode NFC |
--diff-against <PATH> |
off | compares the events against a baseline NDJSON file inside the jail and emits one stream_diff event |
--max-output-bytes <N> |
off | cuts every string value, checksum included; needs --allow-truncate and each flag alone exits 2 |
# Stream shaping examples
|
Commands (47 total — SSOT)
Core I/O
read— read files with metadata, checksum and a bounded body:--format raworndjson,--head,--tail,--linesand--range(repeatable),--number,--symbol NAME,--line N --enclosing,--no-comments,--all, and--pages,--max-tokens,--cropor--ocrfor a PDF or a picturewrite— create or overwrite files atomically via stdin (large existing targets need--ack-overwrite)edit— surgically edit by line number, text marker, or exact matchedit-loop— apply Nold/newpairs from NDJSON stdin in one atomic writedelete— delete files, copying one only when the call asks (--backupor[defaults].backup = true;--planplan-only;--confirm/--yesrejected)copy— copy files with checksum verificationmove— move or rename files atomically (EXDEV copy-fallback)apply— apply patches from stdin (unified diff, search/replace, full, markdown); the target is optional so one call patches several files,--showreturns the changed lines with their numbers, and--no-syntax-checkopts out of the pre/post parsescratch— create agent staging dir under workspace (never OS/tmp)verify— verify file integrity by comparing BLAKE3 checksum
Search and replace
search— search file contents in parallel (ripgrep engine);--format textprints onepath:line:col:textper match under a byte cap,-e/--regexrepeats a pattern andsearch.formatmakes the text format the defaultreplace— replace text across files with atomic writestransform— AST refactoring via ast-grep (28 languages)codemod— multi-rule codemod campaign (YAML rules, delegates to transform)semantic-search— offline token Jaccard search (no network, no embeddings API)semantic-merge— three-way line-based merge (not AST/embedding) for multi-agent writes
Inspection
hash— calculate BLAKE3 checksumsstat— metadata alias forread --stat(size, mode, checksum; no body)count— count lines, matches, or files by extensiondiff— compare two files or a file against stdin (unified or stat), reporting a 1-basedlineplus the separateold_lineandnew_linelist— list the project file structure with metadata (one NDJSON record per entry, or one path per line with--format text, wheretotal_bytescounts files only)sparse— budgeted sparse list/read/outline (cap files and bytes for agent context)extract— extract fields from NDJSON input via pipe (positional fields or local--field; never localextract --select: global--selectonly projects output keys)extract-artifact— bounded signal from PDF, OOXML and image headers (never raw artifact bytes)scope— grammatical scoping (delete all comments, etc.)regex— generate regex from examplescalc— math and unit conversionsdoctor— diagnose environment and dependencieslocale— show resolved UI locale / persist preference (XDG)commands— emit full command tree as JSON for agent discovery, and--briefprints one line per subcommandconfig— persistent tuning keys:config path|list|get|set|unset|doctor, 43 keys,--scope global|workspacerequired onsetandunset(and onpath)agent-surface— agent tool surface manifest (integration by subprocess, CLI with NDJSON output)watch— watch filesystem events (needs a build with--features watch; the default binary exits 78)completions— generate shell completions (bash, zsh, fish, elvish, powershell)
Backup and recovery
backup— create timestamped backups with BLAKE3 checksumsrollback— restore from a previous backupprune-backups— prune.bak.YYYYMMDD_HHMMSSbackups by age or countbatch— NDJSON-driven batch operations (transactional)recipe— named multi-step recipes (list/run)
Structured config editors
set <PATH> <KEY_PATH> <VALUE>— write a value at a dotted path in a TOML or JSON file, preserving comments and key order viatoml_editget <PATH> <KEY_PATH>— read a value at a dotted path, NDJSON{"type":"get","key_path","value","found","format"}del <PATH> <KEY_PATH>— remove a key,--force-missingtreats a missing key as a no-op successcase <FILES...> --subvert OLD NEW --to <style>— rename identifiers inside the given FILES viaheck(styles:snake,camel,pascal,kebab,screaming-snake); a directory argument expands through the shared walker and honours--includeand--exclude, and a directory that yields no file exits 65 instead of succeeding with nothing renamed
AST tools (via tree-sitter-language-pack)
query <PATH> [--kinds|--query <KIND>|-Q <KIND>|--tree] [--positions]— walk a tree-sitter AST and emit nodes as NDJSONoutline <PATH> [--kind <KIND>] [--positions] [--format tsv]— extract high-level structure (functions, classes, structs, enums, traits, modules, Markdown headings) as NDJSON or asline<TAB>kind<TAB>name; needs a file, not a directory, and publishesparse_errorswithfirst_error_linewrite --syntax-check— real syntax check via tree-sitter, exit 88 with first error line, column, kind and message
WAL cleanup
wal-stats— telemetry snapshot: total journals, by-state breakdown, oldest age, total size, by-directory breakdown, auto-heal recommendation, estimated reclaim byteswal-heal <PATH> [--threshold-secs N] [--max-duration-ms N]— reap stale terminal (committed or aborted) journals older than the threshold, and also remove aStartedjournal whose owning PID no longer exists, reported asdead_owner_removed
Common patterns for each subcommand
# read (bounded at read.max_output_bytes; --all removes the cap)
# write
|
# edit
# edit-loop (N old/new pairs, one atomic write)
|
# scratch: stage under .atomwrite/scratch/, never OS /tmp outside --workspace, for --old-file/--new-file
# verify
# search (search.format = text makes the cheap shape the default)
# replace
# hash
# delete
# count
# diff
# move
# copy
# list
# extract: positional fields or local --field; NEVER local extract --select
|
|
# thin agent shape (global --select projects output keys only):
# extract-artifact (PDF, OOXML or image header; an image here)
# calc
# regex
# transform
# scope
# batch
|
# backup
# rollback
# prune-backups
# apply: the target may come from the patch, so one call patches several files
|
|
# set
# get
# del
# case: a file or a directory (the directory is expanded through the walker)
# query
# outline
# wal-stats
# wal-heal
# stat
# sparse
# semantic-merge (line-based, not AST; exit 84 when there are conflicts)
# recipe
# agent-surface
# watch (needs a build with --features watch; the default binary exits 78)
# codemod
# semantic-search
# doctor
# locale
# commands (full clap tree for agent discovery; --brief fits one screen)
# completions
# config (persistent tuning keys, see Configuration)
codemod --rulesreads a YAML list of items withlanguage,pattern,rewriteand an optionalid; the ast-grep stylerule:andfix:form exits 65prune-backups --dry-runtakes no value: omit the flag to apply the pruning
Local Flags Per Command
- Each command accepts the local flags listed here on top of the 33 global flags in the Global Flags section
agent-surface:--formatapply:--strict-atomic,--format,--backup,--no-backup,--keep-backup,--retention,--dry-run,--ack-overwrite,--allow-shrink,--show,--all,--no-syntax-checkbackup:--output-dir,--retention,--dry-runbatch:--strict-atomic,--dry-run,--file,--transaction,--input-schema,--batch-size,--backup,--no-backup,--keep-backup,--retentioncalc:--stdincase:--strict-atomic,-g/--include,--exclude,--subvert,--to,--backup,--no-backup,--keep-backup,--retention,--preserve-timestamps,--dry-runcodemod:--strict-atomic,--rules,--dry-run,--backup,--no-backup,--keep-backup,--retentioncommands:--include-globals,--briefcompletions:--installcopy:--strict-atomic,--backup,--no-backup,--keep-backup,--retention,-f/--force,-r/--recursive,--preserve,--dry-run,--no-reflink,--preserve-xattrcount:--by-extension,--by-size,--top,-g/--include,--excludedel:--strict-atomic,--dry-run,--backup,--no-backup,--keep-backup,--retention,--preserve-timestamps,--force-missingdelete:--backup,--no-backup,--keep-backup,--retention,-r/--recursive,-g/--include,--exclude,--older-than,--plan,--dry-run,--confirm,-y/--yesdiff:--unified,--stat,-C/--context,--algorithmdoctor:--strictedit:--after-line,--before-line,--range,--delete-range,--after-match,--before-match,--between,--old,--new,--old-file,--new-file,--fuzzy,--multi,--expect-checksum,--line-ending,--dry-run,--preserve-timestamps,--partial,--fuzzy-threshold,--replace-all,--wal-policy,--strict-atomic,--backup,--no-backup,--keep-backup,--retention,--allow-sequential-driftedit-loop:--strict-atomic,--allow-sequential-drift,--partial,--backup,--no-backup,--keep-backup,--retention,--syntax-check,--line-endingextract:--field,-d/--delimiter,--stdinextract-artifact:--max-sample-rows,--max-text-charshash:--verify,--stdin,-r/--recursive,--excludelist:-d/--depth,-l/--long,--count-by-ext,--format,--all,-g/--include,--excludelocale:--set,--clearmove:--backup,--no-backup,--keep-backup,--retention,-f/--force,--dry-run,--preserve-hardlinksoutline:--language,--kind,--positions,--formatprune-backups:--max-age-secs,--max-count,-r/--recursive,--dry-runquery:--language,-Q/--query,--tree,--kinds,--positionsread:--lines,--all,--number,--no-comments,--symbol,--enclosing,--line,-C/--context,--head,--tail,--stat,--format,--bytes,--verify-checksum,--grep,--crop,--max-tokens,--force,--pages,--page,--dpi,--ocr,--high-resregex:--stdin,-d/--digits,-w/--words,-s/--spaces,-r/--repetitions,-i/--case-insensitive,--no-anchorsreplace:--strict-atomic,--regex,-w/--word,-F/--literal,--backup,--no-backup,--keep-backup,--retention,-g/--include,--exclude,--preview,-n/--max-replacements,--expect-checksum,--dry-run,--preserve-case,--fuzzy,--fuzzy-threshold,--progress-every,--preserve-timestampsrollback:--strict-atomic,--timestamp,--latest,--verify,--backup,--no-backup,--keep-backup,--retention,--dry-runscope:-l/--language,--query,--pattern,--delete,--action,--replace-with,-g/--include,--exclude,--dry-run,--backup,--no-backup,--keep-backup,--retention,--strict-atomicsearch:-e/--regex,-F/--fixed,-w/--word,-i/--case-insensitive,-S/--smart-case,-C/--context,-g/--include,--exclude,-c/--count,-l/--files,-m/--max-count,-U/--multiline,--invert,--sort,--include-fifo,--max-filesize,--max-columns,--binary,--no-begin-end,-P/--pcre2,--target,--offset,--limit,--formatsemantic-merge:--strict-atomic,--base,--ours,--theirs,--output,--fail-on-conflict,--write-conflict-markers,--no-conflict-markers,--expect-checksum,--dry-run,--backup,--no-backup,--keep-backup,--retentionsemantic-search:--k,--min-score,--index-dir,--include-backupsset:--strict-atomic,--dry-run,--backup,--no-backup,--keep-backup,--retention,--preserve-timestampsstat:--lines,--all,--number,--no-comments,--symbol,--enclosing,--line,-C/--context,--head,--tail,--stat,--format,--bytes,--verify-checksum,--grep,--crop,--max-tokens,--force,--pages,--page,--dpi,--ocr,--high-restransform:--strict-atomic,-p/--pattern,-r/--rewrite,-l/--language,-g/--include,--exclude,--dry-run,--rules,--inline-rules,--backup,--no-backup,--keep-backup,--retention,--verify-parsewal-heal:--threshold-secs,--max-duration-ms,--dry-runwal-stats:--dry-runwatch:--debounce-ms,--max-events,--idle-exit-ms,--checksum,--gitignorewrite:--backup,--no-backup,--keep-backup,--retention,--max-size,--append,--prepend,--syntax-check,--durability,--expect-checksum,--allow-shrink,--line-ending,--allow-empty-stdin,--no-checksum-when-empty,--wal-policy,--strict-atomic,--preserve-timestamps,--require-backup,--confirm,--require-large-ack,--ack-overwrite,--auto-rotate,--risk-threshold,--dry-runconfig,get,recipe,scratch,sparseandverifytake no local flag, and their options come from the global set and from their own subcommands
Configuration
- Precedence: CLI flags, then the workspace
.atomwrite.toml, then the global XDGconfig.toml(the two files are merged key by key), then the built-in defaults config path|list|get|set|unset|doctoris the only way to change a persistent tuning keyconfig set KEY VALUE --scope global|workspaceandconfig unset KEY --scope global|workspacerequire--scope(exit 2 without it, nothing is touched), andconfig pathtakes it tooconfig listandconfig get KEYtake no--scope: they showvalue,origin(default,global,workspaceorexplicitwith--config PATH) anddefault- Scope
globalis the XDGconfig.toml(mode 0600), scopeworkspaceis.atomwrite.tomlin the workspace root setkeeps comments, validates the whole file and writes by tempfile-fsync-rename without a backup; the terminal event carriestarget_resolvedandtarget_source: "argv"- An unknown key or a value out of range exits 65 and writes nothing; a file that is not valid TOML is never rewritten (
setandunsetexit 78);configworks even with a brokenconfig.toml - A flag still wins over the configuration (for example
extract-artifact --max-text-chars)
| Key | Type | Default | Accepted | Scopes |
|---|---|---|---|---|
fuzzy.mode |
string | auto |
auto, aggressive, off |
global, workspace |
fuzzy.threshold |
float | 0.7 | 0.0 to 1.0 | global, workspace |
fuzzy.threshold_aggressive |
float | 0.5 | 0.0 to 1.0 | global, workspace |
fuzzy.threshold_context |
float | 0.8 | 0.0 to 1.0 | global, workspace |
fuzzy.threshold_jw |
float | 0.85 | 0.0 to 1.0 | global, workspace |
fuzzy.soft_floor_delta |
float | 0.05 | 0.0 to 1.0 | global, workspace |
fuzzy.max_content_bytes |
integer | 268435456 (256 MiB) | 1 or more | global, workspace |
write.confirm_large_bytes |
integer | 102400 (100 KiB) | 1 or more | global, workspace |
log.file |
boolean | false |
true, false |
global, workspace |
log.rotation |
string | daily |
daily, hourly |
global, workspace |
storage.home |
string | none | a directory | global only |
locale |
string | none (resolved) | en, pt-BR |
global only |
concurrency.max_threads |
integer | 16 | 1 to 256 | global, workspace |
concurrency.ram_fraction_percent |
integer | 50 | 1 to 100 | global, workspace |
search.max_inflight_bytes |
integer | 8388608 (8 MiB) | 4194304 (4 MiB) to 1073741824 (1 GiB) | global, workspace |
summary.errors_max_entries |
integer | 50 | 1 to 1000 | global, workspace |
lock.acquire_timeout_ms |
integer | 5000 | 100 to 3600000 | global, workspace |
retry.base_ms |
integer | 50 | 1 to 60000, not above retry.max_ms |
global, workspace |
retry.max_ms |
integer | 400 | 1 to 60000 | global, workspace |
retry.max_elapsed_ms |
integer | 2000 | 1 to 3600000 | global, workspace |
extract.max_sample_rows |
integer | 10 | 0 to 100000 | global, workspace |
extract.max_text_chars |
integer | 400 | 1 to 10000000 | global, workspace |
extract.max_sheets |
integer | 32 | 1 to 10000 | global, workspace |
extract.max_slides |
integer | 64 | 1 to 10000 | global, workspace |
read.max_output_bytes |
integer | 24000 | 1 or more | global, workspace |
read.number |
boolean | false |
true, false |
global, workspace |
search.format |
string | ndjson |
ndjson, text |
global, workspace |
output.profile |
string | full |
full, lean |
global, workspace |
apply.max_ellipsis_lines |
integer | 200 | 1 or more | global, workspace |
delete.backup |
boolean | absent | true, false |
global, workspace |
read.max_output_bytesis the ceilingreadhonors before it prints the next--lineson stderr and marks the NDJSON event withtruncated: trueplus thenexthint, and--allis the per-call way past itread.numbermakes--numberthe default, andsearch.formatmakes--format textthe default, while an explicit flag still winsoutput.profile = "lean"drops the digests, the byte counts and the timing from a successful mutation record, andfullis the defaultapply.max_ellipsis_linesbounds the span a...line may match inside a SEARCH blockdelete.backupis absent by default and inheritsdefaults.backup, because a rewrite copies and a delete does not unless the call asks- A scope outside the last column exits 65 (for example
config set storage.home /srv --scope workspace) - These fields are
configkeys like every row above, and each answersconfig get:defaults.backup,defaults.retention,defaults.line_ending,defaults.max_filesize,write.shrink_block_percent,write.auto_rotate_max_age_secs,write.content_risk_patterns,watch.idle_exit_ms,watch.debounce_ms,search.context,search.smart_case,search.max_filesizeandsearch.max_columns; an unknown section in.atomwrite.tomlmakesreadexit 78 (measured) - Files on Linux: global config
$XDG_CONFIG_HOME/atomwrite/config.toml, saved locale$XDG_CONFIG_HOME/atomwrite/locale, log$XDG_STATE_HOME/atomwrite/logs/atomwrite.<date>.jsonl(only withlog.file = true, file mode 0600, directory 0700), parsers$XDG_CACHE_HOME/tree-sitter-language-pack/v1.22.1/ - macOS and Windows resolve the same files through the
directoriescrate; those paths were read from the code and not run there storage.homemovesconfigandstateunder{home}/configand{home}/state
Environment Variables
- Product policy: atomwrite does not use product environment variables for runtime knobs (workspace, backup, locale, log filter, home override, WAL, etc.)
- Configure via CLI flags and XDG storage /
.atomwrite.toml(and optional--config) doctorreads no environment variable: host detection (WSL, container, Kubernetes, Termux, Flatpak, Snap) uses file probes only, and it is not a configuration API- Dependencies read some variables on their own, never as atomwrite configuration: the OS-language crate (
LANG,LC_ALL,LC_MESSAGES,LANGUAGE), the XDG crates (HOME,XDG_*) and the parser download client (ALL_PROXY,HTTPS_PROXY,HTTP_PROXY,NO_PROXY); see ADR-0057 in docs/decisions/ - Shell-level variables used by your agent harness (PATH, etc.) are outside atomwrite product config
Network And Privacy
- No telemetry: atomwrite sends nothing about you or your files
- The only network traffic is the parser download used by
query,outlineandwrite --syntax-check(the last one read from the source, not run);transform,scopeandcodemoduse ast-grep parsers compiled into the binary - On the first use of a language, the binary downloads the parser bundle for the platform from
https://github.com/xberg-io/tree-sitter-language-pack/releases/download/v1.22.1/(for Linux x86_64 the fileparsers-linux-x86_64.tar.zst, 23031807 bytes in the manifest, about 22 MiB, plus 3.9 MiB of extracted parser libraries for the six languages this machine used so far); the manifest carries asha256for each platform bundle - The cache lives at
$XDG_CACHE_HOME/tree-sitter-language-pack/v1.22.1/(bundles,libs,manifest.json), and the download happens only while the needed parser is missing there - The download client honours the proxy variables listed in Environment Variables
- Offline use: fill the cache directory on a host with network access and copy it to the offline host
- A panic writes a crash report file
report-<uuid>.tomlin the OS temporary directory (through thehuman-paniccrate) and prints its path; nothing is transmitted, and you choose whether to send it - Details: PRIVACY.md
Exit Codes
- Error envelopes on stdout are always NDJSON with
ok: false(and usuallymatch_count); readexit/codebefore treating a line as success - The list below is derived from the error enum and checked against
agent-surfaceand--help
0SUCCESS: success1NO_MATCHES: no matches found (search, replace, transform, scope; not a crash)1DOCTOR_CHECKS_FAILED:doctor --strictfound failed or warned checks (the report event carries every check)2ARGUMENT_PARSE_ERROR: command line rejected by the parser2UNSUPPORTED_COMBINATION: two flags this verb refuses to combine (readflagandotherin the envelope)4FILE_NOT_FOUND: file not found4GLOB_NO_MATCHES: pattern expanded to no file13PERMISSION_DENIED: permission denied28DISK_FULL: disk full (no space left on device)30QUOTA_EXCEEDED: quota exceeded65INVALID_INPUT: invalid input (bad arguments or malformed data, including empty stdin without--allow-empty-stdinand a file above[fuzzy].max_content_bytesunder fuzzy)65MATCH_FAILED: pattern did not match, or anedit-looppair has no match (readbest_candidate)65MATCH_AMBIGUOUS: pattern matched more than once (readbest_candidate)65BINARY_FILE: binary content rejected65FILE_TOO_LARGE: file above the size limit69GRAMMAR_UNAVAILABLE: the tree-sitter grammar for a language is not on this host (classprecondition_failed, retryablefalse)73CROSS_DEVICE: cross-device rename (filesystem boundary)74IO_ERROR: I/O error78CONFIG_INVALID: configuration invalid, or a verb that needs a feature missing from this build (slim)79SYMLINK_BLOCKED: symlink refused by the jail; pass--follow-symlinksto resolve it and check the target against the workspace80TRANSACTION_ROLLBACK_FAILED: batch transaction rollback failed (backups kept)81CHECKSUM_VERIFY_FAILED: checksum verify failed82STATE_DRIFT: state drift (checksum mismatch, optimistic lock failed)83LOCK_TIMEOUT: lock not acquired withinlock.acquire_timeout_ms(default 5000)84MERGE_CONFLICT:semantic-mergefound conflicts85FIFO_DETECTED: FIFO detected (named pipe cannot be atomically written)86DEVICE_FILE: device file detected (block or character device)87EDIT_LOOP_PARTIAL:edit-loop --partialwrote the matching pairs and some pairs missed88SYNTAX_ERROR_DETECTED: syntax error detected (--syntax-checkfailed)89ALL_SKIPPED_BINARY: every visited file was binary and was skipped, so nothing was searched (search; pass --binary to search it)91EXDEV_FALLBACK_DISABLED: EXDEV fallback disabled (cross-device copy-fallback is not allowed)92COPY_BACK_BLAKE3_FAILED: copy-back BLAKE3 verification failed93ORPHAN_JOURNAL: orphan journal detected124TIMEOUT: global--timeout-secsdeadline exceeded (default 120; pass0to disable)126WORKSPACE_JAIL: workspace jail violated (path escapes workspace)128IMMUTABLE_FILE: file immutable (cannot modify)129SIGHUP: terminal hangup (SIGHUP)130CANCELLED: run cancelled before it finished (status follows the cause)130SIGINT: interrupted by SIGINT141BROKEN_PIPE: broken pipe (SIGPIPE or aBrokenPipewrite error)143SIGTERM: terminated by SIGTERM255INTERNAL_ERROR: internal error
Signal Handling
- Unix: SIGINT (Ctrl+C), SIGTERM and SIGHUP are intercepted for a cooperative shutdown with exit 130, 143 and 129; the run ends with a
cancelledevent that carriessignalanddeadline_exceeded - Unix: SIGPIPE has a handler, it is neither ignored nor left at its default action; the handler marks a cooperative shutdown with exit 141
- The default SIGPIPE action killed the process before any destructor ran and left lock sidecars, journals and tempfiles of the writes in flight; with the handler every
Dropruns and nothing is left behind - A write that fails because the reader closed exits 141 (
BROKEN_PIPE) with no panic and no crash report:completions,--print-schema,--helpand every verb (fixed in 0.1.37, testcli_v0137_broken_pipe_outputs) - Very short output that fits in the pipe buffer (for example
--version | head -1) can finish before the reader closes and then exits 0 - A write that hits the closed pipe fails with
BrokenPipeand exits 141 as well, and a parent that ignores SIGPIPE gets the same exit 141 - A repeated SIGPIPE never forces an exit; a repeated SIGINT, SIGTERM or SIGHUP does
- Windows: Ctrl+C intercepted via console handler; there is no SIGPIPE, and
BrokenPipefromstdfollows the same path (not validated there) - First signal: sets the shutdown flag and prints a message on stderr in the active locale (
atomwrite: shutting down...with--locale en) - Second signal: immediate process termination via
_exit(Unix) orexit(Windows) - Walker threads (search, replace, transform, scope) stop between files
- Batch operations stop between operations
- Stdin verbs (
write,editand the others) obey the signals and the deadline while stdin is still open: SIGTERM exits 143 (measured)
Error Handling
- All errors emit a JSON object on stdout with
ok: falsepluscode,exit,messageandsuggestion - Error fields:
code,exit,pathwhen there is one,suggestionandworkspace -vrestores the diagnostic prose the default envelope drops:message,error_class,retryableandsuggestion_lang- Every summary that publishes
files_failedaddspartial: trueanderrors[]beside it (each entry haspath,codeandmessage,pathis<walk>when the walk failed without naming a file, at most 50), and that coverssearch,transform,replace,scope,count,list,sparse,semantic-searchandcase - Error classes:
permanent,transient,conflict,precondition_failed - 38 error variants in
src/error/variants.inc.rs, counted withrg -c '#\[error' src/error/variants.inc.rs - Transient and conflict errors set
retryable: true - The
suggestionfield provides actionable recovery guidance for agents in the active locale, andsuggestion_langnames that locale under-v - See
docs/schemas/error-output.schema.jsonfor the full contract
Performance
- Single binary; on Linux it links dynamically against the system C library and nothing else (
lddon the v0.1.37 build listslibgcc_s.so.1,libm.so.6andlibc.so.6) - Release builds use LTO, single codegen unit, and symbol stripping
- Memory-mapped file reads via
memmap2for large files - Parallel multi-file work is the default modus operandi:
ignore::WalkParallel/collect_files_parallel(search content +--target files, replace, count, transform, scope, recursive discovery) +rayon(hash, backup, multi-path + recursive delete/copy, case multi-path, semantic-search scoring, non-txn batch, prune multi-target, sparse read, diff dual-read) - Worker bound:
--threads/-j/--max-concurrency(default = the smaller of the logical CPUs, 16 threads and the RAM cap; an explicit-j Nis honoured as asked; seesrc/concurrency.rs) - Small-file latency: medians of 5.6 ms (
read) and 6.7 ms (write) in one session of 20 runs, and 9.4 ms and 9.7 ms in another of 30 runs, whole process included; machine: Intel Xeon E5-2699 v3 2.30 GHz with 72 logical CPUs, Linux, working directory on tmpfs, measured on 2026-10-19 while other jobs ran on the same host
Known Limits
replace --expect-checksumcompares the checksum under the lock, so a writer that lands between the check and the write is detected as exit 82STATE_DRIFT; verbs that read, change and write back (edit,edit-loop,replace,set,del,config set,apply,write --append) serialize under the lock- A target name long enough to push the sidecar past 255 bytes gets a short BLAKE3 digest as the sidecar name, so a 240-byte target locks instead of failing with
ENAMETOOLONG; a 244-byte target was proven withreplace - The lock is taken on the target's own inode, so a file the caller owns inside a read-only directory is written in place instead of refused with exit 13
- The
.<target>.atomwrite.locksidecar is best effort and its failure no longer aborts the write, because an older release that holds only that file still meets the inode lock - The RAM ceiling for the automatic worker count reads
MemAvailablefrom/proc/meminfoon Linux only and ignores container (cgroup) limits - Without
--sort-by, the order ofsearchresults varies from run to run because the walkers run in parallel caseexpands a directory argument through the shared walker and honours--includeand--exclude; a directory that yields no file exits 65 instead of succeeding with nothing renamedquery,outlineandwrite --syntax-checkdetect only 23 languages by extension;--language NAMEworks for a parser already extracted in the local cache, and exits 65unsupported language overridefor a language not yet usedextract-artifactemits a singleartifactevent and no summary, so a successful run has no event withok: truelocale --setandlocale --clearprint the resolved language from before the change; a followingatomwrite localeshows the new state- macOS and Windows were not run; the Unix-only code has
cfg(windows)pairs that were only compiled withcargo checkfrom Linux
Library API
- The supported interface of atomwrite is the CLI and its NDJSON contract; the crate also ships a Rust library target that is not covered by that promise
- The public Rust API of v0.1.37 changed against the published 0.1.36 in ways SemVer treats as breaking:
cargo semver-checks0.50.0 reported 10 failed major checks (removedlocale::Idiomaandlocale::{negotiate_to_idioma,resolved_idioma}, removedLocaleSource::EnvVar, removedsignal::reset_sigpipe, four removed lock constants,LockGuardno longerSendandSync, newCommandsvariants and new public struct fields without#[non_exhaustive], andwatchno longer a default feature) - Pin
atomwriteas a library dependency to an exact version (=0.1.38) and read CHANGELOG.md before every upgrade
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 --workspace . 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
search with a pattern that starts with a hyphen
- A pattern that starts with
-goes after--, the wayrgandgrepdo it atomwrite --workspace . search -F -- '-deprecated' src/searches for that literal text- Without
--the token is a flag the verb does not have, so the run exits 2 and prints the parser tipto pass '-Z' as a value, use '-- -Z'
search, replace and transform exit 4 although they printed matches
- A root named in the invocation that does not exist fails the run even when the other roots matched, in
search,replaceandtransform - The matches still reach stdout, and the summary carries
ok: false,code: FILE_NOT_FOUND,files_failedand the path inerrors[] - A file that fails during the walk is the other case:
partial: truejoins the summary, and the run keeps exit 0 insearch,replace,transform,scope,case,sparse,semantic-searchandbackup, whilecount,list,hash,copy,deleteandprune-backupsexit with the first failure because their answer is a total over the tree; the contract is ADR-0077 (docs/decisions/0077-answer-family-and-walk-honesty.md)
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
syntax check failed with exit 88
- The real tree-sitter syntax check found a syntax error in the file
- Inspect the first error line/column/kind/message in the JSON error envelope
- Fix the syntax and retry, or remove
--syntax-checkto bypass
empty stdin rejected with exit 65
- The guard rejected 0 bytes from stdin as a likely upstream-pipeline failure
- Pass
--allow-empty-stdinto confirm the empty input is intentional - Or pipe real content:
echo "x" | atomwrite --workspace . write file
edit hangs (or fails with exit 65) on --after-line/--after-match/--between/--multi
- These modes read replacement content from stdin, same as
write - A terminal stdin fails fast with exit 65
INVALID_INPUTinstead of blocking forever - Pipe content:
echo "new text" | atomwrite --workspace . edit file.rs --after-line 10 - Or use
--new-file <PATH>where the mode accepts it --after-match/--before-match/--between/--after-line/--before-line/--range/--delete-rangereject--old/--new/--old-file/--new-fileat parse time (exit 2): these modes only take content from stdin
watch exits 78
- The default binary is built without the
watchfeature - Rebuild with
cargo install --path . --locked --force --features watch
MSRV And Targets
- Minimum supported Rust version: 1.90 (edition 2024);
rust-toolchain.tomlpins channel 1.94 for development - Locales:
enandpt-BR - Linux x86_64 is exercised end to end
- Windows is checked with
cargo check --target x86_64-pc-windows-gnufrom a Linux host only - macOS was not exercised on a real Mac
Documentation
- docs/INSTALL.md: install, features and build profiles
- docs/HOW_TO_USE.md: full usage guide
- docs/COOKBOOK.md: task recipes
- docs/AGENTS.md: contract for LLM agents
- docs/CROSS_PLATFORM.md: platform notes
- docs/MIGRATION.md: upgrade paths between versions
- docs/TESTING.md: how the test suite is organized
- INTEGRATIONS.md: using atomwrite from agents and scripts
- PRIVACY.md: what the binary reads, writes and downloads
- llms.txt and llms-full.txt: summaries for LLM context windows
Architecture
- See ARCHITECTURE.md for module map, data flow, and design decisions
- See docs/decisions/ for the index of 77 ADRs (0019 to 0095; 3 more live in
docs/adr/) - Verification is running the program, not a test suite: every claim in this README is backed by a real invocation of the binary, and
docs/TESTING.mddescribes the harness for those cases a maintainer chooses to keep - See docs/schemas/ for the JSON Schema contracts of the NDJSON output, where 54 files describe the 55 names
atomwrite --print-schemalists
Contributing
- See CONTRIBUTING.md for development setup, local DoD, PR process, and release notes
- See CONTRIBUTING.pt-BR.md for the Portuguese guide
- Follow the Code of Conduct / Código de Conduta
Security
- See SECURITY.md for vulnerability reporting
- See SECURITY.md section "Known Security Advisories" for resolved and active advisories
- See PRIVACY.md for data handling
Changelog
- See CHANGELOG.md for English release history
- See CHANGELOG.pt-BR.md for Portuguese release history
License
- Licensed under MIT OR Apache-2.0
- See LICENSE-MIT and LICENSE-APACHE for details