Skip to main content
NanoClaw has four categories of skills, each with a different structure. Feature skills are distributed as git branches containing all code changes. Utility skills ship code files alongside their SKILL.md. Operational skills live on main as instruction files. Container skills are synced into every container for use by the running agent.

Four types of skills

Operational skills

Operational skills live in .claude/skills/ on main. They contain only a SKILL.md file with instructions for Claude Code — no code changes.
.claude/skills
setup
SKILL.md
debug
SKILL.md
customize
SKILL.md
update-nanoclaw
SKILL.md
update-skills
SKILL.md
These skills are always available in your NanoClaw installation. They guide Claude Code through multi-step workflows like setup, debugging, and updates.

SKILL.md format

---
name: setup
description: Run initial NanoClaw setup. Use when user wants to install dependencies, authenticate messaging channels, register their main channel, or start the background services.
---

# NanoClaw Setup

**Principle:** When something is broken or missing, fix it. Don't tell the user to go fix it themselves unless it genuinely requires their manual action.

## 1. Bootstrap (Node.js + Dependencies)

Run `bash setup.sh` and parse the status block.
...
Frontmatter fields:
  • name (required) — the skill command name (e.g., setup, debug)
  • description (required) — when Claude Code should invoke this skill

Utility skills

Utility skills are standalone tools that ship code files alongside the SKILL.md. The SKILL.md tells Claude how to install the tool; the code lives in the skill directory itself (e.g., in a scripts/ subfolder).
.claude/skills
claw
SKILL.md
scripts
claw
Unlike feature skills, utility skills require no branch merge. The code is self-contained in the skill directory and gets copied into place during installation. Use ${CLAUDE_SKILL_DIR} in the SKILL.md to reference files in the skill directory.

Feature skills

Feature skills are distributed as skill/* branches on the upstream repository. Each branch contains all the code changes for that integration: new files, modified source files, updated package.json dependencies, .env.example additions — everything.
skill/telegram branch
src/channels/telegram.ts
src/channels/telegram.test.ts
src/index.ts
src/config.ts
package.json
.env.example
Feature skills also have a SKILL.md in the marketplace repo (qwibitai/nanoclaw-skills) that provides setup instructions. When you run /add-telegram, Claude reads the SKILL.md and merges the skill branch.

Container skills

Container skills live in container/skills/ and are synced into every container’s .claude/skills/ directory. These run inside the agent container, not on the host. They teach the container agent how to use tools, format output, or perform tasks.
container/skills
agent-browser
SKILL.md
capabilities
SKILL.md
slack-formatting
SKILL.md
status
SKILL.md
Container skills use the same SKILL.md frontmatter format as operational skills. Some are restricted to the main channel by checking for the /workspace/project mount (only present for main groups).
SkillDescriptionAccess
/agent-browserBrowse the web, fill forms, extract dataAll groups
/capabilitiesReport installed skills, tools, MCP tools, container utilities, and group infoMain channel only
/slack-formattingSlack mrkdwn syntax reference for formatting messages in Slack channelsAll groups
/statusSession context, workspace mounts, tool availability, and scheduled task snapshotMain channel only

What’s in a skill branch

A feature skill branch is branched from main and contains commits that add the integration. The branch includes:
  • New files — channel implementations, tests, setup guides
  • Modified source files — changes to src/index.ts, src/config.ts, routing, etc.
  • Updated package.json — new npm dependencies
  • Updated .env.example — new environment variables
  • Updated tests — new test cases for the integration
Since the branch contains real code changes (not templates or instructions), you can inspect exactly what a skill does before applying it:
git diff main...upstream/skill/telegram

How skills compose

When you apply multiple feature skills, git merge handles composition:
git merge upstream/skill/discord
git merge upstream/skill/telegram
If both skills modify the same file (e.g., src/index.ts to add their channel), git merges the changes automatically. If they modify the same lines, it’s a real merge conflict — Claude resolves it. This is standard git behavior. No custom merge machinery is needed.

Skill dependencies

Some skills depend on others. For example, skill/telegram-swarm requires skill/telegram. Dependent skill branches are branched from their parent, not from main. This means skill/telegram-swarm includes all of Telegram’s changes plus its own additions. When you merge skill/telegram-swarm, you get both — no need to merge Telegram separately. Dependencies are implicit in git history — no separate dependency file is needed.

State tracking

Applied skills are tracked through git history. When you merge a skill branch, the merge commit records what was applied and when.
# See which skills were merged
git log --merges --oneline | grep skill/
This provides:
  • Idempotency — git won’t re-merge changes that are already in your history
  • Audit trail — every skill application is a merge commit with a timestamp
  • Easy reversal — revert the merge commit to remove a skill
No separate state files are needed.

Testing skills

Tests live alongside the code in the skill branch. When a skill is applied, its tests are part of your codebase.

Unit tests

Test the new code added by the skill:
// src/channels/telegram.test.ts
import { describe, it, expect } from 'vitest';
import { TelegramChannel } from './telegram.js';

describe('TelegramChannel', () => {
  it('should format JIDs correctly', () => {
    const channel = new TelegramChannel('token', /* ... */);
    expect(channel.ownsJid('tg:123456')).toBe(true);
    expect(channel.ownsJid('wa:123456')).toBe(false);
  });
});

Integration tests

Test that the skill integrates correctly with existing code:
// src/routing.test.ts (additions from skill branch)
describe('Telegram routing', () => {
  it('should route tg: JIDs to TelegramChannel', () => {
    const channel = findChannel(channels, 'tg:123456');
    expect(channel?.name).toBe('telegram');
  });
});

Validation

After applying a skill, always run the full test suite:
npm test
npm run build
All tests must pass before proceeding to setup.

Next steps

Last modified on March 23, 2026