An open API service indexing awesome lists of open source software.

https://github.com/drmowinckels/entracte

Cross-platform break reminder app, named after the theatre interval between acts. macOS-first menubar app built with Tauri 2 + React.
https://github.com/drmowinckels/entracte

break-reminder break-reminder-app desktop-app ergonomics linux macos productivity rust tauri tauri2 typescript windows

Last synced: about 6 hours ago
JSON representation

Cross-platform break reminder app, named after the theatre interval between acts. macOS-first menubar app built with Tauri 2 + React.

Awesome Lists containing this project

README

          


Entracte logo - proscenium arch in a teal-to-rose gradient

Entracte


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/)

[![Checks](https://github.com/drmowinckels/entracte/actions/workflows/ci.yml/badge.svg)](https://github.com/drmowinckels/entracte/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/drmowinckels/entracte/branch/main/graph/badge.svg)](https://codecov.io/gh/drmowinckels/entracte)
[![Latest release](https://img.shields.io/github/v/release/drmowinckels/entracte?include_prereleases&sort=semver)](https://github.com/drmowinckels/entracte/releases/latest)
[![License: Apache 2.0](https://img.shields.io/github/license/drmowinckels/entracte)](LICENSE)
![Platforms: macOS, Windows, Linux](https://img.shields.io/badge/platforms-macOS%20%7C%20Windows%20%7C%20Linux-blue)
[![Built with Tauri 2](https://img.shields.io/badge/built%20with-Tauri%202-24C8DB?logo=tauri&logoColor=white)](https://tauri.app)
[![Written with Claude](https://img.shields.io/badge/written%20with-Claude-D97757?logo=anthropic&logoColor=white)](https://claude.com/claude-code)

---


A micro break overlay: countdown ring at 10 seconds, with Postpone and Skip buttons

## What it does

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:SS` countdown 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.

## Themes

The overlay is always dark โ€” it has to dim everything else โ€” but the accent and background tone follow your choice.


Dark theme overlay
Midnight theme overlay
Forest theme overlay
Sunset theme overlay
Rose theme overlay

## Stats

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.


Stats summary: breaks taken, dismissal rate, time paused, and reasons breaks were suppressed
Stats charts: time-of-day distribution and 12-week heatmap

## Install

**macOS** โ€” via Homebrew (the cask lives in this repo, so tap from URL):

```sh
brew tap drmowinckels/entracte https://github.com/drmowinckels/entracte
brew install --cask drmowinckels/entracte/entracte
```

**Linux / Windows** โ€” download the `.deb`, `.rpm`, `.AppImage`, `.msi`, or `.exe` from the [Releases page](https://github.com/drmowinckels/entracte/releases) (pick the latest tag; pre-releases โ€” the `0.0.X` beta line โ€” don't surface under `releases/latest`).

> **Windows users:** the `.msi` / `.exe` aren'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](https://entracte.drmowinckels.io/guide/install#windows) for how you can [help us get there](https://entracte.drmowinckels.io/guide/install#help-us-get-windows-signed) โ€” stars, forks, mentions, and contributions all count.

## Command line

The same `entracte` binary doubles as a small CLI for scripting / hotkey wiring. Action commands forward to the running tray app:

```sh
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 reference
```

Full command reference, IPC details, and tips in [docs/guide/cli.md](docs/guide/cli.md).

## Free and open

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](docs/guide/supporter.md)** 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.

## Stack

- React 19 + TypeScript + Vite frontend.
- Rust + [Tauri 2](https://tauri.app) + Tokio backend.
- Per-OS native hooks for Do Not Disturb, camera-in-use, and idle detection.

## Architecture

The scheduler is the brain: a Tokio tick loop in [src-tauri/src/scheduler/](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.

```mermaid
flowchart LR
subgraph UI["User surface"]
Tray["Tray icon + menu"]
CLI["entracte CLI"]
SettingsUI["Settings UI
(React)"]
Overlay["Break overlay
(React)"]
SysNotification["System notification"]
end

subgraph Backend["Rust / Tauri backend"]
IPC["ipc.rs
CLI โ†” app bridge"]
Scheduler["scheduler/
tick loop"]
Hooks["Native hooks
DnD ยท camera ยท idle ยท session lock"]
end

subgraph Stores["On-disk state"]
Config[("settings.json
profiles + settings")]
Stats[("events.jsonl
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](.github/AGENTS.md).

## Development

```sh
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 --lib
```

The a11y audit ([scripts/audit-a11y.mjs](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](https://github.com/dequelabs/axe-core) on every tab in both `prefers-color-scheme` modes. It runs on every CI build via [.github/workflows/ci.yml](.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](.github/AGENTS.md).

## Updates

Updates ship via [`tauri-plugin-updater`](https://v2.tauri.app/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/latest` only resolves to stable releases. While we're on the `0.0.X` beta 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](https://github.com/drmowinckels/entracte/releases) or `brew upgrade --cask entracte` if you installed via the tap. Once `0.1.0` ships and is published as a non-prerelease, the in-app check starts working for everyone.

Windows specifically: until [SignPath Foundation](https://signpath.org) 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`](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`](.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.

## Contributing

Bug reports, ideas, and patches are all welcome. Start with [CONTRIBUTING.md](CONTRIBUTING.md) for the setup, test, and PR workflow. Participation is governed by the [Code of Conduct](CODE_OF_CONDUCT.md), which โ€” among the usual things โ€” requires a real human reviewer in the loop on every contribution.

## Status

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](.github/AGENTS.md#known-gaps--next-moves).

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/`