Chatbots Talk. Real AI Agents Schedule Work.
If your agent cannot retry, persist tasks, and survive restarts, it is still just a chatbot. Java already solved this problem.
I met Ronald Dehuysser at Jfokus in February. We talked about Java, background processing, and the kind of problems that look simple until you have to run them reliably in production. I only stumbled over ClawRunr just recently, and it immediately caught my attention because it touches a gap I have been thinking about for a while: most agent discussions focus on prompts, tools, and model choice, but not enough people talk about what happens when the agent needs to do work later, retry something, or survive a restart.
Ronald is the founder behind JobRunr, the open-source Java background job scheduler, and that background shows in this piece. He has spent years working on persistent, distributed job execution in Java, which is exactly why his view on AI agents is interesting. Ronald describes JobRunr as the result of seeing teams repeatedly build fragile schedulers without features like retries and monitoring, and the current JobRunr site positions him as the founder behind that work.
What follows is his take on why agent runtimes need a real scheduling model, and why Java already has most of the building blocks.
Most AI agents are stateless. You send a message, you get a response. That’s a chatbot.
Your AI Agent Has a Job Problem
A real agent does things when nobody’s watching. It checks your email at 8am. It retries a failed API call. It remembers that you asked to be reminded about something next Thursday. It survives a restart.
That’s not a chatbot problem. That’s a job scheduling problem. And Java developers have been solving it for years.
The gap nobody talks about
I’ve spent the last six years building JobRunr, an open-source background job scheduler for Java. So when I started looking at the AI agent space, I had a very specific question: how do these things schedule work?
The answer, in most cases: they don’t. Not really.
Most agent frameworks give you a nice LLM wrapper, some tool calling, maybe a conversation history. But ask the agent to “summarize my emails every morning at 8” and you’re suddenly in DIY territory. A cron job here, a Redis queue there, some in-memory timer that dies when the process restarts. No retry logic. No dashboard. No way to know if your 8am summary actually ran or silently failed.
This felt backwards to me. We have mature, battle-tested solutions for this in Java. JobRunr handles scheduling, retries, persistence, distributed execution, and monitoring out of the box. Why are we reinventing this for agents?
So we built one
Nicholas, my co-founder, got impatient and vibe coded a proof of concept. It worked. Then I read the code.
I’ll spare you the details, but let’s just say we had a productive conversation about dependency management and code that “works by accident.” We scrapped it and rebuilt from scratch.
The result is ClawRunr. We first called it JavaClaw, for obvious naming reasons we had to change it. Everyone still calls it JavaClaw though, and at this point we’ve stopped correcting them. It’s an open-source AI agent runtime written in pure Java.
But the interesting part isn’t the agent itself. It’s the architecture underneath.
Tasks as files, not database rows
Here’s a design decision that surprised people: tasks in ClawRunr are Markdown files.
When you tell the agent “remind me to review that PR tomorrow at 10am,” it creates a file like this:
---
task: Review PR
createdAt: 2026-03-23T14:30:00
status: todo
description: Review the open pull request and provide feedback
scheduledFor: 2026-03-24T10:00:00
---
Check the open pull requests on the project repository.
Review the code changes and leave comments.
Notify me when done.That file lives in workspace/tasks/2026-03-24/100000-review-pr.md. Human-readable. You can open it in your editor. You can grep for it. You can diff it in git. You can edit it yourself if the agent got something wrong.
Compare that to a job stored in a database table with a serialized payload. Sure, it works. But which one would you rather debug at 2am?
When the scheduled time arrives, the job scheduler picks up the task, the agent reads the Markdown instructions, executes them, and updates the status in the frontmatter. If it fails, the scheduler retries it. Up to three times. All visible in a dashboard.
For recurring tasks the same pattern applies. “Summarize my email every morning” becomes a Markdown file in workspace/tasks/recurring/ with a cron expression. The scheduler creates a fresh task from that template on each run. Cancel it through the chat, and both the recurring job and the file disappear.
One agent, many channels
The second architectural decision worth discussing: channel decoupling.
ClawRunr has one agent instance. When a message arrives, whether from Telegram, the web UI, or eventually Discord or Slack, the runtime fires an event. The agent doesn’t know or care where the message came from. It processes the request, produces a response, and the runtime routes it back through the same channel.
Want to add a new channel? Implement a single interface. The agent code doesn’t change.
This matters because real agents live across multiple surfaces. You start a conversation on your phone via Telegram, then continue in the browser at your desk. The agent should handle both without any extra wiring on your end.
Skills at runtime
This one is my favorite. ClawRunr has a skills system that’s almost stupidly simple.
You create a folder under workspace/skills/, drop a SKILL.md file in it, and the agent picks it up. No compilation. No deployment. No restart. The agent periodically scans the skills directory and discovers new capabilities on its own.
The skill file is just instructions. Plain text telling the agent what it can do and how. Need your agent to manage your grocery list? Write a SKILL.md that explains how. Need it to monitor a specific API? Same thing.
It’s extensibility through documentation rather than code. And it works surprisingly well, because at the end of the day, you’re instructing an LLM. Text is the interface.
Why Java
I’m biased, obviously. But hear me out.
An AI agent is a long-running process. It sits there, waits for messages, schedules jobs, executes tasks, manages state. The JVM was built for exactly this kind of workload. Garbage collection, thread management, stable memory usage over time. You get all of that for free.
Job scheduling is a solved problem in Java. JobRunr has been doing this since 2020. Distributed execution, a dashboard, Spring and Quarkus integration, automatic retries with exponential backoff. All out of the box.
Strong typing catches issues early. When your agent has ten tools (shell execution, file access, web search, task management) and the LLM decides which one to call based on conversation context, you want your tool interfaces to be explicit. A typo in a parameter name should be a compile error, not a runtime mystery.
And then there’s GraalVM. Alina Yurenko from the Oracle GraalVM team already made a GraalVM native image of ClawRunr within three days of release. Startup time dropped to under a second. For an agent that runs on your own hardware, that matters.
The building blocks were already there. Job scheduling, LLM integration, web frameworks, modular architectures. Someone just needed to put them together with an opinion about how agents should work.
What happened when we released it
We put it out there expecting a handful of people to try it. We thought it was a nice demo of what JobRunr can do in the AI space.
Instead: 200+ GitHub stars in three days. 32 forks. Our first external pull request. Someone built a plugin. The GraalVM port I mentioned. The LinkedIn announcement went way beyond our usual reach.
So we changed course. From our README:
This project was originally created as a demo to show the use of JobRunr. JavaClaw is now an open invitation to the Java community. Let’s build the future of Java-based AI agents together.
There’s a lot left to do. More AI Providers. More channels. Better memory and context management. Smarter task planning. Better Security and password management. But the foundation is there, and the Java community seems ready for it.
Try it
If you want to see what it looks like in practice, we recorded a demo video showing the onboarding, recurring task scheduling, task cancellation through natural conversation, and browser automation.
The code is at github.com/jobrunr/javaclaw. Clone it, run ./gradlew :app:bootRun, and you’re chatting with your agent in about two minutes.
We’re looking for contributors, ideas, and honest feedback. If something’s broken, tell us. If you think we’re doing something wrong, tell us that too. That’s how open source works.




