Add a Skill

Corresponding source

Extension stepSource
Skill discovery and loadingnanobot/agent/skills.py::SkillsLoader
Writing Skills into model contextnanobot/agent/context.py::ContextBuilder.build_system_prompt
Skill file contractnanobot/skills/*/SKILL.md, nanobot/skills/README.md
Skill commands and Tool discoverynanobot/command/builtin.py, nanobot/agent/tools/search.py
Verificationtests/agent/test_skills_loader.py, tests/command/test_skill_command.py

Learning objectives

After this lesson, you should be able to:

  • explain the permission boundary between a Skill and a Tool;
  • create a directory discoverable by SkillsLoader;
  • understand workspace override, requirements, always, and progressive loading;
  • verify behavior rather than checking only that Markdown exists.

Prerequisites

  • Know that a system prompt influences model decisions but grants no new execution permission.
  • Understand ContextBuilder composition.
  • Write explicit steps, stop conditions, and verification criteria.

1. A Skill is loadable operational guidance

Its core file is:

<workspace>/skills/<skill-name>/SKILL.md

A built-in Skill lives at:

nanobot/skills/<skill-name>/SKILL.md

It teaches the Agent how to combine existing Tools, when to ask the user, and how to verify a result. It does not execute Python and cannot bypass Tool security boundaries.

2. Discovery and override

SkillsLoader.list_skills():

  1. scans workspace Skills;
  2. scans built-in Skills;
  3. lets a same-named workspace Skill replace the built-in Skill;
  4. removes names in disabledSkills;
  5. filters Skills whose requirements are unmet by default.

The runtime identity of a Skill comes from its directory name. Frontmatter name is useful for description and compatibility, but the current loader locates <directory-name>/SKILL.md.

flowchart TD
    A["workspace/skills"] --> C["Merge by directory name"]
    B["nanobot/skills"] --> C
    C --> D["Workspace name wins"]
    D --> E["Filter disabledSkills"]
    E --> F["Filter requirements"]
    F --> G["ContextBuilder"]

3. Minimal frontmatter

---
name: explain-session
description: Guide the agent to inspect and explain one nanobot Session safely.
metadata:
  nanobot:
    requires:
      bins:
        - rg
      env: []
---

The body should state at least:

  • when to use it;
  • required inputs;
  • procedure order;
  • which steps are read-only;
  • when user input is mandatory;
  • completion criteria;
  • how failure converges.

4. Current requirements boundary

SkillsLoader._check_requirements() currently checks:

  • requires.bins with shutil.which();
  • requires.env for environment-variable presence.

Built-in Skill metadata may contain fields such as os, but the current _check_requirements() does not prove OS filtering. A claim about OS gating requires implementation and tests, not only frontmatter.

get_skill_requirements() returns:

  • bins/env;
  • missing_bins/missing_env.

5. always and progressive loading

ContextBuilder handles two groups:

Always-on Skill

When top-level always: true or metadata.nanobot.always is true and requirements pass, get_always_skills() places the full body directly in the system prompt.

Ordinary Skill

build_skills_summary() includes only:

  • name;
  • description;
  • path;
  • availability.

The Agent reads the complete SKILL.md through filesystem capability when needed. This is progressive loading.

always consumes context on every Turn

Reserve it for short rules that must apply every time. Domain workflows, rare platform operations, and long tutorials should load on demand.

6. Writing structure

An Agent-facing Skill is usually more explicit than a long human tutorial:

# Skill name
 
## Use when
 
## Do not use when
 
## Inputs
 
## Procedure
 
## Safety boundaries
 
## Verification
 
## Failure handling

Important principles:

  • make steps observable; do not say only “handle appropriately”;
  • mark read-only and mutating work;
  • identify actions requiring approval;
  • never encourage bypassing a Tool error;
  • use placeholders, never real credentials;
  • specify result verification, not only execution.

7. When to include a script

A Skill directory can contain scripts/, references/, and related resources. A script is appropriate when:

  • a mechanical operation is complex and easy to mistype;
  • repeated execution should remain consistent;
  • a small, testable helper can express it.

The existing Tools still execute the script, so workspace, Shell, permissions, and dependency constraints remain. A Skill does not make bundled code trusted.

8. Verify a Skill

Structural verification

  • SKILL.md is readable;
  • YAML parses;
  • description is nonempty and distinguishes the trigger;
  • unmet requirements report unavailable correctly;
  • a same-named workspace Skill overrides as expected.

Behavioral verification

Use a fixed task and observe:

  1. whether the Skill appears in the system-prompt summary;
  2. whether the model reads the full Skill in an applicable case;
  3. whether it uses the correct Tools in the stated order;
  4. whether it pauses before a write to ask;
  5. whether it verifies the result;
  6. whether it stays inactive in an inapplicable case.

Model behavior is stochastic. Separate deterministic loader/context tests from a real-model smoke test.

9. Source and tests

Source:

  • nanobot/agent/skills.py::SkillsLoader
  • nanobot/agent/context.py::ContextBuilder.build_system_prompt
  • nanobot/skills/README.md
  • nanobot/skills/*/SKILL.md

Tests:

  • tests/agent/test_skills_loader.py
  • tests/command/test_skill_command.py
  • disabled-Skill cases in tests/tools/test_search_tools.py

10. Minimum modification scope

A workspace Skill normally needs only:

workspace/
└── skills/
    └── <name>/
        └── SKILL.md

Only a Skill shipped with nanobot belongs under nanobot/skills, with wheel includes, built-in documentation, and adjacent tests checked.

Self-check

  1. Why can a Skill not grant new filesystem-read permission?
  2. Which wins when workspace and built-in Skills share a name?
  3. Does the current loader enforce metadata.os?
  4. Which kind of Skill should not use always: true?

Next: Integrate MCP