A usage-window schedule is a cron job that starts one Claude Code task at the beginning of each usage window, so the hours you're away from your desk still end in a pull request you can review.
I posted a version of this on r/ClaudeCode on October 20. This is the cleaned-up version, with one improvement that came out of the comments.
It's the smallest beginner setup I know of: a folder of Markdown files, one custom command and one cron line. No extra repos, no frameworks.
1. Understand the window
On the Pro plan, usage resets on a rolling 5-hour window that starts with your first message. If you only use Claude Code when you sit down at 9am, you get one window a day and the rest pass unused: the ones overnight and the ones that run out while you're in meetings. A scheduled run opens a window on its own and spends it on one task.
2. Make a queue
In your repo, create three folders:
tasks/
ready/
blocked/
done/
The folder a file sits in is its status. ready is the queue, blocked holds tasks the agent refused to start, done holds tasks it finished.
3. Write each task as a spec
One Markdown file per task, always with the same four headings:
# Add CSV export to the reports page
## Goal
Users can download the current report as a CSV file.
## Out of scope
PDF export. Changes to how reports are calculated.
## Done when
A "Download CSV" button exists on /reports, and a test checks
that the file has the same rows as the table.
## Agent log
Goal is what you want and why. Out of scope is what the agent should leave alone. Done when is something you can check, ideally a test. Agent log stays empty: that's where the agent writes.
I start file names with the date (2026-10-20-csv-export.md) so "oldest" is never ambiguous.
4. The command
Custom commands in Claude Code are Markdown files in .claude/commands/. Mine is .claude/commands/next-task.md:
Work on the next task in tasks/ready.
1. Take the oldest file in tasks/ready. If the folder is empty, stop.
2. If the Goal or Done when section is empty, move the file to
tasks/blocked, explain under Agent log what is missing, and stop.
Do not guess.
3. Create a new branch named after the task file.
4. Implement the Goal. Do not touch anything listed under Out of scope.
5. Run the tests. Fix failures caused by your change.
6. Open a pull request that links to the task file.
7. Append to Agent log: the branch, the PR link, what you changed
and anything you were unsure about.
8. Write one status line directly under the title of the task file:
"Status: done YYYY-MM-DD, PR <link>" or
"Status: failed YYYY-MM-DD, <one-line reason>".
9. If the task is done, move the file to tasks/done.
If it failed, move it to tasks/blocked.
Step 8 is new since the Reddit post. More on that in step 7 below.
5. The cron line
Run crontab -e and add:
0 */5 * * * cd ~/code/myrepo && claude -p "/next-task" >> ~/agent.log 2>&1
That starts one task every five hours. */5 in the hour field means 00:00, 05:00, 10:00, 15:00 and 20:00, so the gap from 20:00 to midnight is four hours, not five. Shift the hours if you want a run to line up with the start of your workday.
On macOS, cron doesn't run while the lid is closed and the machine is asleep. If that's how your laptop spends the night, use a launchd job with StartCalendarInterval instead.
Check two things before you trust it overnight:
- Headless slash commands. Run
claude -p "/next-task"once by hand and confirm it actually runs your command in your version of Claude Code. - Permissions. Nobody is there to approve a file edit or a
git pushat 3am. Set a permission mode or an allowed tools list (on the command line or in.claude/settings.json) that covers editing, running tests, git and opening PRs, and nothing beyond that. Check the current Claude Code docs for the exact flags.
Cron also runs with a minimal PATH, so you may need the full path to claude.
6. Read the log before the PRs
In the morning, open ~/agent.log first. It shows which runs happened, which hit the usage limit and which errored before doing anything. Then open the PRs. A PR can't tell you about the run that never produced one.
7. Write the status back into the task file
This one comes from u/here_and in the Reddit thread: have the command write a one-line done or failed status into the task file itself. That's step 8 in the command above. Now I can scan tasks/done and tasks/blocked in the morning and see what ran without digging through the log. I still read the log when something says failed.
What I've learned
- Specs I argue out loud turn out better than specs I type. When I talk a task through and get pushback, Out of scope and Done when come out sharper than when I type them alone.
- Missing specs fail safely. A task without a Goal or Done when goes to
blockedwith a note. The agent doesn't improvise. - Every PR still gets a manual review. The schedule changes when the work happens. It doesn't change who approves it.
- The delay between idea and PR got short. An idea I write up as a spec today has a PR the next morning, instead of sitting in a list for weeks.
FAQ
Does this work on the Max plan? The same setup works, but the usage windows and limits differ per plan and change over time. Check what your plan currently gives you and set the cron interval to match.
What if the agent picks a vague task?
If Goal or Done when is empty, it moves the file to blocked and stops. If they're filled in but vague, you'll usually see it in the PR and in the Agent log. The fix is a tighter Done when, not a longer prompt.
Can it run more than one task per window? It can, but I keep it at one. One task per run keeps PRs small and easy to review, and one failure doesn't eat the whole window.
Further reading
I was the bottleneck in my own agent loop: how I built a kanban board for Claude Code from notes, tasks and labels.
I now run this same loop on Vist's agent board, where the queue is a kanban board and the agent reads specs over MCP. It's free, MCP included: https://usevist.dev