> ## Documentation Index
> Fetch the complete documentation index at: https://chatcli.edilsonfreitas.com/llms.txt
> Use this file to discover all available pages before exploring further.

# File Staleness Detection

> mtime and SHA-256 tracking to detect external modifications between read and write

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:

<Steps>
  <Step title="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
  </Step>

  <Step title="Verification (CheckStaleness)">
    Before each `write` or `patch` operation, the tracker checks whether the file has changed.
  </Step>

  <Step title="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.
  </Step>
</Steps>

***

## 2-Step Verification

The verification uses an optimized strategy of **fast path** followed by **full hash**:

<Tabs>
  <Tab title="Step 1: mtime + size (fast)">
    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).

    ```text theme={"system"}
    mtime unchanged + size unchanged -> not stale (fast path)
    ```

    <Tip>
      This optimization avoids reading and hashing the file in most cases, keeping overhead near zero.
    </Tip>
  </Tab>

  <Tab title="Step 2: SHA-256 (full)">
    If `mtime` or `size` changed, the tracker reads the full file and computes the SHA-256 for definitive comparison.

    ```text theme={"system"}
    mtime changed + hash identical -> not stale (e.g., touch without edit)
    mtime changed + hash different -> STALE (real modification)
    ```

    <Note>
      This covers the case of `touch` on a file without editing (mtime changes but content is identical) and the rare case of a modification that maintains the same size.
    </Note>
  </Tab>
</Tabs>

***

## Warning Message

When a stale file is detected, the system generates a formatted warning:

```text theme={"system"}
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

| Scenario                | Result    | Description                         |
| :---------------------- | :-------- | :---------------------------------- |
| File not modified       | Not stale | mtime and size identical            |
| `touch` without editing | Not stale | mtime changes but SHA-256 identical |
| Real edit by user/IDE   | **Stale** | mtime and hash different            |
| File deleted            | **Stale** | File no longer exists               |
| File never read         | Not stale | No record to compare against        |
| Error during check      | Not stale | Assumes 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:

| Character | Description         | Replacement |
| :-------- | :------------------ | :---------- |
| `'` `'`   | 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.).

<Info>
  Documentation files (`.md`, `.txt`, `.rst`) are **not** normalized to preserve intentional typography.
</Info>

***

## Tracking Lifecycle

```text theme={"system"}
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

<CardGroup cols={2}>
  <Card title="Plugin @coder" icon="hammer" href="/features/coder-plugin">
    Complete reference for read/write/patch operations.
  </Card>

  <Card title="Permissions" icon="shield-halved" href="/features/enhanced-permissions">
    Permissions system that protects write operations.
  </Card>

  <Card title="JSON Recovery" icon="screwdriver-wrench" href="/features/json-recovery">
    How tool arguments are fixed before execution.
  </Card>

  <Card title="Coder Security" icon="lock" href="/features/coder-security">
    Path validation and security protections.
  </Card>
</CardGroup>
