Wakes your Mac for scheduled jobs, holds it awake while long work finishes, and lets it sleep otherwise. Finds the cron jobs that have been missing runs; keeps a coding agent running with the lid shut.
30
stars
73
commits
Go
primary language
Aug 29, 2026
updated
Wakes your machine for scheduled jobs, holds it awake
while long work finishes, and lets it sleep otherwise.
getgoguma.com · Download · Security · Coding agents · Architecture · Updates
goguma wakes your machine shortly before each scheduled job, keeps it awake while the job runs, and lets it sleep again as soon as the job is done.
goguma doesn't run your jobs; it makes sure the laptop is awake when they fire.
A sleeping machine doesn't queue the jobs it missed and catch up later. It misses them outright. Nothing fails, nothing retries, and no error is written anywhere, because as far as the scheduler is concerned nothing went wrong. You find out weeks later, when you notice the digest you set up has been arriving on some days and not others.
There is a second version of the same problem, and it is newer. Work that has no schedule at all still takes as long as it takes: a coding agent chewing through a refactor, a long build, a big sync. Close the lid and the machine sleeps underneath it, and you come back to a session that stopped halfway.
goguma run -- claude -p "refactor the auth module"
Sleep is held off for exactly as long as that command runs, lid closed included, then released. For an agent inside an editor, where there is no command to wrap, goguma sets that up and keeps it that way: Claude Code, Codex, Cursor and Gemini CLI report when they are working, and the machine stays awake until they stop. It is a setting, so one switch turns it off again.
goguma fixes both. It lives in the menu bar: what is being held awake and what for, when the next wake is and which job it is for, and how long each job has been taking. Keep the Mac awake, skip the next wake, or pause everything without ever opening a terminal window (Or use the CLI)!
goguma scheduler add)goguma run -- <command>, for as long as that command takes and no longercaffeinate cannot do, so an
agent or a build carries on after you shut the laptopRequires macOS 14 or newer, or Linux with systemd.
Download goguma for macOS, drag it to Applications, and open it. It will offer to set itself up, and the command line tools are inside the app, so this is the whole install.
brew install junnam586/tap/goguma
goguma install
Both paths end in the same place: a background service, a privileged helper and
the goguma command. The app is a viewer for that service, so adding it later
is just opening it, and removing it changes nothing about your jobs.
goguma install sets up the background service and the helper. The helper only blocks
sleep and schedules wakes; everything else runs unprivileged.
Also available as a release archive, via go install, or built from source
with go build ./cmd/.... The Mac app is a universal binary, so Intel and
Apple silicon run the same download; the command line archives are per
architecture and Homebrew picks the right one. Linux builds ship for amd64 and
arm64 and pass CI on every commit.
You don't have to do this. goguma reads every scheduler on the machine by
itself, every couple of minutes, and starts waking for what it finds. Run
goguma import when you want to see what it found, or to give one of those
jobs exact timing:
Adopted jobs are woken for either way. Where a job's process can be picked out of the process table, goguma watches for it and sleeps the moment it exits. Where it can't, the machine is held for a bounded window instead, which costs a little more battery.
goguma import --register is how you close that gap. It offers to wrap the job
in goguma-mark, which reports the exact start, end and exit code. If you
accept, goguma makes that edit for you: it rewrites the crontab line or the
launchd plist, keeps a copy of the original, and puts the original back if the
result doesn't verify. Nothing is changed until you say yes to that job, and
goguma import on its own only reports.
Everything else is a click. The menu bar shows what is being held awake and what is coming next, the jobs window lists everything with its learned duration and lets you add, edit or pause a job, and settings covers the timing and safety limits.
Selecting a job shows where its numbers came from: the hold window underneath is the figure goguma learned, not one you set, and it says which runs it was derived from. The rest of this section is the same features for people who would rather type.
goguma status # see what goguma is doing
Add a job by hand with cron syntax or plain English:
goguma add --name nightly-backup --cron "every day at 3am" \
--command "restic backup /home"
For exact timing, run the job through the included wrapper. It reports the start, end, and exit code, so the machine sleeps the moment the job is done:
0 3 * * * goguma-mark nightly-backup -- restic backup /home
Some apps keep their own job list in a file rather than registering with cron or launchd. Point goguma at that file once and it reads it from then on:
goguma scheduler add cowork ~/Library/Application\ Support/Cowork/tasks.json
goguma help lists all commands, and goguma help <command> explains one.
Everything above is about work with a schedule. For work without one, wrap it:
goguma run -- claude -p "refactor the auth module"
goguma run -- make -j8 release
goguma run --label nightly -- rsync -a ~/work backup:/work
Sleep is held off for exactly as long as the command runs and released when it exits, so the window is the work rather than a guess. Output, input and exit status pass straight through, which means this can go in front of anything without changing what it does or what reads it.
It keeps working with the lid shut, which is the part caffeinate cannot
do: caffeinate holds off idle sleep and a closed lid is not idle sleep. goguma
goes through its helper for that.
An agent running inside an editor never gives you a command to wrap, and it cannot be watched from outside either. The process is there whether or not it is doing anything, and CPU does not separate the two, because an agent waiting on a model is a process blocked on a socket. Measured across four agent processes over ten seconds, the busiest figure belonged to an idle session and the one actually working used less.
So the editor reports it instead, and goguma keeps that arranged for every agent on the machine, including ones installed later. There is nothing to set up:
goguma hooks # what is set up, and what isn't
Claude Code, Codex, Cursor and Gemini CLI are covered. Each session holds
separately, so two
editors at once don't release each other, and the hold ends when the agent does
rather than on a timer. Your existing hooks are kept and a backup is written;
goguma hooks remove undoes it. the notes on coding agents
has the detail.
The hold is leased, so a wrapper that is killed outright cannot strand it: it lapses by itself rather than waiting for someone to notice. Nothing here is recorded as a job run, and the machine still sleeps if it overheats or the battery runs low, exactly as it does for a scheduled job.
A hold is released early if the CPU goes above 80°C or the battery drops below 10%, both configurable. So a laptop that is awake in a closed bag stops heating up, and one on battery doesn't run out of charge.
The 10% floor rises for jobs that are measured to cost more than that. A job that has been drawing 4% per run won't start one below 14%, so it can't strand the machine partway through.
If a job hangs, a time limit learned from its previous runs ends the hold. The default backstop is five minutes.
When goguma wakes the machine itself, it puts it back to sleep afterwards. It has to: macOS treats a scheduled wake as though you had opened the lid, so everything else on the machine wakes up too and can keep it up for hours after a job that took thirty seconds.
It only does this when it actually watched the job finish. That covers more
than it sounds: a job wrapped in goguma-mark, one whose process it can match,
and one whose own scheduler reports the run, which is how an adopted job with no
wrapper at all still qualifies.
What never qualifies is a window that closed without seeing anything, because
the job may still be running and sleeping the machine at the end of a guess
could suspend a backup mid-write. It also needs every hold closed and nobody at
the keyboard for two minutes. Turn it off with
goguma config set sleep_after_wake off.
goguma installs one small program that runs as root, because blocking sleep and setting a wake alarm both need it. security says what that program is allowed to do, who can reach it, and what the rest of it reads.
Does goguma run my jobs? No. Whatever runs them now still runs them; goguma only makes sure the machine is awake at the time.
If I only install the app, does it find my jobs on its own?
Yes. The background service re-reads every scheduler on the machine every couple of
minutes and wakes for whatever is worth waking for, with no terminal step. It
doesn't touch your crontab to do it, so a job whose process it can't recognise
gets a bounded window rather than exact timing. goguma import --register is
how you upgrade those, and goguma sync re-reads everything on demand.
Does it ever edit my crontab?
Only in one place, and only after you say yes to that specific job:
goguma import --register. It keeps a copy of the old crontab first and
restores it if the new one doesn't verify. Everything else reads and never
writes. See Installing and removing it.
What if I can't change a job's command?
goguma can watch the process table for it instead (--detection pattern --match "restic.*backup"), or hold the machine awake for a fixed window
(--detection none).
Can I use this to keep an agent running with the lid closed?
Yes, and it is set up for you. Claude Code, Codex, Cursor and Gemini CLI are
configured to
report when they are working, so the machine stays awake until they finish and
sleeps once they do. It is a setting: goguma config set agent_hooks off, or
the switch in the app, takes it back out. goguma hooks shows what is in place and
goguma hooks remove undoes it. For anything you launch yourself, wrap it:
goguma run -- <command>.
Does it keep the machine awake the whole time an editor is open? No. It holds while an agent is actually working and releases when that session stops, not on a timer. A browser tab running a web agent needs nothing at all: that work is on someone else's server, so your Mac sleeping doesn't interrupt it.
Isn't that just caffeinate?
caffeinate holds off idle sleep, and a closed lid is not idle sleep, so it
stops the moment you shut the laptop. It also cannot wake a sleeping machine at
all, which is the other half of what goguma does.
Why not just sudo pmset -a disablesleep 1?
That is the mechanism goguma uses, and for one supervised run it is enough. It
is a global setting that survives the process exiting, logout and reboot, so
forgetting to clear it means the machine never sleeps again. goguma guarantees
the other half: released when the command exits, when the daemon dies, when the
battery hits 10%, and when the machine hits 80°C.
Does anything leave my machine? Nothing about you. There is no account, no telemetry and no analytics. security lists the only two pieces of code that can open a socket at all.
Does it work on Linux?
Yes, on a distribution with systemd. It uses systemd-inhibit to hold sleep
and rtcwake to set the alarm. Windows isn't supported.
Where's the menu bar app?
In the release download,
or build it yourself from macos/ by running
cd macos && ./scripts/make-app.sh.
How do I hear when something breaks? getgoguma.com/updates.
Where can I read more? How it works, and why it works that way, is in architecture. The Mac app has its own notes.
My name is Juhyun (Jun) Nam. I'm a sophomore at Duke University, and I built goguma because my own automations weren't running at night.
You can find me on LinkedIn, and I'm happy to answer any questions about goguma at junnam586@gmail.com. If it's a security issue rather than a question, security says how to report it.
73 commits
Go
49.3%
HTML
25.8%
Swift
21.8%
Python
1.9%
Shell
1.2%
Wakes your Mac for scheduled jobs, holds it awake while long work finishes, and lets it sleep otherwise. Finds the cron jobs that have been missing runs; keeps a coding agent running with the lid shut.
30
stars
73
commits
Go
primary language
Aug 29, 2026
updated
Wakes your machine for scheduled jobs, holds it awake
while long work finishes, and lets it sleep otherwise.
getgoguma.com · Download · Security · Coding agents · Architecture · Updates
goguma wakes your machine shortly before each scheduled job, keeps it awake while the job runs, and lets it sleep again as soon as the job is done.
goguma doesn't run your jobs; it makes sure the laptop is awake when they fire.
A sleeping machine doesn't queue the jobs it missed and catch up later. It misses them outright. Nothing fails, nothing retries, and no error is written anywhere, because as far as the scheduler is concerned nothing went wrong. You find out weeks later, when you notice the digest you set up has been arriving on some days and not others.
There is a second version of the same problem, and it is newer. Work that has no schedule at all still takes as long as it takes: a coding agent chewing through a refactor, a long build, a big sync. Close the lid and the machine sleeps underneath it, and you come back to a session that stopped halfway.
goguma run -- claude -p "refactor the auth module"
Sleep is held off for exactly as long as that command runs, lid closed included, then released. For an agent inside an editor, where there is no command to wrap, goguma sets that up and keeps it that way: Claude Code, Codex, Cursor and Gemini CLI report when they are working, and the machine stays awake until they stop. It is a setting, so one switch turns it off again.
goguma fixes both. It lives in the menu bar: what is being held awake and what for, when the next wake is and which job it is for, and how long each job has been taking. Keep the Mac awake, skip the next wake, or pause everything without ever opening a terminal window (Or use the CLI)!
goguma scheduler add)goguma run -- <command>, for as long as that command takes and no longercaffeinate cannot do, so an
agent or a build carries on after you shut the laptopRequires macOS 14 or newer, or Linux with systemd.
Download goguma for macOS, drag it to Applications, and open it. It will offer to set itself up, and the command line tools are inside the app, so this is the whole install.
brew install junnam586/tap/goguma
goguma install
Both paths end in the same place: a background service, a privileged helper and
the goguma command. The app is a viewer for that service, so adding it later
is just opening it, and removing it changes nothing about your jobs.
goguma install sets up the background service and the helper. The helper only blocks
sleep and schedules wakes; everything else runs unprivileged.
Also available as a release archive, via go install, or built from source
with go build ./cmd/.... The Mac app is a universal binary, so Intel and
Apple silicon run the same download; the command line archives are per
architecture and Homebrew picks the right one. Linux builds ship for amd64 and
arm64 and pass CI on every commit.
You don't have to do this. goguma reads every scheduler on the machine by
itself, every couple of minutes, and starts waking for what it finds. Run
goguma import when you want to see what it found, or to give one of those
jobs exact timing:
Adopted jobs are woken for either way. Where a job's process can be picked out of the process table, goguma watches for it and sleeps the moment it exits. Where it can't, the machine is held for a bounded window instead, which costs a little more battery.
goguma import --register is how you close that gap. It offers to wrap the job
in goguma-mark, which reports the exact start, end and exit code. If you
accept, goguma makes that edit for you: it rewrites the crontab line or the
launchd plist, keeps a copy of the original, and puts the original back if the
result doesn't verify. Nothing is changed until you say yes to that job, and
goguma import on its own only reports.
Everything else is a click. The menu bar shows what is being held awake and what is coming next, the jobs window lists everything with its learned duration and lets you add, edit or pause a job, and settings covers the timing and safety limits.
Selecting a job shows where its numbers came from: the hold window underneath is the figure goguma learned, not one you set, and it says which runs it was derived from. The rest of this section is the same features for people who would rather type.
goguma status # see what goguma is doing
Add a job by hand with cron syntax or plain English:
goguma add --name nightly-backup --cron "every day at 3am" \
--command "restic backup /home"
For exact timing, run the job through the included wrapper. It reports the start, end, and exit code, so the machine sleeps the moment the job is done:
0 3 * * * goguma-mark nightly-backup -- restic backup /home
Some apps keep their own job list in a file rather than registering with cron or launchd. Point goguma at that file once and it reads it from then on:
goguma scheduler add cowork ~/Library/Application\ Support/Cowork/tasks.json
goguma help lists all commands, and goguma help <command> explains one.
Everything above is about work with a schedule. For work without one, wrap it:
goguma run -- claude -p "refactor the auth module"
goguma run -- make -j8 release
goguma run --label nightly -- rsync -a ~/work backup:/work
Sleep is held off for exactly as long as the command runs and released when it exits, so the window is the work rather than a guess. Output, input and exit status pass straight through, which means this can go in front of anything without changing what it does or what reads it.
It keeps working with the lid shut, which is the part caffeinate cannot
do: caffeinate holds off idle sleep and a closed lid is not idle sleep. goguma
goes through its helper for that.
An agent running inside an editor never gives you a command to wrap, and it cannot be watched from outside either. The process is there whether or not it is doing anything, and CPU does not separate the two, because an agent waiting on a model is a process blocked on a socket. Measured across four agent processes over ten seconds, the busiest figure belonged to an idle session and the one actually working used less.
So the editor reports it instead, and goguma keeps that arranged for every agent on the machine, including ones installed later. There is nothing to set up:
goguma hooks # what is set up, and what isn't
Claude Code, Codex, Cursor and Gemini CLI are covered. Each session holds
separately, so two
editors at once don't release each other, and the hold ends when the agent does
rather than on a timer. Your existing hooks are kept and a backup is written;
goguma hooks remove undoes it. the notes on coding agents
has the detail.
The hold is leased, so a wrapper that is killed outright cannot strand it: it lapses by itself rather than waiting for someone to notice. Nothing here is recorded as a job run, and the machine still sleeps if it overheats or the battery runs low, exactly as it does for a scheduled job.
A hold is released early if the CPU goes above 80°C or the battery drops below 10%, both configurable. So a laptop that is awake in a closed bag stops heating up, and one on battery doesn't run out of charge.
The 10% floor rises for jobs that are measured to cost more than that. A job that has been drawing 4% per run won't start one below 14%, so it can't strand the machine partway through.
If a job hangs, a time limit learned from its previous runs ends the hold. The default backstop is five minutes.
When goguma wakes the machine itself, it puts it back to sleep afterwards. It has to: macOS treats a scheduled wake as though you had opened the lid, so everything else on the machine wakes up too and can keep it up for hours after a job that took thirty seconds.
It only does this when it actually watched the job finish. That covers more
than it sounds: a job wrapped in goguma-mark, one whose process it can match,
and one whose own scheduler reports the run, which is how an adopted job with no
wrapper at all still qualifies.
What never qualifies is a window that closed without seeing anything, because
the job may still be running and sleeping the machine at the end of a guess
could suspend a backup mid-write. It also needs every hold closed and nobody at
the keyboard for two minutes. Turn it off with
goguma config set sleep_after_wake off.
goguma installs one small program that runs as root, because blocking sleep and setting a wake alarm both need it. security says what that program is allowed to do, who can reach it, and what the rest of it reads.
Does goguma run my jobs? No. Whatever runs them now still runs them; goguma only makes sure the machine is awake at the time.
If I only install the app, does it find my jobs on its own?
Yes. The background service re-reads every scheduler on the machine every couple of
minutes and wakes for whatever is worth waking for, with no terminal step. It
doesn't touch your crontab to do it, so a job whose process it can't recognise
gets a bounded window rather than exact timing. goguma import --register is
how you upgrade those, and goguma sync re-reads everything on demand.
Does it ever edit my crontab?
Only in one place, and only after you say yes to that specific job:
goguma import --register. It keeps a copy of the old crontab first and
restores it if the new one doesn't verify. Everything else reads and never
writes. See Installing and removing it.
What if I can't change a job's command?
goguma can watch the process table for it instead (--detection pattern --match "restic.*backup"), or hold the machine awake for a fixed window
(--detection none).
Can I use this to keep an agent running with the lid closed?
Yes, and it is set up for you. Claude Code, Codex, Cursor and Gemini CLI are
configured to
report when they are working, so the machine stays awake until they finish and
sleeps once they do. It is a setting: goguma config set agent_hooks off, or
the switch in the app, takes it back out. goguma hooks shows what is in place and
goguma hooks remove undoes it. For anything you launch yourself, wrap it:
goguma run -- <command>.
Does it keep the machine awake the whole time an editor is open? No. It holds while an agent is actually working and releases when that session stops, not on a timer. A browser tab running a web agent needs nothing at all: that work is on someone else's server, so your Mac sleeping doesn't interrupt it.
Isn't that just caffeinate?
caffeinate holds off idle sleep, and a closed lid is not idle sleep, so it
stops the moment you shut the laptop. It also cannot wake a sleeping machine at
all, which is the other half of what goguma does.
Why not just sudo pmset -a disablesleep 1?
That is the mechanism goguma uses, and for one supervised run it is enough. It
is a global setting that survives the process exiting, logout and reboot, so
forgetting to clear it means the machine never sleeps again. goguma guarantees
the other half: released when the command exits, when the daemon dies, when the
battery hits 10%, and when the machine hits 80°C.
Does anything leave my machine? Nothing about you. There is no account, no telemetry and no analytics. security lists the only two pieces of code that can open a socket at all.
Does it work on Linux?
Yes, on a distribution with systemd. It uses systemd-inhibit to hold sleep
and rtcwake to set the alarm. Windows isn't supported.
Where's the menu bar app?
In the release download,
or build it yourself from macos/ by running
cd macos && ./scripts/make-app.sh.
How do I hear when something breaks? getgoguma.com/updates.
Where can I read more? How it works, and why it works that way, is in architecture. The Mac app has its own notes.
My name is Juhyun (Jun) Nam. I'm a sophomore at Duke University, and I built goguma because my own automations weren't running at night.
You can find me on LinkedIn, and I'm happy to answer any questions about goguma at junnam586@gmail.com. If it's a security issue rather than a question, security says how to report it.
73 commits
Go
49.3%
HTML
25.8%
Swift
21.8%
Python
1.9%
Shell
1.2%