Inspiration
I went to the bathroom at work and could not remember whether I had locked my MacBook. Which made my bathroom time more stressful than it already is. Find My could tell me where the machine was, which was not the question. There was no way to ask the only question I actually had.
The irritating part is that my Mac knew the answer the entire time. It just had no way to tell me.
What it does
Lock Status is two apps and no server.
A free macOS menu-bar helper watches lock, unlock and sleep, and writes each change to your own private iCloud. An iPhone app and its Home and Lock Screen widgets read it back, so the answer sits on your Home Screen and the common case takes no taps at all. You can also lock a Mac from the phone, behind a confirmation.
The one rule: never show old data as if it were current. Every reading says when that Mac was last heard from. After 180 seconds of silence it goes amber and stops claiming to be live, but keeps the last known state. "Locked, 12m ago" is honest. A plain "Locked" is not, because the Mac could have been shut in a bag an hour ago.
One exception, on purpose: a Mac announces that it is going to sleep and then its CPU switches off, so it cannot report anything after that. A stale "Asleep" is still trustworthy, so it stays confident.
How I built it
One data model in three processes.
The Mac helper writes the current state plus a heartbeat to local SQLite, and
SQLiteData's SyncEngine pushes it to your priv
iPhone app syncs the same tables down and renders them with The Composable
Architecture. The widget is a separate process,
Group database directly and also queries CloudKit itself, which keeps it
correct even when the app has been force-quit.
No backend, no account, no analytics. That is no architecture: the data lives in your CloudKit database and I cannot reach it.
Remote lock is just another row in that same private database. A command that arrives late is ignored, and the phone never saye it sent a command, only because the Mac said so.
Challenges I ran into
The two features I deleted are the ones I am happiest about.
I built a "check now" button into the widget. A cold widget takes nearly ten seconds to reach CloudKit, so the button timed o "Couldn't reach iCloud" on devices where iCloud was fine. That is the same lie as stale data, just pointed the other way. I rem
Then I wrote a clever task group and cancellatioKit fetch. It worked, and I deleted that too: it created a path where the widget could hang forever, to solve something `timeoutIy solves.
Two processes, one SQLite file. The app owns the schema and runs migrations. The widget opens the same file read-e it, because two processes writing schema at once corrupts it.
Tests that never ran. My macOS test target pointed at LockGlance.app
while the app is called Lock Status, and no shest
target. The suite had been quietly unrunnable for months.
What I learned
Asking "if this data were an hour old, would this screen still be telling the truth?" killed more features than it saved, and It also turns out that "no contact since 14:32" is a genuinely useful answer. Better than a spinner, and much better than a co
What's next
46 languages are done. Next is working out whetht breaking the honesty rule, since a push saying "unlocked" is a claim made at a moment I cannot re-check.
Log in or sign up for Devpost to join the conversation.