Lockin
Focus blocker for macOS. Blocks distracting websites and apps so you can get work done.
lockin
╭──────────────────────────────────────╮
│ LOCKIN v0.3.0 │
│ Focus when it matters most │
╰──────────────────────────────────────╯
Main Menu
[1] Start a Focus Session
[2] Manage Profiles
[3] Manage Schedules
[4] Always-Blocked Sites
[5] View Presets
[6] Activity Recap
[7] Settings & Info
[0] Exit
How it works
- Blocks websites via
/etc/hosts— works across every browser, no extensions - Kills distracting apps on launch (Discord, Spotify, etc.)
- Sessions are tamper-resistant — once started, they can't be stopped
- A launchd watchdog re-applies blocks every 3 seconds, survives reboots
- Tracks your activity in the background — apps, browser URLs, productivity score
- Menu bar app shows live session countdown and runs the activity tracker
- Periodic screenshot capture (opt-in) for visual activity logging
Install
Requires macOS and Python 3.11+.
pipx install lockin
Setup
# Launch the interactive menu
lockin
# Or use CLI shortcuts
lockin --status # Check active session
lockin --recap # Today's productivity report
lockin --recap weekly # Weekly summary
The interactive menu walks you through everything — creating profiles, starting sessions, configuring settings.
Key concepts
Presets are built-in bundles of sites/apps by category (social, entertainment, news, gaming, communication).
Profiles combine presets with custom sites and apps into a blocking configuration.
Sessions activate a profile for a set duration. Once started, there's no stopping it.
Presets Profile Session
───────── ──────── ────────
social ─┐ "work" 2h focus
entertainment ┼──> + slack.com ────> 96 domains blocked
news ─┘ + Slack app 3 apps killed
Activity tracking
The menu bar app (lockin-menubar) tracks your activity in the background:
- Detects frontmost app and window title every second
- Extracts browser URLs via the Accessibility API
- Categorizes activity as productive / neutral / distracting
- Stores everything in a local SQLite database
- Optional periodic screenshots saved as compressed JPEGs
View your data anytime with lockin --recap or through the interactive menu.
Tamper protection
| Attack | Mitigation |
|---|---|
Edit /etc/hosts |
Immutable flag; watchdog re-applies |
| Kill the watchdog | launchd auto-respawns it |
| Delete session file | Blocks become permanent |
| Modify session times | HMAC signature invalidates |
| Reboot | Session persists, daemon has RunAtLoad |
Storage
- Config:
~/.config/lockin/config.json - Activity DB:
~/.config/lockin/activity.db - Screenshots:
~/.config/lockin/screenshots/ - Sessions:
/var/lockin/session.json
License
MIT
Metadata
Release files for lockin 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lockin-0.5.0.tar.gz | 69.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lockin-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 112.7 kB
Release files / lockin-0.5.0.tar.gz
| Download URL | lockin-0.5.0.tar.gz |
|---|---|
| Size | 69.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
60c9b6aca50a29043bd0960690b4e290b1d53c9f774dda81466433d0e239a9a9
|
|
BLAKE2b-256 checksum How to use checksums |
57ca3a2361709aa34d1e180eb18517a101e9fbd58f9456a4319cf716ebb05219
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Release files / lockin-0.5.0-py3-none-any.whl
| Download URL | lockin-0.5.0-py3-none-any.whl |
|---|---|
| Size | 43.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9bfcc33485f89bf6e7f478a90b6a30ed5b3abb65f0cb9e32e98a3b81aa69de3c
|
|
BLAKE2b-256 checksum How to use checksums |
a865b4991f9c430a5af6f3f88d7073cfe4d666ca2c16cb1a936f891b38ad85b4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|