Metadata-Version: 2.4
Name: pysae-ai-tools
Version: 0.1.1280
Summary: Shared Python tools for Pysae Claude Code skills
Requires-Python: >=3.11
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: anthropic (>=0.85.0,<0.86.0)
Requires-Dist: commitizen (>=4.0,<5.0)
Requires-Dist: dnspython (>=2.7.0,<3.0.0)
Requires-Dist: fastapi (>=0.115)
Requires-Dist: httpx (>=0.28.1,<0.29.0)
Requires-Dist: platformdirs (>=4.0,<5.0)
Requires-Dist: pydantic (>=2.0)
Requires-Dist: pymongo (>=4.16.0,<5.0.0)
Requires-Dist: pyyaml (>=6.0,<7.0)
Requires-Dist: tomlkit (>=0.13,<0.14)
Requires-Dist: typer (>=0.24.1,<0.25.0)
Requires-Dist: uvicorn (>=0.34)
Project-URL: Repository, https://gitlab.com/pysae/tools/ai-tools
Description-Content-Type: text/markdown

# ai-tools

```bash
# Linux / macOS
curl -fsSL https://tools.pysae.com/pysae-ai-tools/install.sh | bash

# Windows (PowerShell)
irm https://tools.pysae.com/pysae-ai-tools/install.ps1 | iex

# Windows (cmd.exe) - requires cURL
winget install -e --id cURL.cURL
curl -fsSL https://tools.pysae.com/pysae-ai-tools/install.cmd -o install.cmd && install.cmd
```

Une fois le package installé, installer (ou mettre à jour) les CLI et serveurs MCP gérés par Pysae :

```bash
pysae-ai-tools tools install
```

> **Prérequis** : des clés d'accès AWS valides (`AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY`). De nombreux outils résolvent leurs tokens (ArgoCD, Datadog, Slack, etc.) via AWS Secrets Manager au moment de l'installation. Si l'AWS CLI n'est pas encore configurée, `tools install` la configure en interactif.

Dépôt central pour l'**outillage IA interne de Pysae** : skills Claude Code, package Python, image Docker CI et relais webhook GitLab.

## Workflow complet (idée → deploy)

```mermaid
flowchart TD
    A["Idéation et cadrage<br/>/product-discover"] --> B["Création du ticket<br/>/glab-issue-create"]
    B --> R["Affinage jusqu'à « prêt »<br/>/glab-issue-refine"]
    R --> C{"Écran UI standard ?<br/>(décision automatique)"}
    subgraph DAUTO ["Pilote design — autonome (design-autopilot-batch)"]
        D["Maquette HTML générée<br/>/design-generate"]
        D -. "corrige, revérifie · jusqu'à maquette conforme + critères couverts" .-> D
        D --> DP["Maquette publiée<br/>URL partageable sur le ticket"]
    end
    C -->|oui| D
    DP --> E["Validation humaine (PM)<br/>juge le rendu, puis « validé »"]
    C -->|"non · sur-mesure"| M["Design manuel<br/>designer + Figma"]
    M --> E
    E --> F["Implémentation<br/>/code-implement"]
    subgraph CAUTO ["Pilote code — autonome (code-autopilot)"]
        F --> G["Revue de code<br/>/code-review-fix"]
        G -. "corrige, re-revue · jusqu'à revue OK (max 5)" .-> G
        G --> H["Intégration continue (CI)"]
        H --> I["Déploiement<br/>/ci-deploy"]
    end
    I --> P(["Production"])
```

Trois phases, **deux pilotes automatiques séparés par une seule décision humaine** :

1. **De l'idée au ticket prêt.** L'idée devient un ticket avec des critères d'acceptation testables, puis on lève les zones d'ombre jusqu'à ce qu'il soit prêt à travailler.
2. **Design, quand c'est un écran standard.** Le système décide seul si la feature est un écran courant (liste, formulaire, détail, onglets, modale) ou une interaction sur-mesure. Si c'est courant : il génère une maquette HTML fidèle au design system, la vérifie en boucle (vraies couleurs et composants du produit, tous les critères couverts) jusqu'à ce qu'elle soit propre, et la publie sur une URL partageable. Sinon, il s'arrête et laisse la main à un designer.
3. **Validation humaine, le seul point de contrôle.** Le PM ouvre l'URL, juge le rendu, le fait éventuellement tester par des utilisateurs, puis valide ou demande une nouvelle passe. Une maquette douteuse s'arrête ici : elle n'atteint jamais la prod.
4. **Du code à la prod, en autopilote.** Une fois validé, l'implémentation, la revue, la CI et le déploiement s'enchaînent sans intervention.

Ce qui dure, c'est le **contrat** (critères d'acceptation + constitution du design). La maquette est **jetable** : régénérée à la demande, jamais stockée ni partagée à la main.

Les deux pilotes autonomes sont la phase 2 (design) et la phase 4 (code) ; les commandes de chaque étape sont dans la section [Skills](#skills) ci-dessous. *À venir : génération automatique de la merge request depuis la maquette validée.*

## Skills

### Code lifecycle

| Skill | Description | Invocation |
|-------|-------------|------------|
| `code-implement` | Implémenter un ticket GitLab : branche, code, tests, commits, MR | `/pysae:code-implement` |
| `code-autopilot` | Pipeline autonome : implémentation, boucle de review, CI, déploiement review | `/pysae:code-autopilot` |
| `code-autopilot-batch` | Orchestrateur batch : pioche les tickets `agent::ready`, score (déterministe + Haiku), enchaîne `/code-autopilot` séquentiellement | `/pysae:code-autopilot-batch` |
| `code-quality` | Lancer tests, linters, pre-commit hooks ; corriger les erreurs avec des commits atomiques | `/pysae:code-quality` |
| `code-review` | Revue de code (bugs, sécurité, perf, qualité) — mode local interactif ou CI headless | `/pysae:code-review` |
| `code-review-fix` | Boucle review-fix : review, correction de tous les problèmes, re-review jusqu'à APPROVED | `/pysae:code-review-fix` |
| `code-review-pre-release` | Audit pré-release : revue du diff depuis le dernier tag semver, triage des problèmes avec création optionnelle de tickets, enchaînement sur `/ci-release`, puis post du recap sur le canal Slack tech du repo | `/pysae:code-review-pre-release` |
| `code-get-next-version` | Déterminer la prochaine version semver d'une application (auto-détection depuis les changelogs, confirmation utilisateur avec changelog agrégé en local, retour direct en CI) — utilisé par `/ci-release` et `/code-review-pre-release` | `/pysae:code-get-next-version` |
| `code-changelog` | Ajouter une entrée changelog dans `changelogs/` | `/pysae:code-changelog` |
| `code-release-notes` | Générer et committer sur la branche principale les notes de release destinées aux utilisateurs en trois langues (`docs/release-notes/RELEASE_NOTES.{fr,en,it}.md`) pour la prochaine version, à partir des commits et entrées changelog depuis le dernier tag — invoqué par `/ci-release` et `/code-review-pre-release` juste avant la création du tag | `/pysae:code-release-notes` |
| `code-profile` | Profiler le code (cProfile, py-spy, pyinstrument, clinic, chrome-devtools MCP) sur un test, un nouveau test ou l'app, analyser les bottlenecks et proposer des pistes d'optimisation | `/pysae:code-profile` |
| `code-python-guidelines` | Appliquer les conventions Python Pysae lors de l'écriture ou la revue de code | `/pysae:code-python-guidelines` |

### Design phase

| Skill | Description | Invocation |
|-------|-------------|------------|
| `design-generate` | Générer un prototype HTML fidèle au design system (feature commodity), vérifié par `design check` / `design coverage` puis la **boucle proto-review** (navigateur : écrans atteignables + fidélité visuelle), prêt pour revue PM + handoff dev | `/pysae:design-generate` |
| `design-autopilot-batch` | Orchestrateur batch au-dessus de `design-generate` : pioche les tickets `workflow::Ready` UI, décide l'éligibilité **automatiquement** (prefilter déterministe + classifieur Haiku + seuil, sans label manuel), enchaîne `design-generate --auto`, rend chaque proto en URL Pages et passe le ticket en `design::review` | `/pysae:design-autopilot-batch` |

**Workflow** (fronts React+Tailwind, features commodity) : `design kit` génère la constitution `design.md` (tokens + catalogue) depuis le code → `design-generate` produit un prototype HTML à vraies classes-tokens depuis les FR du ticket → boucle `design check` jusqu'à `CLEAN` → `design coverage` vérifie qu'aucun FR n'est sans écran → **boucle proto-review** (navigateur headless : aucun overlay bloquant au chargement, chaque écran atteignable, fidélité à l'app réelle) → proto poussé sur la branche `design/<iid>` du front, rendu en **URL GitLab Pages** (même lien pour revue PM et user-test) → revue PM (label GitLab) → PR React au dev. Contrat durable = `design.md` + AC du ticket ; le proto HTML est jetable (régénéré). Détail complet : [`docs/specs/2026-06-09-design-phase-harness-design.md`](docs/specs/2026-06-09-design-phase-harness-design.md).

**Full auto** : `design-autopilot-batch` (CLI `pysae-ai-tools agent design-run`) draine les tickets `workflow::Ready` à signal UI sans label manuel. L'éligibilité est décidée en 2 étages (prefilter déterministe gratuit + classifieur Haiku au-dessus d'un seuil de confiance) ; `design::eligible` / `design::skip` restent des overrides humains optionnels. Le gate PM reste humain (revue de `design::review` + URL Pages).

Commandes CLI (project-agnostic, auto-découverte des tokens `@theme` + du catalogue `components/ui/`) :

- `pysae-ai-tools design kit --root <front> --out design.md` — génère la constitution `design.md`.
- `pysae-ai-tools design check <fichier> [--root <front>]` — oracle déterministe (R1 couleur brute, R2 valeur arbitraire sauf `-[var(--token)]`, R3 primitive hors catalogue, R4 palette Tailwind par défaut ; exit 1 si `VIOLATIONS`).
- `pysae-ai-tools design coverage <spec.md> <coverage-map.md>` — liste les FR de la spec sans écran (exit 1 si `GAPS`).

### GitLab — Issues & Epics

| Skill | Description | Invocation |
|-------|-------------|------------|
| `glab-issue-create` | Créer un ticket GitLab avec templates, labels, poids et epic parent (scoring automatique) | `/pysae:glab-issue-create` |
| `glab-issue-refine` | Affiner un ticket en `workflow::Refinement` : lever toutes les incertitudes fonctionnelles et techniques (lecture code, POC jetables), réécrire la description au présent sans trace des doutes initiaux, transition vers `workflow::Ready` | `/pysae:glab-issue-refine` |
| `glab-issue-find` | Trouver un ticket par IID, URL, auteur, assignee ou mots-clés | `/pysae:glab-issue-find` |
| `glab-issue-next` | Choisir le prochain ticket à implémenter depuis le backlog (scoring par priorité/colonne) | `/pysae:glab-issue-next` |
| `glab-issue-audit` | Auditer les tickets ouverts : conformité labels, placement board, templates, titres | `/pysae:glab-issue-audit` |
| `glab-issue-workflow-update` | Réconcilier les statuts du board avec la réalité MR/changelog : MR ouverte → « In progress » (« Under review » si approuvée), MR toutes mergées → « To deploy », ticket de la dernière version déployée → fermé | `/pysae:glab-issue-workflow-update` |
| `glab-issue-from-ai-note` | Créer des issues GitLab de followup depuis les Open questions d'un fichier ai-note | `/pysae:glab-issue-from-ai-note` |
| `glab-epic-attach-issues` | Trouver les tickets orphelins et les rattacher aux epics (scoring + validation manuelle) | `/pysae:glab-epic-attach-issues` |
| `glab-epic-create` | Générer titre et description d'une epic à partir de ses tickets enfants, ou créer une epic depuis un thème | `/pysae:glab-epic-create` |
| `glab-user-find` | Trouver un utilisateur GitLab par nom (fuzzy match dans le groupe Pysae) | `/pysae:glab-user-find` |

### GitLab — Merge Requests

| Skill | Description | Invocation |
|-------|-------------|------------|
| `glab-mr` | Créer une MR depuis la branche courante avec le bon template | `/pysae:glab-mr` |
| `glab-mr-find` | Trouver une MR par IID, URL, auteur ou mots-clés | `/pysae:glab-mr-find` |
| `glab-mr-approve` | Approuver une MR via glab CLI | `/pysae:glab-mr-approve` |
| `glab-mr-merge` | Fusionner une MR via glab CLI (avec contrôles préalables) | `/pysae:glab-mr-merge` |
| `glab-mr-rebase` | Rebaser une MR sur sa branche cible (avec résolution auto des conflits) et push | `/pysae:glab-mr-rebase` |
| `glab-mr-refresh` | Rebaser les MR ouvertes sur leur branche cible et relancer les pipelines | `/pysae:glab-mr-refresh` |
| `glab-clone-group` | Cloner tous les repos du groupe Pysae récursivement, vérifier les remotes, pull | `/pysae:glab-clone-group` |
| `glab-mr-checkout` | Checkout la branche associée à une MR ou un ticket | `/pysae:glab-mr-checkout` |
| `git-worktree` | Créer un worktree git pour isoler les changements | `/pysae:git-worktree` |

### CI/CD

| Skill | Description | Invocation |
|-------|-------------|------------|
| `ci-run` | Lancer un job CI ou une chaîne de dépendances sur la branche courante | `/pysae:ci-run` |
| `ci-prepare` | Installer les dépendances projet en mode CI (Node via nvm, Python via poetry) | `/pysae:ci-prepare` |
| `ci-debug` | Déboguer les échecs de pipeline CI (logs, analyse, correctifs proposés) | `/pysae:ci-debug` |
| `ci-deploy` | Déployer une application (prod, review, dev) — utilise le job `redeploy` si disponible | `/pysae:ci-deploy` |
| `ci-deploy-status` | Vérifier le statut de déploiement (review, dev, prod) via GitLab, CI, kubectl | `/pysae:ci-deploy-status` |
| `ci-release` | Release complète : bump semver, pipeline, déploiement prod, monitoring rollout | `/pysae:ci-release` |
| `ci-rollback` | Rollback ou redéploiement prod (utilise `redeploy` si disponible, sinon `deploy_prod`) | `/pysae:ci-rollback` |

### Infra & AWS

| Skill | Description | Invocation |
|-------|-------------|------------|
| `infra-ops` | Opérations infrastructure : kubectl, ArgoCD, Helm, déploiements, finops | `/pysae:infra-ops` |
| `aws-eks-optimize` | Optimiser les node groups EKS (SPOT et on-demand) en croisant Spot Advisor (taux prédictif), notre historique d'évictions CloudTrail, le prix (spot + on-demand) et la performance effective (vCPU × fréquence × IPC). Par environnement et par node group : plusieurs mix d'instances proposés avec l'évolution de 4 facteurs (coût, perf, coût/perf, risque d'éviction) et la liste Terraform | `/pysae:aws-eks-optimize` |
| `teammate-access` | Onboarder ou offboarder un collaborateur dans l'IaC Terraform : accès AWS IAM, EKS et MongoDB Atlas, à partir de l'email, du niveau et des environnements | `/pysae:teammate-access` |
| `env-secret` | Lire ou écrire des secrets applicatifs dans AWS Secrets Manager | `/pysae:env-secret` |
| `env-resolve` | Résoudre des variables d'environnement (MCP config → AWS Secrets Manager) et les exporter dans le shell | `/pysae:env-resolve` |
| `env-mcp-cleanup` | Installer un hook `SessionEnd` qui kill les MCP serveurs orphelins (libère la RAM des sessions Claude Code mortes — Linux + macOS) | `/pysae:env-mcp-cleanup` |

### Performance & Monitoring

| Skill | Description | Invocation |
|-------|-------------|------------|
| `infra-perf` | Diagnostics performance API : latence, erreurs, pods, CPU/RAM par service | `/pysae:infra-perf` |
| `infra-perf-setup` | Créer les monitors Datadog pour l'alerting performance API (P99, erreurs, restarts) | `/pysae:infra-perf-setup` |
| `infra-perf-report` | Planifier des rapports de santé API automatiques sur Slack (6h-9h en semaine) | `/pysae:infra-perf-report` |

### Activity Tracker

| Skill | Description | Invocation |
|-------|-------------|------------|
| `track-install` | Installer le hook de suivi d'activité (git, glab, fichiers, skills, agents) | `/pysae:track-install` |
| `track-dashboard` | Ouvrir le tableau de bord d'activité dans le navigateur | `/pysae:track-dashboard` |
| `track-manual` | Enregistrer du temps manuellement sur un ticket ou une epic | `/pysae:track-manual` |
| `track-context` | Attribuer un contexte (ticket, epic, labels) à une session existante | `/pysae:track-context` |

### API & Intégrations

| Skill | Description | Invocation |
|-------|-------------|------------|
| `pysae-api` | S'authentifier (Auth0) et appeler l'API Pysae (dev/prod) : découverte dynamique du spec OpenAPI puis requêtes authentifiées | `/pysae:pysae-api` |
| `openapi-to-postman` | Convertir un spec OpenAPI en collection Postman avec variables d'environnement | `/pysae:openapi-to-postman` |

### Communication & Reporting

| Skill | Description | Invocation |
|-------|-------------|------------|
| `slack-ask-review` | Poster une demande de review sur le bon canal Slack avec le contexte MR | `/pysae:slack-ask-review` |
| `stats-weekly-summary` | Générer un récap hebdomadaire de l'activité engineering formaté pour Slack | `/pysae:stats-weekly-summary` |
| `stats-kpi-ops` | Collecter et formater les KPIs tech hebdo/mensuels du sheet « Suivi des indicateurs Opérations » (uptime, latence p95, incidents, vélocité, DORA) en bloc colonne prêt à coller | `/pysae:stats-kpi-ops` |
| `post-mortem` | Générer un double rapport post-mortem (interne + externe) depuis un incident | `/pysae:post-mortem` |

### Support client (Patrick / CSM)

| Skill | Description | Invocation |
|-------|-------------|------------|
| `support-bug-investigate` | Enquêter sur un bug Pysae en lisant le code cloné localement ; livre un rapport concis (30-40 lignes) avec cause racine et correctif | `/pysae:support-bug-investigate` |
| `support-ticket-create` | Créer un ticket Airtable Customer Service depuis une conversation Intercom, avec pré-analyse injectée dans Notes | `/pysae:support-ticket-create` |
| `support-mr-fix` | Ouvrir une MR de correction directe après un ticket Airtable et une issue GitLab — gate « petit fix sans risque » puis délégation à `/code-implement` | `/pysae:support-mr-fix` |
| `support-product-ticket` | Créer une suggestion produit dans la DB Notion Roadmap (sans investigation GitLab) | `/pysae:support-product-ticket` |
| `support-intercom-article` | Rédiger un article Help Center Intercom opérationnel (FR + EN + IT), draft publié via MCP Intercom + Composio | `/pysae:support-intercom-article` |
| `support-intercom-news` | Produire une annonce News Intercom (HTML autonome pour copier-coller) pour une feature shippée | `/pysae:support-intercom-news` |

`glab-issue-create` accepte un flag `--from-airtable <recID>` pour enchaîner depuis un ticket support : il lit le ticket Airtable, mappe `Sujet` → projet et `Criticité` → label priority, ajoute les labels `workflow::To Do` + `Support 📞`, et écrit l'URL de l'issue dans le champ `Ticket Gitlab` du ticket Airtable après création.

### Meta & DX

| Skill | Description | Invocation |
|-------|-------------|------------|
| `clawd-compound` | Extraire les apprentissages de la session et les persister dans CLAUDE.md | `/pysae:clawd-compound` |
| `clawd-skill-review` | Auditer les skills contre les bonnes pratiques Anthropic | `/pysae:clawd-skill-review` |
| `pysae-design` | Appliquer la charte graphique Pysae à tous les documents et artefacts visuels | `/pysae:pysae-design` |
| `product-discover` | Scanner le codebase, détecter les angles morts fonctionnels, proposer des features | `/pysae:product-discover` |

## Skills publiés sur claude.ai (Claude Desktop)

Une whitelist de skills est aussi poussée vers l'API Workspace Anthropic à
chaque merge sur `main` qui les modifie (job CI `publish-skills`). Les
membres de l'orga les voient dans Claude Desktop et n'ont rien à installer
côté skill, le serveur Anthropic les sert.

| Skill | Pré-requis côté poste user |
|-------|----------------------------|
| `pysae-design` | aucun |
| `clawd-skill-review` | aucun |
| `clawd-compound` | aucun |
| `post-mortem` | aucun (les références projet sont bundlées dans le skill) |
| `product-discover` | `pysae-ai-tools` + `glab` installés, monorepo Pysae cloné localement |

La whitelist est définie dans [`pysae_ai_tools/skills/whitelist.py`](pysae_ai_tools/skills/whitelist.py).
Critère d'éligibilité : skill pure-prompt OU compatible avec un poste sur
lequel `pysae-ai-tools` est installé. Pour publier manuellement en local, voir
[CONTRIBUTING.md](CONTRIBUTING.md#publier-les-skills-sur-claudeai).

## Fonctionnement

Les skills tournent dans trois modes :

- **Interactif (dev)** — les développeurs invoquent les skills localement via Claude Code CLI (`/pysae:<skill>`)
- **CI (headless)** — l'image Docker est utilisée comme image de job GitLab CI ; le template `.ai-tools-skill` lance `claude /<skill>` en mode non-interactif
- **Claude Desktop (non-tech)** — les skills de la whitelist sont disponibles directement dans Claude Desktop pour toute l'orga, sans installation côté user

## Autopilot batch (`/code-autopilot-batch`)

Orchestrateur batch au-dessus de `/code-autopilot` : draine une queue GitLab de tickets opt-in sans intervention humaine. Le PM tague les tickets éligibles, l'orchestrateur les ramasse en séquence, ouvre une MR draft, lance review + CI + merge, et émet un footer JSON parseable.

### Workflow

1. **PM** pose le label `agent::ready` sur un ticket éligible (scope clair, < 1j dev, hors paths sensibles)
2. L'orchestrateur (local manuel, `gstack /loop 15m`, ou CI scheduled) :
   - Pulle les tickets `agent::ready` multi-projets
   - Score : métier déterministe (priorité × type × âge) × signal LLM (Haiku) en moyenne pondérée 70/30
   - Filtre les paths sensibles (regex + LLM) avec override `agent::override-sensitive`
   - Transition labels : `agent::ready` → `agent::wip` + commentaire pickup horodaté
   - Subprocess `claude /code-autopilot <issue_url>` (implement → review-fix → CI → merge → footer JSON)
   - Si escalation : `agent::wip` → `agent::blocked` + commentaire structuré (raison, run_id)
   - Reclaim automatique des WIP orphelins (> 2h sans pickup marker)
3. Report stdout (table ASCII) + Slack (`#tech-ci-agent-autopilot`)

### Labels (à créer au niveau groupe `pysae`)

| Label | Posé par | Sémantique |
|-------|----------|------------|
| `agent::ready` | PM (opt-in explicite) | Ticket éligible à l'agent |
| `agent::wip` | Orchestrateur (pickup) | Lock implicite contre double-pickup |
| `agent::blocked` | Orchestrateur (escalade) | Humain doit reprendre, voir commentaire |
| `agent::override-sensitive` | PM | Force l'agent à traiter malgré la garde regex/LLM |

### Modes d'invocation

```bash
# Local manuel, repo courant
claude /code-autopilot-batch

# Multi-projets, dry-run pour valider sans muter
claude /code-autopilot-batch --project shift --project driver --dry-run

# Cap budget (defaults: --max-tickets 5 --max-tokens 100M, calibrated for
# interactive sessions where real Pysae tickets observed at 3-30M tokens each)
claude /code-autopilot-batch --max-tickets 3 --max-tokens 30000000 --timeout 1h

# Scheduled CI run (conservative: ~2-3 tickets/run, $30-40 cap)
claude /code-autopilot-batch --max-tickets 3 --max-tokens 30000000

# Replay manuel d'un ticket (bypasse les gardes sensitive)
claude /code-autopilot-batch --tickets https://gitlab.com/pysae/shift/app/-/issues/42

# Sans LLM (score métier déterministe seul, pas de clé API requise)
claude /code-autopilot-batch --skip-llm-rank
```

### Exit codes (utiles en CI scheduled)

- `0` : tout traité avec succès, aucune escalade
- `1` : ≥ 1 ticket escaladé en `agent::blocked` (fait échouer le job pour visibilité équipe)
- `2` : erreur technique (GitLab API down, `claude` absent, etc.)

## Contribuer

Setup de développement (linters, tests), publication manuelle des skills, et
intégration des reviews IA dans un projet (template CI + variables groupe) :
voir [CONTRIBUTING.md](CONTRIBUTING.md).

## Mise à jour

```bash
pysae-ai-tools self-update    # depuis un clone (git pull + reinstall)
```

