In this post I demonstrate how I increased my productivity with the help of focus tools. They automatically reserve focus time periods in my calendar and automatically trigger my operating system’s focus mode on and off, based on the calendar events.
Introduction
In my daily work life, it is difficult to allocate time slots where I can get coding work done, without interruptions. My calendar is quickly filled with meetings, even when declining all those invitations where my contribution is not required. Many colleagues of mine have the same problem.
To mitigate this, I found a rather technical approach that works quite well for me:
- I reserve slots in my calendar with blocker events titled “focus time”, 1-2 weeks in advance, at times where I know I’m most productive – this reduces the chance that people send event invitations, and if they do, they can only use slots that are not critical to me. This is a variant of the time blocking technique.
- During these focus time blocker events, I get rid of any notifications, by closing “chatty” programs (looking at you, Outlook and Teams), and by using the focus mode offered by the operating system (on Windows it is called Focus Assist, on macOS the name is Focus mode).
Focus tools support
Both aspects mentioned above can be supported with the help of focus tools, to reduce the administrative work.
For time blocking (reserving slots in your calendar), you have multiple options:
- You could create focus time events manually, right in your calendar. The downside is that doing so for extended periods of time (e.g. the next 2 weeks) can become quite a lot of work.
- You can use tooling that uses some kind of algorithm to reserve such focus time events ahead of time, right in your calendar. For instance, Outlook 365 users can use https://insights.viva.office.com where you set up a focus plan (see docs), which blocks up to N hours each working day for the current week + upcoming week.
- There are dedicated time blocking apps such as Sunsama (see e.g. here for a list) which assist you with organizing and scheduling your tasks and (optionally) syncing them to a calendar (to avoid that other people invite you to meetings during your blocker events). In contrast to just using a “normal” calendar (where you can only define an event title and assign a color), time blocking apps have an optimized user interface and better ways of organizing your blocker events (e.g. adding tags or assigning them to projects that you defined).
To automatically trigger the operating system’s focus mode during blocker events, I was unable to find a solution. However, it is very cumbersome always having to manually close applications or start/stop the OS’s focus mode, whenever a focus time blocker event starts or stops.
To solve this problem, I developed a tool that does exactly that. Meet focus-time, an open-source command-line tool for Windows and macOS, that runs silently in the background. It queries your Outlook 365 or CalDAV calendar once per minute to find focus time events. It then runs a series of Terminal/Bash commands (that you define) whenever such an event starts or ends. There are special commands to turn the focus mode of your OS on or off.
focus-time
also lets you start an ad-hoc focus time session: this creates a focus time blocker event in your calendar that starts now and ends in N (configurable) minutes. You can also stop an ongoing focus time period early at any time, which shortens the calendar event accordingly.
Head over to the focus-time GitHub page to learn how to install and use the tool.
Lessons learned
I’ve been working on focus-time
for a few months now. The application is written in Python (as it is my favorite programming language), but integrating with the operating system required a lot of research, as well as using other languages. Here are some learnings:
I built several E2E (end-to-end) tests to verify that the entire process of configuring and then running focus-time works as expected. The application is first “frozen” with PyInstaller and the frozen binary is then called by the E2E-test-code, using the subprocess.Popen()
API to interact with the frozen binary’s stdout
and stdin
. These tests greatly help with automated dependency updates using Renovate Bot (see my Renovate Bot article), but building them was not trivial. Here are a few isues I had to solve:
- There are multiple E2E and library tests running in parallel (because there is a Windows and macOS GitHub Actions runner). I had to carefully handle race conditions on shared resources, e.g. the Outlook/CalDAV calendar backends. Also, every test must have a clean slate. To solve this, I made sure that there are multiple calendars (per provider) to separate library tests (e.g. testing the caldav library) from E2E tests, so that they cannot interfere with each other. To avoid race conditions in concurrent E2E tests, I simply used different focus time event names.
- To avoid that running E2E tests on my own device overwrites the configuration of my personal “production” installation of
focus-time
, I built in test-mode-awareness, using an environment variable called “CI”. - When using a secure approach to prompt the user for a password (e.g. with getpass), the E2E test cannot simply provide the password using
stdin
, becausegetpass()
does not read fromstdin
, but from the surrounding terminal (TTY). While this problem can be solved by having the E2E test start a PTY (which then starts thefocus-time
binary), there does not seem to be a cross-platform library for this purpose. I would have to use different libraries (e.g. ptyprocess on UNIX and pywinpty on Windows). This would have increased the E2E test complexity significantly, which is why I simply use the (insecure)input()
method for E2E tests.
Querying and setting the focus mode of the operating system is not trivial, because there are no official APIs:
- On Windows, there are two approaches: using WNF (see here for details) or a COM-based approach (see here). The WNF-based approach turned out to be less reliable: it would not properly detect the Focus Assist state (if it was set “externally”, by the user from the task bar), and it was also unable to disable focus modes set manually by the user. The COM-based approach did work fine, all I had to do is to write a CLI wrapper around it (source).
- On macOS, I found the macos-focus-mode Node.js library which demonstrates how to create a shortcut for the Shortcuts app that comes pre-installed with macOS since Monterey (macOS 12). This approach works, but lacks a few convenience functions. For instance, you cannot set the focus mode profile in the
shortcuts run
shell command, nor was I able to find out how to query the currently active focus mode via the shell. However, I found a shell command (defaults read com.apple.controlcenter "NSStatusItem Visible FocusModes"
) from here which does the trick.
On macOS, the Terminal app limits the number of characters you can paste to stdin
to 1024 characters. You can try this yourself: open a Terminal window, run python3 -c "input('type or paste content here')"
and then try to type/paste a string that is longer than 1024 characters. Those characters exceeding the limit are lost, and you cannot even press Enter (until you delete the 1024th character).
This caused problems when I needed to transfer the Outlook 365 OAuth2 authorization code (via the clipboard) from the browser back to the focus-time
app (which runs in the Terminal). Fortunately, the OAuth2 auth code was only exceeding the limit by a few characters, so stripping off some well-known characters at the beginning of the string gave enough leeway to work around the problem.
When you download a macOS application using the browser, such as focus-time.zip
, the browser adds a quarantine flag to the file, to indicate that the file might contain malicious content. When you extract the file, the quarantine flag propagates to every extracted file, including the focus-time
binary. This causes Gatekeeper to check that the app is signed and notarized.
However, to sign apps, Apple requires developers to pay 99€ per year for an Apple developer account. Since this is a hobby project and I’m not an Apple fanboy, paying this kind of extortion money is not something I’m willing to do.
The most simple way I found to work around the problem is to write a simple download/update-script which you can run in your Terminal, which performs the download in such a way that does not set the quarantine flag. Consequently, Gatekeeper is not involved, and no notarization or signing is necessary.
Next steps
For my personal needs, the Focus Time app is feature-complete. However, I do see the following three primary improvements for Focus Time:
- Create a GUI version, which would broaden the audience to less technical users. We could show a tray icon that indicates the focus time app’s status, or allows the user to interact with the Focus Time App. Because designing GUIs is not my strong suit, I’m looking for collaborators for UI/UX/icon design.
- Add support for more calendar providers (based on user requests or pull requests), e.g. Google calendar.
- Add support for Linux
Conclusion
I’ve been using Focus Time for a few months now, and I’m really happy with it. The development has been really fun so far, keeping my software engineering skills sharp while I’m mostly working on cloud and automation tasks in my professional life.
As for the strategy of blocking focus time slots: I’m not a huge fan of the time blocking technique. I tried it, but it caused too much stress for me. Also, the real world is not as predictable as my nice-and-tidy schedule would like it to be. For me, having something like Viva Insights (see above for details) create 1-2 blocker events per day is really good enough.
What are your techniques and experiences regarding “blocking out the noise” or other focus tools? Please let me know in the comments.