Pronounced "ahn-TRAHKT" (French entracte, IPA /ɑ̃.tʁakt/) — not "en-tract".
🔊 Hear it on the docs site
A cross-platform break reminder app for macOS, Windows, and Linux —
named after the theatre interval between acts.
Inspired by [Stretchly](https://hovancik.net/stretchly/)
Entracte lives in your menu bar / tray and nudges you to take breaks. It tries hard not to interrupt:
- Three break kinds — short Micro breaks (eye/posture, ~20s), Long breaks (multi-minute), and a Sleep prompt during a configurable bedtime window.
- Skip when you shouldn't be interrupted — pauses for system Do Not Disturb, an active camera (you're in a meeting), idle time (you already stepped away), or hours outside your work window.
- Pause from the tray — 15m / 30m / 1h / 2h / 4h / until tomorrow 6am / indefinitely. The tray icon shows pause bars while paused, so the state is visible at a glance.
- Multi-monitor aware — show breaks on every display, just the primary, or only the monitor your cursor is on, with no Space-hopping fullscreen.
- Windowed break mode — optionally shrink the overlay to 80% of the monitor (centered) so the rest of your desktop stays reachable while the reminder is up.
- Pre-break heads-up — optional notification a configurable number of seconds before each break.
- Daily screen-time budget — opt-in wind-down nudge when you cross a daily active-time budget (default 8 hours), with a configurable snooze interval.
- Tray countdown — optional
MM:SScountdown next to the menu-bar icon, configurable to track the next short, long, or soonest break (macOS and Linux). - Notification-only mode — per break kind, swap the overlay for a gentle system notification when you'd rather not be interrupted by a full-screen dim. Note that engagement metrics (completion, skip, postpone) aren't recorded for break types in notification mode, since there's no overlay to act on.
- Move with you — export a full local backup (settings, profiles, break history, screen-time, pause state, manual supporter token if you have one) to JSON and import it on another machine. Atomic stage-then-commit on import; partial-failure rollback restores your previous state.
The overlay is always dark — it has to dim everything else — but the accent and background tone follow your choice.
Entracte keeps a local history of breaks taken, dismissed, and suppressed, with a time-of-day breakdown and a 12-week heatmap. Export to CSV, export/import a full local backup bundle, or clear at any time.
macOS — via Homebrew (the cask lives in this repo, so tap from URL):
brew tap drmowinckels/entracte https://github.com/drmowinckels/entracte
brew install --cask drmowinckels/entracte/entracteLinux / Windows — download the .deb, .rpm, .AppImage, .msi, or .exe from the Releases page (pick the latest tag; pre-releases — the 0.0.X beta line — don't surface under releases/latest).
Windows users: the
.msi/.exearen't code-signed yet — SignPath Foundation turned down our first application on visibility grounds (the project is too new). SmartScreen will warn you when you run the installer; click More info → Run anyway to proceed. See the install guide for how you can help us get there — stars, forks, mentions, and contributions all count.
The same entracte binary doubles as a small CLI for scripting / hotkey wiring. Action commands forward to the running tray app:
entracte pause 30m # pause for 30 minutes
entracte trigger long # fire a long break now
entracte --profile=Focus --colour=midnight # switch profile + theme in one call
entracte status # JSON: pause state + active profile
entracte log # tail the entracte log
entracte help # full referenceFull command reference, IPC details, and tips in docs/guide/cli.md.
Entracte is free, cross-platform, and open source under Apache 2.0. Every scheduling, suppression, profile, hooks, stats, accessibility, and CLI feature is available to everyone.
A Supporter pack is available as a way to back development. It unlocks personalisation extras — custom overlay colour, theme rotation, editable break hints, custom CSS, and custom sounds — through a one-off purchase. The unlock check lives in plain source: it's an honour-system thank-you, not a DRM scheme. Nothing in the scheduling, suppression, profile, hooks, stats, accessibility, or CLI surface is gated.
- React 19 + TypeScript + Vite frontend.
- Rust + Tauri 2 + Tokio backend.
- Per-OS native hooks for Do Not Disturb, camera-in-use, and idle detection.
The scheduler is the brain: a Tokio tick loop in src-tauri/src/scheduler/ that consults native hooks, applies pause/suppress rules, and decides when (and how) to surface a break. The tray, CLI, and settings UI all push into the same scheduler; the overlay and stats are downstream of its decisions.
flowchart LR
subgraph UI["User surface"]
Tray["Tray icon + menu"]
CLI["entracte CLI"]
SettingsUI["Settings UI<br/>(React)"]
Overlay["Break overlay<br/>(React)"]
SysNotification["System notification"]
end
subgraph Backend["Rust / Tauri backend"]
IPC["ipc.rs<br/>CLI ↔ app bridge"]
Scheduler["scheduler/<br/>tick loop"]
Hooks["Native hooks<br/>DnD · camera · idle · session lock"]
end
subgraph Stores["On-disk state"]
Config[("settings.json<br/>profiles + settings")]
Stats[("events.jsonl<br/>break history")]
Pause[("pause.json")]
end
CLI -->|subcommands| IPC
Tray -->|menu actions| Scheduler
IPC --> Scheduler
SettingsUI <-->|tauri invoke| Scheduler
Hooks -->|suppress signals| Scheduler
Scheduler -->|fires break| Overlay
Scheduler -->|notify-only mode| SysNotification
Scheduler <--> Config
Scheduler --> Stats
Scheduler <--> Pause
Platform support matrix, scheduler internals, and OS-specific quirks are documented in .github/AGENTS.md.
npm install
npm run tauri dev # full app, hot reload on TS + Rust
npm test # vitest, frontend unit tests
npm run audit:a11y # build + headless Chromium + axe-core on every tab × light/dark
cargo test --manifest-path src-tauri/Cargo.toml --libThe a11y audit (scripts/audit-a11y.mjs) builds dist/, serves it via vite preview, drives Chromium through Puppeteer with a tiny __TAURI_INTERNALS__ shim so the React tree renders normally, then runs axe-core on every tab in both prefers-color-scheme modes. It runs on every CI build via .github/workflows/ci.yml and exits non-zero on any WCAG 2.1 AA violation.
Platform support matrix, scheduler internals, and OS-specific quirks are documented in .github/AGENTS.md.
Updates ship via tauri-plugin-updater against GitHub Releases. The About tab calls check_for_update, which delegates to the plugin: it fetches the signed latest.json manifest at releases/latest/download/latest.json, verifies the bundled signature against the public key pinned in tauri.conf.json, and reports whether a newer version is announced. macOS (Apple-signed + Tauri-signed), Linux AppImages (Tauri-signed), and Windows .msi (Tauri-signed) are all in latest.json. The check is manual — clicking Check for updates opens the release page in your browser; no automatic check on app start, no silent download_and_install. .deb / .rpm users update through their system package manager and are deliberately outside the updater flow.
Beta caveat.
releases/latestonly resolves to stable releases. While we're on the0.0.Xbeta line (no stable yet), the in-app Check for updates returns no update available even when a newer beta has shipped. Beta-to-beta upgrades are manual — watch the Releases page orbrew upgrade --cask entracteif you installed via the tap. Once0.1.0ships and is published as a non-prerelease, the in-app check starts working for everyone.
Windows specifically: until SignPath Foundation approves the project, the .msi is unsigned-via-Authenticode and SmartScreen warns every install. The About tab calls this out next to the "Open release page" link so users know to click More info → Run anyway.
Updater signing key. The pinned public key in src-tauri/tauri.conf.json (plugins.updater.pubkey) is the trust root every installed copy uses to verify the latest.json manifest. Its matching private key lives in two GitHub repo secrets — TAURI_SIGNING_PRIVATE_KEY (base64 contents of the key file) and TAURI_SIGNING_PRIVATE_KEY_PASSWORD (passphrase) — both wired into the build-unix job in .github/workflows/release.yml. The release workflow signs each macOS .app.tar.gz with that key and composes the latest.json manifest from both arches in the publish-updater-manifest job; a pre-flight verify-updater-pubkey job refuses any tag whose pubkey is still the bring-up placeholder.
Rotating the key breaks auto-update for every installed copy on the old pubkey — they can't validate signatures from the new one and silently fall behind. Rotate only when you have a path to manual reinstall for affected users (e.g. a security incident). To rotate: tauri signer generate -w ~/.tauri/entracte.key, paste the new public key into tauri.conf.json, update both TAURI_SIGNING_* GitHub secrets, ship a release that users must install manually, then any later release will auto-update normally.
Bug reports, ideas, and patches are all welcome. Start with CONTRIBUTING.md for the setup, test, and PR workflow. Participation is governed by the Code of Conduct, which — among the usual things — requires a real human reviewer in the loop on every contribution.
Functional and usable day-to-day on macOS. Windows and Linux build and run; some detection features (Linux DnD, Wayland idle) are still gapped — see AGENTS.md.
Settings persist to a JSON file in the OS app-config dir:
- macOS —
~/Library/Application Support/io.drmowinckels.entracte/ - Windows —
%APPDATA%\io.drmowinckels.entracte\ - Linux —
~/.config/io.drmowinckels.entracte/







