app.watcher - File Watching API

Monitor file system changes using FSEvents.

Methods

app.watcher.watch(path, callback)

Start watching a directory or file for changes.

Parameters:

  • path (string) - path to watch (directory or file)
  • callback (function) - change callback function, receives an event table

Callback parameter format:

  • event.path (string) - path of the changed file
  • event.flags (array) - array of change types:
    • "created" - file created
    • "removed" - file removed
    • "modified" - file modified
    • "renamed" - file renamed
    • "metadata" - metadata changed

Returns: string, error - watcher ID

local id, err = app.watcher.watch("/path/to/dir", function(event)
    app.log.info("Changed: " .. event.path)
    app.log.info("Type: " .. table.concat(event.flags, ", "))
end)

app.watcher.stop(id)

Stop a specific watcher.

Parameters:

  • id (string) - watcher ID

Returns: boolean, error

app.watcher.stop(id)

app.watcher.stopAll()

Stop all watchers for the current plugin.

Returns: boolean

app.watcher.stopAll()

app.watcher.list()

List active watchers for the current plugin.

Returns: array<table> - each item: {id, path}

local watchers = app.watcher.list()
for _, w in ipairs(watchers) do
    app.log.info(w.id .. " → " .. w.path)
end

Description

  • Each plugin can have up to 50 watchers
  • Event delay is approximately 500ms (FSEvents coalescing mechanism)
  • Watchers are automatically stopped when the plugin is unloaded
  • Callbacks are invoked on the plugin’s execution queue (thread-safe)
  • Directory watching includes recursive subdirectory changes

Examples

Watch Directory Changes

local watchId = nil

function MyPlugin:onLoad()
    -- Start watching the Downloads directory
    local downloads = app.path.home() .. "/Downloads"
    watchId = app.watcher.watch(downloads, function(event)
        for _, flag in ipairs(event.flags) do
            if flag == "created" then
                app.notification.show("New File", app.path.basename(event.path))
            end
        end
    end)
end

function MyPlugin:onUnload()
    if watchId then
        app.watcher.stop(watchId)
    end
end

Automatically Process New Files

function MyPlugin:init()
    self:registerHandler("start_watch", self.handleStartWatch)
    self:registerHandler("stop_watch", self.handleStopWatch)
end

function MyPlugin:handleStartWatch(context)
    local dir = context.currentDirectory
    self.watchId = app.watcher.watch(dir, function(event)
        for _, flag in ipairs(event.flags) do
            if flag == "created" then
                local ext = app.path.extension(event.path)
                if ext == "png" or ext == "jpg" then
                    app.log.info("New image: " .. event.path)
                    -- Auto-process...
                end
            end
        end
    end)

    if self.watchId then
        app.notification.show("Watching", "Started watching: " .. dir)
    end
end

function MyPlugin:handleStopWatch(context)
    if self.watchId then
        app.watcher.stop(self.watchId)
        self.watchId = nil
        app.notification.show("Watching", "Stopped watching")
    end
end
Developer Documentation
User Guide
Getting Started Script Menus FAQ
Script Development
Development Guide
Plugin Development
Quick Start Development Guide Example Plugins
API Reference
Overview API Query Plugin Info Logging Finder Context Plugin Settings Internationalization
UI & Interaction
Dialog Progress Notification Chooser WebView Status Bar Dock
Files & Paths
File Operations Path Utilities Finder Actions Trash Extended Attributes Metadata File Watcher
Data Formats
JSON Plist CSV XML PDF Image
Text & Encoding
String Regex Date & Time Color Crypto
System
Shell Commands Process Application System Info AppleScript Shortcuts
System Info
Network Power/Battery Screen/Appearance Audio Bluetooth Location
Network
HTTP WebSocket URL
Input & Clipboard
Keyboard Mouse Hotkey Clipboard Window
Storage
SQLite Keychain UserDefaults
Media
OCR QR Code
Utilities
Archive UTI Share Timer Wake Lock Thread