Tutorial

Custom Skills für OpenClaw bauen: eigene KI-Fähigkeiten programmieren

GWGorden Wuebbe·

Direkte Antwort: Ein OpenClaw-Skill besteht aus einer Skill.md-Datei (Beschreibung und Trigger) plus optionalen Tools (TypeScript-Funktionen mit JSON-Schema). Du erstellst einen Ordner unter skills/, schreibst die Markdown-Datei mit klaren Triggern, definierst Tool-Schemas und implementierst die Logik. OpenClaw lädt den Skill automatisch und Claude entscheidet selbst, wann er aktiv wird.

OpenClaw ist nur halb so mächtig ohne eigene Skills. Die Out-of-the-box-Antworten von Claude sind beeindruckend, aber das Magische passiert erst, wenn dein Bot deine Notion-DB aktualisieren, deine MOCO-Rechnungen ziehen oder deinen Wetter-Service abfragen kann. Und das Beste: Skills bauen ist deutlich einfacher als das ganze Plugin-Ökosystem von OpenAI oder die Tool-Choreographie von LangChain. Wenn du einmal verstanden hast, wie ein Skill aufgebaut ist, kannst du in 30-60 Minuten einen neuen schreiben.

In diesem Tutorial bauen wir einen vollständigen Notion-Skill, der Claude beibringt, neue Tasks in einer Notion-DB anzulegen. Du lernst dabei alles, was du brauchst, um danach eigene Skills zu schreiben: Skill-Anatomie, Trigger-Design, Tool-Schemas, Error-Handling, Testing und Distribution.

Code-Editor mit dunklem Theme

Was ist ein OpenClaw-Skill überhaupt?

Ein Skill ist eine paketierte Fähigkeit, die du Claude über OpenClaw zur Verfügung stellst. Technisch besteht er aus zwei Komponenten:

  1. Skill.md: Eine Markdown-Datei, die beschreibt, was der Skill kann, wann er aktiv werden soll, und welche Tools er bereitstellt.
  2. tools/-Ordner (optional): TypeScript- oder JavaScript-Module, die echte Logik ausführen können (HTTP-Calls, Datenbank-Zugriffe, File-System-Operationen).

Wenn ein Skill keine Tools hat, ist er ein reiner "Kontext-Skill" – er wird nur aktiv, um Claude zusätzliche Informationen oder Verhalten zu geben (z. B. "antworte immer im Stil eines Anwalts" oder "die Firmen-DSE ist [folgendes]").

Wenn ein Skill Tools hat, kann Claude diese Tools aufrufen wie Funktionen. OpenClaw kümmert sich um die JSON-RPC-artige Kommunikation, das Schema-Validating und das Zurückspielen der Ergebnisse.

Die Anatomie einer Skill.md

Eine minimale Skill.md sieht so aus:

---
name: notion-task-creator
version: 1.0.0
description: Erstellt neue Tasks in einer Notion-Datenbank
triggers:
  - "neue aufgabe"
  - "task anlegen"
  - "notion task"
  - "todo hinzufügen"
---

# Notion Task Creator

Du kannst neue Tasks in der Notion-Datenbank anlegen. Wenn der User eine
Aufgabe erwähnt, frag nach dem Titel, einem optionalen Fälligkeitsdatum
und einer Priorität (low/medium/high).

## Tools

- `create_task`: Legt einen neuen Task in Notion an

Das Frontmatter ist Konfiguration, der Rest ist eine Anleitung, die Claude direkt liest, sobald der Skill aktiv ist. Hier kannst du erklären:

  • Was der Skill kann
  • In welchem Tonfall geantwortet werden soll
  • Welche Edge-Cases beachtet werden müssen
  • Welche Daten zwingend abgefragt werden müssen, bevor das Tool gerufen wird

Behandle die Skill.md wie eine Job-Description für Claude. Klare Sprache, konkrete Beispiele, eindeutige Trigger.

Das Beispiel: Notion-Skill von 0 auf 100

Wir bauen jetzt den vollständigen Skill. Du brauchst:

  • Einen aktiven OpenClaw-Server (Setup siehe Hostinger-Anleitung)
  • Einen Notion-Account mit einer Datenbank für Tasks
  • Einen Notion-Integrations-Token

Notion vorbereiten

In Notion gehst du auf https://www.notion.so/my-integrations und erstellst eine neue interne Integration namens "OpenClaw". Du bekommst einen Token im Format secret_XXXX.... Speichere ihn.

Dann öffnest du deine Tasks-Datenbank in Notion, klickst auf die drei Punkte oben rechts → "Connections" → wählst deine "OpenClaw"-Integration. Damit hat OpenClaw Lese-/Schreibrechte auf diese DB.

Die Datenbank-ID liest du aus der URL aus: https://www.notion.so/dein-workspace/abc123def456...?v=.... Der Teil zwischen dem letzten / und dem ? ist die ID.

Skill-Ordner anlegen

cd /opt/openclaw
mkdir -p skills/notion-task-creator/tools
cd skills/notion-task-creator

Skill.md schreiben

---
name: notion-task-creator
version: 1.0.0
description: Erstellt neue Tasks in einer Notion-Datenbank
triggers:
  - "neue aufgabe"
  - "task anlegen"
  - "notion task"
  - "todo hinzufügen"
  - "merk dir bitte"
---

# Notion Task Creator

Du kannst neue Tasks in der Notion-Datenbank anlegen.

## Wann du aktiv wirst

Werd aktiv, wenn der User von einer neuen Aufgabe spricht, die er
festhalten will. Typische Phrasen: "Bitte merk dir, dass ich morgen X
muss", "Trag mir bitte ein, dass...", "Neue Aufgabe: ...".

## Was du tun sollst

1. Frag nach dem **Task-Titel**, falls er nicht klar ist
2. Frag nach einem **Fälligkeitsdatum**, falls relevant (auch "morgen",
   "nächste Woche" sind okay – konvertier sie in ISO-Datumsformat)
3. Frag nach einer **Priorität** (low, medium, high) – falls nicht
   genannt, default ist "medium"
4. Bestätige dem User die Eingabe, bevor du das Tool aufrufst
5. Ruf `create_task` auf
6. Bestätige Erfolg mit der erstellten Task-URL

## Beispiel-Dialog

User: "Merk dir bitte, dass ich morgen Steuerunterlagen abgeben muss."
Du: "Klar. Ich lege das als Task mit Fälligkeit morgen an. Welche Priorität - high?"
User: "Ja, high."
Du: [ruft create_task auf]
Du: "Erledigt. Steht jetzt drin: https://notion.so/..."

## Tools

- `create_task`: Legt einen neuen Task in Notion an
  - Argumente: title (string, required), due_date (string, ISO-Format, optional), priority (low|medium|high, optional)
  - Rückgabe: task_url (string)

Das Tool implementieren

Erstelle tools/create_task.ts:

import { Tool } from '@openclaw/sdk';

export const create_task: Tool = {
    name: 'create_task',
    description: 'Erstellt einen neuen Task in der Notion-Datenbank',
    schema: {
        type: 'object',
        properties: {
            title: {
                type: 'string',
                description: 'Der Titel des Tasks'
            },
            due_date: {
                type: 'string',
                description: 'Fälligkeitsdatum im ISO-Format (YYYY-MM-DD)',
                pattern: '^\\d{4}-\\d{2}-\\d{2}$'
            },
            priority: {
                type: 'string',
                enum: ['low', 'medium', 'high'],
                description: 'Priorität'
            }
        },
        required: ['title']
    },
    handler: async ({ title, due_date, priority = 'medium' }) => {
        const NOTION_TOKEN = process.env.NOTION_TOKEN;
        const DATABASE_ID = process.env.NOTION_TASKS_DB_ID;

        if (!NOTION_TOKEN || !DATABASE_ID) {
            throw new Error('Notion-Konfiguration fehlt in .env');
        }

        const response = await fetch('https://api.notion.com/v1/pages', {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${NOTION_TOKEN}`,
                'Notion-Version': '2022-06-28',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                parent: { database_id: DATABASE_ID },
                properties: {
                    Name: { title: [{ text: { content: title } }] },
                    ...(due_date && {
                        'Due Date': { date: { start: due_date } }
                    }),
                    Priority: {
                        select: { name: priority.charAt(0).toUpperCase() + priority.slice(1) }
                    }
                }
            })
        });

        if (!response.ok) {
            const error = await response.text();
            throw new Error(`Notion-API-Fehler: ${error}`);
        }

        const data = await response.json();
        return {
            task_url: data.url,
            task_id: data.id,
            created_at: data.created_time
        };
    }
};

In .env ergänzen:

NOTION_TOKEN=secret_DEIN-TOKEN
NOTION_TASKS_DB_ID=abc123def456...

OpenClaw neu starten:

sudo systemctl restart openclaw

Test in deinem Bot: "Merk dir bitte, dass ich morgen meine Steuererklärung abgeben muss." Bei korrekter Konfig fragt Claude nach Priorität und legt den Task an.

KI mit Daten-Visualisierung

Best Practices für Skill-Design

Ein guter Skill ist nicht nur funktional, sondern auch wartbar und sicher. Sechs Prinzipien, die ich aus 20+ selbstgeschriebenen Skills gelernt habe:

1. Trigger sind kein Auto-Activator

Trigger im Frontmatter sind Hinweise für OpenClaw, ab wann der Skill kontextuell relevant wird. Sie aktivieren den Skill nicht zwangsweise. Claude entscheidet weiterhin selbst, ob das Tool aufgerufen wird, basierend auf dem Gesprächsverlauf. Schreib trotzdem 5-10 Trigger pro Skill, je natürlichsprachlicher, desto besser.

2. Halte Tool-Schemas eng

Je präziser dein JSON-Schema, desto weniger müllt Claude in dein Tool. Nutze:

  • enum für vordefinierte Werte (statt freier Strings)
  • pattern für Format-Validierung (z. B. ISO-Daten)
  • minimum/maximum für Zahlen
  • required-Listen für Pflichtfelder
  • description mit konkreten Beispielen

3. Validation außen, nicht im Prompt

Wenn ein User "next friday" als Datum sagt, soll Claude das in 2026-05-15 umwandeln. Das geht im Prompt. Sicherer ist aber ein Datums-Parser im Handler:

import { parse } from 'chrono-node';
const parsed = chrono.parse(due_date)[0]?.start.date();
if (!parsed) throw new Error('Datum nicht erkannt');

So fängst du auch Fehler ab, wenn Claude mal halluziniert.

4. Idempotenz wo möglich

Wenn der User zweimal "neue Aufgabe X" sagt, willst du nicht zwei Notion-Einträge. Implementiere Idempotenz, z. B. über einen Hash aus Titel+User+Tag, der vor dem Insert geprüft wird.

5. Logging für Debugging

Ein Skill, der "manchmal nicht funktioniert", ist die Hölle. Logge in jedem Handler den Input, das Resultat (oder den Error) und einen Timestamp:

import { log } from '@openclaw/sdk';
log.info('create_task called', { title, due_date, priority });
// ... try/catch mit log.error ...

6. Niemals Secrets in Skill-Repos

.env-Files gehören in .gitignore. Wenn dein Skill API-Keys braucht, dokumentier in der Skill.md, welche .env-Variablen er erwartet, aber commit niemals den Key selbst.

Tipp: Custom Skills laufen direkt auf deinem VPS. Hostinger KVM 2 mit 8 GB RAM ist dafür ideal: viel Platz für Logs, DB und parallele Skills. Hostinger ansehenAffiliate-Link — wir erhalten eine Provision, wenn du über diesen Link bestellst. Für dich ändert sich am Preis nichts.

Testing: So stellst du sicher, dass dein Skill funktioniert

Drei Test-Layer, die ich für jeden ernsthaften Skill schreibe:

Unit-Test für den Handler

import { describe, it, expect, vi } from 'vitest';
import { create_task } from './tools/create_task';

describe('create_task', () => {
    it('legt einen Task mit minimalen Argumenten an', async () => {
        global.fetch = vi.fn().mockResolvedValue({
            ok: true,
            json: async () => ({
                url: 'https://notion.so/mock',
                id: 'mock-id',
                created_time: '2026-05-10T10:00:00Z'
            })
        });

        const result = await create_task.handler({ title: 'Steuerunterlagen' });
        expect(result.task_url).toBe('https://notion.so/mock');
    });

    it('wirft Fehler bei invalidem Datum', async () => {
        await expect(
            create_task.handler({ title: 'Test', due_date: 'morgen' })
        ).rejects.toThrow();
    });
});

Integration-Test mit echtem Notion-Sandbox

Ein zweites Notion-Workspace nur fürs Testen, dort lässt du echte API-Calls laufen. Das ist langsamer, fängt aber API-Brüche.

End-to-End-Test im Bot

Schreib eine Test-Konversation mit deinem Bot, beobachte die Logs:

[OpenClaw] Skill 'notion-task-creator' activated (trigger: "merk dir bitte")
[notion-task-creator] create_task called: { title: "Steuerunterlagen", due_date: "2026-05-11", priority: "high" }
[notion-task-creator] create_task success: https://notion.so/abc...

Wenn du diesen Log-Pfad einmal sauber durchgespielt hast, kannst du dem Skill vertrauen.

Distribution: Skills mit ClawHub teilen

Wenn dein Skill so gut ist, dass andere ihn nutzen sollen, gibts mehrere Wege:

Privates Git-Repo (für Teams/Kunden)

Pack den Skill-Ordner in ein eigenes Git-Repo (mein-notion-skill), gib ihm ein README mit Setup-Anleitung. In OpenClaw klonst du das Repo als Git-Submodul oder per npm install git+ssh://git@github.com/....

ClawHub (öffentliche Verteilung)

ClawHub ist die OpenClaw-Skill-Registry – analog zu npm, aber für Skills. Du veröffentlichst per:

claw skill publish

Voraussetzungen:

  • Ein verifizierter ClawHub-Account
  • Eine vollständige Skill.md mit version, author, license
  • Bestandene Linting-Checks (claw skill lint)
  • Optional: Test-Suite für CI-Validierung

Veröffentlichte Skills landen unter clawhub.dev/skills/dein-username/skill-name. Andere User können sie mit claw skill install dein-username/skill-name ziehen.

Pull-Request in den Core-Skill-Index

Für sehr breit nützliche Skills (z. B. "GitHub-Issues-Lookup", "Wetter", "Wikipedia") kannst du einen PR in das offizielle OpenClaw-Repo machen. Wenn akzeptiert, ist dein Skill out-of-the-box bei jeder Installation dabei.

Distribution und Netzwerk

Häufige Fallstricke beim Skill-Bauen

"Mein Skill wird nie aktiv"

Wahrscheinlichkeiten:

  1. Trigger zu spezifisch oder unnatürlich → mehr Trigger-Phrasen testen
  2. description im Frontmatter zu vage → Claude weiß nicht, wann der Skill passt
  3. Skill-Datei nicht gefunden → claw skill list zeigt geladene Skills

"Tool wird gerufen, aber mit falschen Argumenten"

Schema präziser machen. Wenn ein Argument optional ist, dokumentiere im Description-Feld klar, wann es weggelassen werden soll.

"Fehler in Notion-API erscheint dem User als nackter Stack-Trace"

Im Handler try/catch und einen sauberen Error-Wrap:

catch (err) {
    return {
        error: true,
        message: 'Konnte Task nicht anlegen. Stimmt die Notion-Verbindung noch?'
    };
}

Claude liest das error: true und antwortet user-freundlich.

"Skill blockiert den Bot mehrere Sekunden"

Lange Tool-Calls (HTTP, DB) blockieren OpenClaws Event-Loop nicht, aber den Konversationsfluss. Falls dein Tool >5 Sekunden dauert, gib während der Ausführung ein "Moment, ich check das gerade…" zurück und stream das Ergebnis später nach.

Erweiterte Patterns für fortgeschrittene Skills

Memory-Awareness

Skills können auf den Memory-Store zugreifen, um Kontext über frühere Konversationen zu haben:

import { memory } from '@openclaw/sdk';
const lastTask = await memory.get(userId, 'last_task');

So kann dein Notion-Skill z. B. "Erstelle einen Folge-Task zum letzten" verstehen.

Multi-Step-Tool-Chains

Manche Skills brauchen mehrere Tool-Calls in Sequenz: Suche Notion-DB-Schema → Erstelle Task → Verlinke mit Projekt. Definiere das in der Skill.md klar als Workflow, Claude orchestriert das automatisch.

Skill-übergreifende Kommunikation

Wenn dein Notion-Skill und dein Calendar-Skill zusammenarbeiten sollen ("erstell den Task UND blockier mir 1h im Kalender"), nutze die Skill-Bus-API von OpenClaw:

import { skillBus } from '@openclaw/sdk';
await skillBus.invoke('calendar', 'block_time', { duration: 60 });

Tipp: Multiple Custom Skills + Memory-DB + Logs brauchen Platz. Hostinger KVM 2 mit 100 GB SSD reicht für hunderte Skills und jahrelange Logs. Hostinger ansehenAffiliate-Link — wir erhalten eine Provision, wenn du über diesen Link bestellst. Für dich ändert sich am Preis nichts.

Skill-Architektur-Patterns aus der Praxis

Mit der Zeit kristallisieren sich Patterns heraus, die wiederholt funktionieren. Sechs davon, die ich auf jeden produktiven Skill anwende.

Pattern 1: Read-Tools vor Write-Tools

Wenn ein Skill schreibende Operationen anbietet (create_task, send_email, update_record), gib auch immer das passende Read-Tool dazu (list_tasks, find_email, get_record). Das erlaubt Claude, vor dem Write zu validieren, ob die Aktion sinnvoll ist:

User: "Schließ den Steuer-Task ab"
Claude: [list_tasks aufrufen, finden] [update_task]

Ohne Read-Tool muss Claude raten oder zurückfragen.

Pattern 2: Idempotenz-Keys

Schreibende Tools sollten einen optionalen idempotency_key akzeptieren. Wenn derselbe Key zweimal kommt, wird die Operation nicht doppelt ausgeführt:

const cached = await db.get('idempotency', key);
if (cached) return cached.result;
const result = await actuallyDoIt(args);
await db.set('idempotency', key, { result, ts: Date.now() });

Schützt vor Double-Submits bei Netzwerk-Hiccups.

Pattern 3: Pagination by Default

List-Tools (list_tasks, search_emails) sollten immer paginieren, auch wenn der typische Datensatz klein ist. Default limit: 20, optional offset oder cursor. Ohne Pagination explodieren deine Token-Kosten, sobald der Datensatz wächst.

Pattern 4: Strukturierte Errors

Statt nackten Errors gib strukturierte Fehler zurück, die Claude parsen kann:

return {
    success: false,
    error_code: 'NOTION_RATE_LIMIT',
    message: 'Notion-API ist gerade rate-limited. In 30 Sekunden nochmal versuchen.',
    retry_after_seconds: 30
};

Claude kann dann sinnvoll reagieren ("Ich versuche es in einer halben Minute erneut") statt User-unfreundliche Stack-Traces zu zeigen.

Pattern 5: Dry-Run-Modus

Sensible Tools sollten einen dry_run: true-Modus haben, der die Aktion simuliert, aber nicht ausführt:

User: "Lösche alle alten Tasks"
Claude: [delete_tasks dry_run:true] → bekommt Liste zurück
Claude: "Das würde 47 Tasks löschen. Soll ich das wirklich machen?"
User: "Ja"
Claude: [delete_tasks dry_run:false]

Pattern 6: Skill-Versions-Migration

Wenn du einen Skill aktualisierst und das Schema ändert, dokumentiere Migrations-Pfade in der Skill.md:

## Migration

- v1.x → v2.0: Das Argument `priority` ist jetzt enum statt string.
  Alte Werte werden automatisch gemappt: "wichtig" → "high", etc.

Toolchain für Skill-Entwicklung

Die Tools, die meine Skill-Produktivität deutlich gesteigert haben:

claw skill init

Generiert ein neues Skill-Skelett mit allen Boilerplate-Files:

claw skill init my-new-skill
cd skills/my-new-skill
# Skill.md, tools/, package.json, .gitignore sind da

claw skill test

Local-Testing-Runner, der den Skill mit gemockten Inputs durchspielt:

claw skill test --skill notion-task-creator --input "Erstell einen Task"

Output: Welcher Trigger gefeuert hat, welche Tools gerufen wurden, welche Args.

claw skill lint

Statischer Linter für Skill.md und Tool-Schemas:

claw skill lint
# > Skill.md: missing 'license' in frontmatter
# > tools/create_task.ts: schema property 'priority' has no description

Tracing in Production

Mit OpenTelemetry-Integration kannst du Skill-Aufrufe in Tools wie Honeycomb oder Datadog tracen. Für Solo-Setups ist eine simple Pino-Logging-Ausgabe meist genug.

FAQ

Brauche ich TypeScript für Skills?

Nein. JavaScript geht auch. TypeScript empfehle ich aber stark, weil das JSON-Schema des Tools im Code-Editor mit Auto-Complete und Type-Checking arbeitet. Das spart 50 % der Bugs.

Wie viele Skills lädt OpenClaw maximal?

Technisch unbegrenzt, praktisch wirds bei 30-50 Skills unübersichtlich, weil Claude jeden Skill-Header im Kontext hat. Dann lieber Skills bündeln (z. B. ein "office"-Skill mit Notion + Calendar + Mail) oder Skills nur on-demand laden (Lazy-Loading via loadOn: trigger in der Skill.md).

Können Skills externe Pakete benutzen?

Ja, jede npm-Library ist möglich. Pack die Dependencies in package.json deines Skill-Ordners. OpenClaw installiert sie beim ersten Laden automatisch.

Was, wenn ich einen Skill löschen will?

Den Skill-Ordner aus skills/ entfernen und OpenClaw neu starten. Memory-Daten, die der Skill geschrieben hat, bleiben in der DB – die musst du manuell aufräumen.

Wie hoch sind die Anthropic-Kosten pro Skill-Call?

Ein Skill mit ~500 Wörtern in der Skill.md kostet ~150 Tokens zusätzlich pro Anfrage. Bei Claude Sonnet 4.7 sind das ~0.0005 € pro Skill, also Peanuts. Erst bei 50+ aktiven Skills mit langen Beschreibungen wirds spürbar (~0.025 € pro Anfrage).

Kann ich Skills in Privacy-kritischen Domänen einsetzen?

Ja, aber sei vorsichtig mit Tool-Outputs, die in den Konversations-Kontext gehen. Wenn dein Tool z. B. PII zurückgibt, bleibt das in Claudes Konversations-Memory hängen und wird bei jeder Folge-Anfrage erneut an Anthropic geschickt. Solche Daten lieber nur kurz halten oder gleich abstrahieren ("Ich habe 3 Tasks gefunden" statt der vollen Liste).

Fazit

Custom Skills sind die Killer-Feature von OpenClaw. Mit einem klar strukturierten Skill.md und einem schlanken Tool-Modul kannst du in einer Stunde Fähigkeiten bauen, die kommerziellen KI-Plattformen monatelange Roadmap-Items wären. Wichtig sind drei Dinge: präzise Schemas, ehrliche Trigger und sauberes Error-Handling.

Wenn du gerade erst anfängst, bau dir zuerst 1-2 simple Skills (z. B. ein Wetter-Skill oder ein Calculator-Skill ohne externe APIs), bevor du dich an komplexe Integrationen wie Notion oder MOCO machst. Die Iterations-Geschwindigkeit lernst du nur über Erfahrung – jeder geschriebene Skill macht den nächsten besser. Und wenn du zufällig einen baust, der auch anderen helfen könnte, freut sich ClawHub über deinen Beitrag.