boxlang-file-watchers — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited boxlang-file-watchers (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
BoxLang is the AI-native software productivity platform for building, modernizing and running applications, with developers and AI agents working together.
BoxLang includes a runtime watcher service for real-time filesystem automation.
Watchers are ideal for:
You can register app-scoped watchers directly in Application.bx with this.watchers.
For full descriptor behavior (app discovery, multi-app isolation, lifecycle), see application-descriptor.
class {
this.name = "MyApp"
watcherListener = new app.listeners.HotReloadListener()
this.watchers = {
sourceWatcher : {
paths : [ expandPath( "./src" ) ],
listener : watcherListener,
recursive : true,
debounce : 250,
atomicWrites : true,
errorThreshold : 10
}
}
}Supported watcher definition keys commonly include paths, listener, recursive, debounce, throttle, atomicWrites, and errorThreshold.
Event kinds:
createdmodifieddeletedoverflowListener payload struct keys:
kindpath (absolute path; blank for overflow)relativePath (relative to watcher root; blank for overflow)watchRoot (blank for overflow)timestamp (ISO-8601)watcherNew() registers a watcher but does not automatically start it unless you chain .start() on the returned instance.
watcher = watcherNew(
name = "sourceWatcher",
paths = [ "./src" ],
listener = ( event ) => {
println( "[#event.kind#] #event.relativePath#" )
},
recursive = true,
debounce = 250,
throttle = 0,
atomicWrites = true,
errorThreshold = 10,
force = false
).start()Accepted paths forms:
listener = ( event ) => {
if ( event.kind == "modified" ) {
recompileAsset( event.path )
}
}listener = {
onCreate: ( event ) => onCreated( event ),
onModify: ( event ) => onModified( event ),
onDelete: ( event ) => onDeleted( event ),
onOverflow: ( event ) => fullResync(),
onEvent: ( event ) => writeLog( text: "Watcher event: #event.kind#", log: "async" )
}watcherNew(
name = "prodWatcher",
paths = [ "/srv/import" ],
listener = "app.listeners.ImportWatcher"
)watcherNew(
name = "prodWatcher",
paths = [ "/srv/import" ],
listener = new ImportWatcher()
)For class listeners, implement onEvent( required struct event ) as the baseline and optionally:
onCreate( event )onModify( event )onDelete( event )onOverflow( event )onError( error )watcherNew( name?, paths, listener, recursive=true, debounce=0, throttle=0, atomicWrites=true, delay=0, errorThreshold=10, force=false )watcherStart( name )watcherStop( name, force=false )watcherRestart( name )watcherGet( name )watcherGetAll()watcherList()watcherExists( name )watcherShutdown( name )watcherStopAll( force=false )watcherShutdownAll( force=false )Lifecycle distinctions:
stop = stop execution but keep registrationshutdown = stop + unregister (destructive)watcherNew() and watcherGet() return WatcherInstance:
start()stop( force=false )restart()isRunning() / isStopped()getState() / getStateAsString()getName()getWatchPaths()getListener()getStats()getStats() includes:
namestate (CREATED, RUNNING, STOPPED)pathsrecursivedebouncethrottleatomicWriteserrorThresholdconsecutiveErrorswatcher = watcherNew(
name = "inbound-files",
paths = [ "/data/inbound" ],
listener = new InboundFileListener(),
recursive = true,
debounce = 300,
atomicWrites = true,
errorThreshold = 5
).start()
if ( !watcher.isRunning() ) {
watcher.restart()
}onError and track consecutiveErrors.watcherStopAll() in graceful shutdown flows.debounce, enable atomicWrites, and consider throttle.watcherShutdown() or watcherShutdownAll() was invoked.errorThreshold.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.