I Built a 20–20–20 Reminder System. Yet to Follow It.
This is not a health post. This is a problem-solving post. A problem that started with 15 hours of daily screen time, a doctor’s prescription that felt unsatisfying, and ended with a custom Windows automation pipeline built from curiosity alone.
The Problem: Exam Season and 12 to 15 Hours of Screen Time
During exam preparation, the laptop is on from the moment I wake up until I sleep. Coding practice, study material, online assessments, projects, and reading — all of it on the same screen, for stretches of 12 to 15 hours daily.
The result was predictable in hindsight: persistent eye strain, dryness, and difficulty focusing after prolonged sessions.
What I did not expect was how quickly the eyes adapt to strain in a way that feels normal, until it is no longer manageable.
What the Doctor Said (And Why It Was Not Enough)
The recommendation was sterile eye drops containing Carboxymethylcellulose 0.5% w/v, a lubricating agent used for dry eye syndrome. Maximum usage: 4 times a day, one drop per eye.
CMC eye drops work by supplementing the tear film on the eye surface, temporarily restoring moisture. In clinical settings they are effective. For someone sitting 15 hours in front of a screen, they are a patch, not a fix.
The 20–20–20 Rule: The Only Fix That Actually Works
Every 20 minutes. Look at something at least 20 feet away. For 20 seconds.
That is the entire rule. It sounds trivially simple. It is also backed by real physiology.
When you focus on a nearby screen, the ciliary muscles inside your eye contract and hold that position. They do not release between keystrokes or between tabs. They hold. For hours. That sustained muscular contraction is the primary cause of digital eye strain, not the light from the screen, not the resolution, not the refresh rate. The muscle.
“The 20–20–20 rule forces a periodic relaxation of the ciliary muscle by shifting focus to a distant object. Twenty feet is approximately the distance at which the eye reaches its natural resting state. Twenty seconds is enough time for the muscle to actually release.
With breaks Without breaks Ciliary muscle relaxes every 20 min Sustained contraction for hours Tear film refreshes through blinking Blink rate drops by up to 60% on screen Mild fatigue, recoverable Cumulative strain, dryness, headaches Consistent focus quality Degrading sharpness as the session continues
The rule costs nothing. It requires no equipment. The only thing it requires is that you remember to do it.
And that, specifically, is the problem. When you are in a flow state or under exam pressure, you do not remember. Nobody does.
Why the Mobile Phone Reminder Did Not Work
The obvious solution was to set a reminder on my phone every 20 minutes.
The problem: a phone sitting next to a laptop is not just a reminder device. It is a notification hub, a distraction source, and a psychological pull that breaks focus in ways far more damaging than the 20 seconds spent on the eye break itself.
Using a phone to remind yourself to take a screen break is like walking into a bakery to remind yourself not to eat sugar. The environment defeats the intention.
I needed the reminder to come from the laptop itself: non-intrusive, automatic, persistent across reboots, and completely invisible unless it was time to look away.
The Solution: Windows Task Scheduler + PowerShell + BurntToast
This is where it became a technical problem. And technical problems are satisfying to solve.
Component Role Windows Task Scheduler Triggers the reminder every 20 minutes PowerShell Executes the notification script BurntToast module Renders a proper Windows toast notification VBScript wrapper Suppresses the console window during execution
Step 1: Understanding Windows Task Scheduler
Task Scheduler is a Windows system service that runs programs, scripts, or commands at specified intervals, on startup, on login, or based on system events.
In real-world engineering, the same concept underpins cron jobs on Linux systems, scheduled tasks in cloud infrastructure, and CI/CD pipeline triggers. The underlying principle is identical: define a trigger, define an action, let the scheduler handle execution without manual intervention.
Trigger Type : On a schedule (Daily)
Recur every : 1 day
Advanced : Repeat task every 20 minutes, duration Indefinitely
Second Trigger: At startupThe “At startup” trigger is the key detail. Without it, the task does not persist across reboots. With it, the scheduler reinstates the task automatically every time the laptop powers on.
Step 2: The First Attempt (And Why It Failed)
The initial approach: a PowerShell message box from the scheduler.
powershell.exe -Command "Add-Type -AssemblyName PresentationFramework;[System.Windows.MessageBox]::Show('Blink now!')"Two problems immediately:
Problem 1: A full blocking dialog requires a manual click to dismiss. During an online assessment, popup windows not belonging to the exam software can be flagged by proctoring software as suspicious activity.
Problem 2: The PowerShell console window flashed briefly on screen every time the task ran. Even a fraction of a second is enough to break focus.
Both problems needed separate fixes.
Step 3: Switching to Toast Notifications
Windows 10 and 11 support native toast notifications, the small slide-in alerts near the system clock used by Outlook, Teams, Discord, and every other modern Windows application.
They are non-blocking, auto-dismissing, indistinguishable from standard system notifications, and not flagged by proctoring software because they are part of the Windows notification pipeline.
The challenge: PowerShell does not have a registered app identity in Windows by default. Toast notifications require a registered sender, otherwise Windows suppresses them silently.
The fix: BurntToast, an open-source PowerShell module that handles app identity registration and notification rendering correctly.
Install-Module -Name BurntToast -Scope CurrentUser -Force-Scope CurrentUser installs into the user profile directory without administrator privileges.
Test:
New-BurntToastNotification -Text "Blink Reminder", "Keep your eyes safe. Follow the 20-20-20 rule."Proper Windows toast notification. Identical in appearance to any system alert.
Step 4: The PowerShell Script
Saved at C:\TasksScheduler\BlinkReminder.ps1:
Add-Content "C:\TasksScheduler\ReminderLog.txt" "$(Get-Date) - Reminder fired"
Import-Module BurntToast
New-BurntToastNotification -Text "Blink Reminder", "Keep your eyes safe. Follow the 20-20-20 rule."Two things worth noting.
Import-Module BurntToast is required inside the script. When PowerShell is launched silently by the VBScript wrapper, it does not automatically load modules available in an interactive session. Without the explicit import, New-BurntToastNotification is not recognised and the script exits silently with no notification and no error. This only surfaces when the execution context changes from interactive to automated.
The logging line is optional but strongly recommended. Add-Content writes a timestamped entry every time the script runs. If the log updates but no toast appears, the problem is in the notification layer. If the log is empty, the problem is in the scheduler or script execution. Separating those two failure modes saves significant debugging time.
Step 5: Hiding the Console Window
Task Scheduler was still briefly flashing a PowerShell console window. Default Windows behaviour: when a console application starts as a scheduled task, the window appears for the duration of execution.
Fix: a VBScript wrapper. Shell.Run accepts a window style parameter. Setting it to 0 hides the window entirely.
Set objShell = CreateObject("Wscript.Shell")
objShell.Run "powershell.exe -ExecutionPolicy Bypass -File ""C:\TasksScheduler\BlinkReminder.ps1""", 0, TrueSaved as C:\TasksScheduler\BlinkReminder.vbs.
Task Scheduler action:
Program/script : wscript.exe
Add arguments : "C:\TasksScheduler\BlinkReminder.vbs"The scheduler calls the VBS launcher, which silently invokes PowerShell, which fires the toast. Zero console window.
Step 6: Settings That Matter
Setting Value Reason Allow task to run on demand Enabled Manual testing at any time Run if missed Enabled Catches up if the laptop was off Stop after 3 days Disabled Prevents auto-termination If already running Do not start new instance No stacked notifications
Step 7: The Debugging Session
Setup complete. Waited for the first notification. Nothing appeared.
Get Varun’s stories in your inbox
Join Medium for free to get updates from this writer.
This is the part tutorials skip. The gap between “this should work” and “this is working.”
Bug 1: Emoji Encoding Corruption
The .ps1 file had emoji characters in the notification text. Through the VBScript execution path, the file encoding did not match what PowerShell expected. Emojis became corrupted byte sequences: 😊 instead of the actual character. This broke the string terminator and PowerShell exited with a parse error.
The string is missing the terminator: 'Fix: remove emojis from the .ps1 file. Use plain text. The notification works without them.
File encoding issues only surface when the execution environment changes. In an interactive PowerShell session the file read fine. Through the VBScript launcher it broke. Always test scripts through the exact execution path used in production.
Bug 2: AC Power Condition
Task Scheduler’s default Conditions tab includes “Start the task only if the computer is on AC power.” The laptop was on battery. The scheduler silently skipped the trigger. No error. No log entry. Just silence.
Fix: uncheck both “Start only if on AC power” and “Stop if the computer switches to battery power.”
This is a particularly deceptive bug because the task appears correctly configured in every visible setting and the failure produces no diagnostic output. The log file revealed it: no timestamp meant the task had not run at all.
Bug 3: The Delay Setting
A hidden “Delay task for up to 1 hour” setting had been left enabled in the Triggers tab. Execution was being deferred by a random interval of up to 60 minutes. A 20-minute reminder was appearing unpredictably, or not at all.
Fix: disable the delay in the trigger’s advanced settings.
The Diagnostic Tool That Made All Three Bugs Trivial
Add-Content "C:\TasksScheduler\ReminderLog.txt" "$(Get-Date) - Reminder fired"One line. If the timestamp appears but no toast, the problem is notification suppression. If the log is empty, the problem is the scheduler. That separation of concerns is how observability works in production systems: logs confirm execution, metrics confirm behaviour.
Step 8: The Corrected Configuration
Triggers tab:
Type : Daily, Recur every 1 day
Repeat every : 20 minutes
Duration : Indefinitely
Delay : None (disabled)
Second trigger: At startupConditions tab:
Start only on AC power : Disabled
Stop on battery switch : Disabled
Start only if idle : DisabledSettings tab:
Allow on demand : Enabled
Run if missed : Enabled
Stop after 3 days : Disabled
If already running : Do not start new instanceRAM Usage: A Quick Check
Get-Process powershell | Format-Table Id, CPU, @{Name="MemoryMB";Expression={[math]::Round($_.PM/1MB,2)}}Id CPU MemoryMB
-- --- --------
22020 0.6875 64.79Around 65 MB during execution only. Released on exit. The Windows Notification Service manages the toast independently of the script. Leaving multiple notifications unacknowledged in the Action Center does not accumulate memory.
The Real-World Parallel: This Is Just a Cron Job
# Linux equivalent
*/20 * * * * /usr/bin/notify-send "Blink Reminder" "Keep your eyes safe. 20-20-20 rule."Windows Task Scheduler is the Windows-native equivalent of cron, with a GUI layer and additional trigger types. In enterprise environments it handles log rotation, backup jobs, monitoring scripts, and maintenance automation.
The mental model that makes this blink reminder work is the same one DevOps engineers use when writing cron expressions for pipeline schedules and maintenance windows.
Curiosity-driven tinkering with system tools is how engineers develop intuition for infrastructure. The blink reminder is a toy problem. The skills it touches are not.
The Final Setup
BlinkReminder.ps1atC:\TasksScheduler\with explicitImport-Module BurntToastReminderLog.txtauto-created on first runFBlinkReminder.vbswrapper in the same folder- Two triggers: Daily repeat every 20 minutes, and At startup
- Action points to
wscript.exewith the VBS file as argument - AC power conditions disabled
- Delay setting removed
- Console window fully hidden
- Toast appears and auto-dismisses
- Persistent across reboots
The Question I Could Not Answer
After getting the system working, I explained the whole thing to someone non-technical nearby. The setup, the debugging, the VBScript wrapper, the encoding bug, all of it.
Their response:
“That is impressive. But did you actually follow the 20–20–20 rule today after setting it up?”
I had not.
I built a fully automated, persistent, reboot-proof reminder system in an afternoon. And I still did not look away from the screen every 20 minutes, because when the notification appeared, I was mid-thought and dismissed it without acting on it.
The engineering problem was solved. The behavioural problem remains open.
I have maintained a 500+ day coding streak. I have read books on habit formation, identity, and systems thinking. I understand the theory of why habits are hard to build and exactly what conditions make them more likely to stick.
And I still dismiss the notification.
There is a meaningful gap between building a system that prompts a behaviour and actually performing the behaviour. The notification is the cue. What it cannot do is manufacture the will to act on it in the moment. That part is entirely on the person looking at the screen.
The system is running. The notification fires. Whether I look away or not is still a choice I make twenty times a day, and I do not always make the right one.
What I Learned From This
Layer 1: The medical layer. Eye drops treat the symptom. The 20–20–20 rule addresses the cause. Prevention is always cheaper than treatment.
Layer 2: The engineering layer. A small automation problem touched process scheduling, scripting, notification APIs, file encoding, memory management, and execution context differences. All concepts that appear at much larger scale in real engineering work.
Layer 3: The behavioural layer. A reminder system is not a habit. It is a prompt. The habit still has to be built by the person receiving the prompt. That distinction matters more than the engineering.
“The best engineers are not the ones who know the most tools. They are the ones who treat every small problem as a reason to understand how the system actually works.”
Final Thought
Exam season will end. The screen hours will reduce. But the habit of questioning why the obvious solution does not work, and building something better from the available tools, that does not end with the semester.
Take your eye breaks. The code will still be there in 20 seconds. Your eyesight might not be, in 20 years.
The notification will appear. What you do when it does is up to you.
I write about projects, system design, dev journeys, and the books shaping how I think, on my personal platform VSKript . If this post was useful, you will find more there.




