| name | jaiclaw-developer |
| description | Comprehensive guide for building JaiClaw applications — project setup, tools, plugins, channels, skills, and testing |
| alwaysInclude | false |
| requiredBins | ["mvn"] |
| platforms | ["darwin","linux"] |
| version | 1.0.0 |
| tenantIds | [] |
JaiClaw Developer Guide
You are an expert at building applications with JaiClaw — a Java 21 / Spring Boot 3.5 / Spring AI framework for embeddable AI agents with multi-channel messaging, tool execution, plugins, skills, and MCP server hosting.
1. Architecture Overview
JaiClaw is layered bottom-up:
| Layer | Modules | Purpose |
|---|
| 0 - Core | jaiclaw-core | Pure Java records, sealed interfaces, enums — zero Spring dependency |
| 1 - Channel SPI | jaiclaw-channel-api | ChannelAdapter SPI, ChannelMessage, attachments |
| 2 - Tools | jaiclaw-tools | ToolRegistry, built-in tools, Spring AI bridge |
| 3 - Features | jaiclaw-agent, jaiclaw-skills, jaiclaw-plugin-sdk, jaiclaw-memory, jaiclaw-security, jaiclaw-documents, jaiclaw-media, jaiclaw-audit, jaiclaw-compaction, jaiclaw-browser, jaiclaw-cron, jaiclaw-voice, jaiclaw-identity, jaiclaw-canvas, jaiclaw-code, jaiclaw-messaging | Agent runtime, session management, plugins, memory, security, media, scheduling, MCP messaging |
| 4 - Gateway | jaiclaw-gateway, channel adapters (Telegram, Slack, Discord, Email, SMS) | REST/WebSocket API, webhook dispatch, MCP hosting |
| 5 - Auto-Config | jaiclaw-spring-boot-starter | 3-phase auto-configuration |
| 6 - Starters | jaiclaw-starter-anthropic, jaiclaw-starter-openai, jaiclaw-starter-gateway, etc. | Dependency aggregation |
| 7 - Apps | jaiclaw-gateway-app, jaiclaw-shell | Runnable Spring Boot applications |
Key design decisions:
- Java records everywhere for immutable value types
- Sealed interfaces for
ToolResult (Success/Error), DeliveryResult (Success/Failure)
- Dual tool bridge: JaiClaw
ToolCallback SPI ↔ Spring AI ToolCallback via SpringAiToolBridge
- Tool profiles: MINIMAL (read-only), CODING (file ops), MESSAGING (channels), FULL (all)
- Session key:
{agentId}:{channel}:{accountId}:{peerId}
2. Quick Start
Minimal pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.6</version>
</parent>
<groupId>com.example</groupId>
<artifactId>my-jaiclaw-app</artifactId>
<version>0.1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>io.jaiclaw</groupId>
<artifactId>jaiclaw-spring-boot-starter</artifactId>
0.1.0-SNAPSHOT
io.jaiclaw
jaiclaw-gateway
0.1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.ai
spring-ai-starter-model-anthropic
org.springframework.ai
spring-ai-bom
1.1.1
pom
import
org.springframework.boot
spring-boot-maven-plugin
Application Class
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyJaiClawApplication {
public static void main(String[] args) {
SpringApplication.run(MyJaiClawApplication.class, args);
}
}
application.yml
server:
port: 8080
jaiclaw:
identity:
name: My Assistant
description: An AI assistant built with JaiClaw
agent:
default-agent: default
agents:
default:
id: default
name: Default Agent
tools:
profile: full
spring:
ai:
anthropic:
enabled: true
api-key: ${ANTHROPIC_API_KEY}
chat:
options:
model: claude-sonnet-4-5
Run with: mvn spring-boot:run
3. Creating Custom Tools
Tools are the primary way to give the LLM executable capabilities. Implement io.jaiclaw.core.tool.ToolCallback:
package com.example.tools;
import io.jaiclaw.core.tool.ToolCallback;
import io.jaiclaw.core.tool.ToolContext;
import io.jaiclaw.core.tool.ToolDefinition;
import io.jaiclaw.core.tool.ToolResult;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class SearchFaqTool implements ToolCallback {
@Override
public ToolDefinition definition() {
return new ToolDefinition(
"search_faq",
"Search the FAQ knowledge base",
"helpdesk",
"""
{
"type": "object",
"properties": {
"question": { "type": "string", "description": "The user's question" },
"category": { "type": "string", "description": "FAQ category" }
},
"required": ["question"]
}
"""
);
}
@Override
public ToolResult execute(Map<String, Object> parameters, ToolContext context) {
String question = (String) parameters.get("question");
String category = (String) parameters.getOrDefault("category", );
queryFaqDatabase(question, category);
.Success(result);
}
}
Core Tool Types
| Type | Class | Purpose |
|---|
ToolCallback | Interface | SPI — implement definition() and execute() |
ToolDefinition | Record | Name, description, section, JSON Schema, profiles |
ToolResult | Sealed interface | Success(content) or Error(message) |
ToolContext | Record | Runtime context: agentId, sessionKey, sessionId, workspaceDir |
ToolProfile | Enum | MINIMAL, CODING, MESSAGING, FULL |
Tool Profiles
Control tool visibility per agent:
import io.jaiclaw.core.tool.ToolProfile;
import java.util.Set;
new ToolDefinition("file_edit", "Edit a file", "files", schema,
Set.of(ToolProfile.CODING, ToolProfile.FULL));
new ToolDefinition("danger_tool", "Risky operation", "admin", schema);
Registration
Tools annotated with @Component are auto-discovered by Spring. They are automatically registered in the ToolRegistry and bridged to Spring AI via SpringAiToolBridge.
4. Creating Plugins
Plugins bundle multiple tools and can hook into lifecycle events:
package com.example.plugins;
import io.jaiclaw.core.plugin.PluginDefinition;
import io.jaiclaw.core.plugin.PluginKind;
import io.jaiclaw.plugin.JaiClawPlugin;
import io.jaiclaw.plugin.PluginApi;
import org.springframework.stereotype.Component;
@Component
public class CodeReviewPlugin implements JaiClawPlugin {
@Override
public PluginDefinition definition() {
return new PluginDefinition(
"code-review",
"Code Review Plugin",
"PR diff and review",
"1.0.0",
PluginKind.GENERAL
);
}
@Override
public void register(PluginApi api) {
api.registerTool(new GetDiffTool());
api.registerTool(new PostCommentTool());
}
}
Plugin discovery works via:
- Spring
@Component scanning (recommended)
ServiceLoader (META-INF/services/io.jaiclaw.plugin.JaiClawPlugin)
- Explicit
PluginRegistry.register() calls
5. Creating Skills
Skills are markdown files with YAML frontmatter that provide behavioral guidance to the LLM.
Skill File Format
Create SKILL.md in a named directory:
my-app/
└── .jaiclaw/skills/
└── my-domain/
└── SKILL.md
---
name: my-domain-skill
description: Domain expertise for X
alwaysInclude: false
requiredBins: [git]
platforms: [darwin, linux, windows]
version: 1.0.0
tenantIds: []
---
# My Domain Skill
Instructions for the LLM about how to handle domain-specific tasks...
## Tool Usage
- Use **my_tool** for...
- Use **other_tool** when...
Frontmatter Fields
| Field | Type | Default | Purpose |
|---|
name | string | derived from directory name | Skill identifier |
description | string | "" | One-line description |
alwaysInclude | boolean | false | Include in every system prompt |
requiredBins | string[] | [] | Required CLI tools (checked via which) |
platforms | string[] | [] | Supported OSes: darwin, linux, windows |
version | string | "1.0.0" | Semantic version |
tenantIds | string[] | [] | Empty = all tenants; populated = restrict to listed tenants |
Loading
- Bundled skills: Place in
src/main/resources/skills/{name}/SKILL.md — loaded from classpath
- Workspace skills: Place in
.jaiclaw/skills/{name}/SKILL.md — loaded from configured jaiclaw.skills.workspace-dir
- Eligibility: Skills are filtered at load time by platform and binary availability
6. Channel Adapters
JaiClaw supports 5 messaging channels out of the box:
| Channel | Module | Inbound | Outbound |
|---|
| Telegram | jaiclaw-channel-telegram | Bot API polling + webhook | Bot API sendMessage |
| Slack | jaiclaw-channel-slack | Socket Mode + Events API | Web API |
| Discord | jaiclaw-channel-discord | Gateway WebSocket + Interactions | REST API |
| Email | jaiclaw-channel-email | IMAP polling | SMTP |
| SMS | jaiclaw-channel-sms | Twilio webhook | Twilio REST API |
Channel Configuration
jaiclaw:
channels:
telegram:
enabled: true
bot-token: ${TELEGRAM_BOT_TOKEN}
slack:
enabled: true
bot-token: ${SLACK_BOT_TOKEN}
app-token: ${SLACK_APP_TOKEN}
discord:
enabled: true
bot-token: ${DISCORD_BOT_TOKEN}
email:
enabled: true
imap-host: imap.gmail.com
smtp-host: smtp.gmail.com
username: ${EMAIL_USERNAME}
password: ${EMAIL_PASSWORD}
sms:
enabled: true
account-sid: ${TWILIO_ACCOUNT_SID}
auth-token: ${TWILIO_AUTH_TOKEN}
from-number: ${TWILIO_FROM_NUMBER}
Custom Channel Adapter
Implement io.jaiclaw.channel.ChannelAdapter:
public interface ChannelAdapter {
String channelId();
String displayName();
void start(ChannelMessageHandler handler);
DeliveryResult sendMessage(ChannelMessage message);
default void stop() {}
default boolean supportsStreaming() { return false; }
}
7. Configuration Reference
jaiclaw:
identity:
name: "Assistant Name"
description: "What this assistant does"
agent:
default-agent: default
agents:
default:
id: default
name: Agent Name
tools:
profile: full
skills:
allow-bundled: ["*"]
workspace-dir: null
security:
mode: api-key
api-key: ${JAICLAW_API_KEY:}
jwt:
secret: ${JWT_SECRET:}
mcp-servers:
server-name:
description: "Server description"
type: http
url: "http://localhost:8090/mcp/server-name"
enabled: true
channels:
8. Starters & Dependencies
Use the appropriate starter for your deployment:
| Starter | Use Case | Includes |
|---|
jaiclaw-starter-anthropic | Anthropic Claude apps | starter + anthropic AI provider |
jaiclaw-starter-openai | OpenAI apps | starter + openai AI provider |
jaiclaw-starter-ollama | Local LLM apps | starter + ollama AI provider |
jaiclaw-starter-gateway | Full gateway with all channels | starter + gateway + all 5 channel adapters |
jaiclaw-starter-shell | CLI app | starter + Spring Shell |
jaiclaw-starter-embabel | Embabel agent integration | starter + embabel agent |
jaiclaw-starter-personal-assistant | Personal assistant preset | starter + common features |
jaiclaw-starter-k8s-monitor | K8s monitoring preset | starter + k8s tools |
When building inside the JaiClaw mono-repo, use <parent>jaiclaw-parent</parent> and omit versions (managed by parent BOM).
9. Multi-Tenancy
JaiClaw supports per-tenant isolation:
- TenantContext: ThreadLocal via
TenantContextHolder, carries tenantId + metadata
- JWT auth:
JwtTenantResolver extracts tenant from JWT claims
- API key auth:
BotTokenTenantResolver maps tokens to tenants
- Session isolation: Session keys include tenant context
- Skill scoping: Skills can be restricted to specific tenants via
tenantIds in metadata
- Tool context:
ToolContext.contextData carries tenant info to tools
10. MCP Server Hosting
JaiClaw can host MCP (Model Context Protocol) servers, exposing tools to external clients:
McpToolProvider SPI
public interface McpToolProvider {
String serverName();
List<McpToolDefinition> tools();
McpToolResult executeTool(String toolName, Map<String, Object> args);
}
MCP Transport Types
| Type | Config key | Use case |
|---|
| HTTP | type: http | Streamable HTTP with JSON-RPC 2.0 |
| stdio | type: stdio | Subprocess communication |
| SSE | type: sse | Server-Sent Events |
REST Endpoints
GET /mcp — List all MCP servers
GET /mcp/{serverName}/tools — List tools for a server
POST /mcp/{serverName}/tools/{toolName} — Execute a tool
11. Cron Jobs
Schedule recurring agent tasks:
import io.jaiclaw.core.model.CronJob;
import io.jaiclaw.cron.CronService;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyCronConfig {
@Bean
ApplicationRunner registerJobs(CronService cronService) {
return args -> {
CronJob job = new CronJob(
"daily-report",
"Daily Sales Report",
"default",
"0 9 * * MON-FRI",
"America/New_York",
"Generate a sales report with key metrics",
"telegram",
null,
true,
null,
null
);
cronService.addJob(job);
};
}
}
12. Testing
JaiClaw uses Spock Framework (Groovy) for all tests:
- Test files:
src/test/groovy/ with *Spec.groovy naming
- Dependencies needed:
groovy, spock-core (test scope)
- For mocking concrete classes: add
byte-buddy + objenesis (test scope)
- Build plugin:
gmavenplus-plugin for Groovy compilation
mvn test
mvn test -Dtest=MyToolSpec
mvn test -o
Example Spec
package com.example
import io.jaiclaw.core.tool.ToolContext
import io.jaiclaw.core.tool.ToolResult
import spock.lang.Specification
class SearchFaqToolSpec extends Specification {
def tool = new SearchFaqTool()
def "returns FAQ results for valid question"() {
given:
def params = [question: "How do I reset my password?"]
def context = new ToolContext("default", "default:web:user1:peer1", "sess-1", "/tmp")
when:
def result = tool.execute(params, context)
then:
result instanceof ToolResult.Success
((ToolResult.Success) result).content().contains("password")
}
}
13. MCP Resource References
The following resource URIs are designed for a future JaiClaw MCP resource server. When available, an LLM can fetch detailed documentation on demand:
| Resource URI | Description |
|---|
jaiclaw://docs/architecture | Full architecture diagram with all layers |
jaiclaw://docs/modules | Complete module dependency graph (40 modules) |
jaiclaw://docs/auto-config | Auto-configuration ordering and bean wiring details |
jaiclaw://examples/tool | Complete custom tool implementation with tests |
jaiclaw://examples/plugin | Complete plugin implementation with tool registration |
jaiclaw://examples/skill | Skill file template with all frontmatter fields |
jaiclaw://examples/channel | Custom channel adapter implementation |
jaiclaw://examples/cron | Cron job scheduling example |
jaiclaw://examples/app-scaffold | Full app scaffold: pom.xml + Application + application.yml |
jaiclaw://examples/helpdesk-bot | Multi-tenant helpdesk bot (FAQ + tickets) |
jaiclaw://examples/code-review-bot | Code review plugin with diff analysis |
jaiclaw://examples/daily-briefing | Cron-scheduled daily briefing with weather + news |
jaiclaw://schema/application-yml | Full configuration schema reference |
jaiclaw://schema/tool-definition | ToolDefinition JSON Schema specification |
jaiclaw://schema/skill-frontmatter | Skill YAML frontmatter specification |
When the MCP resource server is not available, use the inline examples in this skill as your reference.