RL RanceLee Tutorials
← Retour aux tutoriels

Skills : ce qu'elles sont et comment les utiliser

De dactylographe à super assistant

Nous avons déjà appris à utiliser Claude Code pour des projets, et vous avez peut-être expérimenté la puissance de la programmation IA. Mais avez-vous remarqué un problème :

Chaque fois que vous faites quelque chose de similaire, vous devez décrire les exigences à nouveau.

Par exemple, vous voulez que l’IA vous aide à :

  • Rédiger des messages de commit Git
  • Réviser du code
  • Générer la documentation du projet
  • Synchroniser des fichiers

Vous pouvez effectuer ces tâches plusieurs fois par jour, mais à chaque fois vous devez taper un long paragraphe pour dire à l’IA quoi faire. C’est épuisant !

C’est comme si chaque fois que vous commandez un repas à emporter, vous deviez dire au restaurant :

« Je veux un bol de nouilles au bœuf braisé, pas de coriandre, extra piment, les nouilles doivent être fermes, moins de soupe… »

Existe-t-il un moyen de transformer ces opérations courantes en commandes en un clic ?

Oui, c’est ce dont nous allons parler aujourd’hui : Skill.


Qu’est-ce que Skill ?

Explication en une phrase

Skill = la commande raccourci de l’IA

Tout comme l’application Raccourcis sur votre téléphone, Skill encapsule des opérations complexes en une commande simple.

Définition officielle

Skill désigne un « module de capacité » réutilisable qui encapsule des outils/API/scripts et des invites dans une interface standard, permettant à l’IA de les appeler à la demande pour effectuer des tâches spécifiques.

Il met l’accent sur :

  • Entrée et sortie claires
  • Gestion des dépendances et des versions
  • Testable et mise à jour
  • Transformer une IA générale en un assistant professionnel orienté métier

Compréhension intuitive

Sans Skill :

You: Please review this code and check the following:
1. Are there any performance issues?
2. Are there any security vulnerabilities?
3. Does the code style follow the conventions?
4. Is there any duplicate code?
5. Are variable names clear?
6. Are comments complete?
……(continue describing for 10 more lines)

Avec Skill :

You: /review

L’IA révise automatiquement le code selon des normes prédéfinies et fournit un rapport détaillé.

Vous voyez la différence ? De centaines de mots à une seule commande—c’est la puissance de Skill.


Différences entre Skill, Prompt et MCP

Beaucoup de gens demandent : Quelles sont les différences entre Skill, Prompt et MCP ?

Comparaison des concepts

Aspect Prompt Skill MCP
Essence Instruction textuelle Module de capacité encapsulé Protocole pour connecter des outils externes
Réutilisabilité Faible, doit être ressaisi à chaque fois Élevée, définir une fois et réutiliser Élevée, configurer une fois et utiliser en continu
Complexité Simple Moyenne Complexe
Périmètre de capacité Traitement de texte uniquement Texte + scripts simples Texte + interaction avec systèmes externes
Courbe d’apprentissage La plus faible Moyenne Relativement élevée

Utilisation d’analogies

Prompt = Instruction verbale

  • Vous devez dire verbalement à l’IA quoi faire à chaque fois
  • Adapté aux tâches ponctuelles et ad hoc
  • Par exemple : « Traduis ce paragraphe »

Skill = Flux de travail

  • Solidifier les instructions courantes en un flux de travail standard
  • Adapté aux tâches répétitives et standardisées
  • Par exemple : /commit génère automatiquement des messages de commit Git

MCP = Système externe

  • Permet à l’IA de se connecter à des outils et sources de données externes
  • Adapté aux tâches nécessitant l’accès à des systèmes externes
  • Par exemple : se connecter à Obsidian pour lire/écrire des notes, se connecter à une base de données pour interroger des données

Relation entre les trois

Prompt → The most basic interaction method
    ↓
Skill → Encapsulates prompt + simple logic
    ↓
MCP → Skill + external system capabilities

En termes imagés :

  • Prompt = Vous cuisinez vous-même
  • Skill = Réchauffer un plat instantané au micro-ondes
  • MCP = Commander sur une plateforme de livraison de repas

Quand utiliser quoi ?

Utilisez Prompt si :

  • La tâche est simple, ponctuelle
  • Les exigences sont flexibles et changeantes
  • Pas besoin de réutilisation

Utilisez Skill si :

  • La tâche est très répétitive
  • A un flux de travail standardisé
  • Vous voulez améliorer l’efficacité

Utilisez MCP si :

  • Besoin d’accéder à des données externes (base de données, API, système de fichiers, etc.)
  • Besoin d’interagir avec d’autres logiciels (Obsidian, navigateur, etc.)
  • Besoin d’obtenir des informations en temps réel

Comparaison de cas pratiques :

Scénario 1 : Traduire un paragraphe

  • Utilisez Prompt : « Traduis ce paragraphe » (le plus simple)

Scénario 2 : Traduire de nombreux documents quotidiennement

  • Utilisez Skill : /translate (flux de traduction standardisé)

Scénario 3 : Traduire automatiquement des notes Obsidian et les sauvegarder

  • Utilisez MCP : Connectez-vous à Obsidian, lisez, traduisez, sauvegardez automatiquement (le plus puissant)

Utilisation de base de Skill

Comment voir les Skills existantes ?

Dans Claude Code ou Codex, entrez :

/skill

Cela listera toutes les Skills disponibles.

Comment utiliser Skill ?

Méthode 1 : Exécution directe

Entrez /skill, puis utilisez Tab pour sélectionner la Skill souhaitée, et appuyez sur Entrée pour exécuter.

Méthode 2 : Exécution avec paramètres

Après avoir sélectionné une Skill, continuez à taper votre demande spécifique :

/translate translate the comments in this code to English

Skills intégrées courantes

La plupart des outils de programmation IA sont livrés avec des Skills intégrées couramment utilisées :

Skill Fonction Exemple
/commit Générer automatiquement un message de commit Git /commit
/review Réviser la qualité du code /review
/fix Corriger les erreurs de code /fix
/test Générer des cas de test /test
/doc Générer de la documentation /doc
/refactor Refactoriser le code /refactor

Ces Skills intégrées peuvent déjà résoudre 80 % des besoins quotidiens.


Créer votre propre Skill

Si les Skills intégrées ne suffisent pas, vous pouvez créer votre propre Skill.

Deux méthodes de création

Méthode 1 : Laissez l’IA la créer pour vous (recommandé)

Codex est livré avec une Skill pour créer des Skills (cela semble déroutant, mais c’est puissant).

Étapes :

  1. Entrez /skill
  2. Trouvez l’option liée à « Créer une Skill »
  3. Après avoir sélectionné, dites à l’IA quelle Skill vous voulez

Exemple :

/create-skill

I want a translation Skill with the following features:
1. Automatically detect Chinese comments in code
2. Translate them into English
3. Keep the code format unchanged

L’IA créera automatiquement le fichier Skill et le placera au bon endroit.

Méthode 2 : Création manuelle

Si vous voulez comprendre plus en profondeur la structure de Skill, vous pouvez la créer manuellement.

Structure du fichier Skill :

Chaque Skill est un dossier qui doit contenir un fichier SKILL.md :

my-skill/
  ├── SKILL.md          # Skill description and configuration
  └── scripts/          # Optional: helper scripts
      └── helper.py

Format de base de SKILL.md :

---
name: Skill name
description: Skill description
---

# Detailed description

Write detailed usage instructions and implementation logic here.

## Parameters

- `--param1`: Description of parameter 1
- `--param2`: Description of parameter 2

## Example

Example usage code

La section « Cas pratique » plus loin dans ce chapitre détaillera comment créer une Skill complète.


Installer les Skills des autres

Il existe de nombreuses Skills prêtes à l’emploi sur GitHub que vous pouvez télécharger et utiliser directement.

Trouver le dossier Skill

Emplacement des Skills Codex :

  • Mac/Linux : ~/.codex/skills/
  • Windows : %USERPROFILE%\.codex\skills\

Emplacement des Skills Claude Code :

  • Mac/Linux : ~/.claude/skills/
  • Windows : %USERPROFILE%\.claude\skills\

Étapes d’installation

  1. Ouvrez le dossier Skill

Si le dossier n’existe pas, vous pouvez le créer manuellement :

# Mac/Linux
mkdir -p ~/.codex/skills

# Windows (PowerShell)
New-Item -Path "$env:USERPROFILE\.codex\skills" -ItemType Directory -Force

  1. Téléchargez le fichier Skill

Téléchargez le dossier Skill depuis GitHub ou d’autres sources.

  1. Copiez dans le répertoire Skill

Copiez tout le dossier Skill dans le répertoire skills correspondant.

  1. Redémarrez l’outil

Remarque : Codex ne prend actuellement pas en charge le rechargement à chaud ; vous devez quitter et redémarrer pour voir la nouvelle Skill. Claude Code peut généralement la reconnaître automatiquement.

Vérifier l’installation

Après le redémarrage, entrez /skill pour voir la liste et confirmer que la nouvelle Skill est apparue.


Cas pratique : Créer une Skill de synchronisation

Scénario problème

Si vous utilisez à la fois Codex et Claude Code (beaucoup de gens le font), vous rencontrerez un problème :

Les Skills des deux outils doivent être gérées séparément, ce qui est très gênant.

  • Les Skills Codex sont dans ~/.codex/skills/
  • Les Skills Claude Code sont dans ~/.claude/skills/

Chaque fois que vous créez une Skill utile dans Codex, vous devez la copier manuellement dans le dossier de Claude. Trop fastidieux !

À ce stade, nous pouvons créer une Skill pour synchroniser automatiquement le contenu des deux dossiers—utiliser une Skill pour gérer les Skills.

Cette Skill va :

  1. Vérifier les différences entre les deux dossiers Skill
  2. Signaler quelles Skills doivent être synchronisées
  3. Après votre confirmation, synchroniser automatiquement

Nous avons juste besoin de dire les exigences à l’IA.

Ci-dessous ce que l’IA fait pour vous. Notez que ces étapes sont toutes automatiques ; vous n’avez rien à faire ! C’est montré ici à titre de démonstration uniquement.

Étape 1 : Créer le dossier Skill

Dans le répertoire skills de Codex ou Claude Code, créez un nouveau dossier :

mkdir ~/.codex/skills/codex-claude-skill-sync

Étape 2 : Créer SKILL.md

Créez un fichier SKILL.md dans le dossier :

name: codex-claude-skill-sync
description: Sync Codex and Claude Skills
---

# Codex/Claude Skill Sync

## Overview

Used to check and sync the Skill directories of Codex and Claude, keeping both sides consistent. By default, only reports differences; executes sync after user confirmation.

## Workflow

1. Run difference report (no modification):

   `python3 scripts/sync_skills.py`

2. Report differences to the user in English and wait for explicit consent before proceeding.
3. After consent, execute sync:

   `python3 scripts/sync_skills.py --apply`

4. When encountering a conflict (same modification time but different content), pause and ask the user which side to keep.

## Rules

- Default directories:
  - Codex: `/Users/yourusername/.codex/skills`
  - Claude: `/Users/yourusername/.claude/skills`
- Only process top-level directories that contain `SKILL.md`, skip hidden directories and `.system`
- Determine which side is newer based on the latest modification time in the directory
- When syncing, delete the target Skill directory first, then copy the entire source directory

## Parameters

- `--apply` Execute sync (default is report only)
- `--codex <path>` Override Codex directory
- `--claude <path>` Override Claude directory
- `--prefer codex|claude` When modification time is the same but content differs, use the specified side to overwrite (requires explicit user authorization)

Important : Modifiez les chemins ci-dessus avec vos chemins réels !

Étape 3 : Créer le fichier script

Créez un répertoire scripts sous le dossier Skill, puis créez sync_skills.py :

mkdir ~/.codex/skills/codex-claude-skill-sync/scripts

Code complet pour sync_skills.py :

#!/usr/bin/env python3
"""
Compare and sync skill folders between Codex and Claude.

Default behavior is report-only. Use --apply to perform sync.
"""

from __future__ import annotations

import argparse
import hashlib
import os
from datetime import datetime
from pathlib import Path
import shutil
import sys

DEFAULT_CODEX = Path("/Users/yourusername/.codex/skills")
DEFAULT_CLAUDE = Path("/Users/yourusername/.claude/skills")

IGNORE_DIR_NAMES = {".git", ".idea", ".vscode", "__pycache__", ".pytest_cache", ".mypy_cache"}
IGNORE_FILE_NAMES = {".DS_Store"}
TIME_EPSILON = 1.0


def format_time(timestamp: float) -> str:
    return datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")


def list_skill_dirs(root: Path) -> tuple[dict[str, Path], list[str]]:
    if not root.exists():
        raise FileNotFoundError(f"Root path does not exist: {root}")
    if not root.is_dir():
        raise NotADirectoryError(f"Root path is not a directory: {root}")

    skills: dict[str, Path] = {}
    ignored: list[str] = []
    for entry in sorted(root.iterdir(), key=lambda p: p.name):
        if not entry.is_dir():
            continue
        if entry.name.startswith("."):
            ignored.append(entry.name)
            continue
        if not (entry / "SKILL.md").is_file():
            continue
        skills[entry.name] = entry
    return skills, ignored


def dir_state(path: Path) -> tuple[str, float, int]:
    hasher = hashlib.sha256()
    latest_mtime = path.stat().st_mtime
    file_count = 0

    for root, dirs, files in os.walk(path):
        dirs[:] = [d for d in dirs if d not in IGNORE_DIR_NAMES]
        dirs.sort()
        files = sorted(f for f in files if f not in IGNORE_FILE_NAMES)

        rel_dir = os.path.relpath(root, path)
        if rel_dir == ".":
            rel_dir = ""
        hasher.update(f"D|{rel_dir}\n".encode())

        try:
            latest_mtime = max(latest_mtime, os.stat(root).st_mtime)
        except FileNotFoundError:
            continue

        for name in files:
            file_path = Path(root) / name
            rel_path = os.path.relpath(file_path, path)

            if file_path.is_symlink():
                try:
                    target = os.readlink(file_path)
                except OSError:
                    target = ""
                hasher.update(f"L|{rel_path}\n{target}\n".encode())
                try:
                    latest_mtime = max(latest_mtime, file_path.lstat().st_mtime)
                except FileNotFoundError:
                    pass
                continue

            if not file_path.is_file():
                continue

            stat = file_path.stat()
            latest_mtime = max(latest_mtime, stat.st_mtime)
            file_count += 1
            hasher.update(f"F|{rel_path}\n{stat.st_size}\n".encode())

            with open(file_path, "rb") as handle:
                for chunk in iter(lambda: handle.read(1024 * 1024), b""):
                    hasher.update(chunk)

    return hasher.hexdigest(), latest_mtime, file_count


def build_plan(
    codex_skills: dict[str, Path],
    claude_skills: dict[str, Path],
    codex_root: Path,
    claude_root: Path,
    prefer: str | None,
) -> tuple[list[dict], list[str], list[dict]]:
    actions: list[dict] = []
    identical: list[str] = []
    conflicts: list[dict] = []

    all_names = sorted(set(codex_skills) | set(claude_skills))
    for name in all_names:
        codex_path = codex_skills.get(name)
        claude_path = claude_skills.get(name)

        if codex_path and not claude_path:
            actions.append(
                {
                    "name": name,
                    "src": codex_path,
                    "dst": claude_root / name,
                    "reason": "only in codex",
                    "direction": "codex -> claude",
                }
            )
            continue
        if claude_path and not codex_path:
            actions.append(
                {
                    "name": name,
                    "src": claude_path,
                    "dst": codex_root / name,
                    "reason": "only in claude",
                    "direction": "claude -> codex",
                }
            )
            continue

        if not codex_path or not claude_path:
            continue

        codex_hash, codex_mtime, _ = dir_state(codex_path)
        claude_hash, claude_mtime, _ = dir_state(claude_path)

        if codex_hash == claude_hash:
            identical.append(name)
            continue

        time_delta = codex_mtime - claude_mtime
        if abs(time_delta) <= TIME_EPSILON:
            if prefer == "codex":
                actions.append(
                    {
                        "name": name,
                        "src": codex_path,
                        "dst": claude_path,
                        "reason": "same mtime, prefer codex",
                        "direction": "codex -> claude",
                        "codex_mtime": codex_mtime,
                        "claude_mtime": claude_mtime,
                    }
                )
            elif prefer == "claude":
                actions.append(
                    {
                        "name": name,
                        "src": claude_path,
                        "dst": codex_path,
                        "reason": "same mtime, prefer claude",
                        "direction": "claude -> codex",
                        "codex_mtime": codex_mtime,
                        "claude_mtime": claude_mtime,
                    }
                )
            else:
                conflicts.append(
                    {
                        "name": name,
                        "codex_mtime": codex_mtime,
                        "claude_mtime": claude_mtime,
                    }
                )
            continue

        if time_delta > 0:
            actions.append(
                {
                    "name": name,
                    "src": codex_path,
                    "dst": claude_path,
                    "reason": "codex newer",
                    "direction": "codex -> claude",
                    "codex_mtime": codex_mtime,
                    "claude_mtime": claude_mtime,
                }
            )
        else:
            actions.append(
                {
                    "name": name,
                    "src": claude_path,
                    "dst": codex_path,
                    "reason": "claude newer",
                    "direction": "claude -> codex",
                    "codex_mtime": codex_mtime,
                    "claude_mtime": claude_mtime,
                }
            )

    return actions, identical, conflicts


def print_report(
    actions: list[dict],
    identical: list[str],
    conflicts: list[dict],
    codex_root: Path,
    claude_root: Path,
    apply: bool,
    ignored_codex: list[str],
    ignored_claude: list[str],
) -> None:
    print("Skill sync report")
    print(f"Codex: {codex_root}")
    print(f"Claude: {claude_root}")

    if ignored_codex:
        print(f"Ignored in Codex: {', '.join(sorted(ignored_codex))}")
    if ignored_claude:
        print(f"Ignored in Claude: {', '.join(sorted(ignored_claude))}")

    print("\nPlanned sync actions:")
    if not actions:
        print("- none")
    else:
        for item in actions:
            codex_mtime = item.get("codex_mtime")
            claude_mtime = item.get("claude_mtime")
            details = []
            if codex_mtime is not None:
                details.append(f"codex mtime: {format_time(codex_mtime)}")
            if claude_mtime is not None:
                details.append(f"claude mtime: {format_time(claude_mtime)}")
            detail_text = f" ({', '.join(details)})" if details else ""
            print(f"- {item['name']}: {item['direction']} [{item['reason']}]" + detail_text)

    print("\nConflicts:")
    if not conflicts:
        print("- none")
    else:
        for item in conflicts:
            print(
                f"- {item['name']}: same mtime but different content "
                f"(codex {format_time(item['codex_mtime'])}, claude {format_time(item['claude_mtime'])})"
            )

    print(f"\nUp-to-date skills: {len(identical)}")

    if not apply:
        print("\nDry run only. Re-run with --apply to sync.")


def apply_actions(actions: list[dict]) -> None:
    for item in actions:
        src = Path(item["src"])
        dst = Path(item["dst"])

        if dst.exists():
            if dst.is_dir():
                shutil.rmtree(dst)
            else:
                dst.unlink()

        shutil.copytree(src, dst, symlinks=True)


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Sync Codex and Claude skill folders")
    parser.add_argument("--codex", type=Path, default=DEFAULT_CODEX, help="Codex skill root")
    parser.add_argument("--claude", type=Path, default=DEFAULT_CLAUDE, help="Claude skill root")
    parser.add_argument("--apply", action="store_true", help="Apply sync actions")
    parser.add_argument(
        "--prefer",
        choices=["codex", "claude"],
        help="Break ties when mtimes are equal",
    )
    return parser.parse_args()


def main() -> int:
    args = parse_args()

    try:
        codex_skills, ignored_codex = list_skill_dirs(args.codex)
        claude_skills, ignored_claude = list_skill_dirs(args.claude)
    except (FileNotFoundError, NotADirectoryError) as exc:
        print(str(exc), file=sys.stderr)
        return 2

    actions, identical, conflicts = build_plan(
        codex_skills,
        claude_skills,
        args.codex,
        args.claude,
        args.prefer,
    )
    print_report(
        actions,
        identical,
        conflicts,
        args.codex,
        args.claude,
        args.apply,
        ignored_codex,
        ignored_claude,
    )

    if args.apply and actions:
        apply_actions(actions)
        print("\nSync complete.")
    elif args.apply and not actions:
        print("\nNo changes to apply.")

    if conflicts and not args.prefer:
        return 1
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Important : N’oubliez pas de modifier les chemins au début :

DEFAULT_CODEX = Path("/Users/yourusername/.codex/skills")
DEFAULT_CLAUDE = Path("/Users/yourusername/.claude/skills")

Remplacez-les par vos chemins réels.

Utiliser la Skill de synchronisation

Étape 1 : Voir les différences

Dans Claude Code ou Codex, entrez :

/codex-claude-skill-sync

L’IA exécutera automatiquement le script et signalera les différences entre les deux dossiers Skill.

Étape 2 : Confirmer la synchronisation

Si vous acceptez la synchronisation, dites à l’IA :

Agreed, please execute sync.

L’IA exécutera python3 scripts/sync_skills.py --apply pour terminer la synchronisation.

Terminé ! Désormais, chaque fois que vous créez ou modifiez une Skill d’un côté ou de l’autre, exécutez cette Skill de synchronisation une fois, et les deux côtés resteront cohérents.


Astuces avancées pour les Skills

Astuce 1 : Combiner les Skills

Plusieurs Skills peuvent être utilisées en séquence :

/review then /fix to fix the issues found

L’IA va d’abord réviser le code, puis corriger automatiquement en fonction des résultats de la révision.

Astuce 2 : Personnaliser les paramètres Skill

De nombreuses Skills prennent en charge les paramètres :

/commit --type feat --scope api

Cela générera un message de commit dans un format spécifique.

Astuce 3 : Modèles de Skill

Vous pouvez créer des modèles de Skill pour générer rapidement de nouvelles Skills :

  1. Copiez un dossier Skill existant
  2. Modifiez SKILL.md
  3. Sauvegardez

Astuce 4 : Partager les Skills avec l’équipe

Placez le dossier Skill dans un dépôt Git afin que les membres de l’équipe puissent partager :

git clone https://github.com/your-team/skills.git ~/.codex/skills/team-skills

Résumé

Ce que nous avons appris aujourd’hui :

  1. Qu’est-ce que Skill : Un module de capacité réutilisable qui transforme des opérations complexes en commandes simples
  2. Skill vs Prompt vs MCP : Différences et scénarios applicables
  3. Comment utiliser Skill : /skill pour voir et invoquer
  4. Comment créer Skill : Laissez l’IA aider ou créez manuellement
  5. Comment installer Skill : Copiez dans le dossier correspondant
  6. Cas pratique : Créer une Skill de synchronisation pour résoudre la gestion multi-outils

Points clés :

  • Skill fait passer l’IA de « dactylographe » à « assistant professionnel »
  • Les opérations courantes doivent être encapsulées dans des Skills
  • Une bonne Skill peut économiser 90 % du temps