Profile
Back to NewsBack
GitHub Trending 12 min
Reader Mode
sorkila/lockpaw: Cover your Mac's screen with a hotkey while AI agents keep running, even with the lid closed. The covered screen glows when Claude Code, Codex or Gemini needs you. Touch ID unlock.

sorkila/lockpaw: Cover your Mac's screen with a hotkey while AI agents keep running, even with the lid closed. The covered screen glows when Claude Code, Codex or Gemini needs you. Touch ID unlock.

3 hours ago

Lockpaw: lock your screen, agents keep working

Lockpaw

One hotkey covers your screen. One hotkey uncovers it. Everything keeps running.
No sleep. No display disconnect. No process interruption. The screen glows when your agent needs you.

Download CI Release macOS 14+ Swift 5.9 MIT License Stars

Lockpaw demo: lock the screen while your agent works, get a glow when it needs you


You could set up Amphetamine, configure Hot Corners, tweak energy settings, and adjust your screen saver. Or you could press ⌘⇧L.

Features

  • One hotkey. Lock and unlock with ⌘⇧L, or record your own.
  • Touch ID unlock. Rest a finger on the sensor, nothing to click first. Password fallback like your Mac.
  • Every screen covered. All displays, including ones you plug in while locked.
  • Agents keep running. AI coding tools, builds, downloads and SSH sessions carry on underneath.
  • Agent alerts. The locked screen glows when Claude Code, Codex, Gemini, Cursor, Copilot or Aider needs you, and the notification says which agent and why.
  • Lid closed, still running. Optional. Close the MacBook lid while locked and your agents keep going, no external display needed. It uses one small helper you approve once, and sleep comes back when you unlock, when the Mac runs hot, or at 20% battery.
  • Pings on your phone. Optional. Forward agent pings to ntfy, Pushover or any webhook, such as Home Assistant.
  • Shortcuts and Spotlight. Lock Screen and Is Lockpaw Locked? actions. There's no unlock action, on purpose.
  • Your wallpaper, Aerials included. Optionally shows each display's macOS wallpaper behind the lock screen; Aerials keep moving while plugged in.
  • Fade to black. Optionally dims the lock screen to pure black after a while (good for OLED) without sleeping the display.
  • Small and native. About 14 MB of Swift. No Electron.
  • No analytics. No accounts, and the only network call is the signed update check, plus anything you switch on yourself.
  • Dog, cat, or your own. Pick the origami dog or cat, drop in your own image, or show no mascot at all.

Usage

| Action | How | |--------|-----| | Lock | Your hotkey (default Cmd+Shift+L) | | Quick unlock | Same hotkey, or rest a finger on Touch ID | | Fallback unlock | Click Use Password at the bottom of the lock screen and type your Mac password | | Settings | Menu bar → Settings… | | Change hotkey | Settings → General → Shortcut, click to record | | Change mascot, use your own image, or turn it off | Settings → Lock Screen → Mascot | | Hide the menu bar icon | Settings → General → Show in menu bar (open Lockpaw from Applications to bring it back) | | Keep agents running with the lid closed | Settings → General → Keep running with the lid closed | | Send pings to your phone | Settings → Agents → Send pings off this Mac → Send to | | Claude's phone pushes only while you're away | Settings → Agents → Claude phone pushes only while away → Set Up |


Agent alerts

Lock your screen and walk away. When your AI agent pauses for permission or finishes, the locked screen glows from across the room and a notification fires. You stay covered (and private) until you unlock. The glow is always silent; turn on a sound in Settings → Agents if you want one (off by default for shared offices).

The lock screen says who is waiting, one quiet line per session: Claude Code 2m, Codex 12m. Each has a dot that's amber while it needs you, teal once it's done, and red on an error. Project names stay off the lock screen, since anyone walking past can read it; turn them on in Settings → Agents. The notification always names the project: Claude Code needs permission in my-app. The glow is teal when your agents are done and amber while any of them is blocked on you or stopped on an error (a red dot marks the error); a later "done" never repaints a waiting glow teal.

Easiest: open Settings → Agents → Connect an agent and click your agent. A check marks the ones already connected. Prefer the terminal? Lockpaw ships a tiny lockpaw command-line tool (Lockpaw.app/Contents/SharedSupport/lockpaw); one command wires everything up, including installing itself into ~/.local/bin (add --print to just see the snippet):

| Agent | Setup | What it hooks | |-------|-------|---------------| | Claude Code | lockpaw install-hook claude | Notification + Stop + StopFailure hooks in ~/.claude/settings.json (honors $CLAUDE_CONFIG_DIR); Notification is matched to the types that need you, so auth_success and the like stay quiet | | Codex CLI | lockpaw install-hook codex | notify in ~/.codex/config.toml for finished, plus a PermissionRequest hook in ~/.codex/hooks.json for waiting. Trust it once via /hooks in Codex (honors $CODEX_HOME). If another tool already uses notify, it keeps running, right after Lockpaw | | Gemini CLI | lockpaw install-hook gemini | Notification + AfterAgent hooks in ~/.gemini/settings.json | | Cursor | lockpaw install-hook cursor | stop hook in ~/.cursor/hooks.json (--done) | | Copilot CLI | lockpaw install-hook copilot | agentStop + notification hooks in ~/.copilot/hooks/lockpaw.json (honors $COPILOT_HOME) | | Aider | lockpaw install-hook aider | notifications-command in ~/.aider.conf.yml | | Anything else | append ; lockpaw ping --agent my-tool --done to your command | runs after your agent finishes (--waiting / --error for the other two) |

The hooks reference ~/.local/bin/lockpaw by path, so they work no matter what's on your PATH, and keep working when the app moves or updates. Re-running install-hook upgrades older hook entries in place; existing foreign hooks are never clobbered, and a .bak backup is saved next to any config it touches. lockpaw install-cli is still there if you just want the command on your PATH.

Under the hood, lockpaw ping posts a local notification that Lockpaw listens for. It never launches the app if it isn't already running.

Claude phone pushes only while you're away

Claude Code's Remote Control can push to your phone. It skips the push while a marker file exists, if you set CLAUDE_CLIENT_PRESENCE_FILE (Claude Code 2.1.181 or later). Lockpaw keeps that file for you.

  • The file is ~/Library/Application Support/Lockpaw/present. It is empty.
  • It exists while your Mac is unlocked and awake. Lockpaw removes it when you lock
Lockpaw, when macOS locks, when the Mac or its displays sleep, and when Lockpaw quits.
  • It comes back when you unlock.
Lockpaw always keeps the file. Nothing reads it until you set the variable, so that is the switch. Click Set Up in Settings → Agents, or run lockpaw install-hook claude --presence. Both add this to ~/.claude/settings.json (or $CLAUDE_CONFIG_DIR) next to the Claude hook, with a .bak backup:
"env": { "CLAUDE_CLIENT_PRESENCE_FILE": "/Users/you/Library/Application Support/Lockpaw/present" }

A value you set yourself is never overwritten. Copy Setup puts the line on the clipboard if you'd rather add it by hand. New Claude Code sessions pick it up.

One edge: if Lockpaw crashes while unlocked, the file stays and pushes stay quiet. The next launch fixes it, and it removes the file at once if the screen is locked.


Install

Download

Grab the latest signed & notarized DMG from getlockpaw.com or GitHub Releases.

Homebrew

brew tap sorkila/lockpaw
brew install --cask lockpaw

Build from source

brew install xcodegen
git clone https://github.com/sorkila/lockpaw.git
cd lockpaw
xcodegen generate
xcodebuild -scheme Lockpaw -configuration Release build

On first launch, grant Accessibility when prompted. The Lockpaw icon appears in your menu bar.

Lockpaw is free and stays free. If it earns its place, you can support Lockpaw: $9 is a fine thank-you, $19 if it saves your afternoons.


Design

The lock screen is intentionally minimal. Near-black canvas. Subtle radial glow. One element at a time.

Calm by default. The screen opens with your chosen mascot, your message, and a quiet elapsed timer; the pointer slips away after a moment of stillness. The fallback auth button waits quietly at the bottom. When an agent pings, the screen breathes two slow waves of light (teal when it's done, amber when it's waiting on you), then keeps a soft glow and a quiet line per agent under the timer until you return.

Mascots. A metallic origami dog or cat rendered in teal and amber, floating in a pool of light. Slow 12-second breathing cycle. On successful unlock, the mascot scales up with a teal bloom and fades away. Or bring your own: a custom image gets a soft feathered edge so it sits in the same pool of light (transparent backgrounds look best).

Typography. System San Francisco throughout. Regular weight message at 55% white. Monospaced timer at 35%. The screen whispers.

Auth button. Glass material with a subtle border, easy to find without drawing the eye.


Under the hood

Hotkey. CGEvent.tapCreate on a dedicated background thread. Bypasses the LSUIElement activation issue that affects Carbon hotkeys in menu bar apps. The tap consumes the matched keystroke so it never reaches the app in front. Requires Accessibility permission.

Input blocking. A separate CGEventTap intercepts keyboard, scroll, tablet and trackpad-gesture events system-wide while locked, including the Dock's own gesture stream, so a three-finger swipe can't slide another Space in. Mouse events pass through to the overlay (SwiftUI buttons need clicks). If macOS disables the tap, it re-enables synchronously in the callback.

Window level. CGShieldingWindowLevel(), the highest level in the system. Above Spotlight, Notification Center, screen savers, everything.

Multi-display. One overlay window per screen, recreated on hot-plug.

State machine. LockState enum with validated transitions. Every transitionTo() call is checked. State is verified again after async authentication returns.

Sleep prevention. IOPMAssertion keeps the Mac awake while locked. With the lid closed that isn't enough, so the optional LockpawHelper LaunchDaemon (registered with SMAppService) sets pmset disablesleep while locked and clears it on unlock, at boot, and a minute after the app goes away. Its XPC interface is that one switch, and both ends check each other's code signature. See SECURITY.md.

Auth. While locked, a biometrics-only LAContext is already armed behind the overlay, so the first finger press unlocks with nothing to click. The fallback is a password field on the lock screen itself, checked against your login password through Open Directory and rate-limited to a 30s cooldown after 3 failed attempts. The cover never comes down for it, and while the field is open Lockpaw runs in kiosk mode, so app switching and Force Quit stay blocked even though macOS hides typed keys from the input tap. A rejected finger on the armed sensor costs no attempt: it may be a palm or a bag strap, and Touch ID enforces its own lockout in hardware.

Auto-updates. Sparkle framework checks for updates automatically. Appcast hosted at getlockpaw.com.


Security model

Lockpaw is a visual privacy tool, not a security boundary.

It guards against accidents: a colleague, a cat, your own muscle memory while agents run. It won't stop someone who means to get in.

What it does

  • Overlay at highest system window level
  • Event tap blocks all keyboard, scroll and trackpad-gesture input
  • Quit is refused while locked
  • Fast User Switching cancels auth, keeps lock active
  • Accessibility revocation detected and handled (force unlock with warning)
  • URL scheme rate-limited (100ms debounce)
  • Debug escape hatch compile-gated (#if DEBUG)
  • State machine validates every transition
  • Hotkey conflict detection against system shortcuts

What it doesn't do

  • Prevent pkill Lockpaw
  • Block synthetic events (AppleScript, Accessibility API)
  • Survive kernel-level access
  • Protect against screen recording during overlay fade-in
For real security: Ctrl+Cmd+Q.

Found a lock or auth bypass anyway? Please report it privately.


URL scheme

lockpaw://lock              Lock the screen
lockpaw://unlock            Show the password field (Touch ID is always live)
lockpaw://unlock-password   Show the password field
lockpaw://toggle            Toggle lock state


Architecture

Lockpaw/
├─ LockpawApp                     Entry, MenuBarExtra, AppDelegate, onboarding
├─ Controllers/
│  ├─ LockController              State machine, lock/unlock orchestration
│  ├─ Authenticator               LAContext · armed Touch ID · password check
│  ├─ InputBlocker                CGEventTap · keyboard/scroll blocking
│  ├─ HotkeyManager               CGEventTap · global hotkey detection
│  ├─ OverlayWindowManager        NSWindow · multi-display · shielding level
│  ├─ SleepPreventer              IOKit · idle sleep assertion
│  ├─ LidSleepController          Lid-closed mode · SMAppService helper · XPC · power cutouts
│  ├─ WebhookRelayController      Optional ping relay · ntfy / Pushover / webhook · Keychain
│  └─ AgentNotifier               UNUserNotificationCenter · agent-ping notifications
├─ Models/
│  ├─ LockState                  .unlocked → .locking → .locked → .unlocking
│  ├─ HotkeyConfig               Centralized hotkey UserDefaults access
│  ├─ PingDecision               Pure agent-ping decision (pulse/notify/sound)
│  ├─ PassiveAuthPolicy          Pure armed-Touch-ID rules (arm/re-arm/stand down)
│  ├─ AgentPing                  Typed ping: hook payload → agent · project · kind (shared with the CLI)
│  ├─ LockdownPolicy             Pure gesture lockdown (Space swipes)
│  ├─ LidSleepPolicy             Pure lid-closed rules (thermal, battery) + macOS lock handling
│  ├─ WebhookRelay               Pure relay request builder + per-session throttle
│  ├─ SupporterLicence           Polar key check · supporter state
│  ├─ Mascot                     Dog/cat/custom/none lock screen preference (+ supporter mascots, seasonal skins)
│  └─ TerminationPolicy          Quit is refused while guarded (+ LockStatus mirror)
├─ Views/
│  ├─ LockScreenView             Mascot (dog/cat/custom) · agent-ping glow · fallback auth
│  ├─ AmbientScreenView          Secondary display gradient animation
│  ├─ MenuBarView                Dropdown · lock/unlock/quit
│  ├─ Settings                   Native toolbar tabs (General, Lock Screen, Agents, About) · hotkey recorder · updates
│  └─ OnboardingView             5-step wizard · hotkey · accessibility · agent alerts
├─ Utilities/
│  ├─ Constants                  Timing, animations, formatting
│  ├─ Notifications              All Notification.Name in one place
│  └─ AccessibilityChecker       AXIsProcessTrusted + System Settings
└─ Resources/
   └─ Assets                      App icon, mascot, menu bar icon, colors

LockpawCLI/ └─ main lockpaw CLI · ping · install-cli · install-hook

LockpawHelper/ Lid-closed mode's root LaunchDaemon (opt-in) · one XPC call: sleep on/off


CI

Pushes to main and PRs run the build and the full unit test suite via GitHub Actions. Shipped DMGs are Developer ID-signed, notarized, and published to GitHub Releases; auto-updates are delivered through Sparkle with EdDSA-signed appcasts.


Support

Everything in Lockpaw is free and MIT-licensed, and everything that ships stays free. No feature is ever moved behind a payment.

If Lockpaw earns its place on your Mac, you can become a supporter (once, $9 or $19 suggested, or pay what you want) or sponsor me on GitHub. Supporters get a few thank-yous: four extra mascots, seasonal skins for the Dog and Cat, and no more asks: Lockpaw asks once, in a small card after it has done its job, and after that at most once a year in the menu bar. Contributors get a supporter licence on the house.


Pairs with

Tintpad is the other half of the loop: one hotkey opens your terminal at the right repo with Claude Code, Codex, or any agent already running. Tintpad starts your agents. Lockpaw covers for you while they run. Also free, also MIT.



getlockpaw.com


Chat with me