sentinel
Overview
When a Crystal application writes files to disk that are concurrently monitored by a filesystem watcher (such as in static site generators, live compilers, or dev servers), the watcher receives notification events for those internal writes. Without suppression, this creates infinite echo feedback loops.
sentinel provides Sentinel::AntiEcho, a high-performance, concurrency-safe registry that lets background writers register impending writes before disk commit. Filesystem watchers query the sentinel to instantly distinguish between internal programmatic writes and external user modifications.
Key Features
- π‘οΈ Zero Background Timer Overhead: Expired suppression entries are evicted inline during reads and writes under mutex synchronization, eliminating fiber leaks and GC pressure.
- β‘ Execution Contexts Ready: Thread-safe synchronization backed by
Sync::Mutexfor multi-threaded Crystal runtimes (-Dpreview_mt). - π Cross-Platform CRLF Normalization: Pre-computes normalized SHA-256 checksums converting CRLF to LF to prevent phantom modification loops across different operating systems.
- π¦ Pure Crystal: Zero external shard dependencies. Uses only standard library primitives.
Architecture & Workflow
ββββββββββββββββββββββββ ββββββββββββββββββββββββ
β Writer Fiber / Task β β Watcher Routine β
ββββββββββββ¬ββββββββββββ ββββββββββββ¬ββββββββββββ
β 1. calculate_checksum β
β 2. register_write(path, hash) β
βΌ β
ββββββββββββββββββββ β
β Disk Write β β
β (File.write) β βββ [OS Inotify / FS Event] ββββΊ β
ββββββββββββββββββββ βΌ
ββββββββββββββββββββββββ
β 3. suppressed?(...) β
ββββββββββββ¬ββββββββββββ
β
ββββββββββββββββββββββ΄βββββββββββββββββββββ
βΌ βΌ
[ Match Found ] [ No Match ]
(Drop event: Internal Write) (Process: User Modification)
Installation
Add sentinel to your shard.yml:
dependencies:
sentinel:
gitlab: renich/sentinel
version: ~> 0.1.0
Run shards install.
Quick Start
require "sentinel"
# Initialize with 5-second suppression TTL
sentinel = Sentinel::AntiEcho.new(ttl: 5.seconds)
# 1. Compute checksum before writing to disk
content = "# Hello World\n"
checksum = Sentinel::AntiEcho.calculate_checksum(content)
# 2. Register write in sentinel and commit to disk
sentinel.register_write("content/post.md", checksum)
File.write("content/post.md", content)
# 3. Inside your filesystem watcher event callback:
file_on_disk = File.read("content/post.md")
current_checksum = Sentinel::AntiEcho.calculate_checksum(file_on_disk)
if sentinel.suppressed?("content/post.md", current_checksum)
puts "Suppressed echo event for internal write: content/post.md"
else
puts "External modification detected on content/post.md. Triggering build..."
end
API Reference
Sentinel::AntiEcho
| Method | Parameters | Description |
|---|---|---|
new(ttl : Time::Span = 10.seconds) |
ttl |
Creates a new anti-echo registry with given retention window |
register_write(path : String, checksum : String) |
path, checksum |
Registers an impending write in the thread-safe registry |
suppressed?(path : String, checksum : String) : Bool |
path, checksum |
Checks if a file event matches a known write and consumes/suppresses it |
size : Int32 |
None | Returns active tracked entry count after inline TTL eviction |
clear |
None | Clears all registered write entries |
Sentinel::AntiEcho.calculate_checksum(content : String) : String |
content |
Computes SHA-256 after CRLF-to-LF normalization |
Development & Testing
# Run Crystal specs
make spec
# Run Ameba static analysis
make lint
# Format codebase
make format
Support & Donation
If you find sentinel or other tools in this ecosystem valuable, consider supporting continued FOSS development:
- Liberapay: liberapay.com/renich
License
GNU General Public License v3.0 or later (GPL-3.0-or-later).
Copyright Β© 2026 RΓ©nich Bon ΔiriΔ and Contributors.
sentinel
- 0
- 0
- 0
- 1
- 1
- about 3 hours ago
- August 26, 2026
GNU General Public License v3.0 only
Wed, 26 Aug 2026 04:03:57 GMT