Skip to content

How to Add Runtime-Extensible Skills to Your AI Agent Without Code Changes

Purpose

I wanted to add new capabilities to my AI agent without touching the codebase. Every time I needed a new skill, I had to modify source code, rebuild, and redeploy. This was slow and error-prone.

This post shows how to solve this problem with the SKILL.md pattern. The key is treating skills as discoverable Markdown files that your agent loads at runtime.

The Problem I Faced

My AI agent had hardcoded tools. When I wanted to add a new capability, I followed this tedious process:

┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Write new │───▶│ Modify │───▶│ Rebuild │───▶│ Redeploy │
│ code │ │ source │ │ project │ │ agent │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘

This workflow had several problems:

  • Slow iteration: Adding a skill took 10-15 minutes minimum
  • Technical barrier: Non-developers couldn’t add skills
  • Deployment risk: Each change risked breaking existing functionality
  • Scattered definitions: Skills were spread across the codebase

I needed a better approach. One where adding a skill was as simple as dropping a file into a folder.

My First Attempt: Plugin Architecture

I initially tried a plugin architecture with compiled JAR files. It worked, but it had issues:

Plugin problems I encountered
1. Users needed Java development environment
2. Each plugin required compilation
3. Plugin version conflicts were common
4. Debugging was difficult

Then I discovered a simpler approach from the JavaClaw project: filesystem-based skill discovery using Markdown files.

The SKILL.md Pattern

The solution is deceptively simple. Instead of compiling skills into code, define them as Markdown files that the agent discovers at runtime.

How It Works

workspace/
└── skills/
├── web-search/
│ └── SKILL.md # Web search skill definition
├── email-sender/
│ └── SKILL.md # Email sending capability
└── data-analyzer/
└── SKILL.md # Data analysis skill

The agent scans this directory at startup and loads each SKILL.md file. When I drop a new skill into the folder, the agent picks it up automatically.

A Simple SKILL.md Example

Here’s what a basic skill definition looks like:

workspace/skills/web-search/SKILL.md
# Web Search Skill
## Purpose
Search the web for information using Brave Search API.
## When to Use
- User asks about current events
- User needs real-time information
- User wants to research a topic
## How It Works
1. Receive search query from user
2. Call Brave Search API
3. Summarize results for user
4. Return relevant information
## Required Configuration
- BRAVE_API_KEY in environment variables
## Examples
- "What's the weather in Tokyo?"
- "Search for latest Spring Boot features"
- "Find documentation for React hooks"

That’s it. No compilation, no deployment, just a Markdown file.

How I Implemented It

In JavaClaw, the SkillsTool scans the skills directory and loads each SKILL.md:

SkillsTool.java
@Component
public class SkillsTool {
@Value("${agent.workspace}")
private String workspacePath;
public List<Skill> loadSkills() {
Path skillsDir = Path.of(workspacePath, "skills");
if (!Files.exists(skillsDir)) {
return List.of();
}
try {
return Files.list(skillsDir)
.filter(Files::isDirectory)
.map(dir -> dir.resolve("SKILL.md"))
.filter(Files::exists)
.map(this::parseSkill)
.toList();
} catch (IOException e) {
log.error("Failed to load skills", e);
return List.of();
}
}
private Skill parseSkill(Path skillFile) {
String content = Files.readString(skillFile);
return SkillParser.fromMarkdown(content);
}
}

The key insight is that skills become data, not code. The agent reads them like configuration files.

What Changed in My Workflow

Before the SKILL.md pattern:

Old workflow
# Adding a new skill required:
1. Create Java class for the skill
2. Register skill in configuration
3. Rebuild project with Maven
4. Deploy new JAR to server
5. Restart agent process
# Total time: 15-30 minutes

After the SKILL.md pattern:

New workflow
# Adding a new skill requires:
1. Create directory: workspace/skills/new-skill/
2. Write SKILL.md file
3. Agent picks it up automatically
# Total time: 1-2 minutes

The difference is dramatic. I can now iterate on skills rapidly without touching code.

Mistakes I Made Along the Way

Mistake 1: Over-Engineering the Schema

Initially, I tried to define a complex JSON schema for skills:

Over-engineered skill schema (DON'T DO THIS)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"metadata": {
"type": "object",
"properties": {
"name": { "type": "string" },
"version": { "type": "string" },
"author": { "type": "string" }
}
},
"capabilities": {
"type": "array",
"items": {
"type": "object",
"properties": {
"action": { "type": "string" },
"parameters": { "type": "object" }
}
}
}
}
}

This was a mistake. The schema became so complex that nobody wanted to write skills. Keep it simple with Markdown sections.

Mistake 2: Requiring Agent Restart

At first, I only loaded skills at startup. This meant I still had to restart the agent for new skills. I fixed this by implementing a file watcher:

SkillWatcher.java
@Component
public class SkillWatcher {
private WatchService watchService;
public void startWatching(Path skillsDir) {
watchService = FileSystems.getDefault().newWatchService();
skillsDir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
while (true) {
WatchKey key = watchService.take();
for (WatchEvent<?> event : key.pollEvents()) {
if (event.context().toString().equals("SKILL.md")) {
reloadSkills();
}
}
key.reset();
}
}
}

Now the agent detects new skills without restart.

Mistake 3: Storing Skills in a Database

I briefly tried storing skills in PostgreSQL for “better management.” This was wrong because:

  • Skills became hard to version control
  • I couldn’t easily see skill differences
  • Sharing skills between environments required database dumps

The filesystem is the right place for skills. They become version-controllable alongside your project code.

Benefits I’ve Seen

After implementing the SKILL.md pattern, I noticed several improvements:

AspectBeforeAfter
Time to add skill15-30 minutes1-2 minutes
Non-technical usersCannot add skillsCan write Markdown
Skill visibilityHidden in codeHuman-readable files
Version controlTied to code releasesIndependent versioning
Skill sharingCopy codeCopy directory

When This Pattern Works Best

The SKILL.md pattern is ideal when:

  • You frequently add new capabilities
  • Non-developers need to extend the agent
  • You want skills versioned with project code
  • You need to share skills between projects

It may not be the best fit when:

  • Skills require complex compiled logic
  • You need strong typing and validation
  • Performance of skill loading is critical

Summary

I solved the problem of adding skills to my AI agent by implementing the SKILL.md pattern. Instead of modifying code, I drop Markdown files into a watched directory. The agent discovers and loads them at runtime.

The key changes I made:

  1. Created a workspace/skills/ directory for skill definitions
  2. Wrote SKILL.md files in human-readable Markdown format
  3. Implemented a SkillsTool that scans and parses the directory
  4. Added a file watcher for automatic skill discovery

This approach reduced skill addition time from 15-30 minutes to 1-2 minutes. Non-developers can now extend the agent by writing Markdown. Skills travel with the workspace and stay version-controlled.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments