Guardrails: check before it happens
Stop a send, a quit or a push at the last second. A macro checks first, then lets the key through, blocks it, or asks "Send anyway?". Five ready-made ones.
Most automation runs after something happened. A guardrail runs before. You press Command-Return in Mail, and before Mail sees it a small macro reads the message. If the text says "attached" and nothing is attached, a panel says so and asks. If everything is fine, the key goes through and you never notice.
How it works #
A guardrail is a macro whose trigger is Before a key, click or quit. You choose the app and what to catch: a key combination, a click on a button you picked with the Recorder, or Quit. The macro then ends with one of three answers:
Let it through. The default. A macro that finishes without saying anything lets it through.
Block it, with a reason. The key is dropped and the reason shows for two seconds.
Ask Send anyway? A panel opens at the pointer with your question and two buttons. Return cancels, which is the safe choice if you press it twice by reflex. Command-Return goes ahead.
Anything you type while the check runs is held and delivered afterwards, in the order you typed it. If the check is slow or breaks, the action goes through, and the run says so. Set onTimeout to block on a guardrail where that is the wrong way round.
Five to add #
Press Add to Library on one, read it, then turn it on. They need the Input Monitoring permission. The Mail ones also need Automation for Mail, which macOS asks for the first time they run.
Forgot the attachment #
When the message says "attach", "attached" or "attachment" and has no attachments.
- Before ⌘↩ reaches Mail
- Read the mail being written
- If body matches “(?i)attach(ed|ment|ments|ing)?\b” and {{ attachmentCount }} is 0
- Ask “No attachment. The message mentions one.” with “Send Anyway”
Wrong From #
When you write to a work address from your personal one. Change the two addresses to yours.
- Before ⌘↩ reaches Mail
- Read the mail being written
- If recipientsText contains “@mycompany.com” and from contains “@icloud.com”
- Ask “This goes to a work address from {{…” with “Send Anyway”
Unsaved work #
When you quit an app that has windows with unsaved changes. It watches every app (*), and Quit only; the Dock's Quit and the Apple menu's Quit are not caught.
- Before you quit *
- Count the windows with unsaved changes in {{ app }}
- If {{ unsavedCount }} is above 0
- Ask “{{ unsavedText }}. Quit anyway?” with “Quit”
Friday push #
When you press Return on a git push line in Terminal or Ghostty after four on a Friday.
- Before ↩ reaches Terminal
- Before ↩ reaches Ghostty
- If the time is between 16:00 and 23:59 on Fri
- Read the text area into screen
- If screen matches “git push[^\n]*\s*$”
- Ask “It's Friday after 4. Push?” with “Push”
Reply all to a big list #
When a message goes to more than ten people.
- Before ⌘↩ reaches Mail
- Read the mail being written
- If {{ recipientCount }} is above 10
- Ask “This goes to {{ recipientCount }}…” with “Send Anyway”
Good to know #
Settings > Guardrails lists every guardrail with how long its check takes. One that is slower than half a second gets an amber dot and a note such as "Slows your ⌘↩ in Mail by 0.6 s". Keep checks short: reading a window is fast, a model call is not.
Secure input turns guardrails off, for example while a password field has focus, and the menu bar item says so.
Only the key is caught. The same command chosen from a menu isn't, nor are Force Quit, logging out, or the Dock's Quit.
A hot key macro on the same key runs instead and the guardrail never sees it.
Look in Activity to see what a guardrail decided: "Blocked: …", "Asked: …" or "Allowed in 140 ms".