Inspiration
We've all been there: a friend sends a message, "let's grab lunch next Tuesday at 1pm," or you're in a meeting taking notes, "project sync tomorrow at 10am on Zoom." The next step is always the same tedious, manual process: open your calendar, click "new event," copy and paste the title, find the date, set the time, and save.
This project was inspired by that simple annoyance. We wanted to build an intelligent assistant that closes the loop—an app that sees a potential event on your screen and lets you save it to your calendar with a single click.
What it does
Event Sniffer is a smart macOS assistant that lives in your menu bar. It securely and "surgically" reads the text from your currently focused application window (like a chat app, your notes, or a webpage).
It sends this text to a locally-running, custom-trained machine learning model that analyzes it for event-related details. If it finds a potential event, it triggers a native macOS notification:
Found Event: quick sync On: tomorrow at 10am. Location: Zoom [ Add to Calendar ]
Clicking the "Add to Calendar" button instantly creates the event in your Apple Calendar, no copying or pasting required.
How we built it
This project was built in two distinct parts: the native macOS "body" and the local Python "brain."
The macOS Agent (Swift): We built a native macOS app using SwiftUI for the simple menu bar interface. The core logic uses:
Accessibility (AX) APIs: To read text from the user's active window. We made this "surgical" by preferring the kAXFocusedUIElement (the active text box) over reading the entire window, which prevents it from picking up UI "junk."
EventKit & UserNotifications: To get permission and then create calendar events and display actionable notifications.
URLSession: To send the captured text to our local Python server and parse the incoming JSON response.
The ML "Brain" (Python):
spaCy: We built a custom Named Entity Recognition (NER) model from scratch. We trained it on a custom dataset of ~70 examples (including many "negative" examples) to teach it to find four specific labels: EVENT, DATE, TIME, and LOCATION.
Flask: The trained spaCy model is loaded and "served" by a minimal Flask API. The Swift app sends a POST request with {"text": "..."} to a /parse endpoint, and the server responds with {"entities": [...]}.
Challenges we ran into
The biggest challenges were all related to macOS permissions, which are notoriously difficult to debug.
Accessibility Permission: Getting the app to "see" other apps was the first major hurdle. We learned that simply adding the Info.plist key wasn't enough. We had to disable App Sandbox in our project's capabilities, as this security "wall" (which is on by default) prevents an app from even asking for this permission.
ML Model Training: Our first model was useless! The training console was full of [W030] alignment warnings, which we learned meant our manually-counted training labels were broken. The model "trained" to a low loss score, but it had learned nothing. We fixed this by programmatically generating the training data, which eliminated all warnings and resulted in a genuinely smart model.
Calendar Permission: We ran into a wall where the app would claim "permission denied" without ever showing the user the permission pop-up. This was also tied to the App Sandbox and Hardened Runtime settings. Disabling them allowed the OS to read our Info.plist description and correctly show the pop-up.
Accomplishments that we're proud of
This project is a true end-to-end success. We're most proud of:
Building a Custom NER Model: The "Aha!" moment when our model went from finding No entities found to perfectly parsing "quick sync" (EVENT), "tomorrow" (DATE), "at 10am" (TIME), and "Zoom" (LOCATION) was a massive win.
Bridging Swift and Python: We successfully connected a native Swift app to a local Python/Flask server. This is a powerful pattern that opens the door to building all kinds of smart desktop apps.
Taming macOS Permissions: We debugged and solved three separate, high-friction permission issues (Accessibility, Calendar, and Notifications), which is a major accomplishment for any macOS developer.
What we learned
For macOS dev, check security settings first: 99% of permission-related bugs aren't in your code, they're in the Info.plist or the "Signing & Capabilities" tab (like App Sandbox).
ML is all about data quality: A model with 1,000 bad labels is worse than a model with 50 perfect labels. Fixing our broken data was more important than adding more of it.
Start simple, then refine: Our first screen reader read everything. Our final one reads one text box. This "surgical" refinement made the app 10x more useful and accurate.
What's next for EventSniffer
We've built a powerful prototype, and a "v2" would focus on polish and robustness.
A "Real" Date Parser: The current date parser is very simple (it only really understands "tomorrow" and an hour). The next step is to integrate a proper natural language date-parsing library to handle complex phrases like "next Wednesday at 3:30pm."
Package the Python Server: We'd use a tool like PyInstaller to package the Python server into a single executable. We could then bundle this inside the Swift app, so the user never has to run a separate terminal command.
Improve the Model: We'd add 500+ more training examples to make the model even more accurate and reduce false positives (like it finding a date in "I'm free this afternoon").
Log in or sign up for Devpost to join the conversation.