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:
1. Users needed Java development environment2. Each plugin required compilation3. Plugin version conflicts were common4. Debugging was difficultThen 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 skillThe 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:
# Web Search Skill
## PurposeSearch 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 Works1. Receive search query from user2. Call Brave Search API3. Summarize results for user4. 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:
@Componentpublic 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:
# Adding a new skill required:1. Create Java class for the skill2. Register skill in configuration3. Rebuild project with Maven4. Deploy new JAR to server5. Restart agent process
# Total time: 15-30 minutesAfter the SKILL.md pattern:
# Adding a new skill requires:1. Create directory: workspace/skills/new-skill/2. Write SKILL.md file3. Agent picks it up automatically
# Total time: 1-2 minutesThe 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:
{ "$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:
@Componentpublic 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:
| Aspect | Before | After |
|---|---|---|
| Time to add skill | 15-30 minutes | 1-2 minutes |
| Non-technical users | Cannot add skills | Can write Markdown |
| Skill visibility | Hidden in code | Human-readable files |
| Version control | Tied to code releases | Independent versioning |
| Skill sharing | Copy code | Copy 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:
- Created a
workspace/skills/directory for skill definitions - Wrote SKILL.md files in human-readable Markdown format
- Implemented a SkillsTool that scans and parses the directory
- 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