Anatoly's watch mode is a long-running daemon that monitors your TypeScript files for changes and triggers incremental re-review automatically. It keeps the audit report up to date as you work, without requiring manual re-runs.
Table of Contents#
- Quick Start
- How It Works
- File Change Handling
- Performance Characteristics
- Locking
- Use Cases
- Configuration
- Comparison with Hooks
Quick Start#
npx anatoly watchThe process runs in the foreground. Press Ctrl+C to stop. On startup, it performs a full initial scan to index all matching files, then watches for incremental changes.
How It Works#
Watch mode uses chokidar (v5) to monitor the filesystem. The lifecycle is:
-
Initial scan: On startup,
scanProject()runs to index all files matching the configured glob patterns. This ensures the review cache and task files are populated before watching begins. -
File watcher: chokidar monitors the
scan.includeglobs with thescan.excludepatterns filtered out. It listens foradd,change, andunlinkevents. -
Sequential processing queue: Changed files are added to an internal queue and processed one at a time. Duplicate entries (same file queued multiple times before processing) are deduplicated.
-
Per-file pipeline: For each changed file:
- Compute SHA-256 hash.
- Parse the AST with web-tree-sitter to extract symbols.
- Write a
.task.jsonfile. - Run the evaluator (same review pipeline as
anatoly review). - Write the
.rev.jsonoutput. - Regenerate the aggregate
report.md.
-
File deletion: When a file is deleted (
unlinkevent), its task file, review file, and progress entry are removed. The report is regenerated to reflect the deletion. -
Graceful shutdown: On
SIGINT(Ctrl+C), the watcher closes and the lock file is released.
File Change Handling#
chokidar is configured with write stabilization to avoid processing partially-written files:
awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 }This means a file change event only fires after the file has been stable (no further writes) for 200ms, polled every 50ms.
Filtering:
- Files matching
scan.excludepatterns are ignored by chokidar. - Files tracked by
.gitignoreare skipped via a runtimeisGitIgnored()check. - Initial file events are suppressed (
ignoreInitial: true) since the startup scan already covers existing files.
Performance Characteristics#
| Aspect | Behavior |
|---|---|
| Startup | Full project scan (AST parsing + hashing). Scales linearly with file count. |
| Incremental | Only the changed file is re-scanned and re-reviewed. One API call per file. |
| Queue | Serial processing. Multiple rapid edits to different files are queued and processed in order. |
| Deduplication | If the same file is modified multiple times while a review is in progress, only one re-review is queued. |
| Report regeneration | After each review completes, the full report is regenerated from all cached reviews. This is a local operation (no API calls). |
| Memory | chokidar uses efficient filesystem watchers (inotify on Linux, FSEvents on macOS). Memory overhead is minimal for typical project sizes. |
| CPU | Idle when no files change. Each file change triggers AST parsing (fast, <100ms for most files) plus one LLM evaluation call. |
Typical latency: From file save to updated review, expect 5--15 seconds depending on file complexity and API response time.
Locking#
Watch mode acquires a project lock (acquireLock) on startup to prevent conflicts with concurrent Anatoly instances. This means:
- Running
anatoly runwhile watch mode is active will detect the lock and warn. - The Claude Code
post-edithook checksisLockActive()and exits silently if watch mode holds the lock, avoiding duplicate reviews. - The lock is released on graceful shutdown (
SIGINT).
If the process is killed forcefully (e.g., SIGKILL), the stale lock file may need manual removal. It is located at .anatoly/lock.
Use Cases#
Active Development#
Run watch mode in a terminal while coding. Every save triggers a background review, so you get near-real-time feedback on code quality without switching context.
# Terminal 1: your editor
# Terminal 2:
npx anatoly watchThe console shows live output:
anatoly -- watch
watching src/**/*.ts, src/**/*.tsx
press Ctrl+C to stop
initial scan 42 files (0 new, 42 cached)
scanned src/utils/cache.ts
reviewed src/utils/cache.ts -> PASS
scanned src/core/scanner.ts
reviewed src/core/scanner.ts -> NEEDS_WORKPre-Commit Verification#
Start watch mode, make your changes, then check the report before committing:
npx anatoly watch &
# ... make changes ...
# Check .anatoly/report.md
kill %1Pairing with Claude Code Hooks#
Watch mode and Claude Code hooks serve similar purposes but operate differently. You typically use one or the other, not both. See Comparison with Hooks below.
Configuration#
Watch mode respects the same .anatoly.yml configuration as all other commands:
scan:
include:
- 'src/**/*.ts'
- 'src/**/*.tsx'
exclude:
- 'node_modules/**'
- 'dist/**'
- '**/*.test.ts'
- '**/*.spec.ts'All llm settings (model, concurrency, min_confidence, axes, etc.) apply identically to watch mode reviews.
Comparison with Hooks#
Both watch mode and Claude Code hooks provide real-time audit feedback, but they target different workflows:
| Watch Mode | Claude Code Hooks | |
|---|---|---|
| Trigger | Filesystem events (any editor) | Claude Code Edit/Write tool calls |
| Scope | All file changes in the project | Only files edited by Claude Code |
| Feedback | Console output + report file | Injected directly into Claude Code as blocking feedback |
| Autocorrection | Manual (you read the report and fix) | Automatic (Claude Code fixes issues in-loop) |
| Best for | Manual development, any editor | Claude Code agentic sessions |
If you are using Claude Code and want automatic fix cycles, use the hooks (anatoly hook init). If you want passive monitoring during manual development, use watch mode.