CLI focus blocker for macOS — block distracting websites and apps
Project description
Lockin
A CLI focus blocker for macOS. Blocks distracting websites and apps at the network level so you can actually get work done.
- Blocks websites via
/etc/hosts(not a browser extension — works across all browsers) - Kills distracting app processes (Discord, Spotify, etc.)
- Tamper-resistant: sessions cannot be stopped early, even with
sudo - Enforced by a launchd watchdog daemon that re-applies blocks every 3 seconds
- Survives reboots, browser restarts, and DNS flushes
Install
pip install lockin
Or with pipx (recommended):
pipx install lockin
Requires macOS and Python 3.11+.
Concepts
There are three layers: presets, profiles, and sessions.
Presets (built-in) Profiles (you create) Sessions (you start)
┌──────────────┐ ┌────────────────────┐ ┌──────────────────┐
│ social │────┐ │ "work" │ │ active session │
│ entertainment│────┼───>│ presets: social, │──────> │ profile: work │
│ news │ │ │ entertainment │ │ duration: 2h │
│ gaming │ │ │ custom: slack.com │ │ 96 domains │
└──────────────┘ │ │ apps: Slack │ │ 3 apps │
│ └────────────────────┘ └──────────────────┘
│ ┌────────────────────┐
└───>│ "study" │
│ presets: social, │
│ news, gaming │
└────────────────────┘
- Presets are built-in bundles of sites and apps grouped by category (social media, entertainment, etc.). You can't edit them — they're just building blocks.
- Profiles are blocking configs you create. A profile picks one or more presets and optionally adds custom sites/apps on top. Think of it as "what do I want blocked when I'm doing X?"
- Sessions are timed activations of a profile. Once started, a session is locked in — no stopping, no editing, no cheating.
Quick Start
# 1. Create a profile that combines presets
lockin profile create work --preset social --preset entertainment
# 2. Start a 2-hour focus session with that profile
sudo lockin start work --duration 2h
# 3. Check remaining time
lockin
That's it. For the next 2 hours, social media and streaming sites are unreachable and Discord/Spotify get killed on launch.
Presets
Built-in categories you can mix into profiles. Run lockin preset to see them:
| Preset | Sites | Apps |
|---|---|---|
| social | x.com, twitter.com, facebook.com, instagram.com, tiktok.com, reddit.com, threads.net, snapchat.com, linkedin.com | Discord |
| entertainment | youtube.com, netflix.com, twitch.tv, hulu.com, disneyplus.com, primevideo.com, spotify.com | Spotify |
| news | news.ycombinator.com, cnn.com, bbc.com, nytimes.com, theguardian.com | — |
| gaming | steampowered.com, store.steampowered.com, epicgames.com, riotgames.com | Steam, Epic Games Launcher |
Each domain is also blocked with subdomain variants (www, m, api, mobile, app).
Commands
Profiles
Profiles define what to block. Combine presets with custom sites and apps:
# Block social + entertainment (presets only)
lockin profile create work --preset social --preset entertainment
# Block social + a custom site + an app
lockin profile create coding --preset social --site chatgpt.com --app Slack
# Block everything
lockin profile create lockdown --preset social --preset entertainment --preset news --preset gaming
lockin profile list # List all profiles
lockin profile show work # See exactly what a profile blocks
lockin profile delete old-profile
Sessions
sudo lockin start work --duration 2h # Start a focus session
sudo lockin start coding --duration 30m # Short sprint
lockin status # Check remaining time (or just `lockin`)
lockin stop # Refused during active sessions (by design)
Always-Blocked
Block domains permanently, outside of any session:
lockin block reddit.com
lockin unblock reddit.com
Schedules
lockin schedule create mornings --profile work --days mon,tue,wed,thu,fri --start 09:00 --duration 120
lockin schedule list
lockin schedule delete mornings
Other
lockin apps # List detected macOS apps
sudo lockin install # Install watchdog daemon
sudo lockin uninstall # Uninstall daemon (only when no active session)
lockin --version
How It Works
- Website blocking: Writes blocked domains to
/etc/hostspointing to0.0.0.0, then sets the system immutable flag (chflags schg) to prevent edits - App blocking: Kills blocked apps via
osascript(graceful quit) thenkillall(force kill) - Watchdog daemon: A launchd daemon (
KeepAlive: true) runs every 3 seconds to re-apply blocks if tampered with, re-kill blocked apps, and clean up when the session expires - Session signing: Sessions are signed with HMAC-SHA256 (key derived from hardware UUID). Modifying the session file invalidates the signature
Tamper Protection
The whole point of Lockin is that you cannot bypass it during a session:
| Attack | Mitigation |
|---|---|
Edit /etc/hosts |
Immutable flag (schg) blocks writes; watchdog re-applies if removed |
| Kill the watchdog | launchd auto-respawns it immediately |
sudo lockin stop --force |
No code path exists to stop active sessions |
| Delete the session file | Blocks become permanent (no valid session = no cleanup) |
| Change the end time in session file | HMAC validation fails, watchdog ignores it |
| Reboot | Session persists at /var/lockin/, daemon has RunAtLoad: true |
| Change system clock | Watchdog cross-checks elapsed time vs 2x duration |
Configuration
Profiles and schedules are stored in ~/.config/lockin/config.json. Sessions are stored in /var/lockin/session.json.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lockin-0.1.2.tar.gz.
File metadata
- Download URL: lockin-0.1.2.tar.gz
- Upload date:
- Size: 42.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f21b744de564c99a74e4428d1675024638053922e063b00a32a4b5ad3df38475
|
|
| MD5 |
12af3882d6cf0e6113b510e6b238865d
|
|
| BLAKE2b-256 |
a4f2e46dc6facc00def4ad2272a9066e49e7f731b2eed158ddd82c734f5e638d
|
File details
Details for the file lockin-0.1.2-py3-none-any.whl.
File metadata
- Download URL: lockin-0.1.2-py3-none-any.whl
- Upload date:
- Size: 17.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
93184c48fb684ed829e90d28bca9b1570c7f99fa73b787f535e9c3ad21109d89
|
|
| MD5 |
a226cc78198cab198e95651beacbfcd4
|
|
| BLAKE2b-256 |
3db76b953ef25247fb4c2e5a5b3313e0e6824b22da0e6d8a3fca4a01af7c1544
|