A menu-bar-only macOS app that keeps your Mac awake while AI coding agents run — so long overnight tasks aren't cut short when you step away.
The Arabic root د‑ل‑ج means to journey through the night — الإدلاج / الدُّلجة is travel in the dark, especially the final push before dawn. A مُدْلِج is one who travels by night. While you sleep, your Mac keeps journeying through the night so the agents reach their destination by morning. The machine is the مدلج.
Mudlej lives in the menu bar (next to Control Center) — no Dock icon, no window.
It holds off idle system sleep using
ProcessInfo.processInfo.beginActivity(...) and releases it when it's no longer
needed. The menu-bar glyph reflects state:
- 🥷 — awake, holding sleep off (journeying)
moon.zzz— idle, the Mac is free to sleep
- Auto (default) — every ~5 s it checks for running agents and holds sleep off only while at least one is detected.
- Keep awake — sleep is always held off, regardless of detection.
- Allow sleep — sleep is never held off.
- Keep display awake too — also blocks display sleep.
- Keep awake with lid closed — see below.
- Launch at login — start Mudlej automatically.
A power assertion (beginActivity) only blocks idle sleep. Closing a laptop
lid triggers a separate clamshell sleep path that ignores all power
assertions — the only software override is pmset disablesleep, which needs root.
The Keep awake with lid closed toggle runs that command via the native macOS
admin prompt (no background daemon, no extra install). Because disablesleep is
a system-wide, persistent setting, Mudlej:
- prompts again to restore normal sleep when you turn the toggle off or quit, and
- shows a
⚠️ warning in the menu the whole time it's active.
Warning
While this toggle is on, your Mac will not sleep at all — even on battery.
If Mudlej is force-quit or crashes while it's enabled, sleep stays disabled;
just relaunch and turn the toggle off (or run sudo pmset -a disablesleep 0)
to restore it.
The UI is localized in English and Arabic (a Localizable.xcstrings
String Catalog). It follows the system language by default. Open About Mudlej
from the menu to switch between System / English / العربية on the fly — the
menu and About panel re-render in the chosen language (Arabic also flips the
About layout to right-to-left). The choice is persisted.
Requires macOS 14+ and Xcode.
open Mudlej.xcodeproj # then press Run
# or from the command line:
xcodebuild -project Mudlej.xcodeproj -scheme Mudlej -configuration Debug buildAfter launch, look for the glyph in the menu bar — there is intentionally no Dock icon and no window.
LSUIElement = YES(Application is agent) — makes it menu-bar-only: no Dock icon, no main window. Set as theINFOPLIST_KEY_LSUIElementbuild setting.- App Sandbox is OFF. Agent detection shells out to
/bin/ps, and the lid-close toggle runspmsetwith admin privileges — both blocked by the sandbox. This is a personal tool (not App Store), soENABLE_APP_SANDBOXisNO. The manual Keep awake / Allow sleep modes work even if detection is unavailable.
Detection lowercases the output of ps -Axo comm= and substring-matches it
against a pattern list. The defaults are claude, codex, cursor-agent,
aider. To change them without rebuilding, edit the AgentPatterns default and
relaunch:
defaults write com.amjadkhalfan.Mudlej AgentPatterns -array claude codex cursor-agent aider mytoolTo find the exact string for your tool, run this while the agent is active and look for its process name:
ps -Axo comm=-
Lid-close sleep needs the toggle (and a password). Without Keep awake with lid closed enabled, closing a laptop lid still sleeps the Mac. With it enabled, sleep is disabled system-wide until you turn it off — read the warning above.
-
Detection is a substring match. It can false-positive (an unrelated process with
codexin its name) or false-negative (an agent running under anodeor other wrapper, socommshows the wrapper, not the agent). If your agent isn't detected, runps -Axo comm=while it's active to find the real string and add it to the patterns list (above).
Pushing a version tag builds, signs (Developer ID), notarizes, and attaches a
.dmg to a GitHub Release — see .github/workflows/release.yml.
git tag v1.0 && git push origin v1.0One-time setup — add these repo secrets (Settings → Secrets and variables → Actions):
| Secret | Reuse from Surrah? |
|---|---|
ASC_KEY_ID, ASC_ISSUER_ID, ASC_API_KEY_P8 |
✅ same values (App Store Connect API key) |
DEVELOPER_ID_CERT_P12_BASE64, DEVELOPER_ID_CERT_PASSWORD |
❌ new — Surrah's iOS Distribution cert can't sign a macOS .dmg; create a Developer ID Application cert (Xcode → Settings → Accounts → Manage Certificates → +), export as .p12, then base64 -i DeveloperID.p12 | pbcopy |
APPLE_TEAM_ID |
the Developer ID cert's 10-char team id |