cd /news/ai-agents/one-heartbeat-not-84-cron-jobs-the-s… Β· home β€Ί topics β€Ί ai-agents β€Ί article
[ARTICLE Β· art-148930] src=dev.to β†— pub= topic=ai-agents verified=true sentiment=↑ positive

One heartbeat, not 84 cron jobs: the scheduler at the core of a self-hosted agent

A developer behind OpenAmer, an open-source Apache-2.0 desktop AI agent that runs locally on Windows, replaced 84 separate cron and Task Scheduler jobs with a single in-process "ASI heartbeat" loop that owns scheduling for the whole agent. Each subsystem declares an interval in one dictionary, last-run timestamps persist to a JSON state file, and capabilities are invoked as direct function calls rather than subprocesses, so cadence survives restarts and can be changed with a one-line edit.

by read4 min views1 publishedOct 10, 2026

Why an autonomous desktop agent should own a clock instead of outsourcing it to the operating system's job runner β€” and what that buys you when things fail.

If you run an agent that is supposed to keep working while you sleep, you eventually face a scheduling problem. The obvious answer is the system's own job runner: cron on Linux, Task Scheduler on Windows. Start with five jobs. Then twelve. Then you are at eighty-four, each with its own interval, its own log, its own way of failing silently β€” and no single place where you can answer the only question that matters at 3am: what is actually running, and what is stuck?

OpenAmer is an open-source desktop AI agent (Apache-2.0) that runs locally on Windows. This post is the deep-dive I get asked for most: the ASI heartbeat β€” a single in-process loop that replaced our pile of scheduled jobs.

Job-per-concern looks clean in a diagram and rots in practice, for three reasons:

The deeper issue is architectural: the schedule lives outside the agent. The agent's own logic cannot see, reason about, or adjust its own cadence. That is backwards for a system whose whole job is to keep itself running.

The heartbeat is a single loop that owns cadence for the whole system. Each subsystem declares an interval; the loop checks whether it is due and, if so, runs it β€” in the same process, via a direct function call.

class Heartbeat:
    SUBSYSTEMS = {
        "learning": 300,   # every 5 min
        "system":   300,   # self-heal, resource monitor
        "senses":   1800,  # circadian, trend scout
        "swarm":    1800,
        "infra":    1800,  # env check, browser, plugin, mesh
        "meta":     3600,  # reflection, goal, research
        "security": 14400, # bugbot, CVE scan, code review
        "a2a":      14400, # brain export, peer comms
        "darwin":   900,   # evolution, autopatch, publish, probe
        "outreach": 10800,
    }

    def tick(self, system=None, force=False):
        for name, interval in self.SUBSYSTEMS.items():
            if system and name != system:
                continue
            if force or self.is_due(name, interval):
                self.run(name)          # direct call, not a subprocess
                self.mark_ran(name)     # persisted timestamp

Last-run timestamps live in a small JSON state file (memory/asi_heartbeat.json), so the cadence survives across process restarts. The loop is driven by one scheduler entry β€” asi-heartbeat-tick, every five minutes β€” and every subsystem rides on top of it.

The subsystems are not arbitrary; they are the organs the agent needs to stay alive and improve:

Subsystem Cadence What it covers
learning 5m internet learner, active learn, knowledge transfer
system 5m self-healer, resource monitor, traffic cop
darwin 15m evolution, autopatch, publish, probe
senses 30m circadian rhythm, watchtower, trend scout
swarm 30m swarm intelligence, autonomous loop
infra 30m env check, browser, plugin, mesh, cache
meta 60m reflection, self-rewriter, goal, research
security 240m bugbot, CVE scan, pen test, code review
a2a 240m brain export, peer communication
outreach 180m social, GitHub, growth report, funding

Cadence lives in one dict. Changing "how often does the agent learn from the internet" is a one-line edit, not a hunt through a job runner's UI.

The heartbeat is only half the story. The other half is what a job runs.

Previously each capability was an external script invoked as a process:

import subprocess
subprocess.run([sys.executable, "scripts/training/self_model.py"])

Now each subsystem is imported and called directly:

from tools.asi import self_model
state = self_model.gather_state()

Three things fall out of this:

The same five capabilities are also exposed as native agent tools β€” asi_status, asi_think, asi_learn, asi_remember, asi_trigger β€” and as a CLI:

openamer asi status      # full system + heartbeat health
openamer asi heartbeat   # tick the loop (optionally one subsystem)
openamer asi trigger <capability>

This is not free lunch, and the trade is deliberate:

The point is not that a heartbeat is clever. It is that an autonomous system should own its own clock, its own state and its own health β€” in one place it can measure. Once scheduling is a function call inside the agent, "is the agent healthy?" stops being an archaeology exercise across a job runner and becomes a single status query.

Code and the heartbeat module live here: https://github.com/openamer/openamer β€” the scheduler is under tools/asi/heartbeat.py.

If you've run a long-lived agent in production: what finally made you move scheduling into the system, or what made you keep it outside? I'm especially curious about the failure-isolation patterns people land on.

── more in #ai-agents 4 stories Β· sorted by recency
── more on @openamer 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/one-heartbeat-not-84…] indexed:0 read:4min 2026-10-10 Β· β€”