Every morning, once I’ve sorted the coffee, I open my laptop and go through a set of tasks. These aren’t directly part of my work, but like a pre-workout, they set the pace for the rest of the day. This includes opening a bunch of apps, like the browser, calendar, my notes, and several other apps, and opening several browser tabs. None of this is time-consuming, and it’s such a habit now that I don’t even realize I’m doing it.
But I’ve noticed that when I open everything all at once, I slip into a reactive mode before I’ve even decided what I actually need to work on. That was the problem I wanted to solve, so I wrote a single script that I run once after booting my Mac to prepare my entire work environment for the day.
4 automation tools that save time for Windows users
Save time and streamline your workflow with the help of these automation tools for your PC.
How I set up the automation script
A neat Python script gets the job done
When I was evaluating this automation, I was confused about whether to go with an n8n workflow that connects different nodes like Gmail, Google Docs, and Chrome, or with the good old Python. I decided to go ahead with the latter because it gives more control over the workflow.
This script streamlines my daily routine right after booting my computer in the morning, handling a lot of the basic manual tasks I have to get through before I can actually start working. This routine involves opening specific browser tabs, showing routine reminders, starting Slack, and running my self-hosted apps via Docker.
Instead of launching everything at once, the script is intentionally gated. When it first runs, it only opens what I need to orient myself. The calendar comes up, my notes app opens, and a single browser window loads using my work profile. Email and Slack are delayed by five to ten minutes. This small pause stops me from falling into a reactive loop before I have even decided what I want to work on.
The browser setup is also more intentional than a generic “open Chrome” command. The script opens the browser in a ready-to-work state. That means loading the document I am currently working on, my task manager (like Asana), and tools I use for research, such as NotebookLLM.
One of the more useful parts of the script is calendar-aware behavior. My laptop behaves differently depending on how my day looks. If my first meeting is before 10, the calendar opens in full-screen mode, and my meeting notes document loads automatically. If there are no meetings until noon, the script opens the writing app and a deep work task list instead. On Fridays, it switches gears and opens the reporting document and analytics dashboard. Pulling today’s calendar and branching on it turns out to be simpler than it sounds, but it makes the system feel smart.
It's all tied to a single desktop shortcut
You can also add so much more to the script
The script also handles background context setup. It starts Docker and brings up the self-hosted services running locally on my Mac, so they are ready when I need them. There is also a lightweight morning briefing step that pulls today’s meetings, highlights my top three tasks, and surfaces a reminder I often forget. While I decide to get this briefing via mail, you can also use the built-in library subprocess to call the notification system and send a simple message.
I’ve included the exact script below; you can copy it, replace the placeholders, and run it as is. It works out of the box, but it’s not meant to be one-size-fits-all. This setup reflects how I work, not how everyone should. For example, I use Slack for communication, but you might be on Teams. I keep my notes in Joplin, while you might prefer Notion or Google Keep.
You can also add more functionality to this. For instance, you can collect and visualize data. You can run background scripts that log active windows and track focus time, storing this information in text files or CSVs. From there, you can take it further by building a simple tool using something like Replit to visualize the data. This lets you review daily performance metrics such as time spent in different apps. It can also help enforce a specific order of operations, where communication checks like email and messaging are pushed to the very end of the routine. That way, higher-priority tasks like planning and skill-building happen first, before anything reactive creeps in.
#!/usr/bin/env python3
import subprocess
import time
import os
from datetime import datetime
import webbrowser
CONFIG = {
"chrome_profile": "Profile 1",
"urls": {
"current_doc": "https://docs.google.com/document/d/YOUR_DOC_ID",
"task_manager": "https://app.asana.com/0/home",
"research_tool": "https://notebooklm.google.com",
"email": "https://mail.google.com",
},
"apps": {
"notes": "Notes",
"calendar": "Calendar",
"slack": "Slack",
},
"docker_services": [],
"delays": {
"email": 300,
"slack": 600,
},
}
def run_command(cmd, shell=False):
try:
result = subprocess.run(cmd, shell=shell, capture_output=True, text=True, check=False)
return result.stdout.strip()
except Exception as e:
print(f"Error: {e}")
return ""
def open_app(app_name):
subprocess.Popen(["open", "-a", app_name])
def open_url(url, profile=None):
if profile:
chrome_path = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
subprocess.Popen([chrome_path, f"--profile-directory={profile}", url])
else:
webbrowser.open(url)
def notify(title, message):
script = f'display notification "{message}" with title "{title}"'
subprocess.run(["osascript", "-e", script])
def start_docker():
for service in CONFIG["docker_services"]:
if service.endswith("docker-compose.yml"):
service_dir = os.path.dirname(os.path.expanduser(service))
subprocess.Popen(["docker-compose", "up", "-d"], cwd=service_dir)
else:
subprocess.Popen(["docker", "start", service])
def get_calendar_mode():
now = datetime.now()
hour = now.hour
is_friday = now.weekday() == 4
# check if early meeting (before 10am)
# in real version: pull from gcal api
has_early_meeting = False # placeholder
if is_friday:
return "friday"
elif has_early_meeting:
return "meeting"
elif hour return "deep_work"
else:
return "standard"
def meeting_mode():
open_app(CONFIG["apps"]["calendar"])
time.sleep(2)
run_command("""
osascript -e 'tell application "Calendar"
activate
tell application "System Events"
keystroke "f" using {command down, control down}
end tell
end tell
""", shell=True)
open_url(CONFIG["urls"]["current_doc"], CONFIG["chrome_profile"])
def deep_work_mode():
open_app(CONFIG["apps"]["notes"])
open_url(CONFIG["urls"]["task_manager"], CONFIG["chrome_profile"])
def friday_mode():
# point these at actual urls
reporting_doc = "https://docs.google.com/document/d/YOUR_REPORTING_DOC"
analytics = "https://your-analytics-dashboard.com"
open_url(reporting_doc, CONFIG["chrome_profile"])
open_url(analytics, CONFIG["chrome_profile"])
def standard_mode():
open_app(CONFIG["apps"]["calendar"])
open_app(CONFIG["apps"]["notes"])
open_url(CONFIG["urls"]["current_doc"], CONFIG["chrome_profile"])
time.sleep(1)
open_url(CONFIG["urls"]["task_manager"], CONFIG["chrome_profile"])
time.sleep(1)
open_url(CONFIG["urls"]["research_tool"], CONFIG["chrome_profile"])
def show_briefing():
now = datetime.now()
briefing = f"""Good morning - {now.strftime('%A, %B %d')}
Meetings today:
- (pull from calendar api)
Top priorities:
1.
2.
3.
Reminder: [your thing]
"""
print(briefing)
notify("Morning", "Briefing ready")
def main():
start_docker()
show_briefing()
mode = get_calendar_mode()
if mode == "meeting":
meeting_mode()
elif mode == "deep_work":
deep_work_mode()
elif mode == "friday":
friday_mode()
else:
standard_mode()
# delayed opens
subprocess.Popen([
"python3", "-c",
f"import time; time.sleep({CONFIG['delays']['email']}); "
f"import subprocess; subprocess.run(['open', '{CONFIG['urls']['email']}'])"
])
subprocess.Popen([
"python3", "-c",
f"import time; time.sleep({CONFIG['delays']['slack']}); "
f"import subprocess; subprocess.run(['open', '-a', '{CONFIG['apps']['slack']}'])"
])
if __name__ == "__main__":
main()
Automate your life with Python
Python makes automation far easier. If you are not sure where to start, check out these seven tiny Python scripts that can save you hours every week, or these three automation scripts that can replace paid apps in your productivity stack. If Python isn’t your thing, you can also try n8n. It lets you automate large parts of your workflow for free, without writing much code at all.
I found this new NotebookLM feature so good, I might stop using all my other productivity apps
Might be time to make NotebookLM my only productivity tool.
