# Mitarbeiten Einen Skill ohne Git installieren: ZIP aus der Tabelle in der [README](README.md) laden und in Claude hochladen. Dieser Text ist für alle, die einen Skill anlegen oder aktualisieren. ## Aufbau eines Skills ``` skills// ├── SKILL.md Pflicht – Anweisungen für Claude (liegt im ZIP) ├── README.md Pflicht – Doku für Menschen (nicht im ZIP) ├── CHANGELOG.md Pflicht – Versionen (nicht im ZIP) ├── extension/ optional – Claude-Desktop-Erweiterung (.mcpb) │ ├── manifest.json │ ├── icon.png optional │ ├── upstream.json von scripts/fetch-cli geschrieben │ ├── LICENSES/ Upstream-Lizenztexte │ └── server/ CLI-exe nur beim Bauen (nicht committen) ├── scripts/ optional – Hilfsskripte, die Claude ausführen kann ├── references/ optional – Nachschlagematerial, das Claude bei Bedarf liest └── assets/ optional – Vorlagen, Bilder usw. ``` `README.md` hat dieselben Abschnitte wie [templates/skill/README.md](templates/skill/README.md): Zweck, Voraussetzungen, Installation, Einrichtung, Stolpersteine, Test, Deinstallation/Update, Link zum Changelog. Skills mit `extension/` beschreiben die Installation über `.mcpb` + ZIP und verweisen auf [docs/INSTALLATION.md](docs/INSTALLATION.md). ## Regeln - **Name:** kebab-case, nur `a-z`, `0-9` und einzelne Bindestriche, höchstens 64 Zeichen, ohne „claude“ oder „anthropic“. Der Ordnername ist der Skill-Name. - **Frontmatter:** `SKILL.md` beginnt mit ```yaml --- name: description: "Wann dieser Skill verwendet werden soll – ein Satz." --- ``` `name` muss dem Ordnernamen entsprechen. `description` ist Pflicht, höchstens 1024 Zeichen, ohne spitze Klammern. Sie entscheidet, wann Claude den Skill benutzt – also beschreiben, *wann* er gebraucht wird, nicht nur *was* er ist. Enthält sie „: “, in Anführungszeichen setzen. Dieselbe `description` erscheint als Kurzbeschreibung in der Tabelle der Wurzel-README. - **Kodierung:** UTF-8 ohne BOM, Zeilenenden LF (regelt `.gitattributes`). - **CHANGELOG.md:** Einträge als `## x.y.z (YYYY-MM-DD)`, neuester oben. Der oberste Eintrag ist die aktuelle Version. ## Neuer Skill 1. Ordner aus der Vorlage anlegen: `scripts/new-skill.sh ` bzw. `scripts\new-skill.ps1 -Name ` 2. `SKILL.md` und `README.md` ausfüllen. 3. Prüfen: `scripts/validate.sh ` bzw. `scripts\validate.ps1 -Name ` 4. Tabelle in der Wurzel-README neu erzeugen: `scripts/update-index.sh` bzw. `scripts\update-index.ps1` 5. Committen und nach `main` pushen. 6. Tag setzen und pushen. Bestehende Tags nicht verschieben und nicht löschen. Der Push allein legt kein Release an. ```sh git tag /v git push origin main /v ``` 7. Release vom eigenen Rechner anlegen (siehe unten). Auf git.gundel.dev läuft kein Actions-Runner. ## Update eines Skills 1. `SKILL.md` und `README.md` ändern. 2. Im `CHANGELOG.md` einen neuen Eintrag `## x.y.z (YYYY-MM-DD)` oben einfügen. 3. Prüfen (`validate`), dann `update-index` ausführen. 4. Committen und nach `main` pushen. 5. Neuen Tag `/v` setzen und pushen. Der Tag muss exakt zur obersten CHANGELOG-Version passen. Danach das Release vom eigenen Rechner anlegen. ## Versionen - **Patch** (0.1.0 → 0.1.1): Korrekturen, Tippfehler, präzisere Formulierungen, Doku - **Minor** (0.1.0 → 0.2.0): neue Abschnitte, neue bekannte Fallen, neue Beispiele - **Major** (0.x → 1.0.0): geänderte Voraussetzungen oder Arbeitsweise, die bestehende Einrichtungen betreffen ## Release Ein Paket pro Skill, Dateiname `dist/-v.zip`. Im ZIP liegt der Ordner `/` mit `SKILL.md` auf oberster Ebene. `README.md` und `CHANGELOG.md` werden nicht eingepackt. Skills mit `extension/` liefern zusätzlich `dist/-v.mcpb`. Die CLI wird aus der ArtCraft-Launcher-Installation kopiert (`scripts/fetch-cli`), nicht von GitHub heruntergeladen. Die `.mcpb` bleibt unsigniert, solange kein Code-Signing-Zertifikat vorliegt (`mcpb sign` braucht `--cert` / `--key`; `--self-signed` hilft nicht gegen Defender). ```sh scripts/package.sh # nur Skill-ZIPs scripts/package.sh scripts/package-mcpb.sh # eine .mcpb scripts/package-all.sh # ZIP + .mcpb wo extension/ existiert ``` ```powershell powershell -ExecutionPolicy Bypass -File scripts\package.ps1 powershell -ExecutionPolicy Bypass -File scripts\package.ps1 -Name powershell -ExecutionPolicy Bypass -File scripts\package-mcpb.ps1 -Name powershell -ExecutionPolicy Bypass -File scripts\package-all.ps1 ``` ### Vom eigenen Rechner Auf git.gundel.dev ist kein Actions-Runner registriert. Das Release legt deshalb ein Skript auf dem Rechner an, der das ZIP schon gebaut hat. Es spricht die Gitea-API an ([Release anlegen](https://docs.gitea.com/enterprise/api/21/operations/repo-create-release/), [Anhang hochladen](https://docs.gitea.com/api/operations/repo-create-release-attachment/)): - `POST /api/v1/repos/dg/claude-skills/releases` - `POST /api/v1/repos/dg/claude-skills/releases/{id}/assets` Dafür braucht es ein persönliches Zugangs-Token mit Schreibrecht auf dieses Repository (`write:repository`). Anlegen unter Profil → Einstellungen → Applications. Authentifizierung: [`Authorization: token …`](https://docs.gitea.com/development/api-usage/). Das Token nur in die Umgebung legen, nicht ins Repository. Der Tag `/v` muss lokal existieren und schon auf dem Server liegen. Das Skript verschiebt keine Tags und pusht nichts. ```powershell $env:GITEA_TOKEN = '' powershell -ExecutionPolicy Bypass -File scripts\release.ps1 -Name ``` ```sh GITEA_TOKEN='' scripts/release.sh ``` ### Manuell, ohne Token 1. Paket bauen (Befehle oben). Prüfen, dass `dist/-v.zip` die Einträge `/` und `/SKILL.md` enthält und weder `README.md` noch `CHANGELOG.md`. 2. Unter [Releases](https://git.gundel.dev/dg/claude-skills/releases) ein neues Release anlegen. 3. Tag: `/v` (der Tag muss schon auf dem Server liegen). Titel: ` `. 4. Als Text den Abschnitt dieser Version aus `skills//CHANGELOG.md` einfügen. 5. `dist/-v.zip` als Anhang hochladen. 6. Falls vorhanden: `dist/-v.mcpb` ebenfalls hochladen (oder `scripts/release.ps1` nutzen – hängt beides an). Nur die `.mcpb` nachträglich an ein bestehendes Release hängen (Token nur in der Umgebung): ```powershell $env:GITEA_TOKEN = '' $id = $name = 'wordcraft-mcp-v0.2.0.mcpb' $bytes = [IO.File]::ReadAllBytes("dist\$name") $req = [Net.HttpWebRequest]::Create("https://git.gundel.dev/api/v1/repos/dg/claude-skills/releases/$id/assets?name=$name") $req.Method = 'POST' $req.Headers.Add('Authorization', "token $env:GITEA_TOKEN") $req.ContentType = 'application/octet-stream' $req.ContentLength = $bytes.LongLength $s = $req.GetRequestStream(); $s.Write($bytes, 0, $bytes.Length); $s.Close() $resp = $req.GetResponse(); (New-Object IO.StreamReader($resp.GetResponseStream())).ReadToEnd() ``` ## Hinweise zu den Skripten - Für jedes Skript gibt es eine Bash- (`.sh`) und eine PowerShell-Variante (`.ps1`). Die Bash-Skripte brauchen `zip` und `unzip`, die PowerShell-Skripte laufen ohne Zusatztools unter Windows PowerShell 5.1 und PowerShell 7. `release.sh` braucht zusätzlich `curl` und `python3`; unter Windows genügt `release.ps1`. - `.ps1`-Dateien enthalten nur ASCII-Zeichen. Windows PowerShell 5.1 liest UTF-8 ohne BOM als ANSI; Umlaute oder Gedankenstriche können ein Skript dort unbrauchbar machen. - `package.ps1` baut ZIPs mit `System.IO.Compression` statt `Compress-Archive`, weil `Compress-Archive` unter 5.1 Pfade mit `\` schreibt. - Unter Windows bei gesperrter Ausführungsrichtlinie: `powershell -ExecutionPolicy Bypass -File scripts\.ps1`