Field Notes

Call one alert workflow from every other flow

A dozen flows each ended with their own copy of "notify me and log it". Now each one calls a shared workflow with Run Watchflow, and alerts change in one place.

A real invoice PDF lands in the watched folder: it is filed, Run Watchflow calls Tell Me, and Tell Me logs it, files a High priority reminder and posts the notification.

Most of my flows end the same way. Something happened, so post a notification and append a line to a log file. After a year that tail had been copied into twelve flows: the Downloads sorter, the backup check, the build watcher, the invoice filer. Then I wanted urgent messages to land in Reminders as well, so they would still be on the phone after the notification was dismissed. That meant twelve canvases, and the two I missed kept the old behavior for a month.

The fix is the one you would reach for in code: write it once and call it. In Watchflows the function is an ordinary flow, and calling one workflow from another takes a Run Watchflow node.

What it does

Tell Me takes three values, title, body and level. It appends the message to ~/logs/tell-me.jsonl, files a High priority reminder when the level is urgent, and posts a notification either way. Every other flow ends by handing it those three values. The download on this page is one caller, File Invoices and Receipts. Tell Me is a second download, tell-me.watchflow, and it goes in first.

Tell Me, the flow being called

Fig. 1Tell Me: log every message, add a reminder only when the level is urgent, notify either way.
Fig. 2What Tell Me posted when a receipt came through: the caller's title and body, unchanged.

A caller that files invoices from Downloads

Fig. 3Three Sections: sort what landed in Downloads, file it, hand one message to Tell Me. Each Run Watchflow node draws Tell Me as a dimmed preview.

File Invoices and Receipts watches ~/Downloads with Directory Changed, Event Types set to Created. Invoice? checks that fileExtension equals pdf and fileName contains invoice; Receipt? does the same for receipt. Both ignore case. Move File puts the file in ~/Documents/Invoices or ~/Documents/Receipts with Overwrite Existing off, so a second invoice.pdf is saved as invoice-1.pdf rather than replacing the first.

The last two columns are what every caller now ends with: a Map Keys node that writes the message, and a Run Watchflow node that sends it.

Fig. 4Invoice message builds exactly three keys. Include Unmapped Keys is off, so nothing else reaches Tell Me.

An invoice is something to pay, so Invoice message sets level to urgent and body to {{fileName}} is in Documents/Invoices. Move File updates fileName after it moves, so the body names invoice-1.pdf when that is what was saved. Receipt message sends info. Include Unmapped Keys is off on both, so Tell Me receives three keys instead of the whole file event.

Fig. 5The Run Watchflow inspector: Tell Me picked, its input passed down, and what a failure does.

On both Run Watchflow nodes, Input passes this payload down, which is what hands the three keys over. The colored bands are Sections: Notes with the backdrop switched on. They change nothing about a run. On a canvas this wide they are how you find the part you came to edit. Drag one by its label band and every card whose centre sits inside moves with it. Select some cards and press ⌘G to wrap them in a new one.

My backup check and build watcher end with the same pair of nodes, each with its own title and level. Changing what "urgent" means now happens in Tell Me alone.

Paste into the Flow Builder

When a PDF with "invoice" in its name lands in ~/Downloads, move it to ~/Documents/Invoices without overwriting, then run my Tell Me flow with title "Invoice to pay", body "{{fileName}} is in Documents/Invoices." and level urgent.

What comes back, and what goes wrong

The trigger does not wait. A called flow's trigger is only the door. The caller's payload is dropped in at its outlet and Tell Me runs at once, and the Input's own settings, Custom Arguments included, are ignored for the call.

Done carries Tell Me's final payload. With one flow picked and a run that completes, Done hands over what Tell Me's last node emitted, with no wrapper. Notification replaces the payload instead of adding to it, so a caller reads {{notified}}, {{title}} and {{body}}. If notifications are off for Watchflows, Notify does not fail: notified is false and error reads permission_denied: notifications, which a caller can branch on. Pass-through, the third outlet, forwards the caller's own input unchanged.

Expect a warning key. Passing the payload down fills in the fields Tell Me's Input would normally produce (text, contentType, data, filePath, timestamp) as empty strings, and Done carries a warning naming them because the caller did not supply them. Tell Me ignores them.

A failed Tell Me does not undo the caller's work. The first urgent message raises a macOS prompt asking to let Watchflows control Reminders. Decline it and Remind me fails, so Tell Me's run fails and Notify never posts. The invoice has already moved and the log line is already written, because both happened earlier. What the caller does next is its On fail setting. Set it to Continue and Done still fires, carrying the result under the flow's namespace instead: {{tell_me.status}} reads failed. Branch on that when a caller needs to know. Each call is saved in Tell Me's own run history, which is where you find why it failed.

Loops and depth are refused. A flow cannot appear twice on one call stack, so if Tell Me ever called a flow that calls Tell Me, the call is refused with "Run Watchflow would create a loop" and the path it found. Nesting stops at four levels, counting the first caller as one. Every call made under one root run shares a budget of 64, so a For Each that calls Tell Me once per file is refused at the 65th.

Setting it up

  1. Import tell-me.watchflow, then file-invoices.watchflow.
  2. The download cannot point at your copy of Tell Me, so both Run Watchflow nodes arrive empty. Select each one and pick Tell Me in the inspector.
  3. Arm File Invoices and Receipts. Tell Me needs no arming, since an Input flow has no watcher.

Variations

What's in this flow

One trigger. Nodes are listed in the order a run reaches them; the canvas above shows where it branches.

Download this flow
  1. Directory ChangedNew in Downloads
  2. ConditionInvoice?
  3. ConditionReceipt?
  4. Move FileFile invoice
  5. Move FileFile receipt
  6. Map KeysInvoice message
  7. Map KeysReceipt message
  8. Run WatchflowTell Me (invoice)
  9. Run WatchflowTell Me (receipt)

Run this one yourself

Download the flow, double-click it, and Watchflows opens it on the canvas. Everything in this note is on the 14-day free trial.