Skip to main content

SkillsLoader

The SkillsLoader class manages agent skills - markdown files (SKILL.md) that teach the agent how to use specific tools or perform certain tasks. Skills provide a flexible way to extend agent capabilities without modifying core code.

Constructor

SkillsLoader(
    workspace: Path,
    builtin_skills_dir: Path | None = None
)
workspace
Path
required
The workspace directory containing user skills
builtin_skills_dir
Path | None
default:"None"
Directory containing built-in skills. Defaults to nanobot’s bundled skills
Skill search order:
  1. Workspace skills: {workspace}/skills/{skill-name}/SKILL.md
  2. Built-in skills: {builtin_skills_dir}/{skill-name}/SKILL.md
Workspace skills override built-in skills with the same name. Example:
from nanobot.agent.skills import SkillsLoader
from pathlib import Path

workspace = Path("/home/user/workspace")
skills = SkillsLoader(workspace)

Methods

list_skills

def list_skills(filter_unavailable: bool = True) -> list[dict[str, str]]
List all available skills.
filter_unavailable
bool
default:"True"
If True, filter out skills with unmet requirements (missing binaries or env vars)
skills
list[dict]
List of skill info dicts with keys: name, path, source (“workspace” or “builtin”)
Example:
skills = SkillsLoader(workspace)

# List only available skills
available = skills.list_skills(filter_unavailable=True)
for skill in available:
    print(f"{skill['name']}: {skill['path']}")

# List all skills including unavailable
all_skills = skills.list_skills(filter_unavailable=False)

load_skill

def load_skill(name: str) -> str | None
Load a skill’s content by name.
name
str
required
Skill name (directory name)
content
str | None
Skill content (SKILL.md file), or None if not found
Example:
skills = SkillsLoader(workspace)

# Load a specific skill
content = skills.load_skill("python-debug")
if content:
    print(f"Loaded {len(content)} characters")
else:
    print("Skill not found")

load_skills_for_context

def load_skills_for_context(skill_names: list[str]) -> str
Load multiple skills formatted for inclusion in agent context.
skill_names
list[str]
required
List of skill names to load
formatted
str
Formatted skills content with headers and separators, or empty string if no skills found
Format:
### Skill: python-debug

(skill content with frontmatter stripped)

---

### Skill: docker-compose

(skill content with frontmatter stripped)
Example:
skills = SkillsLoader(workspace)

# Load specific skills for a task
context = skills.load_skills_for_context(["python-debug", "pytest"])

# Add to system prompt
system_prompt = f"""
You are nanobot...

# Active Skills
{context}
"""

build_skills_summary

def build_skills_summary() -> str
Build an XML-formatted summary of all skills for progressive loading.
summary
str
XML summary of all skills with names, descriptions, paths, and availability
Output format:
<skills>
  <skill available="true">
    <name>python-debug</name>
    <description>Debug Python applications using pdb and breakpoint()</description>
    <location>/workspace/skills/python-debug/SKILL.md</location>
  </skill>
  <skill available="false">
    <name>docker-compose</name>
    <description>Work with Docker Compose multi-container apps</description>
    <location>/workspace/skills/docker-compose/SKILL.md</location>
    <requires>CLI: docker-compose</requires>
  </skill>
</skills>
Example:
skills = SkillsLoader(workspace)
summary = skills.build_skills_summary()

# Used by ContextBuilder
system_prompt = f"""
You are nanobot...

# Skills

The following skills extend your capabilities. To use a skill, read its SKILL.md
file using the read_file tool. Skills with available="false" need dependencies
installed first.

{summary}
"""

get_always_skills

def get_always_skills() -> list[str]
Get skill names that should always be loaded in context.
names
list[str]
List of skill names marked with always: true in their metadata
Example:
skills = SkillsLoader(workspace)

# Get skills to always include
always = skills.get_always_skills()
print(f"Always-on skills: {', '.join(always)}")

# Load them
if always:
    content = skills.load_skills_for_context(always)

get_skill_metadata

def get_skill_metadata(name: str) -> dict | None
Get metadata from a skill’s YAML frontmatter.
name
str
required
Skill name
metadata
dict | None
Metadata dict parsed from frontmatter, or None if not found
Example:
skills = SkillsLoader(workspace)

meta = skills.get_skill_metadata("python-debug")
if meta:
    print(f"Description: {meta.get('description')}")
    print(f"Always load: {meta.get('always')}")

Skill File Format

Skills are markdown files with optional YAML frontmatter:
---
description: Debug Python applications using pdb
always: false
metadata: |
  {
    "nanobot": {
      "requires": {
        "bins": ["python"],
        "env": []
      },
      "always": false
    }
  }
---

# Python Debugging

This skill teaches you how to debug Python applications.

## Using pdb

Add a breakpoint:

```python
import pdb; pdb.set_trace()

Using breakpoint()

Python 3.7+ built-in:
breakpoint()  # Drops into debugger

## Metadata Fields

<ParamField path="description" type="string">
  Short description of what the skill does
</ParamField>

<ParamField path="always" type="boolean">
  If true, skill is always loaded in context
</ParamField>

<ParamField path="metadata" type="JSON string">
  Extended metadata in JSON format with `nanobot` or `openclaw` key
</ParamField>

### Extended Metadata Format

```json
{
  "nanobot": {
    "requires": {
      "bins": ["docker", "docker-compose"],
      "env": ["DOCKER_HOST"]
    },
    "always": false
  }
}
requires.bins
array
List of required CLI binaries (checked with which)
requires.env
array
List of required environment variables
always
boolean
If true, skill is always loaded in context (overrides frontmatter always)

Progressive Loading

The skills system uses progressive loading to optimize context usage:
  1. Always-on skills: Loaded in every request (marked with always: true)
  2. Skills summary: XML list of all skills in system prompt
  3. On-demand loading: Agent uses read_file tool to load skills when needed
Example system prompt:
# Active Skills

### Skill: core-guidelines
(Core guidelines always loaded)

---

# Skills

The following skills extend your capabilities. To use a skill, read its
SKILL.md file using the read_file tool.

<skills>
  <skill available="true">
    <name>python-debug</name>
    <description>Debug Python applications</description>
    <location>/workspace/skills/python-debug/SKILL.md</location>
  </skill>
  ...
</skills>
Agent can then:
I'll help you debug that Python error. Let me first load the python-debug skill.

[calls read_file("/workspace/skills/python-debug/SKILL.md")]

Now I'll add a breakpoint...

Requirements Checking

Skills can specify requirements:
{
  "nanobot": {
    "requires": {
      "bins": ["docker", "kubectl"],
      "env": ["KUBECONFIG"]
    }
  }
}
Skills with unmet requirements:
  • Show available="false" in summary
  • Include <requires> tag explaining what’s missing
  • Can still be listed but agent knows they may not work
Example unavailable skill:
<skill available="false">
  <name>kubernetes</name>
  <description>Deploy and manage Kubernetes apps</description>
  <location>/skills/kubernetes/SKILL.md</location>
  <requires>CLI: kubectl, ENV: KUBECONFIG</requires>
</skill>

Creating Custom Skills

  1. Create directory: {workspace}/skills/my-skill/
  2. Create file: my-skill/SKILL.md
  3. Add frontmatter and content:
---
description: My custom skill
always: false
---

# My Skill

This skill teaches the agent...

## Usage

...
  1. Skill is automatically available in next session

Built-in Skills

Nanobot includes several built-in skills:
  • Core guidelines and best practices
  • Programming language support
  • Development tools (git, docker, etc.)
  • Testing frameworks
  • And more…
Run skills.list_skills() to see all available skills.

Architecture Notes

  • Skills are stateless - pure markdown content
  • No code execution - skills are instructions for the LLM
  • Workspace skills override built-in skills
  • Skills can include code examples, tips, and workflows
  • Skills are cached by the context builder for efficiency

Build docs developers (and LLMs) love