Skip to main content
ChatCLI implements a file staleness detection system that tracks the state of files between read and write operations. When a file is modified externally (by the user, an IDE, or another process) after the agent has read it, the system emits a warning before overwriting — preventing the silent loss of external changes.

How It Works

The tracker records the state of each file after reading and verifies it before writing:
1

Read (RecordRead)

After each successful read operation, the tracker records:
  • mtime: file modification timestamp
  • SHA-256: cryptographic hash of the complete content
  • Size: size in bytes
  • ReadAt: timestamp of when the read occurred
2

Verification (CheckStaleness)

Before each write or patch operation, the tracker checks whether the file has changed.
3

Warning or Proceed

If the file has changed, a warning is injected into the tool result so the model can decide how to proceed. If it has not changed, the write proceeds normally.

2-Step Verification

The verification uses an optimized strategy of fast path followed by full hash:
First, the tracker compares the current mtime and size with the recorded values. If both are identical, the file is not stale (immediate return, no additional I/O).
mtime unchanged + size unchanged -> not stale (fast path)
This optimization avoids reading and hashing the file in most cases, keeping overhead near zero.

Warning Message

When a stale file is detected, the system generates a formatted warning:
WARNING: File "/path/to/file.go" has been modified externally since you last read it.
Reason: file modified externally (mtime: 2026-04-10T10:30:00Z -> 2026-04-10T10:35:22Z,
  size: 2048 -> 2156)
You should re-read the file before making changes to avoid overwriting external edits.
If you proceed anyway, external changes will be lost.
The warning instructs the model to:
  1. Re-read the file before making changes
  2. Understand that proceeding will overwrite the external changes

Covered Scenarios

ScenarioResultDescription
File not modifiedNot stalemtime and size identical
touch without editingNot stalemtime changes but SHA-256 identical
Real edit by user/IDEStalemtime and hash different
File deletedStaleFile no longer exists
File never readNot staleNo record to compare against
Error during checkNot staleAssumes not stale to avoid blocking

Quote Normalization

ChatCLI also normalizes Unicode quotes in code files to prevent compilation errors caused by typographic quotes generated by LLMs:
CharacterDescriptionReplacement
' 'Curly single quotes'
" "Curly double quotes"
'Prime'
"Double prime"
<< >>Angle quotes<< >>
Normalization is applied automatically to 60+ code file types (.go, .py, .js, .ts, .java, .rs, .sh, .sql, .json, .yaml, etc.) and to special file names (Makefile, Dockerfile, .gitignore, etc.).
Documentation files (.md, .txt, .rst) are not normalized to preserve intentional typography.

Tracking Lifecycle

1. @coder read main.go     -> RecordRead(main.go): records mtime + SHA-256
2. (user edits main.go in IDE)
3. @coder write main.go    -> CheckStaleness(main.go): detects change
                            -> WARNING injected into result
                            -> Model decides: re-read or proceed
4. @coder read main.go     -> RecordRead(main.go): updates record
5. @coder write main.go    -> CheckStaleness(main.go): not stale
                            -> Normal write
6. (after successful write) -> Clear(main.go): removes record

Next Steps

Plugin @coder

Complete reference for read/write/patch operations.

Permissions

Permissions system that protects write operations.

JSON Recovery

How tool arguments are fixed before execution.

Coder Security

Path validation and security protections.