Back to FocusLock

Changelog

What's new

A running log of every meaningful change to the FocusLock app and website. Newest first.

Approval requests, tightened

  • 15 / 30 / 60 minute options. The 5-minute option is gone — five minutes was a fast doomscroll, not a real ask. The shortest exception is now 15 minutes, which makes "yes" mean something.
  • Parents get a full day to respond. Asks now stay open for 24 hours instead of expiring after one. If you're in meetings all morning, the kid's request is still waiting when you get back.
  • No more request spam. A kid can only have one open ask at a time. After a deny, the same target is on a 10-minute cooldown before they can re-ask — short enough that a real follow-up gets through quickly, long enough to make the kid pause.

Kids ask, parents approve — Family Approval Requests are live

  • Kid taps "Ask for N min" on any active block. 5 / 15 / 30 / 60-minute options. The parent sees a card in the Family Inbox with one-tap Approve or Deny, and a desktop notification fires the moment it arrives.
  • Approvals lift the block for just that one thing, for just that long. Approving "reddit.com for 15 min" lifts reddit.com for 15 minutes — everything else stays blocked. When the timer hits zero, the block re-engages automatically.
  • Asks expire after an hour. If nobody answers in an hour, the request quietly expires — no stale "yes" 6 hours later. The kid sees "No reply — try again later."
  • No emails. Lives in the Inbox we shipped last week. One surface for everything family-related.

You can always see — and stop — your running session

  • A persistent banner across every page. A sticky top bar now appears on Dashboard, Block Lists, Profiles, Schedules, Family, Analytics, and Settings whenever a session is active. Big bold label ("BLOCKING — Normal" / "BLOCKING — Hardcore" / "BLOCKING — Friend lock"), a pulsing colour-keyed dot, and the live countdown. Before, the banner only showed on two of the seven pages — and on the others the only signal was a small pill at the bottom of the sidebar.
  • End session button is reachable from anywhere now. In Normal mode the banner shows a prominent red End session button on the right; clicking it stops the session immediately, on any page. Before this, you had to navigate back to Dashboard (or be on Profiles / Block Lists) just to find a stop control.
  • Hardcore mode means something again. In Hardcore mode the End button is replaced with a "🔒 Locked until end" label. That contrast — big red button in Normal, padlock in Hardcore — is what gives Hardcore its meaning. Previously, if you couldn't even stop a Normal-mode session from most pages, Hardcore wasn't any different.

Admin analytics — five new charts and a coat of polish

  • Five new visualizations. Responses per month (bar), OS mix over time (stacked area, Mac vs Windows growth side by side), survey funnel (prompts shown → completed with a completion-rate readout), downloads per release (pulled live from GitHub for every shipped version), and average NPS by age bracket — so we can finally see which age group is happiest with the app.
  • Polish across the board. Tooltips now show percentages alongside counts. Each card shows its sample size in the title (e.g. "Profession · 487"). Bar charts sort biggest-first by default. macOS and Windows now use the same colour everywhere they appear. Pie slices are labelled with their percent. The grid collapses cleanly on phones instead of squishing the charts.
  • Behind the scenes. A new Supabase aggregation (0005_survey_crosstabs) snapshots responses_by_month, os_by_month, and nps_by_age nightly alongside the existing breakdowns. Release counts come from a new admin-only /api/survey/releases endpoint that proxies GitHub Releases with our auth token so we don't burn through the unauthenticated rate limit.

Admin analytics sign-in actually works now

  • The internal analytics dashboard couldn't send its magic-link email. When we verified tryfocuslock.com in Resend back on June 5, that switched the family-server emails (password reset, etc.) to deliver from a real domain — but Supabase has its own separate SMTP config for the analytics dashboard's admin sign-in, and that one was still pointed at Resend's sandbox sender (onboarding@resend.dev). Resend's sandbox only delivers to the Resend account owner, so any other admin email got rejected with a 550. From the dashboard side it looked identical to "email not authorized." Sender is now hello@tryfocuslock.com and magic links arrive.
  • No user-visible behavior change. Only the internal analytics dashboard is affected — the desktop app and family-server flows were already on the verified domain.

Family Inbox — weekly recaps and pair notices, inside the app

  • New "Inbox" card at the top of the Family tab. Chronological feed of things you'd otherwise miss: weekly recap of which apps and sites got blocked the most, and a notice every time a new device pairs to your account. No emails, nothing in your inbox you didn't ask for.
  • Mark-read per card or in bulk. Unread items have an accent border and a dot; click the check to dismiss, or hit "Mark all read" in the header.
  • Unread badge on the Family nav link. A small accent pill next to "Family" tells you how many things are waiting without opening the tab.
  • Foundation for child approval requests. The same feed will surface "Sam wants 15 min on reddit.com" when that feature ships — no second UI surface needed.

The Family "Walkthrough" button works again

  • Clicking Walkthrough on the Family page now actually re-opens the walkthrough. It only worked for signed-out users on an unpaired device — the button cleared the "already seen it" flag, but a second condition further down still suppressed the modal whenever you were signed in or on a paired child device, so the click looked like a no-op. The button now explicitly opens the walkthrough regardless of sign-in state.

Family page no longer takes the whole app down

  • Fixed a blank-window crash after signing in to Family. When the daemon couldn't enumerate local user accounts (we saw it on macOS), EnvironmentWarning tried to call .filter() on a missing array and threw — and because there was no React error boundary, the entire window turned solid black with no way to recover. Now defaults to an empty list and renders normally.
  • Added a top-level error boundary. If anything else throws during render, you'll see a small "Something went wrong" card with the actual error message and a Try again button, instead of losing the whole app. The other tabs keep working.
  • Async errors no longer disappear silently. Errors thrown outside the render cycle — IPC callbacks, promise rejections, module-load failures — bypass React's boundary. A global handler now surfaces them as a red overlay with the message and stack, so you can see what went wrong instead of staring at a frozen UI.

Family Controls actually works from the app now

  • "Load failed" on Create account / Log in / Forgot password is gone. The family-server worker was missing CORS headers, so every POST from the desktop app (Create account, Log in, Forgot password) failed in the browser engine before the request even reached the server — direct API calls worked, but the in-app form didn't. The worker now responds to preflight and includes Access-Control-Allow-Origin on every response.
  • Forgot-password emails actually arrive. Previously the reset email was wired to Resend's sandbox sender (onboarding@resend.dev), which only delivered to the Resend account owner — every other family's reset request silently no-op'd. We've verified tryfocuslock.com in Resend, so the reset link reaches any inbox.
  • Emails come from FocusLock <hello@tryfocuslock.com>. Replies land in the same inbox as the Contact page, so a confused parent who hits Reply gets to a real human.
  • No app update required. Both fixes are server-side — desktop installs from 1.1.2 onward already point at the right endpoint.

macOS install just works now

  • The background service can no longer go missing. It now ships inside FocusLock.app itself and is registered with macOS via Apple's SMAppService API on first launch. One admin password prompt, ever — subsequent launches and auto-updates are silent.
  • If something does go wrong, the app tells you. If the background service is disabled in System Settings → Login Items, or the binary fails its signature check, the app now shows a clear recovery screen with a button that opens the right pane in System Settings — instead of silently failing to connect.
  • Tamper detection is stronger and quieter. The old "daemon binary hash mismatch" warning fired on every legitimate update because the recorded hash never matched a freshly-built daemon. Replaced with Apple's SecCodeCheckValidity against the FocusLock Developer Team ID, which survives cert renewals and only fires on actual tampering.
  • One-file distribution. The separate .pkg installer is retired — releases ship a single signed .dmg. If you're upgrading from a previous install, the app does a one-time cleanup of the old /Library/PrivilegedHelperTools/ daemon for you. Your settings, PIN, and session history are preserved.
  • Requires macOS 13 Ventura or newer.

Rebuilt the Contact page

  • Fixed a broken email card. The "Get in touch" block was an inline anchor wrapping block-level children, so the browser drew the border around line-boxes — the disconnected slivers visible around the email address. Switched it to a proper block-level card with a soft purple glow and a hover lift; mailto: still opens your email app.
  • Made it feel like the rest of the site. The page was a barebones one-off with system fonts and the wrong purple. It now uses the same top navigation as the homepage (with Contact highlighted), the Fraunces serif headline ("Get in touch."), the real #6C63FF accent, and a footer that matches the homepage's bottom bar.
  • Icons on the "What to write about" cards. A bug, shield, lightbulb, and megaphone now sit on the four cards. Hovering lifts the card and brightens the purple border.
  • Polish. The "Response time" box matches the new card style, the literal subject-line keyword reads as a real security pill, focus rings are visible on all links and buttons for keyboard navigation.

Simplified the top navigation

  • The top bar had grown to nine items and felt cluttered. Removed Features, How it works, Story, and FAQ — they were either duplicated further down the page or rarely used. Kept Reviews, Changelog, and Contact alongside the Source, Donate, and Download buttons.
  • Re-packed the bar as a single centered group so there's no more empty stretch between the links and the right-side buttons.

Hosts file no longer accumulates duplicate blocks; YouTube is blocked on macOS too

  • Your hosts file isn't piling up FocusLock entries anymore. Two parallel bugs were stacking a fresh FocusLock-tagged section on every 30-second enforcement tick — on a real dev box, 113 duplicate copies of the same block had accumulated over time. On Windows the markers used Unicode em-dashes but the file was written as ASCII, so the on-disk text never matched what the code was searching for; on macOS, the strip logic only removed the first match, leaving any duplicates from older buggy versions in place forever. Both daemons now use ASCII-only markers and a permissive strip that catches canonical, legacy em-dashed, and mojibaked forms in one pass. Existing boxes self-heal on the first re-enforce.
  • YouTube is blocked on macOS now too. The Windows-only DoH fix from v1.1.5 has a macOS mirror: during an active session the daemon writes the equivalent managed-preference plist values for Chrome / Edge / Brave / Firefox, then restores the originals byte-perfect on session end. The same browser-restart caveat applies — open tabs hold live TCP connections that survive the policy change.

YouTube actually gets blocked now (Windows)

  • The bug. The daemon was correctly writing 127.0.0.1 youtube.com to the Windows hosts file, but Chrome / Edge / Brave / Firefox default to DNS-over-HTTPS on most networks — which never asks the OS resolver. So the hosts entry was invisible to the browser, you added youtube.com to your block list, started a session, and YouTube still loaded.
  • The fix. During an active session, the daemon now forces all four browsers off DoH via HKLM Group Policy keys. Your prior settings are backed up to %ProgramData%\FocusLock\doh_backup.json on session start and restored byte-perfect on session end, including the "was never set" case.
  • One caveat we now flag. Browsers cache live TCP connections independently of DNS — a YouTube tab already open when the session started can keep loading because the connection is established. A browser restart drops it. The Block Lists page now has a one-liner reminding you of this when you Quick Block.
  • No more no-op sessions. Profiles with no blocks at all could start a session that did nothing. Every start path now refuses an empty payload and names which profile is missing rules.
  • Visible session banner on Profiles and Block Lists. A running session is now obvious from every configure page, with a live countdown and End early button, colour-keyed to the session type (focus / Hardcore / Friend lock).
  • Clearer feedback when a session is already running. Quick Start chips and the main Start button disable themselves with a tooltip instead of letting you click and hit a generic daemon error.
  • macOS DoH parity is not in this release — it lands in v1.1.6.

In-app survey

  • Optional 2-minute survey in Settings → Feedback → "Take survey". NPS, demographics, usage patterns, and a free-text "What do you like most / least". Stored anonymously in Supabase. Submit once locks the entry against dupes; you can delete your response any time from the same panel.
  • Smart nudge. A small bottom-right banner suggests the survey after 5 completed sessions or 7 days of use, hard-capped at 3 lifetime appearances. Never interrupts an active block or pomodoro work phase. "Maybe later" snoozes 7 days, "No thanks" snoozes 60 days.
  • Inline newsletter opt-in at the end of the survey — sends signups directly to Beehiiv via an embedded form. No email leaves FocusLock except to Beehiiv if you choose to subscribe.
  • Privacy. An install_id (UUID v4 generated on your machine) prevents duplicate submissions but isn't linked to any identifying data. Privacy policy updated to disclose the new optional collection.

Daemon safety, macOS app blocking, and Light mode

  • The daemon will no longer kill system-critical processes (CRITICAL — affected 1.1.2 and earlier). Before this release, typing explorer.exe, winlogon.exe, or svchost.exe into the blocked-process textarea would have those processes killed during a focus session — including the Windows shell itself. Both daemons now check a hard-coded protected-name denylist before killing anything, and skip processes running in system sessions (Windows session 0; macOS uid 0 / under 100).
  • App blocking on macOS actually works. The Mac daemon now resolves running apps via NSWorkspace.runningApplications and matches by bundle identifier. Previously the matcher only saw process names and full paths, so .app packages were invisible — blocking "Steam" on Mac silently did nothing. Now actually blocks the app.
  • Complete Light mode. The old half-broken light theme (sidebar stayed dark while cards turned white) is replaced with a full CSS-custom-property token system. Cohesive across every screen, modal, and the command palette. Settings → Appearance now has Dark / Light / System — System follows the OS preference live.
  • Suggested apps picker. 14 curated common-distraction apps (Steam, Discord, Spotify, Slack, Battle.net, Epic, Riot, Roblox, Minecraft, OBS, Twitch, WhatsApp, Telegram, Signal). One-click adds the right token per platform — process name on Windows, bundle ID on macOS.
  • Suggested-domain chips show the actual domain. "Reddit" with reddit.com in muted text below — no more guessing what each chip blocks. Section renamed "Suggested Sites" → "Suggested Domains" to make the apps-vs-sites split obvious.
  • Steam suggested-domain fixed. Was pointing at steam.com, which isn't actually Steam's domain — blocking it did almost nothing. Now uses store.steampowered.com plus a new steamcommunity.com chip.
  • Working scan-this-download links on the landing page — the old VirusTotal "scan" link returned an empty search; replaced with real upload pages for VirusTotal, MetaDefender, and Hybrid Analysis.

Family controls: real password-reset emails, data export, login rate limit

  • Forgot-password emails actually send now. The reset flow used to only log the token to the family-server worker output. It now sends a real email via Resend. The response shape doesn't change whether the email is registered or whether the send succeeded, so account enumeration stays blocked. Login screen has a "Forgot password?" button → modal → "check your inbox" confirmation.
  • Export and delete your account. New "Your data" card on the parent dashboard: "Export as JSON" downloads a versioned dump of your account, devices, rules, and audit history (secrets and IPs stripped). "Delete account" opens a danger-zone modal that requires password re-entry plus a typed confirmation phrase. Deletion is permanent and cascades to every paired device.
  • Login + reset-request rate limiting. Per-email sliding window: 5 failed logins in 15 min triggers a 30-min block; 3 reset requests in 60 min triggers a 60-min block. Failed attempts on a non-existent email are counted equally so 429 vs 401 can't be used to enumerate accounts. Successful login clears the counter so legitimate users aren't punished for typos.

The Family tab actually ships this time

  • v1.1.0's release workflow forgot to pass VITE_FAMILY_API_URL to the Tauri build, so the Family tab was hidden in shipped artifacts even though the backend was live. CI now reads the URL from a GitHub Actions repository variable and bakes it into the build. Self-host forks without that variable set still get the Family tab hidden (same as 1.0.x) — this isn't a behaviour change for forks.

Family Controls — closed beta

  • The thing the 1.0.26 changelog promised. A parent on one machine can hard-lock specific apps and websites on a child's machine, at any time, from anywhere. Cloud-synced rules, real-time push, anti-bypass enforcement on the child side.
  • How it works. Parent signs up on their own machine, generates a 6-digit pairing code, enters it on the child's machine. From then on, the parent's dashboard shows the child's device with a live online dot, a block-now form (apps + domains), an audit log of what's happened, and an emergency-unblock button when something gets stuck.
  • The threat model FocusLock can actually defend. Killing the daemon (auto-restart watchdog), editing the family-rule cache (HMAC-signed, tamper-detected), rebooting into Safe Mode (Windows registers the service to start there too), uninstalling via Settings → Apps (now requires explicit parent authorization with a 15-minute window from inside FocusLock), and — opt-in — renaming a blocked binary (Windows Firewall blocks per-EXE-path, macOS pfctl blocks per-IP when daemon's been offline > 5 minutes).
  • The threat model FocusLock can't. A kid with administrator rights, a Linux USB boot, or BIOS access defeats all of this in minutes. The parent dashboard surfaces this directly — it now enumerates every local administrator account on the device by name with platform-specific instructions for demoting them. Nothing else FocusLock does matters until that step is done.
  • Closed beta. Free during the beta, then ~$5/mo per family for the hosted cloud once it stabilizes. Single-device FocusLock stays free forever. The full backend is open-source under the same GPL repo, so anyone can self-host their own family server and stay free that way too. Beta details + setup guide →

"No turning back" confirmation before Hardcore sessions

  • The Hardcore toggle was a one-click flip, which felt too casual for what it actually does — start a session you can't end early no matter what. Now there's a deliberate confirmation step between clicking Start and the session actually beginning: a modal spells out what's about to happen (Stop is disabled, closing the app doesn't end it, killing the daemon doesn't end it, only the timer does), and you have to type LOCK ME IN to confirm.
  • Quick-Start chips (the one-tap launchers for your saved profiles) still apply the gate when the profile is Hardcore — there's no shortcut around it. Starting a non-Hardcore session is unchanged.

Hardcore mode is now a one-tap toggle on the Dashboard

  • Before, you had to create a dedicated "Hardcore" profile to use Hardcore mode (the no-early-stop variant). That meant if you just wanted to lock in one quick session without thinking ahead, the only path was through a multi-step setup. Now the toggle lives directly on the Dashboard start screen, right below the duration picker.
  • Flip it on → session runs the full duration with no escape hatch. Flip it off → you can stop anytime. It pre-fills from your selected profile's setting, so existing Hardcore profiles still behave the same way; you can also override either direction before starting.
  • Same daemon logic as before — Hardcore mode is enforced by the background daemon, not the UI, so killing the app or rebooting doesn't end the session early.

Renamed "Parent controls" → "Settings lock"

  • The PIN-gated settings feature shipped yesterday has always been about locking your own settings so you can't disable FocusLock when willpower fails — single device, single user. Calling it "Parent controls" implied a parent-on-one-device-controlling-a-child-on-another setup that doesn't actually exist. The label was misleading, so it's now Settings lock with copy that's honest about what it does. Same PIN, same recovery key, same audit log — only the labels changed.
  • Real cross-device parental controls is a separate upcoming feature. A future release will let a parent log in on their own machine and hard-lock specific apps on a child's machine at any time, with proper anti-bypass on the child side. That's a multi-week build, not a label tweak — keep an eye out.

Parental controls — lock settings behind a PIN

  • You can now set a 4-digit PIN in Settings → Parent controls that gates every settings change behind it — profile edits, block list changes, removing a block — all prompt for the PIN before they apply. Useful if you want to set up FocusLock for someone else (a kid, yourself-in-the-past, a study group) and prevent the obvious workaround of just turning it off when willpower fails.
  • A 16-character recovery key is shown once when you set the PIN — save it somewhere safe. It's the only way to clear the PIN if you forget it. Every PIN action (set, unlock, failed attempt, recovery-key reset) goes into a local audit log you can review later.
  • Same logic ships on Windows and macOS, enforced inside the background daemon — so the lock isn't a UI sticker you can bypass by editing a file.

Site streamlined — shorter, clearer, less padding

  • Cut five sections that didn't earn their place: the duplicate stats bar (info was already in the hero), the "built for everyone" persona row, the academic studies section, the head-to-head comparison table, and the hero app mockup. The landing page is now about a third shorter and tells a tighter story.
  • The remaining flow: headline → how it works → features → reviews → the story behind FocusLock → open source → FAQ → support → final CTA.

Installer now elevates itself — no more right-click

  • The Windows installer used to silently fail to register the background daemon if you double-clicked it normally — you had to remember to right-click and pick Run as administrator. From v1.0.24 the installer triggers the UAC prompt itself on launch, so any user can double-click and just click Yes on the dialog. The daemon registers and starts automatically.

Auto-update actually works now (it didn't before)

  • Every release from v1.0.18 through v1.0.22 had a one-character typo in the public key baked into the app. Releases were signed correctly by the matching private key, but the installed app verified against a corrupted pubkey — so every "Update available" notification you ever saw failed silently behind the scenes. Fixed: the pubkey in the config now matches the key the releases are signed with. If you're on v1.0.18-v1.0.22, you need to download v1.0.23 (or later) once manually — but every future auto-update will install for real.

Daemon reliability — four bugs fixed

  • The background daemon (the part that enforces blocks at the OS level) had four separate bugs that combined to break the connection between the app and the daemon on fresh installs:
    • The SQLite library used for storing focus profiles wasn't compatible with single-file deployment — daemon crashed instantly at startup.
    • The daemon's signing key file had a permission setting so strict that the daemon couldn't read its own key on subsequent runs.
    • The IPC pipe (how the app talks to the daemon) required an OS privilege that wasn't always available — pipe was never created.
    • After fixing the first three by switching SQLite libraries, the new library's native code couldn't be loaded from a single-file bundle — another instant crash.
  • All four are now resolved. The daemon connects reliably on a fresh v1.0.22+ install.

Auto-update signing fixed

  • Auto-update actually works now. Earlier releases shipped without signature files, which Tauri's updater silently rejected on install. Rotated the updater keypair, wired the new key into CI, and verified end-to-end that signed updates now install. From v1.0.14 forward, future updates land automatically.

Achievement counter fix · CI resilience

  • Iron Will and Accountability achievements now actually unlock — they previously failed to count because the local tag used a random ID instead of the real session ID.
  • Release CI no longer gets blocked by transient cache-save failures on the GitHub Actions runner.

Visual redesign · command palette · achievements · intentions

  • Full visual redesign on a new Linear/Raycast-inspired design system — Inter typography, animated aurora background, film grain, gradient hero text, dramatic active-route glows.
  • Command palette (⌘K / Ctrl+K) — fuzzy-searchable command runner for sessions, navigation, theme toggle, and data export.
  • Achievements — 9 unlockable milestones with quiet unlock toasts and a full grid on Analytics.
  • Focus intentions — pre-session prompt persisted into the session log and shown on the active Dashboard.
  • Daily focus goal — configurable target with progress bar on the dashboard and sidebar, confetti when you hit it.
  • Smart block suggestions — one-click pills with favicons for the most-blocked sites, grouped by category.
  • Intercept page (the one you see when you try to visit a blocked site) rebuilt to match the new design, with a "what were you trying to do?" input that logs the attempt.
  • Onboarding rewritten as 4 steps: welcome → pick distractions → set goal → try a 5-min session.
  • Sidebar grouped into Configure / Insights with a live daily-progress widget at the bottom.

Auto-updates

  • FocusLock now checks for updates on launch and shows a small banner in the bottom-right when a new version is available — click Install now and the app downloads, installs, and restarts itself on the new version.
  • Updates are cryptographically signed and verified before install.
  • From this version onwards you'll never have to manually re-download — future releases come to you automatically.

Changelog page added

  • You're looking at it. New /changelog.html for tracking app releases and site updates in one place.

Site redesign — Freedom-style layout, dark palette

  • Refreshed the entire landing page: new Fraunces serif headlines, redesigned hero, hand-drawn step arrows, and a cleaner section rhythm.
  • Added a "Built for everyone" section showing who FocusLock is for — students, entrepreneurs, freelancers, parents, people with ADHD, and self-learners.
  • Added a Ko-fi donation section and Donate button in the nav.
  • Mobile nav now hides the download button and shows a desktop-only notice (FocusLock is a desktop app).
  • Final dark color palette applied across all components.

Daemon install reliability

  • Fixed an issue where the privileged daemon failed to install on first launch on some Windows setups (resolved by using the current executable path instead of the Tauri resource directory).

Windows daemon packaging fix

  • Fixed daemon installation on the new Windows package layout — the daemon binary is now staged correctly before the Tauri build.

Better downloads, hosting move

  • Download buttons now serve the installer directly instead of redirecting to GitHub — you stay on the site.
  • Added a Windows architecture picker modal (x64 / ARM64) so you don't have to guess.
  • Replaced the platform emojis with proper Windows and Apple SVG logos on download buttons.
  • Migrated hosting from Netlify to Vercel.

Reviews, newsletter, story

  • Added a live review system — leave a review right on the site, with AI moderation to keep things constructive.
  • Added an inline newsletter signup (Beehiiv-powered) for occasional updates about new features.
  • Added an "Our Story" section and a founder card so you know who built FocusLock and why.
  • Security hardening: stricter response headers, rate limiting on form endpoints, input sanitization.

New app icon

  • Replaced the app icon with a new converging-arrows design that matches the site branding.
  • CI/build improvements — macOS builds are now always unsigned (we no longer ship a signed/unsigned split), and all platform jobs run independently so one failure doesn't block the others.

Initial release

  • FocusLock launches for macOS and Windows — free and open source under GPL-3.0.
  • OS-level DNS blocking — every browser, no extension required.
  • App blocking by process name with a 2-second kill loop.
  • Friend Lock — generate a token, send it to a friend; only they can end the session early. SHA-256 hashed; you can't retrieve the original.
  • Hardcore Mode — cryptographically committed at session start; nothing ends it early.
  • Pomodoro engine with configurable work/break intervals.
  • Scheduled sessions via cron syntax — the daemon handles them even if the app is closed.
  • Focus analytics — streaks, weekly bar charts, focus score, 52-week heatmap.
  • Motivational intercept — your own message replaces blocked-site error pages.
  • Daemon runs as SYSTEM/root and starts before the desktop loads — closing or uninstalling the app doesn't stop active blocks.