Files
mes_skills/docs/superpowers/plans/2026-05-16-repo-et-installeur.md

46 KiB

Dépôt Skills IA + Installeur Bash — Plan d'implémentation

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Créer la structure complète du dépôt de skills multi-agents et le script install.sh interactif (fzf + couleurs Gruvbox).

Architecture: Dépôt Gitea avec skills organisés par catégorie puis par agent. Script bash autonome avec menu fzf, état par skill dans un fichier temporaire, palette Gruvbox Dark 256 couleurs. Aucun sudo requis, zéro dépendance hors git+fzf.

Tech Stack: Bash 5+, fzf, git, sort -V (semver), ANSI 256 couleurs.

Spec de référence: docs/superpowers/specs/2026-05-16-mes-skills-design.md


Fichiers à créer / modifier

Fichier Rôle
skills/dev/debugging/claude-code.md Skill démo Claude Code
skills/dev/debugging/gemini-cli.md Skill démo Gemini CLI
skills/dev/debugging/codex.md Skill démo Codex
skills/dev/debugging/hermes.md Skill démo Hermes
templates/claude-code.md Squelette vierge Claude Code
templates/gemini-cli.md Squelette vierge Gemini CLI
templates/codex.md Squelette vierge Codex
templates/hermes.md Squelette vierge Hermes
web/.gitkeep Réserve le dossier web pour le plan 2
docs/structure_skill.md Référence format SKILL.md par agent
docs/structure_repo.md Référence structure bibliothèque
docs/structure_script_install.md Référence architecture install.sh
README.md Guide d'utilisation
evolution.md Améliorations prévues
install.sh Script principal (exécutable)
tests/test_install.sh Tests bash (assertions simples)

Task 1 : Structure des dossiers et templates

Files:

  • Create: skills/dev/debugging/claude-code.md

  • Create: skills/dev/debugging/gemini-cli.md

  • Create: skills/dev/debugging/codex.md

  • Create: skills/dev/debugging/hermes.md

  • Create: templates/claude-code.md

  • Create: templates/gemini-cli.md

  • Create: templates/codex.md

  • Create: templates/hermes.md

  • Create: web/.gitkeep

  • Étape 1 : Créer l'arborescence des dossiers

mkdir -p skills/{dev,infra,ai,tools,jardinage,electronique,diy,task}
mkdir -p skills/dev/debugging
mkdir -p templates
mkdir -p web
touch web/.gitkeep
mkdir -p tests
  • Étape 2 : Créer le template Claude Code

Créer templates/claude-code.md :

---
name: mon-skill
version: 1.0.0
description: Décris clairement ce que fait ce skill et quand il se déclenche.
agents: [claude-code]
category: dev
tags: [tag1, tag2]
---

# Mon Skill

## Objectif

Décris l'objectif du skill en une phrase.

## Quand l'utiliser

- Cas d'usage 1
- Cas d'usage 2

## Instructions

Écris ici les instructions que Claude Code doit suivre.
  • Étape 3 : Créer le template Gemini CLI

Créer templates/gemini-cli.md :

---
name: mon-skill
version: 1.0.0
description: Décris clairement ce que fait ce skill et quand il se déclenche.
agents: [gemini-cli]
category: dev
tags: [tag1, tag2]
---

# Mon Skill

## Objectif

Décris l'objectif du skill en une phrase.

## Quand l'utiliser

- Cas d'usage 1
- Cas d'usage 2

## Instructions

Écris ici les instructions que Gemini CLI doit suivre.
  • Étape 4 : Créer le template Codex

Créer templates/codex.md :

---
name: mon-skill
version: 1.0.0
description: Décris clairement ce que fait ce skill et quand il se déclenche.
allow_implicit_invocation: true
agents: [codex]
category: dev
tags: [tag1, tag2]
---

# Mon Skill

## Objectif

Décris l'objectif du skill en une phrase.

## Quand l'utiliser

- Cas d'usage 1
- Cas d'usage 2

## Instructions

Écris ici les instructions que Codex doit suivre.
  • Étape 5 : Créer le template Hermes

Créer templates/hermes.md :

---
name: mon-skill
version: 1.0.0
description: Décris clairement ce que fait ce skill et quand il se déclenche.
agents: [hermes]
category: dev
tags: [tag1, tag2]
metadata:
  hermes:
    tags: [tag1, tag2]
    category: dev
---

# Mon Skill

## Quand utiliser ce skill

- Cas d'usage 1

## Référence rapide

| Élément | Valeur |
|---------|--------|
| Commande | `exemple` |

## Procédure

1. Étape 1
2. Étape 2

## Pièges connus

- Piège 1

## Vérification

- [ ] Résultat attendu 1
  • Étape 6 : Créer le skill de démo debugging pour Claude Code

Créer skills/dev/debugging/claude-code.md :

---
name: debugging
version: 1.0.0
description: Systématise le processus de débogage. Utiliser quand un bug est détecté, un test échoue ou un comportement inattendu est observé.
agents: [claude-code]
category: dev
tags: [debug, test, bug]
---

# Debugging Systématique

## Objectif

Fournir une approche structurée et reproductible pour identifier et corriger les bugs.

## Quand l'utiliser

- Un test échoue
- Un comportement inattendu est observé
- Une erreur apparaît dans les logs

## Instructions

1. **Reproduire** : Isoler le cas minimal qui déclenche le bug
2. **Observer** : Lire le message d'erreur complet sans supposer
3. **Hypothèse** : Formuler une seule hypothèse à la fois
4. **Tester** : Vérifier l'hypothèse avec une modification minimale
5. **Corriger** : Appliquer la correction et vérifier que le test passe
6. **Régression** : S'assurer qu'aucun autre test n'est cassé
  • Étape 7 : Créer le skill démo pour Gemini CLI, Codex, Hermes

Créer skills/dev/debugging/gemini-cli.md :

---
name: debugging
version: 1.0.0
description: Systématise le débogage. Utiliser quand un bug ou comportement inattendu est observé.
agents: [gemini-cli]
category: dev
tags: [debug, test, bug]
---

# Debugging Systématique

## Instructions

1. Reproduire le bug avec le cas minimal
2. Lire le message d'erreur complet
3. Formuler une hypothèse unique
4. Tester et corriger
5. Vérifier les régressions

Créer skills/dev/debugging/codex.md :

---
name: debugging
version: 1.0.0
description: Systématise le débogage. Utiliser quand un bug ou comportement inattendu est observé.
allow_implicit_invocation: true
agents: [codex]
category: dev
tags: [debug, test, bug]
---

# Debugging Systématique

## Instructions

1. Reproduire le bug avec le cas minimal
2. Lire le message d'erreur complet
3. Formuler une hypothèse unique
4. Tester et corriger
5. Vérifier les régressions

Créer skills/dev/debugging/hermes.md :

---
name: debugging
version: 1.0.0
description: Systématise le débogage. Utiliser quand un bug ou comportement inattendu est observé.
agents: [hermes]
category: dev
tags: [debug, test, bug]
metadata:
  hermes:
    tags: [debug, test, bug]
    category: dev
---

# Debugging Systématique

## Quand utiliser ce skill

- Un test échoue
- Un comportement inattendu est observé

## Procédure

1. Reproduire le bug avec le cas minimal
2. Lire le message d'erreur complet
3. Formuler une hypothèse unique
4. Tester et corriger
5. Vérifier les régressions

## Vérification

- [ ] Le bug est reproduit avant correction
- [ ] La correction ne casse aucun autre test
  • Étape 8 : Commit
rtk git add skills/ templates/ web/.gitkeep
rtk git commit -m "feat: structure dossiers, templates et skill démo debugging"

Task 2 : Documentation — docs/structure_skill.md

Files:

  • Create: docs/structure_skill.md

  • Étape 1 : Créer docs/structure_skill.md

# Structure des Skills par Agent IA

Ce document décrit le format exact attendu pour chaque agent.
Un même skill peut exister en plusieurs versions (une par agent).

---

## Format commun (frontmatter YAML)

Tous les agents partagent ces champs de base :

| Champ | Requis | Description |
|-------|--------|-------------|
| `name` | oui | Identifiant unique du skill (kebab-case) |
| `version` | oui | Version semver `X.Y.Z` |
| `description` | oui | Description + déclencheurs (crucial pour l'activation automatique) |
| `agents` | oui | Liste des agents : `[claude-code]`, `[gemini-cli]`, etc. |
| `category` | oui | Catégorie : `dev`, `infra`, `ai`, `tools`, `jardinage`, `electronique`, `diy`, `task` |
| `tags` | recommandé | Mots-clés libres : `[bash, debug, git]` |

---

## Claude Code

**Docs :** https://code.claude.com/docs/en/skills

**Fichier dans le dépôt :** `skills/<categorie>/<nom>/claude-code.md`
**Destination globale :** `~/.claude/skills/<categorie>/<nom>/SKILL.md`
**Destination locale :** `.claude/skills/<categorie>/<nom>/SKILL.md`

```yaml
---
name: mon-skill
version: 1.0.0
description: Description et déclencheurs.
agents: [claude-code]
category: dev
tags: [tag1, tag2]
# Optionnels :
# disable-model-invocation: true   # seul l'utilisateur peut invoquer
# user-invocable: false            # seul Claude peut invoquer
# allowed-tools: [Read, Grep]      # restreint les outils disponibles
---

Commande de test :

claude "utilise le skill <nom>" --print

Gemini CLI

Docs : https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/skills.md

Fichier dans le dépôt : skills/<categorie>/<nom>/gemini-cli.md Destination globale : ~/.gemini/skills/<categorie>/<nom>/SKILL.md Destination locale : .gemini/skills/<categorie>/<nom>/SKILL.md Alias : ~/.agents/skills/ et .agents/skills/

---
name: mon-skill
version: 1.0.0
description: Description et déclencheurs.
agents: [gemini-cli]
category: dev
tags: [tag1, tag2]
---

Commande de test :

gemini -p "utilise le skill <nom>"

Codex (OpenAI)

Docs : https://developers.openai.com/codex/skills

Fichier dans le dépôt : skills/<categorie>/<nom>/codex.md Destination globale : ~/.codex/skills/<categorie>/<nom>/SKILL.md Destination locale : .codex/skills/<categorie>/<nom>/SKILL.md

---
name: mon-skill
version: 1.0.0
description: Description et déclencheurs.
allow_implicit_invocation: true
agents: [codex]
category: dev
tags: [tag1, tag2]
---

Commande de test :

codex "$<nom>"

Hermes Agent (NousResearch)

Docs : https://hermes-agent.nousresearch.com/docs/user-guide/features/skills/

Fichier dans le dépôt : skills/<categorie>/<nom>/hermes.md Destination globale : ~/.hermes/skills/<categorie>/<nom>/SKILL.md Destination locale : .hermes/skills/<categorie>/<nom>/SKILL.md

---
name: mon-skill
version: 1.0.0
description: Description et déclencheurs.
agents: [hermes]
category: dev
tags: [tag1, tag2]
metadata:
  hermes:
    tags: [tag1, tag2]
    category: dev
---

Structure Markdown recommandée par Hermes :

  • ## Quand utiliser ce skill
  • ## Référence rapide
  • ## Procédure
  • ## Pièges connus
  • ## Vérification

Commande de test :

hermes "utilise le skill <nom>"

- [ ] **Étape 2 : Commit**

```bash
rtk git add docs/structure_skill.md
rtk git commit -m "docs: référence format SKILL.md par agent"

Task 3 : Documentation — docs/structure_repo.md et docs/structure_script_install.md

Files:

  • Create: docs/structure_repo.md

  • Create: docs/structure_script_install.md

  • Étape 1 : Créer docs/structure_repo.md

# Structure de la Bibliothèque de Skills

## Arborescence

mes_skills/ ├── skills/ ← bibliothèque principale │ ├── / ← catégorie (dev, infra, jardinage, ...) │ │ └── / ← un dossier par skill │ │ ├── claude-code.md ← variante Claude Code │ │ ├── gemini-cli.md ← variante Gemini CLI │ │ ├── codex.md ← variante Codex │ │ └── hermes.md ← variante Hermes Agent ├── templates/ ← squelettes vierges par agent │ ├── claude-code.md │ ├── gemini-cli.md │ ├── codex.md │ └── hermes.md ├── web/ ← portail web statique (Hugo + Docker) ├── docs/ ← documentation du dépôt ├── tests/ ← tests bash de install.sh ├── install.sh ← installeur interactif ├── README.md ├── evolution.md └── CLAUDE.md


## Catégories disponibles

| Catégorie | Usage |
|-----------|-------|
| `dev` | Développement : debug, git, tests, refactoring |
| `infra` | Infrastructure : docker, proxmox, homelab |
| `ai` | Agents IA : prompting, workflows |
| `tools` | Scripts utilitaires, automatisations |
| `jardinage` | Jardinage et plantes |
| `electronique` | Électronique, Arduino, ESP32 |
| `diy` | Bricolage, impression 3D |
| `task` | Gestion de tâches, organisation |

## Conventions

- Nom du skill : kebab-case (`mon-skill`)
- Nom des fichiers : `<agent>.md` (ex: `claude-code.md`)
- Version : semver `X.Y.Z` dans le frontmatter
- Tags : minuscules, sans espace (ex: `[bash, debug]`)
- L'installeur copie `<agent>.md` → `SKILL.md` dans la destination

## Ajouter un nouveau skill

1. Créer le dossier : `skills/<categorie>/<nom>/`
2. Copier un template depuis `templates/<agent>.md`
3. Remplir le frontmatter et le contenu
4. Committer et pusher vers Gitea
  • Étape 2 : Créer docs/structure_script_install.md
# Architecture de install.sh

## Vue d'ensemble

`install.sh` est un script bash autonome qui :
1. Vérifie les dépendances (git, fzf)
2. Détecte les agents IA installés
3. Clone le dépôt en /tmp
4. Présente un menu fzf interactif avec état par skill
5. Installe les skills sélectionnés sans sudo
6. Affiche un bilan + commandes de test

## Variables d'environnement

| Variable | Défaut | Effet |
|----------|--------|-------|
| `SKILLS_DEBUG=1` | non | Affiche chaque étape en détail |
| `SKILLS_DRY_RUN=1` | non | Simule sans écrire de fichiers |
| `SKILLS_REPO=/path` | (Gitea) | Utilise un dépôt local |
| `SKILLS_TAG=bash` | (tous) | Filtre les skills par tag |
| `SKILLS_AGENT=claude` | (auto) | Force un seul agent |

## Palette Gruvbox Dark (256 couleurs)

| Variable | Code | Usage |
|----------|------|-------|
| `GRV_GREEN` | `\033[38;5;142m` | Succès, installé ✓ |
| `GRV_YELLOW` | `\033[38;5;214m` | MAJ dispo ↑ |
| `GRV_AQUA` | `\033[38;5;108m` | Nouveau skill + |
| `GRV_GRAY` | `\033[38;5;245m` | Non applicable · |
| `GRV_RED` | `\033[38;5;167m` | Erreur fatale |
| `GRV_ORANGE` | `\033[38;5;208m` | Avertissement |
| `GRV_BLUE` | `\033[38;5;109m` | Info, action globale |
| `GRV_PURPLE` | `\033[38;5;175m` | Encadrés, titres |

## Flux d'exécution

check_deps() └─ fzf absent → install_fzf() ou exit └─ git absent → exit 1

detect_agents() → tableau DETECTED_AGENTS[]

clone_repo() → /tmp/mes_skills_/

scan_skills() └─ pour chaque skills///.md du dépôt └─ si agent dans DETECTED_AGENTS └─ get_local_version() vs get_repo_version() └─ compare_versions() → état (✓ ↑ + ·)

run_menu() [fzf + fichier état /tmp/skills_state_] └─ TAB → cycle_action() + reload └─ ENTER → liste des sélections

install_selected() └─ mkdir -p destination └─ cp .md → SKILL.md

print_summary() └─ bilan coloré └─ commandes de test copiables └─ liens docs agents

cleanup() [trap EXIT]


## Destinations d'installation (sans sudo)

| Agent | Global | Local |
|-------|--------|-------|
| claude-code | `~/.claude/skills/<cat>/<nom>/SKILL.md` | `.claude/skills/<cat>/<nom>/SKILL.md` |
| gemini-cli | `~/.gemini/skills/<cat>/<nom>/SKILL.md` | `.gemini/skills/<cat>/<nom>/SKILL.md` |
| codex | `~/.codex/skills/<cat>/<nom>/SKILL.md` | `.codex/skills/<cat>/<nom>/SKILL.md` |
| hermes | `~/.hermes/skills/<cat>/<nom>/SKILL.md` | `.hermes/skills/<cat>/<nom>/SKILL.md` |
  • Étape 3 : Commit
rtk git add docs/structure_repo.md docs/structure_script_install.md
rtk git commit -m "docs: structure dépôt et architecture install.sh"

Task 4 : README.md et evolution.md

Files:

  • Create: README.md

  • Create: evolution.md

  • Étape 1 : Créer README.md

# mes_skills — Bibliothèque personnelle de skills IA

Dépôt Gitea personnel de skills réutilisables pour agents IA :
**Claude Code**, **Gemini CLI**, **Codex (OpenAI)**, **Hermes Agent**.

## Installation rapide

```bash
curl -fsSL https://gitea.maison43.duckdns.org/gilles/mes_skills/raw/branch/main/install.sh | bash

Ce que fait l'installeur

  1. Détecte les agents IA présents sur ton système
  2. Affiche la liste des skills disponibles avec leur statut (installé / nouveau / MAJ dispo)
  3. Menu interactif fzf : TAB pour choisir local/global/ignorer, ENTER pour confirmer
  4. Installe sans sudo dans ~/.claude/skills/, ~/.gemini/skills/, etc.
  5. Affiche les commandes pour tester chaque skill installé

Options avancées

SKILLS_DEBUG=1   bash install.sh   # mode verbeux
SKILLS_DRY_RUN=1 bash install.sh   # simulation sans écriture
SKILLS_TAG=bash  bash install.sh   # filtre par tag
SKILLS_REPO=/path bash install.sh  # dépôt local (sans clone)

Structure du dépôt

skills/<categorie>/<nom>/
  claude-code.md    ← skill pour Claude Code
  gemini-cli.md     ← skill pour Gemini CLI
  codex.md          ← skill pour Codex
  hermes.md         ← skill pour Hermes

Voir docs/structure_repo.md pour le détail complet.

Créer un nouveau skill

cp templates/claude-code.md skills/dev/mon-skill/claude-code.md
# Éditer le fichier, remplir name, version, description, tags
# Committer et pusher

Documentation


- [ ] **Étape 2 : Créer `evolution.md`**

```markdown
# Évolutions et Améliorations Prévues

## v2 — Site web statique (en cours de conception)

- Portail Hugo + Docker dans `web/`
- Navigation par catégorie, agent et tags
- Style CSS Gruvbox dark
- Synchronisation automatique avec le dépôt Gitea (git pull toutes les heures)
- Voir `docs/superpowers/plans/` pour le plan d'implémentation

## v2.1 — Éditeur de skills depuis le navigateur

- Éditeur Markdown intégré au portail web
- Création depuis template
- Push vers Gitea via token API

## Futures idées

- Upload de skills locaux vers Gitea (token API)
- Support des dossiers `scripts/` et `references/` (format Hermes complet)
- Signature/vérification d'intégrité des skills
- Synchronisation automatique via cron système
- Interface similaire à [skillsmp.com](https://skillsmp.com/fr)
  • Étape 3 : Commit
rtk git add README.md evolution.md
rtk git commit -m "docs: README et evolution.md"

Task 5 : install.sh — socle, couleurs et helpers

Files:

  • Create: install.sh

  • Étape 1 : Créer install.sh avec en-tête et palette Gruvbox

Créer install.sh :

#!/usr/bin/env bash
# install.sh — Installeur interactif de skills IA
# Dépôt : https://gitea.maison43.duckdns.org/gilles/mes_skills
set -euo pipefail

# ── Couleurs Gruvbox Dark 256 ──────────────────────────────────────
GRV_FG='\033[38;5;223m'
GRV_RED='\033[38;5;167m'
GRV_GREEN='\033[38;5;142m'
GRV_YELLOW='\033[38;5;214m'
GRV_BLUE='\033[38;5;109m'
GRV_PURPLE='\033[38;5;175m'
GRV_AQUA='\033[38;5;108m'
GRV_ORANGE='\033[38;5;208m'
GRV_GRAY='\033[38;5;245m'
RESET='\033[0m'

# ── Icônes ────────────────────────────────────────────────────────
ICO_OK="✓"
ICO_UPD="↑"
ICO_NEW="+"
ICO_NA="·"
ICO_LOCAL="●L"
ICO_GLOBAL="●G"
ICO_SKIP="○"

# ── Configuration ─────────────────────────────────────────────────
REPO_URL="https://gitea.maison43.duckdns.org/gilles/mes_skills.git"
REPO_DIR="/tmp/mes_skills_$$"
STATE_FILE="/tmp/skills_state_$$"

SKILLS_DEBUG="${SKILLS_DEBUG:-0}"
SKILLS_DRY_RUN="${SKILLS_DRY_RUN:-0}"
SKILLS_REPO="${SKILLS_REPO:-}"
SKILLS_TAG="${SKILLS_TAG:-}"
SKILLS_AGENT="${SKILLS_AGENT:-}"

# ── Helpers couleur ───────────────────────────────────────────────
ok()     { echo -e "${GRV_GREEN}${ICO_OK}  $*${RESET}"; }
err()    { echo -e "${GRV_RED}$*${RESET}" >&2; }
info()   { echo -e "${GRV_BLUE}$*${RESET}"; }
warn()   { echo -e "${GRV_ORANGE}$*${RESET}"; }
debug()  { [[ "$SKILLS_DEBUG" == "1" ]] && echo -e "${GRV_GRAY}[DBG] $*${RESET}" || true; }
header() { echo -e "\n${GRV_PURPLE}╔══ $* ══╗${RESET}\n"; }
  • Étape 2 : Ajouter la fonction cleanup (trap EXIT)

Ajouter à la suite dans install.sh :

# ── Nettoyage automatique ─────────────────────────────────────────
cleanup() {
    debug "Nettoyage $REPO_DIR et $STATE_FILE"
    [[ -d "$REPO_DIR" ]] && rm -rf "$REPO_DIR"
    [[ -f "$STATE_FILE" ]] && rm -f "$STATE_FILE"
}
trap cleanup EXIT
  • Étape 3 : Commit intermédiaire
chmod +x install.sh
rtk git add install.sh
rtk git commit -m "feat: install.sh socle — palette Gruvbox et helpers"

Task 6 : install.sh — vérification des dépendances et détection agents

Files:

  • Modify: install.sh

  • Étape 1 : Ajouter install_fzf()

Ajouter dans install.sh après cleanup :

# ── Installation fzf ──────────────────────────────────────────────
install_fzf() {
    warn "fzf non trouvé."
    echo -e "  ${GRV_FG}Installer fzf ? [o/N]${RESET} \c"
    read -r answer
    [[ "$answer" != "o" && "$answer" != "O" ]] && err "fzf requis. Abandon." && exit 1

    if command -v apt-get &>/dev/null; then
        debug "Installation via apt"
        apt-get install -y fzf 2>/dev/null || {
            warn "apt échoué, tentative binaire GitHub..."
            _install_fzf_binary
        }
    else
        _install_fzf_binary
    fi
    command -v fzf &>/dev/null && ok "fzf installé." || { err "Impossible d'installer fzf."; exit 1; }
}

_install_fzf_binary() {
    local fzf_url="https://github.com/junegunn/fzf/releases/latest/download/fzf-linux_amd64.tar.gz"
    local tmp_fzf="/tmp/fzf_$$.tar.gz"
    info "Téléchargement fzf depuis GitHub Releases..."
    curl -fsSL "$fzf_url" -o "$tmp_fzf"
    tar -xzf "$tmp_fzf" -C "$HOME/.local/bin/" fzf
    rm -f "$tmp_fzf"
    export PATH="$HOME/.local/bin:$PATH"
}
  • Étape 2 : Ajouter check_deps()
# ── Vérification des dépendances ──────────────────────────────────
check_deps() {
    header "Vérification des dépendances"
    command -v git &>/dev/null || { err "git non trouvé. Installer git et relancer."; exit 1; }
    ok "git $(git --version | awk '{print $3}')"
    command -v fzf &>/dev/null || install_fzf
    ok "fzf $(fzf --version | awk '{print $1}')"
}
  • Étape 3 : Ajouter detect_agents()
# ── Détection des agents IA ───────────────────────────────────────
DETECTED_AGENTS=()

detect_agents() {
    header "Détection des agents IA"

    local check_agent() {
        local name="$1" primary="$2" secondary="$3"
        if [[ -n "$SKILLS_AGENT" && "$SKILLS_AGENT" != "$name" ]]; then
            debug "Agent $name ignoré (SKILLS_AGENT=$SKILLS_AGENT)"
            return
        fi
        if eval "$primary" &>/dev/null || eval "$secondary" &>/dev/null 2>/dev/null; then
            DETECTED_AGENTS+=("$name")
            ok "Agent détecté : $name"
        else
            echo -e "${GRV_GRAY}${ICO_NA}  Agent absent : $name${RESET}"
        fi
    }

    check_agent "claude-code" "test -d $HOME/.claude" "command -v claude"
    check_agent "gemini-cli"  "command -v gemini"     "test -f $(npm config get prefix 2>/dev/null)/bin/gemini"
    check_agent "codex"       "command -v codex"      "test -f $HOME/.npm-global/bin/codex"
    check_agent "hermes"      "command -v hermes"     "test -f $HOME/.local/bin/hermes"

    if [[ ${#DETECTED_AGENTS[@]} -eq 0 ]]; then
        warn "Aucun agent IA détecté. L'installation continuera mais aucun skill ne sera filtré."
    fi
}
  • Étape 4 : Commit
rtk git add install.sh
rtk git commit -m "feat: install.sh — détection dépendances et agents IA"

Task 7 : install.sh — clone, scan skills et versions

Files:

  • Modify: install.sh

  • Étape 1 : Ajouter clone_repo()

# ── Clone du dépôt ────────────────────────────────────────────────
clone_repo() {
    header "Récupération du dépôt"
    if [[ -n "$SKILLS_REPO" ]]; then
        REPO_DIR="$SKILLS_REPO"
        info "Utilisation du dépôt local : $REPO_DIR"
        return
    fi
    info "Clonage depuis $REPO_URL..."
    git clone --depth=1 "$REPO_URL" "$REPO_DIR" &>/dev/null
    ok "Dépôt cloné dans $REPO_DIR"
}
  • Étape 2 : Ajouter les fonctions de parsing et comparaison versions
# ── Gestion des versions ──────────────────────────────────────────
get_frontmatter_field() {
    local file="$1" field="$2"
    grep "^${field}:" "$file" 2>/dev/null | head -1 | awk '{print $2}' | tr -d '"'\'
}

get_local_version() {
    local cat="$1" skill="$2" agent="$3"
    local dest
    dest=$(get_dest_path "$cat" "$skill" "$agent" "local")
    [[ -f "$dest" ]] && get_frontmatter_field "$dest" "version" || echo ""
}

# Retourne 1 si ver1 < ver2 (ver2 est plus récente)
version_is_newer() {
    local ver1="$1" ver2="$2"
    [[ "$ver1" == "$ver2" ]] && return 1
    local newest
    newest=$(printf '%s\n%s' "$ver1" "$ver2" | sort -V | tail -1)
    [[ "$newest" == "$ver2" ]]
}
  • Étape 3 : Ajouter get_dest_path() et scan_skills()
# ── Chemins de destination ────────────────────────────────────────
get_dest_path() {
    local cat="$1" skill="$2" agent="$3" scope="$4"
    local base
    case "$agent" in
        claude-code) base="${scope//local/.claude}"; [[ "$scope" == "global" ]] && base="$HOME/.claude" ;;
        gemini-cli)  [[ "$scope" == "global" ]] && base="$HOME/.gemini"  || base=".gemini" ;;
        codex)       [[ "$scope" == "global" ]] && base="$HOME/.codex"   || base=".codex" ;;
        hermes)      [[ "$scope" == "global" ]] && base="$HOME/.hermes"  || base=".hermes" ;;
    esac
    echo "${base}/skills/${cat}/${skill}/SKILL.md"
}

# ── Scan des skills disponibles ───────────────────────────────────
# Format interne : "cat|skill|agent|etat|repo_version|local_version"
SKILLS_LIST=()

scan_skills() {
    header "Scan des skills disponibles"
    SKILLS_LIST=()

    while IFS= read -r skill_file; do
        local rel="${skill_file#$REPO_DIR/skills/}"   # dev/debugging/claude-code.md
        local agent_file="${rel##*/}"                  # claude-code.md
        local agent="${agent_file%.md}"                # claude-code
        local skill_path="${rel%/*}"                   # dev/debugging
        local cat="${skill_path%%/*}"                  # dev
        local skill="${skill_path#*/}"                 # debugging

        # Filtre agent
        local agent_detected=0
        for a in "${DETECTED_AGENTS[@]:-}"; do [[ "$a" == "$agent" ]] && agent_detected=1; done
        [[ "$agent_detected" -eq 0 && ${#DETECTED_AGENTS[@]} -gt 0 ]] && continue

        # Filtre tag
        if [[ -n "$SKILLS_TAG" ]]; then
            grep -q "$SKILLS_TAG" "$skill_file" || continue
        fi

        local repo_ver; repo_ver=$(get_frontmatter_field "$skill_file" "version")
        local local_ver; local_ver=$(get_local_version "$cat" "$skill" "$agent")
        local etat

        if [[ -z "$local_ver" ]]; then
            etat="new"
        elif version_is_newer "$local_ver" "$repo_ver"; then
            etat="upd"
        else
            etat="ok"
        fi

        SKILLS_LIST+=("${cat}|${skill}|${agent}|${etat}|${repo_ver}|${local_ver}")
        debug "Skill trouvé : $cat/$skill [$agent] état=$etat"
    done < <(find "$REPO_DIR/skills" -name "*.md" | sort)

    ok "${#SKILLS_LIST[@]} skill(s) trouvé(s)"
}
  • Étape 4 : Commit
rtk git add install.sh
rtk git commit -m "feat: install.sh — clone dépôt, scan skills et comparaison versions"

Task 8 : install.sh — menu fzf et installation

Files:

  • Modify: install.sh

  • Étape 1 : Configurer le thème fzf Gruvbox

Ajouter dans install.sh après les variables de config :

# ── Thème fzf Gruvbox Dark ────────────────────────────────────────
export FZF_DEFAULT_OPTS="
  --color=bg+:#3c3836,bg:#282828,spinner:#fb4934,hl:#928374
  --color=fg:#ebdbb2,header:#928374,info:#8ec07c,pointer:#fb4934
  --color=marker:#fb4934,fg+:#ebdbb2,prompt:#fb4934,hl+:#fb4934
  --border=rounded --height=80% --layout=reverse
  --header-lines=2
"
  • Étape 2 : Ajouter les fonctions de gestion d'état par skill
# ── État du menu (fichier clé=valeur) ────────────────────────────
state_init() {
    > "$STATE_FILE"
    for entry in "${SKILLS_LIST[@]}"; do
        local key="${entry//|/_}"
        local etat; etat=$(echo "$entry" | cut -d'|' -f4)
        # Défaut : local (sauf si etat=ok → local aussi mais MAJ si upd)
        echo "${key}=local" >> "$STATE_FILE"
    done
}

state_get() { grep "^${1}=" "$STATE_FILE" 2>/dev/null | cut -d'=' -f2; }

state_cycle() {
    local key="$1"
    local etat="$2"     # ok|new|upd
    local current; current=$(state_get "$key")
    local next
    case "$current" in
        local)  next="global" ;;
        global) next="skip" ;;
        skip)
            if [[ "$etat" == "upd" ]]; then next="update"
            else next="local"; fi ;;
        update) next="local" ;;
        *)      next="local" ;;
    esac
    sed -i "s/^${key}=.*/${key}=${next}/" "$STATE_FILE"
}
  • Étape 3 : Ajouter format_skill_line() et run_menu()
# ── Formatage d'une ligne du menu ─────────────────────────────────
format_skill_line() {
    local entry="$1"
    IFS='|' read -r cat skill agent etat repo_ver local_ver <<< "$entry"
    local key="${cat}_${skill}_${agent}"
    local action; action=$(state_get "$key")

    # Icône état
    local ico_etat color_etat
    case "$etat" in
        ok)  ico_etat="$ICO_OK";  color_etat="$GRV_GREEN" ;;
        upd) ico_etat="$ICO_UPD"; color_etat="$GRV_YELLOW" ;;
        new) ico_etat="$ICO_NEW"; color_etat="$GRV_AQUA" ;;
        *)   ico_etat="$ICO_NA";  color_etat="$GRV_GRAY" ;;
    esac

    # Icône action
    local ico_action color_action
    case "$action" in
        local)  ico_action="$ICO_LOCAL";  color_action="$GRV_GREEN" ;;
        global) ico_action="$ICO_GLOBAL"; color_action="$GRV_BLUE" ;;
        skip)   ico_action="$ICO_SKIP";   color_action="$GRV_GRAY" ;;
        update) ico_action="$ICO_UPD";    color_action="$GRV_YELLOW" ;;
    esac

    local ver_info=""
    [[ "$etat" == "upd" ]] && ver_info=" (${local_ver}${repo_ver})"
    [[ "$etat" == "new" ]] && ver_info=" (v${repo_ver})"

    printf "${color_etat}%s${RESET}  %-30s ${GRV_GRAY}[%s]${RESET}  ${color_action}%s${RESET}%s\n" \
        "$ico_etat" "${cat}/${skill}" "$agent" "$ico_action" "$ver_info"
}

# ── Menu fzf principal ────────────────────────────────────────────
SELECTED_SKILLS=()

run_menu() {
    header "Sélection des skills"
    state_init

    # Fichier helper pour le cycle TAB (appelé par fzf)
    local cycle_script="/tmp/skills_cycle_$$.sh"
    cat > "$cycle_script" << 'CYCLE_EOF'
#!/usr/bin/env bash
STATE_FILE="$1"
KEY="$2"
ETAT="$3"
current=$(grep "^${KEY}=" "$STATE_FILE" | cut -d'=' -f2)
case "$current" in
    local)  next="global" ;;
    global) next="skip" ;;
    skip)   [[ "$ETAT" == "upd" ]] && next="update" || next="local" ;;
    update) next="local" ;;
    *)      next="local" ;;
esac
sed -i "s/^${KEY}=.*/${KEY}=${next}/" "$STATE_FILE"
CYCLE_EOF
    chmod +x "$cycle_script"

    # Generateur de liste pour fzf
    local list_script="/tmp/skills_list_$$.sh"
    cat > "$list_script" << LIST_EOF
#!/usr/bin/env bash
source /tmp/skills_fns_$$.sh
for entry in $(printf '"%s" ' "${SKILLS_LIST[@]}"); do
    format_skill_line "\$entry"
done
LIST_EOF
    # Exporter les fonctions nécessaires
    declare -f format_skill_line state_get > "/tmp/skills_fns_$$.sh"
    echo "STATE_FILE='$STATE_FILE'" >> "/tmp/skills_fns_$$.sh"
    # Variables icônes et couleurs
    declare -p GRV_GREEN GRV_YELLOW GRV_AQUA GRV_GRAY GRV_BLUE GRV_RED GRV_PURPLE RESET \
               ICO_OK ICO_UPD ICO_NEW ICO_NA ICO_LOCAL ICO_GLOBAL ICO_SKIP >> "/tmp/skills_fns_$$.sh"
    chmod +x "$list_script"

    local legend
    legend="$(echo -e "${GRV_GRAY}État: ${GRV_GREEN}✓ installé  ${GRV_YELLOW}↑ MAJ  ${GRV_AQUA}+ nouveau  ${GRV_GRAY}· n/a   Action: ${GRV_GREEN}●L local  ${GRV_BLUE}●G global  ${GRV_GRAY}○ ignorer   TAB=changer ENTER=ok${RESET}")"

    fzf \
        --ansi \
        --multi \
        --prompt="Skills > " \
        --header="$legend" \
        --bind="tab:execute-silent($cycle_script '$STATE_FILE' {1} {4})+reload($list_script)" \
        < <(bash "$list_script") | while IFS= read -r line; do
            SELECTED_SKILLS+=("$line")
        done

    rm -f "$cycle_script" "$list_script" "/tmp/skills_fns_$$.sh"
}

Note : L'approche execute-silent+reload permet le cycle d'état en temps réel dans fzf.

  • Étape 4 : Ajouter install_selected()
# ── Installation des skills sélectionnés ─────────────────────────
install_selected() {
    header "Installation"
    local count_install=0 count_update=0 count_skip=0

    for entry in "${SKILLS_LIST[@]}"; do
        IFS='|' read -r cat skill agent etat repo_ver local_ver <<< "$entry"
        local key="${cat}_${skill}_${agent}"
        local action; action=$(state_get "$key")

        [[ "$action" == "skip" ]] && (( count_skip++ )) && continue

        local src="${REPO_DIR}/skills/${cat}/${skill}/${agent}.md"
        local dest; dest=$(get_dest_path "$cat" "$skill" "$agent" "$action")
        [[ "$action" == "update" ]] && dest=$(get_dest_path "$cat" "$skill" "$agent" "local")

        debug "Copie $src$dest"

        if [[ "$SKILLS_DRY_RUN" == "1" ]]; then
            info "[DRY-RUN] cp $src$dest"
        else
            mkdir -p "$(dirname "$dest")"
            cp "$src" "$dest"
        fi

        if [[ "$action" == "update" ]]; then
            ok "Mis à jour : ${cat}/${skill} [${agent}] ${local_ver}${repo_ver}"
            (( count_update++ ))
        else
            ok "Installé : ${cat}/${skill} [${agent}] → ${action}"
            (( count_install++ ))
        fi
    done

    echo -e "\n${GRV_PURPLE}╔══ Bilan ══╗${RESET}"
    echo -e "  ${GRV_GREEN}${ICO_OK} $count_install installé(s)${RESET}"
    echo -e "  ${GRV_YELLOW}${ICO_UPD} $count_update mis à jour${RESET}"
    echo -e "  ${GRV_GRAY}${ICO_SKIP} $count_skip ignoré(s)${RESET}"
}
  • Étape 5 : Commit
rtk git add install.sh
rtk git commit -m "feat: install.sh — menu fzf Gruvbox et installation des skills"

Task 9 : install.sh — écran de fin et main()

Files:

  • Modify: install.sh

  • Étape 1 : Ajouter print_summary()

# ── Récapitulatif final ───────────────────────────────────────────
print_summary() {
    local installed_skills=()
    for entry in "${SKILLS_LIST[@]}"; do
        IFS='|' read -r cat skill agent etat repo_ver local_ver <<< "$entry"
        local key="${cat}_${skill}_${agent}"
        local action; action=$(state_get "$key")
        [[ "$action" != "skip" ]] && installed_skills+=("${skill}|${agent}")
    done

    if [[ ${#installed_skills[@]} -gt 0 ]]; then
        echo -e "\n${GRV_PURPLE}╔══ Tester vos skills ══╗${RESET}\n"
        local shown_agents=()
        for item in "${installed_skills[@]}"; do
            IFS='|' read -r skill agent <<< "$item"
            local already_shown=0
            for a in "${shown_agents[@]:-}"; do [[ "$a" == "${skill}|${agent}" ]] && already_shown=1; done
            [[ "$already_shown" -eq 1 ]] && continue
            shown_agents+=("${skill}|${agent}")

            case "$agent" in
                claude-code) echo -e "  ${GRV_AQUA}claude \"utilise le skill ${skill}\" --print${RESET}" ;;
                gemini-cli)  echo -e "  ${GRV_AQUA}gemini -p \"utilise le skill ${skill}\"${RESET}" ;;
                codex)       echo -e "  ${GRV_AQUA}codex \"\$${skill}\"${RESET}" ;;
                hermes)      echo -e "  ${GRV_AQUA}hermes \"utilise le skill ${skill}\"${RESET}" ;;
            esac
        done
    fi

    echo -e "\n${GRV_PURPLE}╔══ Documentation agents ══╗${RESET}\n"
    for agent in "${DETECTED_AGENTS[@]:-}"; do
        case "$agent" in
            claude-code) echo -e "  ${GRV_BLUE}Claude Code${RESET}  →  https://code.claude.com/docs/en/skills" ;;
            gemini-cli)  echo -e "  ${GRV_BLUE}Gemini CLI ${RESET}  →  https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/skills.md" ;;
            codex)       echo -e "  ${GRV_BLUE}Codex      ${RESET}  →  https://developers.openai.com/codex/skills" ;;
            hermes)      echo -e "  ${GRV_BLUE}Hermes     ${RESET}  →  https://hermes-agent.nousresearch.com/docs/user-guide/features/skills/" ;;
        esac
    done
    echo ""
}
  • Étape 2 : Ajouter main() et l'appel final
# ── Point d'entrée ────────────────────────────────────────────────
main() {
    echo -e "\n${GRV_PURPLE}╔══════════════════════════════════════╗${RESET}"
    echo -e "${GRV_PURPLE}║   mes_skills — Installeur de skills   ║${RESET}"
    echo -e "${GRV_PURPLE}╚══════════════════════════════════════╝${RESET}\n"

    check_deps
    detect_agents
    clone_repo
    scan_skills

    if [[ ${#SKILLS_LIST[@]} -eq 0 ]]; then
        warn "Aucun skill compatible trouvé. Vérifier les agents détectés ou SKILLS_TAG."
        exit 0
    fi

    run_menu
    install_selected
    print_summary
}

main "$@"
  • Étape 3 : Vérifier la syntaxe bash
bash -n install.sh

Résultat attendu : aucune sortie (syntaxe valide).

  • Étape 4 : Commit
rtk git add install.sh
rtk git commit -m "feat: install.sh — écran de fin, commandes test et point d'entrée main()"

Task 10 : Tests bash

Files:

  • Create: tests/test_install.sh

  • Étape 1 : Créer le runner de tests

Créer tests/test_install.sh :

#!/usr/bin/env bash
# Tests unitaires pour install.sh
set -euo pipefail

PASS=0
FAIL=0

assert_eq() {
    local desc="$1" expected="$2" actual="$3"
    if [[ "$expected" == "$actual" ]]; then
        echo "  ✓ $desc"
        (( PASS++ ))
    else
        echo "  ✗ $desc"
        echo "    attendu : '$expected'"
        echo "    obtenu  : '$actual'"
        (( FAIL++ ))
    fi
}

assert_true() {
    local desc="$1"
    shift
    if eval "$@" &>/dev/null; then
        echo "  ✓ $desc"
        (( PASS++ ))
    else
        echo "  ✗ $desc"
        (( FAIL++ ))
    fi
}

# Charger les fonctions de install.sh sans exécuter main()
# (on commente temporairement l'appel main pour les tests)
source_install() {
    # Extraire toutes les fonctions sauf main() et son appel
    sed '/^main "\$@"/d' ../install.sh > /tmp/install_testable.sh
    sed -i 's/^main()/# main()/' /tmp/install_testable.sh || true
    source /tmp/install_testable.sh
}

echo ""
echo "══ Tests install.sh ══"
echo ""

# ── Test 1 : Comparaison de versions ──────────────────────────────
echo "1. Comparaison de versions"
source_install

version_is_newer "1.0.0" "1.2.0"
assert_true "1.2.0 > 1.0.0" "version_is_newer '1.0.0' '1.2.0'"

! version_is_newer "1.2.0" "1.0.0" 2>/dev/null
assert_true "1.0.0 n'est pas > 1.2.0" "! version_is_newer '1.2.0' '1.0.0'"

! version_is_newer "1.0.0" "1.0.0" 2>/dev/null
assert_true "1.0.0 == 1.0.0 → pas plus récent" "! version_is_newer '1.0.0' '1.0.0'"

# ── Test 2 : Parsing frontmatter ──────────────────────────────────
echo ""
echo "2. Parsing frontmatter"

cat > /tmp/test_skill_$$.md << 'EOF'
---
name: test-skill
version: 2.1.0
description: Skill de test
agents: [claude-code]
category: dev
tags: [bash, test]
---
# Contenu
EOF

result=$(get_frontmatter_field "/tmp/test_skill_$$.md" "version")
assert_eq "version parsée correctement" "2.1.0" "$result"

result=$(get_frontmatter_field "/tmp/test_skill_$$.md" "name")
assert_eq "name parsé correctement" "test-skill" "$result"

rm -f "/tmp/test_skill_$$.md"

# ── Test 3 : get_dest_path ────────────────────────────────────────
echo ""
echo "3. Chemins de destination"

result=$(get_dest_path "dev" "debugging" "claude-code" "global")
assert_eq "chemin global claude-code" "$HOME/.claude/skills/dev/debugging/SKILL.md" "$result"

result=$(get_dest_path "dev" "debugging" "gemini-cli" "local")
assert_eq "chemin local gemini-cli" ".gemini/skills/dev/debugging/SKILL.md" "$result"

result=$(get_dest_path "jardinage" "arrosage" "codex" "global")
assert_eq "chemin global codex jardinage" "$HOME/.codex/skills/jardinage/arrosage/SKILL.md" "$result"

# ── Test 4 : État fichier (state_get/state_cycle) ─────────────────
echo ""
echo "4. Gestion d'état"

STATE_FILE=$(mktemp)
echo "dev_debugging_claude_code=local" > "$STATE_FILE"

result=$(state_get "dev_debugging_claude_code")
assert_eq "state_get retourne 'local'" "local" "$result"

state_cycle "dev_debugging_claude_code" "ok"
result=$(state_get "dev_debugging_claude_code")
assert_eq "cycle local→global" "global" "$result"

state_cycle "dev_debugging_claude_code" "ok"
result=$(state_get "dev_debugging_claude_code")
assert_eq "cycle global→skip" "skip" "$result"

state_cycle "dev_debugging_claude_code" "upd"
result=$(state_get "dev_debugging_claude_code")
assert_eq "cycle skip→update (si upd)" "update" "$result"

state_cycle "dev_debugging_claude_code" "upd"
result=$(state_get "dev_debugging_claude_code")
assert_eq "cycle update→local" "local" "$result"

rm -f "$STATE_FILE"

# ── Bilan ─────────────────────────────────────────────────────────
echo ""
echo "══ Résultats : ${PASS} passés, ${FAIL} échoués ══"
echo ""
[[ "$FAIL" -eq 0 ]]
  • Étape 2 : Exécuter les tests
cd tests && bash test_install.sh

Résultat attendu :

══ Tests install.sh ══

1. Comparaison de versions
  ✓ 1.2.0 > 1.0.0
  ✓ 1.0.0 n'est pas > 1.2.0
  ✓ 1.0.0 == 1.0.0 → pas plus récent

2. Parsing frontmatter
  ✓ version parsée correctement
  ✓ name parsé correctement

3. Chemins de destination
  ✓ chemin global claude-code
  ✓ chemin local gemini-cli
  ✓ chemin global codex jardinage

4. Gestion d'état
  ✓ state_get retourne 'local'
  ✓ cycle local→global
  ✓ cycle global→skip
  ✓ cycle skip→update (si upd)
  ✓ cycle update→local

══ Résultats : 13 passés, 0 échoués ══
  • Étape 3 : Test de dry-run de install.sh
SKILLS_DRY_RUN=1 SKILLS_REPO=. bash install.sh

Résultat attendu : le menu fzf s'ouvre, et après sélection les lignes [DRY-RUN] cp ... s'affichent sans écrire de fichiers.

  • Étape 4 : Test de débogage
SKILLS_DEBUG=1 SKILLS_DRY_RUN=1 SKILLS_REPO=. bash install.sh

Résultat attendu : lignes [DBG] visibles en gris entre chaque étape.

  • Étape 5 : Commit final
cd ..
chmod +x install.sh tests/test_install.sh
rtk git add install.sh tests/test_install.sh
rtk git commit -m "feat: tests bash et install.sh complet — v1 prête"

Auto-revue de couverture spec

Exigence spec Tâche
Structure dépôt par catégorie Task 1
Templates par agent Task 1
Dossier web/ réservé Task 1
Frontmatter avec tags Tasks 1-2
docs/structure_skill.md avec liens Task 2
docs/structure_repo.md Task 3
docs/structure_script_install.md Task 3
README.md Task 4
evolution.md Task 4
Palette Gruvbox Dark 256 Task 5
Thème fzf Gruvbox Task 8
Zéro sudo Task 6, 8
Détection agents (2 méthodes) Task 6
Installation fzf si absent Task 6
Clone /tmp Task 7
Comparaison versions semver Task 7
Menu fzf + TAB cycle Task 8
Légende permanente Task 8
install_selected() Task 8
Écran de fin + commandes test Task 9
Liens docs agents détectés Task 9
SKILLS_DEBUG/DRY_RUN/REPO/TAG/AGENT Tasks 5, 10
Tests unitaires bash Task 10
Tests d'intégration dry-run Task 10