Skip to main content
Tilbake til blogg
OpenClawMarch 28, 20269 min

The Cron Jobs Running My AI Company at 4am

26 AI agents need care and feeding even when I am asleep. Here is the full cron schedule, what broke before I got it right, and how to build your own.

DB

David Bakke

Founder, Bakke & Co

PostShare
ForsidebildeOpenClaw

Every night while I sleep, my Mac Studio in Oslo runs about 20 cron jobs. By the time I wake up, my 26 AI agents have already cleaned their workspaces, synced their memories, classified my email, backed up the entire system to GitHub, and prepared a morning brief waiting for me in Slack.

This didn't happen overnight. The current schedule is the result of five weeks of trial, error, rate limit catastrophes, and one memorable morning where I woke up to find three agents had been fighting over the same file at 3am.

Here is the full schedule, what each job does, and everything that went wrong getting here.

The nighttime window: 2am to 4am

The heavy maintenance work runs between 2am and 4am Oslo time. This is when I'm asleep, my agents aren't getting interactive tasks from me, and Anthropic's API has the lowest traffic. That last part matters more than you'd think.

2:17 AM - Hermes subtype and context refresh. My email agent, Hermes, has a SQLite database with 83,000 emails. This nightly job runs two Python scripts that classify new emails by subtype and context using deterministic rules. No AI involved. Pure pattern matching against sender domains, subject line keywords, and thread history. It runs on Gemini 2.5 Flash because it just needs to execute scripts, not think.

3:00 AM - OpenClaw backup to GitHub. The entire OpenClaw configuration, all agent configs, all workspace files, the cron schedule itself, gets committed and pushed to a private GitHub repo. This is about 594 files and 4MB of text. Media files, browser data, and the Hermes SQLite database are excluded. Runs on Gemini Flash because it's a single bash script. Takes about 30 seconds.

3:11 AM - Synapse nightly ops cleanup. This is the big one. Synapse, my operations agent running on a local Llama model, does the janitorial work. It copies shared knowledge files (ORG.md, TEAM.md, AGENTS-ROSTER.md) to every agent workspace. It verifies every agent has the required files: MEMORY.md, SOUL.md, IDENTITY.md. It runs a memory file size audit, because any MEMORY.md over 10,000 characters gets silently truncated at session start, which means the agent loses context without knowing it. It checks listening ports against the process registry. It scans for cron jobs with consecutive errors. And it writes a daily memory bundle summarizing what every agent is focused on.

3:30 AM - Nyx broadcast maintenance. Nyx, my primary orchestrator, handles the broadcast system. It archives broadcasts older than 14 days, verifies that permanent directives are still present, and regenerates the communications architecture document if it's stale. This is the housekeeping that keeps the information layer healthy.

4:00 AM - Synapse broadcast processor. After Nyx has cleaned up, Synapse reads any new broadcasts and pushes summaries to every relevant agent's MEMORY.md file. If I issued a new standing order yesterday, by 4am it's been written into all 26 agents' long-term memory. When they wake up for their first session, they already know. This one runs on Claude Sonnet 4.6 because it needs genuine reasoning about which agents need which information.

The morning shift: 6am to 9am

By morning, the system transitions from maintenance to active intelligence work.

6:53 AM - Hermes token healthcheck. Before anything email-related runs, a quick check that the Gmail OAuth tokens are still valid. Runs on Haiku (fast, cheap) and only alerts me if something is wrong. This exists because I once spent an entire day not getting email briefs before realizing the OAuth token had expired at 2am and nobody told me.

7:47 AM - Security audit. Nyx runs a deep security check on the Mac Studio. Listening ports, firewall status, screen sharing, SMB guest access, FileVault, SIP. Compares everything against a known-good baseline. If anything deviates, I get an alert in Slack. If everything's fine, it writes a one-line log entry and stays quiet. I don't need a daily "everything is fine" message.

8:19 AM - OpenClaw doctor. Synapse runs openclaw doctor to check the health of the gateway itself. Are all agents reachable? Are models responding? Any config issues? Runs on Haiku because it's mostly just executing a diagnostic command.

8:20 AM - Hermes email morning brief. This hits the Hermes API to pull stats: how many ACTION_REQUIRED emails, what's unread, anything time-sensitive. If there's nothing to act on, it posts a single line: "No email actions this morning." If there are action items, I get a formatted summary with sender, subject, date, and a one-line context for each. Runs on Gemini Flash.

8:23 AM - Nyx morning brief. The main event. Nyx reads yesterday's daily notes, all project context files (Wheelhouse, PortLink, EventRipple), recent decisions, and my task manager. Then it posts a tight Norwegian morning brief to my main Slack channel. Top 3 priorities. Quick wins I can knock out in under 30 minutes. Open threads from yesterday. One observation or tip. Max 200 words. No greeting, no filler. Just the brief.

8:30 AM - Nyx PM morning brief. After the personal brief, Nyx sends targeted updates to the project management agents. PortLink's agent gets the latest on Wheelhouse and PortLink. EventRipple's agent gets its sprint status. MissionControl gets deployment health. Each agent only gets what's relevant to them. If nothing changed since yesterday, the agent gets skipped entirely. Zero noise.

9:31 AM - Hermes inbox training. This one is interesting. Hermes pulls 5 unclassified emails from the database, presents them in Slack with its current classification, and asks me to confirm or correct. It's a feedback loop that makes the classification system smarter over time. The variety rule ensures it picks from different categories, not just newsletters. Runs on Gemini Flash.

The daytime watch: 10am to 9pm

During working hours, the cron schedule shifts to monitoring and incremental work.

Every 30 minutes, 7am-11pm - Gmail incremental sync. Hermes runs a sync and embed cycle. New emails get pulled into SQLite, then vectorized into ChromaDB for semantic search. This keeps the 83K email database current. Runs on Haiku because it's just executing Python scripts.

Every 2 hours - Hermes V6 pipeline. The classification pipeline runs twelve times a day. It classifies unclassified emails using the V6 label system, applies an age rule (anything ACTION_REQUIRED or WAITING for more than 90 days gets downgraded to FYI), then syncs labels to Gmail. The V6 system was a painful migration, involving stripping labels from 58,000 messages, but the result is clean.

7 times daily (8am to 8pm) - Action required check. Hermes queries the API for any ACTION_REQUIRED emails and posts a summary if there are any. If the inbox is clean, it stays silent. This is my "don't let important things slip" mechanism.

The evening wind-down: 9pm to midnight

9:30 PM - Hermes evening email brief. Similar to the morning brief but with a different angle: what came in today, what's still unresolved, anything that can wait until tomorrow.

10:07 PM - Nyx evening brief. Nyx posts a daily retrospective. What got done. What's still open. Top 3 for tomorrow. One pattern or observation from the day. Again, max 180 words. Written in Norwegian because that's how I think about my day.

The weekly jobs

Some things only need to happen once a week.

Sunday 8:13 PM - Weekly brief. Nyx reads the last 7 daily memory files and all project context to write a weekly retrospective. Top results, blockers, decisions made, next week's priorities, and one strategic question for me to think about.

Sunday 9:41 PM - Cross-agent memory sync. This is the deepest maintenance job. Nyx reads MEMORY.md from every active agent workspace, identifies cross-agent insights, and sends targeted messages to relevant agents. If Forge made an architectural decision that affects how EventRipple should build its next feature, this is when that connection gets made. Takes about 4 minutes and runs on Sonnet 4.6 because it requires genuine analysis.

Sunday 9:43 AM - Weekly quality audit. Synapse runs a deep audit of every agent's SOUL.md and AGENTS.md files, verifying they contain all required rules (Quality Mandate, No Half-Messages, Research Before Acting). If a rule is missing, Synapse adds it. It also audits model assignments against the tier structure and flags mismatches.

Monday 8:41 AM - Content weekly digest. My content agent reads the latest intel from Scout (research) and Atlas (analysis) to update its content idea pipeline. This runs on Gemini Flash and feeds into the content planning system.

Monday 9:29 AM - Update status check. Simple: check if a new OpenClaw version is available. If yes, tell me. If not, do nothing.

What broke before the overhaul

The current schedule looks orderly. It wasn't always.

The first version had everything running at the top of the hour. Synapse cleanup at 3:00, backup at 3:00, broadcast processing at 3:00. Three agents, same minute, all hitting Anthropic's API. The result: 529 errors (rate limit exceeded) cascading across all three jobs. One would succeed, one would partially complete, one would fail entirely. The partial completion was the worst case because the agent would write half its output to a file, then die. Next morning, another agent would read that half-written file and make decisions based on incomplete data.

The fix was staggering. Every job now runs at an odd minute offset. Not :00, not :30. The backup runs at 3:00, cleanup at 3:11, broadcast maintenance at 3:30, broadcast processing at 4:00. That 11-minute gap between jobs isn't arbitrary. It's enough time for a Gemini Flash job to finish before a Sonnet job starts, keeping within the "max 2 parallel Anthropic jobs" rule.

Another early problem: agents corrupting each other's context files. When Synapse was copying shared files at the same time Nyx was reading them, Nyx would occasionally get a partial read. The solution was sequencing. Nyx's maintenance jobs run after Synapse's. The broadcast processor (4:00 AM) runs after Nyx's broadcast maintenance (3:30 AM). Order matters.

The file size issue took weeks to diagnose. MEMORY.md files that grew past 10,000 characters were getting silently truncated at session start. An agent would accumulate knowledge all week, cross the threshold, and then Monday morning it would wake up dumber than the previous Friday. The memory size audit in the nightly cleanup now catches this before it becomes a problem.

How to build your own schedule

If you're running any kind of multi-agent system, here's what I'd suggest.

Stagger everything. Never schedule two jobs in the same minute. Give yourself 10-15 minute gaps between heavy jobs. Assume your API provider's rate limits are stricter than documented.

Use cheap models for mechanical work. Backup scripts, file copies, health checks, running Python scripts. These don't need Opus or Sonnet. Gemini Flash, Haiku, even a local Llama 8B can execute bash commands just fine. Save your expensive model budget for jobs that require actual reasoning.

Build monitoring into the jobs themselves. Every job in my system either stays silent on success or alerts on failure. I don't want 20 "everything is fine" messages every morning. I want to know about problems, not the absence of problems.

Test at the scheduled time, not just manually. A job that works perfectly when you run it at 2pm might fail at 3am because another job is running at the same time, or because an API has different rate limits during off-peak hours, or because the file it depends on hasn't been created yet by an earlier job.

Keep a stagger buffer. Every cron job in my system has a staggerMs value, usually 900,000 milliseconds (15 minutes). If the scheduler can't run the job at the exact scheduled time because another job is running, it has a 15-minute window to find a slot. Without this, you get pile-ups.

The monitoring problem

Here's what I still haven't fully solved: how do you know a 4am job failed if you're asleep?

My current approach is the consecutive errors counter. Every cron job tracks consecutiveErrors. If a job fails once, it's probably a transient issue. If it fails twice in a row, Synapse alerts me in Slack during its next run. I'll see it in the morning.

But there's a gap. If Synapse itself fails, no one alerts me about Synapse. If the OpenClaw gateway goes down, none of the cron jobs run, and none of them can tell me they didn't run. This is the watchdog problem, and it's not unique to AI systems.

The backup job partially addresses this. If the GitHub backup doesn't appear, I'd notice the commit streak breaking. But "I'd notice" is not the same as "the system would tell me." I'm considering an external healthcheck service that expects a ping from my system every 6 hours. If the ping doesn't arrive, it emails me. Classic dead man's switch.

For now, the 8:23 AM morning brief is my canary. If I don't see it in Slack when I wake up, something is very wrong. It's a human-checkable signal for systemic failure. Low-tech. Effective enough.

The whole cron system is about 20 jobs running on a single Mac Studio. It's not a distributed cluster. It's not Kubernetes. It's a JSON file with schedules and prompts. And most mornings, by the time I pour my coffee, every agent has already done their homework.

openclawcronautomationmaintenance