Model or dataset
ClawRunr/JavaClaw avatar
ClawRunr/JavaClaw

JavaClaw: a Spring Boot personal agent with a local job queue and Markdown tasks

JavaClaw, a Java version of OpenClaw built on Spring Boot, Spring AI and JobRunr

754 stars167 forksJavaLGPL-3.0

At a glance

What is it?
JavaClaw is a Java personal AI assistant that acts as a gateway between an LLM and your own devices, reachable over a web chat, Telegram, Discord and WhatsApp. It stores tasks as Markdown files in a workspace directory, runs background jobs through JobRunr, and can be extended with skills dropped into a folder as SKILL.md files.
Who is it for?
JavaClaw suits a Java developer who wants a personal agent that runs on their own machine, keeps its memory in files they can read, and is extended by dropping Markdown into a folder rather than by writing code. It does not suit a team that needs a hosted, multi tenant assistant with an audit trail, because the workspace directory and the embedded database are per-machine by design.
Can I use it commercially?
Yes, with conditions. LGPL-3.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A control plane that the agent reaches you through, not a chat app

JavaClaw is described as a Java-based personal AI assistant that runs on your own devices, and it acts as a control plane, or gateway, for an AI agent that can interact across multiple communication channels, manage tasks, execute shell commands, browse the web, and more, all while keeping your data local.

The gateway framing is the important architectural idea. The agent itself is not the product. The product is the surface that lets the agent reach you, and the local environment that lets it act. That is why the feature list is a mix of interface and capability: multi-channel support with a chat UI over WebSocket, Telegram, Discord and an extensible plugin-based channel architecture, plus task management, extensible skills, LLM provider choice, MCP support, shell and file access, web tools, background jobs and privacy.

The privacy claim is stated precisely, and the precision is what makes it credible. It runs entirely on your own hardware, with no data leaving unless you configure an external LLM. If you point it at Ollama, the traffic stays local. If you point it at OpenAI or Anthropic, your prompts go to that provider, and the project is telling you so rather than implying otherwise.

The README also carries an honest note about the project's origin. It was originally created as a demo to show the use of JobRunr, and it is now described as an open invitation to the Java community to build Java-based AI agents together. That is worth knowing, because a project that starts as a framework demo and becomes a product has a different risk profile from one designed as a product from the start, and the feature list here has the density of something that grew quickly.

The audience is a Java developer who wants a personal agent rather than a hosted assistant, and who is comfortable with Spring Boot and with an agent that can run bash commands on their machine.

The stack is a specific set of versions, and Spring AI is still a snapshot

The technology stack table is unusually concrete, and one entry stands out.

The layers are Java 25 for the language, Spring Boot 4.0.3 with Spring Modulith 2.0.3 for the framework, Spring AI 2.0.0-SNAPSHOT for the LLM layer, Spring AI Agent Utils for the agent, and the Spring AI MCP Client for Model Context Protocol. Jobs run on JobRunr 8.5.0, storage is an embedded file-backed H2 database, templating is Pebble 4.1.1, and the frontend is htmx 2.0.8 with Bulma 1.0.4. The channel libraries are JDA 6.1.1 for Discord and Telegrambots 9.4.0 for Telegram.

The Spring AI dependency being a SNAPSHOT is the detail to hold onto. Spring AI 2.0.0-SNAPSHOT is not a released artifact, so a build that resolves it is depending on a moving target, and the exact version of the LLM client behaviour you get depends on when you build. For a personal tool that is a reasonable trade. For a deployment you intend to keep running for a year, it means your dependency resolution is part of your maintenance, and a snapshot can change under you without a version bump anywhere in your own build files.

The choice of htmx and Bulma over a modern JavaScript front end is deliberate in the same way. Server-rendered HTML with htmx means the web chat interface needs no separate build pipeline and no node_modules, which is a good fit for a Spring Boot application that is otherwise one jar plus a workspace directory.

The module layout follows the same logic. There is a base/ module for the core, covering the agent, tasks, tools, channels and config, an app/ module that is the Spring Boot entry point with the onboarding UI, web routes and chat channel, and a plugins/ directory holding the channel and tool integrations, with brave, discord, playwright and telegram as the named examples. A providers/ directory also sits at the repository root, though the README does not describe what goes in it.

Tasks are Markdown files you can read, with a state machine on the filename

The task system is the part of JavaClaw that is most likely to be genuinely useful to a developer, and it is also the part with the least magic in it.

Tasks are tracked as human-readable Markdown files in the workspace/tasks/ directory, date-bucketed with a filename pattern of yyyy-MM-dd/HHmmss-<state>-<name>.md. The state is right there in the filename, which means you can see the state of every task with ls, and you can read a task with cat. There is a separate workspace/tasks/recurring/ directory for cron-scheduled recurring task templates.

The state machine is four states: todo, then in_progress, then completed or awaiting_human_input. That last state is the interesting one, because it is the point where the agent stops and waits for a person. An agent that can run shell commands and read and write files on your machine needs a way to get stuck safely, and awaiting_human_input is it.

The rest of the workspace layout follows the same readable philosophy. workspace/AGENT.md is the system prompt, editable during onboarding or at any time, and workspace/INFO.md holds environment context that is injected into every prompt. workspace/context/ holds agent memory and long-term context files. So the entire state of the assistant, its instructions, its memory and its to-do list, is a directory of text files that you own and can read at any moment.

That is a meaningful design choice in a category where most assistants keep their state in a database or, worse, in a vendor's cloud. Here the only structured store is the embedded H2 file, and the H2 file holds the job queue and whatever the framework needs, while the things a human would want to see are Markdown.

The job queue is what makes the scheduling work. JobRunr runs the background jobs, and the feature list mentions a built-in dashboard at port 8081, which is a separate port from the application itself. Scheduling supports one-off, delayed and cron recurring tasks, so a task can be a single reminder, a delayed job, or something that repeats on a schedule.

Skills are Markdown files, and they can also ship as jars

Extending the agent does not require writing code. Skills are loaded from workspace/skills/ and from skills jar packages on the classpath, and the mechanism is a file.

To add a capability you create a directory under workspace/skills/<skill-name>/ containing a SKILL.md file, and the agent loads it automatically through what the documentation calls SkillsTool. There is no registry, no manifest schema beyond the filename convention, and no restart required, since the description says the skills are loaded at runtime without code changes.

The jar route is the part that makes this a Java project rather than a convention. A skill can be packaged into a jar, or a prebuilt one can be used, and JavaClaw can load skills from classpath:/META-INF/skills. The build dependency is added like any other.

gradle
dependencies {
  runtimeOnly("com.skillsjars:some-skill-pack:VERSION")
}

And the scan path is configured in the application configuration.

yaml
agent:
  skills:
    paths: classpath:/META-INF/skills

So there are two distribution models for the same thing. A skill you wrote for yourself is a folder of Markdown you can edit with your editor. A skill you want to share with other JavaClaw users is a jar, published to a repository, pulled in as a runtime dependency. The SkillsJars naming in the documentation suggests a convention for the second case, and the gradle coordinates shown are com.skillsjars:some-skill-pack with a placeholder version.

This is the part of the design that makes JavaClaw extensible in a way that fits the JVM rather than fighting it. A skill is still just instructions the agent reads, but the delivery mechanism is a dependency you can version and publish.

Running it locally takes a Gradle wrapper and an onboarding wizard

The prerequisites are Java 25, Gradle or the included ./gradlew wrapper, and either an LLM API key for OpenAI or Anthropic or a running Ollama instance.

The dev run is a single Gradle task.

bash
./gradlew :app:bootRun

The Docker route builds a Jib image and runs it, with both the application port and the JobRunr dashboard port published, and the workspace directory mounted so the agent's files survive the container.

bash
./gradlew app:jibDockerBuild
docker run -it -p 8080:8080 -p:8081:8081 -v "$(pwd)/workspace:/workspace" jobrunr.io/javaclaw

Note the mount. The workspace is where AGENT.md, INFO.md, the context directory, the skills and the tasks live, so mounting it is what makes the containerised agent share state with your local files, and the fact that the image is published under the jobrunr.io registry is a leftover of the JobRunr origins the README mentions.

Onboarding happens at http://localhost:8080/onboarding and is a seven step wizard. You are welcomed, you choose a provider between Ollama, OpenAI and Anthropic, you enter the API key and the model name, you customise the agent prompt in workspace/AGENT.md with your own details such as name, email and role, you optionally configure MCP servers, you optionally add channel and tool plugins such as Telegram and Discord, and then you review and save.

The persistence detail is worth catching. Configuration is written to app/src/main/resources/application.yaml and takes effect immediately. That is convenient, and it means your API key ends up in a file inside the source tree of the application module, which is the sort of thing you want to know before you commit anything to version control. It also means the configuration is where the running instance reads from, so changing a channel token means editing that file.

The channel configuration is plain YAML, and the same keys work whether you set them in the wizard or by hand.

yaml
agent:
  channels:
    telegram:
      token: <your-bot-token>
      username: <your-telegram-username>

The built-in chat interface is at http://localhost:8080/chat and uses a WebSocket for real-time delivery, falling back to REST polling when no WebSocket session is active.

WhatsApp is a Go subprocess, and the project says why

The WhatsApp channel is the most interesting implementation decision in the project, because it solves a problem that has no Java solution.

There is no Java WhatsApp library, so JavaClaw launches wacli, a small Go CLI, as a subprocess and receives inbound messages through a local webhook. The CLI pairs as a WhatsApp Web linked device, which means you scan a QR code with your phone from Settings, Linked devices, Link a device.

bash
# macOS
brew install openclaw/tap/wacli

# Linux
go install github.com/openclaw/wacli@latest
bash
wacli auth

The configuration carries a single allowed chat identifier.

yaml
agent:
  channels:
    whatsapp:
      enabled: true
      allowed-chat-jid: "[email protected]"

Two security properties follow from that design and they are the most carefully argued part of the README. The allowed-chat-jid is the JID of the single WhatsApp chat the assistant responds in, and during onboarding you pick it by name from your synced chats rather than typing it, because WhatsApp issues opaque @lid identifiers that cannot be derived from a phone number. To find one yourself, the CLI lists chats and can search them by name.

The second property is that only one-to-one chats are accepted. Groups, newsletters and broadcasts are deliberately refused, and the reasoning is stated plainly: the assistant authorises by chat, so every member of a group would be able to instruct it, and the agent can run shell commands. The suggested workaround is to point it at your own Message Yourself chat, so you talk to the assistant from your own number. wacli itself is taken from your PATH, so it is a real external process you can inspect and replace.

The disclaimer at the end is short and should not be skipped. wacli uses the unofficial WhatsApp Web protocol, and the project says to use it at your own risk. That is the cost of the channel.

Where JavaClaw is the wrong tool

The first wrong-tool case is a hosted or multi-user deployment. The whole architecture assumes one person and one machine. The workspace is a directory of files, the H2 database is embedded and file-backed, and the JobRunr dashboard is a single instance. There is no tenancy model, no role separation, and no audit log of what the agent did beyond the Markdown it wrote.

The second case is an environment where the agent should not have shell access. The feature list is explicit that the agent can read and write files and run bash commands on your machine, and the WhatsApp section repeats the point about group chats being refused because the agent can run shell commands. If that capability is unacceptable on a given host, the answer is not configuration, it is a different tool.

The third case is a Java shop that already has a working agent. JavaClaw describes itself as a Java version of OpenClaw, and the openclaw project is referenced elsewhere in the documentation, with wacli published under an openclaw tap. If you already run that, the value here is the Java ecosystem integration and the JobRunr-based job model, and if you do not, this is a substantial piece of infrastructure to run for a chat interface you could get elsewhere.

The fourth case is anything that needs reliability guarantees. The LLM dependency is a snapshot artifact, the WhatsApp channel rides on an unofficial protocol, and the model itself is whatever you point it at. The project is candid about the WhatsApp risk, which is a good sign, but candidness is not the same as a guarantee.

On licensing, the project is LGPL-3.0 with a license.md file at the root. That is the weak copyleft, and it matters if you plan to modify JavaClaw and distribute the result: the LGPL requires that modifications to the library itself stay available under the same terms, while linking it into your own application is fine. For a personal tool that is irrelevant, and for a product you ship, it is a term to read before you fork.

The last push was on 2026-10-07 and the repository has no GitHub releases, so there is no versioned artefact to pin. For a tool whose whole promise is that it runs on your own machine and can run shell commands, that is a reasonable trade, and it also means you are running whatever is in the working tree.

Editorial conclusion

JavaClaw suits a Java developer who wants a personal agent that runs on their own machine, keeps its memory in files they can read, and is extended by dropping Markdown into a folder rather than by writing code. It does not suit a team that needs a hosted, multi tenant assistant with an audit trail, because the workspace directory and the embedded database are per-machine by design. Before adopting, read the agent prompt at workspace/AGENT.md, decide whether the shell access the agent has is acceptable on that machine, and note that configuration is written into app/src/main/resources/application.yaml at onboarding time, so the credentials end up in a file inside your source tree.

Frequently asked questions

What is JavaClaw?

JavaClaw is a Java-based personal AI assistant that runs on your own devices and acts as a control plane for an AI agent, reachable over a web chat, Telegram, Discord and WhatsApp, with task management, extensible skills and background jobs.

How do I run JavaClaw locally?

You need Java 25, Gradle or the included wrapper, and either an OpenAI or Anthropic API key or a running Ollama instance. Start it with ./gradlew :app:bootRun, or build a Jib image and run it with the workspace directory mounted, then complete the guided onboarding at http://localhost:8080/onboarding.

How are JavaClaw tasks stored?

Tasks are human-readable Markdown files in the workspace/tasks/ directory, bucketed by date with a yyyy-MM-dd/HHmmss-<state>-<name>.md naming pattern, and recurring task templates live in workspace/tasks/recurring/. The states are todo, in_progress and completed or awaiting_human_input.

How do I add a new capability to JavaClaw?

Create a directory under workspace/skills/<skill-name>/ containing a SKILL.md file and the agent loads it automatically at runtime. Skills can also be packaged as jars and loaded from classpath:/META-INF/skills, with the scan path configured under agent.skills.paths.

How does the JavaClaw WhatsApp channel work?

There is no Java WhatsApp library, so JavaClaw launches wacli, a small Go CLI that pairs as a WhatsApp Web linked device, as a subprocess and receives inbound messages through a local webhook. Only one-to-one chats are accepted, and the project warns that wacli uses the unofficial WhatsApp Web protocol.

Official sources

  1. ClawRunr/JavaClaw on GitHub
  2. Issues
  3. License: LGPL-3.0
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/clawrunr-javaclaw.svg)](https://hysenlabs.com/projects/clawrunr-javaclaw)

Was this useful?