Living Document Notice
Published 2026-09-24. The evolving architecture, revisions, and connected notes for this dispatch live in the Stax Digital Garden.
Local-First Without Isolation
Summary
Local-first architectures protect data sovereignty, but complete network isolation prevents users from sharing technical notes with teams or deploying static documentation to web audiences. Systems that bridge local storage to remote networks often compromise local performance by coupling UI threads directly to network requests.
Bosun deploys the Tender daemon to bridge local disk writes to Harbor edge runtime edge HTTP caches. By monitoring Linux kernel inotify queues asynchronously, Tender captures filesystem modifications, coalesces rapid edit streams, and pushes static publication artifacts to edge endpoints without delaying local file operations.
The Tender Event Pipeline
Bridging local filesystems to remote HTTP caches requires separating the writer thread from the replication pipeline. When a user or automated agent saves a document, the write operation completes locally on disk in microseconds. The Tender daemon observes this modification through operating system kernel notifications.
+-------------------------------------------------------------+
| Local Inode Write |
| (POSIX Atomic File Replacement) |
+-------------------------------------------------------------+
|
v
+-------------------------------------------------------------+
| Linux Kernel Inotify |
| (IN_CLOSE_WRITE / IN_MOVED_TO) |
+-------------------------------------------------------------+
|
v
+-------------------------------------------------------------+
| Tender Watcher Daemon |
| +--------------------+ +--------------------+ |
| | Debounce Window | ----------> | Content Hashing | |
| | (500ms Bucket) | | (SHA-256 Filter) | |
| +--------------------+ +--------------------+ |
+-------------------------------------------------------------+
|
HTTP / TLS 1.3
|
v
+-------------------------------------------------------------+
| Harbor Edge Cache |
| (Geo-Distributed Read Node) |
+-------------------------------------------------------------+
Tender consumes notifications from the kernel queue into an in-memory ring buffer. To avoid saturating upstream network links during continuous typing, events pass through an adaptive 500-millisecond debounce window. Once the debounce timer expires, Tender verifies file content hashes and dispatches compressed delta payloads to Harbor edge caches.
Comparison of Filesystem Notification Subsystems
Handling filesystem change events cross-platform introduces distinct kernel abstractions. The table below compares the primary notification mechanisms evaluated for the synchronization engine.
| Operating System Interface | Event Delivery Latency | Recursive Directory Monitoring | Queue Saturation Mode | File Descriptor Cost |
|---|---|---|---|---|
Linux inotify | < 15 μs | Requires explicit descriptor per directory | Drops events on IN_Q_OVERFLOW | One watch descriptor per folder |
Linux fanotify | < 10 μs | Native filesystem mount monitoring | Drops events on overflow flag | Single file descriptor for entire mount |
BSD / macOS kqueue | < 20 μs | Requires file descriptor per directory | Kernel evicts event on memory limit | High descriptor overhead on large vaults |
Windows ReadDirectoryChangesW | < 45 μs | Native recursive monitoring via directory handle | Overflows fixed Win32 buffer | Single handle per root watch |
Linux inotify provides predictable behavior within developer environments, provided the daemon handles the IN_Q_OVERFLOW condition by initiating a full vault diff scan against the SQLite index.
Asynchronous Debouncing Loop
The Tender watcher aggregates file system events within a sliding time window. Rapid edits occurring within a half-second interval collapse into a single publication event.
use std::collections::HashMap;
use std::path::PathBuf;
use std::time::{Duration, Instant};
use tokio::sync::mpsc;
pub struct DebounceEngine {
pending_events: HashMap<PathBuf, Instant>,
debounce_duration: Duration,
}
impl DebounceEngine {
pub fn new(window_ms: u64) -> Self {
Self {
pending_events: HashMap::new(),
debounce_duration: Duration::from_millis(window_ms),
}
}
pub fn record_event(&mut self, path: PathBuf) {
self.pending_events.insert(path, Instant::now());
}
pub fn drain_ready(&mut self) -> Vec<PathBuf> {
let now = Instant::now();
let mut ready = Vec::new();
self.pending_events.retain(|path, last_seen| {
if now.duration_since(*last_seen) >= self.debounce_duration {
ready.push(path.clone());
false
} else {
true
}
});
ready
}
}The debounce loop prevents editor autosave mechanisms from flooding the edge network with hundreds of intermediate draft revisions, ensuring that only finalized document states trigger cache invalidations.
Edge Cache Invalidation Semantics
Harbor edge caches retain pre-rendered HTML fragments and serialized JSON document graphs. When Tender dispatches an update, it issues an HTTP PURGE request carrying the target path and its calculated SHA-256 hash.
Edge nodes inspect the hash header. If the incoming hash matches the active edge cache entry, the edge server skips invalidation, preventing redundant cache thrashing across globally distributed proxy nodes.
Event Queue Invariant
The synchronization boundary enforces a strict non-blocking invariant: an unresponsive or disconnected Harbor edge endpoint must never block local filesystem writes or cause the local editor process to stall.
Verify active kernel inotify watch allocation and buffer consumption:
cat /proc/sys/fs/inotify/max_user_watches && grep inotify /proc/*/fd/* 2>/dev/null | wc -l- Directus Target: bosunpkm-blog
- Garden Source Reference: MOC - Bosun PKM Engine, MOC - Bosun PKM Tools, MOC - Local-First Systems and Synchronization, MOC - Harbor Ecosystem, MOC - Ingestion & Capture