ADR 4: Silent Filesystem Indexing via Watchdog and Decoupling Git Sync
- Status: Superseded by ADR 0014
- Date: 2026-10-03
- Author: Antigravity (AI Coding Assistant) & User
Context
Originally, Jotter exposed a prominent "Sync" button in the global navigation bar and ran an automatic timer in the frontend every few minutes. Under the hood, this single "sync" action performed two distinct operations simultaneously:
- Local Filesystem Reindexing (
sync_all): Scanned the local task markdown directory on disk and reconciled the SQLite index with external changes (e.g. edits made in Obsidian, VS Code, or CLI). - Git Synchronization (
git_sync): Rangit add,git commit,git fetch,git merge, andgit pushagainst configured remote repositories across all projects.
This conflated architecture caused several issues:
- Flawed Conceptual Model: Users should not need to think about local database synchronization. In a "file-over-app" architecture, local file changes (made by text editors, scripts, or agents) should be reflected effortlessly and immediately in the UI.
- Unwanted Git Operations: Triggering Git sync every few minutes created excessive empty or micro-commits, network noise, and potential merge conflict alerts for users who merely wanted their local edits indexed.
- Sluggish Feedback Loop: Relying on a manual click or a periodic polling interval meant external edits were delayed, causing stale board state or confusing UI race conditions.
Decision
We decided to decouple local filesystem indexing from Git synchronization and make local index reconciliation completely silent and automatic using an in-process filesystem watcher (watchdog).
Specifically:
In-Process Filesystem Watcher (
watchdog):- The backend runs a
FileWatcherServiceduring the FastAPI application lifespan. - It monitors the task directory for file creations, modifications, deletions, and moves.
- It incorporates a 500ms debounce window and ignores temporary files (
.tmp_*, hidden dotfiles, and SQLite lock/WAL files). - On detecting filesystem changes, it quietly runs
sync_all()in the background to update the SQLite index.
- The backend runs a
Removal of the Global "Sync" Button:
- The prominent "Sync" button in the top navigation bar has been removed.
- Users no longer manually trigger local index updates.
Multi-Tab / Window Revalidation:
- The frontend listens to browser
focusandvisibilitychangeevents to silently revalidate board state and active projects whenever the user switches back to the Jotter tab or window.
- The frontend listens to browser
Dedicated Git Sync Action:
- Git synchronization is isolated as a deliberate remote networking operation (
POST /api/git/syncor MCPgit_sync), independent of local database maintenance.
- Git synchronization is isolated as a deliberate remote networking operation (
Explicit Maintenance Card in Settings:
- To retain full operational control without cluttering everyday UI, a "Rebuild Search Index" button was added to the Settings view (
SettingsView.vue) for manual re-indexing and troubleshooting.
- To retain full operational control without cluttering everyday UI, a "Rebuild Search Index" button was added to the Settings view (
Rationale
- "File-over-App" Harmony: Changes made by external tools (Obsidian, vim, MCP agents, or scripts) update the database index sub-second without user intervention.
- Separation of Concerns: Git push/pull is a network and versioning concern, whereas database reindexing is an internal cache invalidation detail. Decoupling them prevents unwanted Git commits and unnecessary network roundtrips.
- Cleaner UX: Eliminates cognitive burden and visual clutter from the navigation bar.
Architecture
mermaid
flowchart TD
subgraph External [External Actors]
Editor[Obsidian / VS Code / Scripts]
Agent[MCP Server / CLI]
end
subgraph Filesystem [Local Disk]
Files[(Markdown Files .md)]
end
subgraph Backend [Jotter Backend Server]
Watcher[Watchdog FileWatcherService]
SyncEngine[SyncService.sync_all]
DB[(SQLite Index tasks.db)]
end
subgraph Frontend [Vue 3 Client]
Board[Kanban Board View]
Focus[Window Focus / Visibility Change]
end
Editor -->|Edit / Save| Files
Agent -->|Write / Move| Files
Files -.->|FS Events| Watcher
Watcher -->|Debounced (500ms)| SyncEngine
SyncEngine -->|Reconcile| DB
Focus -->|Silent Refetch| DB
DB -->|Fresh State| BoardConsequences
- The Python dependencies now require
watchdog >= 4.0.0. - In test environments with ephemeral directory setups, file watching should be disabled (
enable_watcher=Falseincreate_app) to avoid filesystem lock conflicts during teardown. - Git sync is no longer periodic by default and is triggered either deliberately by the user or through automated CI/cron/MCP commands.
