Intelligent auto-quit for macOS.
Encodes each running app into a 7-dimensional CDE state vector, then drives a lifecycle state machine that auto-quits idle, low-priority apps. It still polls on a timer and the core trigger is an idle threshold — the CDE vector augments that threshold with protection and priority signals rather than replacing it.
Each running app is encoded into a 7-dimensional vector, every component normalized to [0.0, 1.0]
(see Models/AppStateDimensions.swift and Services/CDEAppStateEncoder.swift):
- Activity level —
1.0if frontmost, otherwise decays toward0.0as time since last activity approaches the timeout. - System impact — coarse resource-cost estimate keyed off the bundle id (browsers, IDEs, media editors, chat apps).
- Protection level —
1.0whitelisted,0.0blacklisted,0.5otherwise. - Interaction frequency —
0.5if an activity timestamp is known, else0.1. - System priority — heuristic by bundle id / name (Apple system apps, Finder, IDEs, office, mail, etc.).
- Lifecycle stage — time since launch normalized over a 300s equilibrium window.
- User preference alignment —
1.0whitelisted,0.0blacklisted,0.5otherwise.
Note: the source doc-comments still call this a "GGDP vector"; the project's framing is CDE. The math (7 normalized components, L2 norm) is the same either way.
The encoder does not emit "log / prompt / exit". It feeds a lifecycle state machine
(Models/AppLifecycleState.swift, Services/AppStateTransitionManager.swift) whose states are
launching → active → idle → pendingQuit → terminated. Transitions:
launching → activewhenlifecycleStage > 0.8active → idlewhenactivityLevel <= 0.3idle → pendingQuitwhenidleScore > idleThresholdANDsystemPriority < priorityThreshold(defaults:idleThreshold = 0.7,priorityThreshold = 0.8; per-app overrides supported)pendingQuit → terminated, afterAppQuitHelperissues the quit
where idleScore = (1 - activityLevel) × (1 - protectionLevel). Reaching pendingQuit is what
triggers the actual quit. The trigger is fundamentally an idle threshold; the additional dimensions
gate it (protection lowers idleScore, priority can veto the quit).
The claim that these 7 dimensions are a minimal sufficient statistic for the quit decision is a
design assumption, not a proven guarantee — there is no proof or test in this repo establishing
minimality or sufficiency. The decision is in fact computed from only two derived scalars
(idleScore and systemPriority), so several dimensions are unused by the current quit rule and
exist for the UI/analytics views.
open chronoquit.xcodeproj
# ⌘B to build, ⌘R to run- macOS 12.0+
- Xcode 14.0+
On first quit attempt the app requests permissions in System Settings (Automation under
Privacy & Security; it also checks Accessibility via AXIsProcessTrusted). Grant these, then
configure thresholds and the per-app whitelist/blacklist via the menu bar icon. The auto-quit
loop runs on a 60-second timer while enabled.
See CONTRIBUTING.md for development guidelines.
Apache-2.0 © 2026 Jacob Coleman — See LICENSE for details.