fson runs no watcher thread. You drive the check — on a timer, or from an OS file event (inotify, kqueue, ReadDirectoryChangesW).

auto result = Fson::load( "service.fson" );
auto snap   = Fson::snapshot( "service.fson" );

// ... later ...
if( Fson::isStale( "service.fson", snap, Fson::StaleMode::ContentHash ) )
{
  result = Fson::load( "service.fson" );
  snap   = Fson::snapshot( "service.fson" );   // re-snapshot after a reload
}

The two modes

StaleModeCostA bare touch (mtime bump, same bytes)
MtimeSizecheap — stat only, no re-readcounts as a change
ContentHashre-reads every fileignored — only real content changes

Both modes also catch:

  • a deleted dependency (an %include target that vanished);
  • an include-graph change — a new or removed %include directive, even if every existing file is byte-identical.

What "the file" means

snapshot and isStale cover the whole dependency set — the host file plus every file reachable through %include, transitively. You pass only the host path; the snapshot carries the rest.

If you keep the document, LoadResult::dependencySet is the same list, already sorted — useful as the set of paths to register with your OS watcher. Without a document, Fson::dependenciesOf("service.fson") returns it directly.