{"id":50533076,"url":"https://github.com/drmowinckels/entracte","last_synced_at":"2026-06-03T15:02:04.009Z","repository":{"id":359563437,"uuid":"1241748663","full_name":"drmowinckels/entracte","owner":"drmowinckels","description":"Cross-platform break reminder app, named after the theatre interval between acts. macOS-first menubar app built with Tauri 2 + React.","archived":false,"fork":false,"pushed_at":"2026-05-29T21:58:03.000Z","size":49443,"stargazers_count":7,"open_issues_count":15,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-29T22:06:37.448Z","etag":null,"topics":["break-reminder","break-reminder-app","desktop-app","ergonomics","linux","macos","productivity","rust","tauri","tauri2","typescript","windows"],"latest_commit_sha":null,"homepage":"https://drmowinckels.io/entracte/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/drmowinckels.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":".github/AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-17T19:11:11.000Z","updated_at":"2026-05-29T21:57:37.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/drmowinckels/entracte","commit_stats":null,"previous_names":["drmowinckels/entracte"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/drmowinckels/entracte","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drmowinckels%2Fentracte","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drmowinckels%2Fentracte/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drmowinckels%2Fentracte/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drmowinckels%2Fentracte/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/drmowinckels","download_url":"https://codeload.github.com/drmowinckels/entracte/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drmowinckels%2Fentracte/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33870026,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["break-reminder","break-reminder-app","desktop-app","ergonomics","linux","macos","productivity","rust","tauri","tauri2","typescript","windows"],"created_at":"2026-06-03T15:02:03.001Z","updated_at":"2026-06-03T15:02:04.002Z","avatar_url":"https://github.com/drmowinckels.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/logo_gradient.svg\" alt=\"Entracte logo - proscenium arch in a teal-to-rose gradient\" width=\"160\" /\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eEntracte\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cem\u003ePronounced \"ahn-TRAHKT\" (French \u003cem\u003eentracte\u003c/em\u003e, IPA /ɑ̃.tʁakt/) — not \"en-tract\".\u003c/em\u003e\u003cbr/\u003e\n  \u003csub\u003e\u003ca href=\"https://entracte.drmowinckels.io/#how-to-say-it\"\u003e🔊 Hear it on the docs site\u003c/a\u003e\u003c/sub\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  A cross-platform break reminder app for macOS, Windows, and Linux —\u003cbr/\u003e\n  named after the theatre interval between acts.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Inspired by [Stretchly](https://hovancik.net/stretchly/)\n\u003c/p\u003e\n\n[![Checks](https://github.com/drmowinckels/entracte/actions/workflows/ci.yml/badge.svg)](https://github.com/drmowinckels/entracte/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/drmowinckels/entracte/branch/main/graph/badge.svg)](https://codecov.io/gh/drmowinckels/entracte)\n[![Latest release](https://img.shields.io/github/v/release/drmowinckels/entracte?include_prereleases\u0026sort=semver)](https://github.com/drmowinckels/entracte/releases/latest)\n[![License: Apache 2.0](https://img.shields.io/github/license/drmowinckels/entracte)](LICENSE)\n![Platforms: macOS, Windows, Linux](https://img.shields.io/badge/platforms-macOS%20%7C%20Windows%20%7C%20Linux-blue)\n[![Built with Tauri 2](https://img.shields.io/badge/built%20with-Tauri%202-24C8DB?logo=tauri\u0026logoColor=white)](https://tauri.app)\n[![Written with Claude](https://img.shields.io/badge/written%20with-Claude-D97757?logo=anthropic\u0026logoColor=white)](https://claude.com/claude-code)\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/screenshots/break-overlay-active.png\" alt=\"A micro break overlay: countdown ring at 10 seconds, with Postpone and Skip buttons\" width=\"720\" /\u003e\n\u003c/p\u003e\n\n## What it does\n\nEntracte lives in your menu bar / tray and nudges you to take breaks. It tries hard not to interrupt:\n\n- **Three break kinds** — short _Micro_ breaks (eye/posture, ~20s), _Long_ breaks (multi-minute), and a _Sleep_ prompt during a configurable bedtime window.\n- **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.\n- **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.\n- **Multi-monitor aware** — show breaks on every display, just the primary, or only the monitor your cursor is on, with no Space-hopping fullscreen.\n- **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.\n- **Pre-break heads-up** — optional notification a configurable number of seconds before each break.\n- **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.\n- **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).\n- **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.\n- **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.\n\n## Themes\n\nThe overlay is always dark — it has to dim everything else — but the accent and background tone follow your choice.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/screenshots/break-overlay-dark.png\" alt=\"Dark theme overlay\" width=\"240\" /\u003e\n  \u003cimg src=\"docs/screenshots/break-overlay-midnight.png\" alt=\"Midnight theme overlay\" width=\"240\" /\u003e\n  \u003cimg src=\"docs/screenshots/break-overlay-forest.png\" alt=\"Forest theme overlay\" width=\"240\" /\u003e\n  \u003cimg src=\"docs/screenshots/break-overlay-sunset.png\" alt=\"Sunset theme overlay\" width=\"240\" /\u003e\n  \u003cimg src=\"docs/screenshots/break-overlay-rose.png\" alt=\"Rose theme overlay\" width=\"240\" /\u003e\n\u003c/p\u003e\n\n## Stats\n\nEntracte 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.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/screenshots/stats-summary.png\" alt=\"Stats summary: breaks taken, dismissal rate, time paused, and reasons breaks were suppressed\" width=\"480\" /\u003e\n  \u003cimg src=\"docs/screenshots/stats-heatmap.png\" alt=\"Stats charts: time-of-day distribution and 12-week heatmap\" width=\"480\" /\u003e\n\u003c/p\u003e\n\n## Install\n\n**macOS** — via Homebrew (the cask lives in this repo, so tap from URL):\n\n```sh\nbrew tap drmowinckels/entracte https://github.com/drmowinckels/entracte\nbrew install --cask drmowinckels/entracte/entracte\n```\n\n**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`).\n\n\u003e **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.\n\n## Command line\n\nThe same `entracte` binary doubles as a small CLI for scripting / hotkey wiring. Action commands forward to the running tray app:\n\n```sh\nentracte pause 30m                 # pause for 30 minutes\nentracte trigger long              # fire a long break now\nentracte --profile=Focus --colour=midnight   # switch profile + theme in one call\nentracte status                    # JSON: pause state + active profile\nentracte log                       # tail the entracte log\nentracte help                      # full reference\n```\n\nFull command reference, IPC details, and tips in [docs/guide/cli.md](docs/guide/cli.md).\n\n## Free and open\n\nEntracte 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.\n\nA **[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.\n\n## Stack\n\n- React 19 + TypeScript + Vite frontend.\n- Rust + [Tauri 2](https://tauri.app) + Tokio backend.\n- Per-OS native hooks for Do Not Disturb, camera-in-use, and idle detection.\n\n## Architecture\n\nThe 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.\n\n```mermaid\nflowchart LR\n    subgraph UI[\"User surface\"]\n        Tray[\"Tray icon + menu\"]\n        CLI[\"entracte CLI\"]\n        SettingsUI[\"Settings UI\u003cbr/\u003e(React)\"]\n        Overlay[\"Break overlay\u003cbr/\u003e(React)\"]\n        SysNotification[\"System notification\"]\n    end\n\n    subgraph Backend[\"Rust / Tauri backend\"]\n        IPC[\"ipc.rs\u003cbr/\u003eCLI ↔ app bridge\"]\n        Scheduler[\"scheduler/\u003cbr/\u003etick loop\"]\n        Hooks[\"Native hooks\u003cbr/\u003eDnD · camera · idle · session lock\"]\n    end\n\n    subgraph Stores[\"On-disk state\"]\n        Config[(\"settings.json\u003cbr/\u003eprofiles + settings\")]\n        Stats[(\"events.jsonl\u003cbr/\u003ebreak history\")]\n        Pause[(\"pause.json\")]\n    end\n\n    CLI --\u003e|subcommands| IPC\n    Tray --\u003e|menu actions| Scheduler\n    IPC --\u003e Scheduler\n    SettingsUI \u003c--\u003e|tauri invoke| Scheduler\n    Hooks --\u003e|suppress signals| Scheduler\n    Scheduler --\u003e|fires break| Overlay\n    Scheduler --\u003e|notify-only mode| SysNotification\n    Scheduler \u003c--\u003e Config\n    Scheduler --\u003e Stats\n    Scheduler \u003c--\u003e Pause\n```\n\nPlatform support matrix, scheduler internals, and OS-specific quirks are documented in [.github/AGENTS.md](.github/AGENTS.md).\n\n## Development\n\n```sh\nnpm install\nnpm run tauri dev     # full app, hot reload on TS + Rust\nnpm test              # vitest, frontend unit tests\nnpm run audit:a11y    # build + headless Chromium + axe-core on every tab × light/dark\ncargo test --manifest-path src-tauri/Cargo.toml --lib\n```\n\nThe 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.\n\nPlatform support matrix, scheduler internals, and OS-specific quirks are documented in [.github/AGENTS.md](.github/AGENTS.md).\n\n## Updates\n\nUpdates 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.\n\n\u003e **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.\n\nWindows 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**.\n\n**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.\n\n**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.\n\n## Contributing\n\nBug 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.\n\n## Status\n\nFunctional 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).\n\nSettings persist to a JSON file in the OS app-config dir:\n\n- **macOS** — `~/Library/Application Support/io.drmowinckels.entracte/`\n- **Windows** — `%APPDATA%\\io.drmowinckels.entracte\\`\n- **Linux** — `~/.config/io.drmowinckels.entracte/`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrmowinckels%2Fentracte","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrmowinckels%2Fentracte","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrmowinckels%2Fentracte/lists"}