CommunityRédaction et éditiongithub.com

serhii-nochevnyi/shipyard

Convoy de livraison pour Claude Code et l'interface en ligne de commande OpenAI Codex (investigation → décomposition → livraison), avec un conteneur reproductible : portes mécaniques, worktree par ticket, PRs menées au vert.

Qu'est-ce que shipyard ?

Shipyard est un système de convoyage automatisé de tickets, conçu pour fonctionner avec Claude Code et l'interface en ligne de commande OpenAI Codex. Il guide le processus de livraison à travers des phases d'investigation, de décomposition et de livraison, en appliquant des règles mécaniques strictes via un conteneur reproductible. Ce système introduit des portes de validation automatisées (Gates), comme la validation du graphe de dépendances, et des vérifications de portée pour garantir que chaque ticket reste atomique et ne chevauche pas d'autres travaux. Le comportement central repose sur une structure de planification rigide (frontmatter, fichiers modifiés, dépendances), une gestion des worktrees par ticket, et une intégration avec Jira pour le suivi des épopées et des tickets. Le système empêche toute création manuelle de branches ou de PRs, celles-ci étant gérées entièrement par le processus de convoyage. Shipyard vérifie également la présence d’une implémentation existante avant d’en écrire une nouvelle, réduisant ainsi le code en double. Il prend en charge les dépendances en cascade au sein d'une même phase et signale les dépendances inter-phases comme des blocages, encourageant une redécoupe. Le langage des artefacts est l’anglais, mais les réponses adressées à l’utilisateur sont dans la langue de ce dernier.

Compatible avec✓Claude Code✓Codex CLI~Cursor
npx skills add serhii-nochevnyi/shipyard

Installed? Explore more Rédaction et édition skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Règles du convoyage de livraison

Ce projet exécute un convoyage de livraison par ticket au-dessus de GSD (voir docs/gsd_multilevel_delivery_pipeline.md). Les plans font office de tickets ; ces règles les maintiennent exploitables par la couche déterministe du convoyage.

Langue. Tous les artefacts — plans, frontmatter, commits, code, corps de PR — sont rédigés en anglais. Lorsque vous vous adressez directement à l'utilisateur, répondez dans la langue de l'utilisateur ; l'anglais est réservé aux artefacts, la langue de l'utilisateur l'est pour la conversation.

Pour les planificateurs (rédaction de PLAN.md)

  1. Frontmatter complet, toujours : phase, plan, title, type, wave, depends_on: [], files_modified: [], requirements: []. Un requirements vide est un BLOCAGE — le vérificateur de plan de GSD ainsi que la Porte 2 (validate-graph) le rejettent ; référencez les identifiants d'exigence du ROADMAP, ou l'identifiant du suivi externe lorsque le plan a été importé. wave est une documentation pour le lecteur humain : le graphe fait autorité et le validateur recalcule la profondeur réelle des dépendances, avertissant lorsque votre valeur diffère. Gardez-la véridique plutôt que décorative.

  2. Bloc de livraison (additif, ne remplace jamais les champs GSD) :

    delivery:
      ticket: T-<phase>-<plan>
      risk: low|medium|high        # high REQUIERT human_checkpoint: true
      human_checkpoint: false
      repo: owner/name             # UNIQUEMENT lorsque le travail réside dans un autre dépôt
    

    repo est obligatoire pour tout ticket qui ne touche PAS à ce dépôt. Si vous l'omettez, le convoyage suit le ticket par rapport au mauvais dépôt : sa PR peut être verte et fusionnée ailleurs alors que le tableau indique pending pour toujours, et chaque ticket dépendant reste bloqué derrière un ticket qui ne bougera jamais. Les chemins dans files_modified sont alors relatifs à CE dépôt — jamais ../other-repo/x.ts, qu'aucun worktree ne peut atteindre (la Porte 2 avertit, la synchronisation d'état met le ticket en attente). Les dépendances inter-dépôts ne cascadent pas : le parent doit d'abord FUSIONNER, donc découpez le côté contrat (types/noms d'outils) dans son propre ticket plutôt que de faire attendre le consommateur pour une fonctionnalité complète.

  3. N'inventez pas de noms de branches. La branche canonique est ticket/<ID>-<slug> où le slug est le titre du ticket nettoyé (minuscules, translittéré, les caractères non alphanumériques réduits à un seul trait d'union, ≤40 caractères). Omettez delivery.branch — le validateur de graphe la génère ; une valeur explicite est validée selon la même règle.

  4. files_modified est un contrat, pas une estimation — listez chaque chemin que le plan touche. Un files_modified VIDE échoue la Porte 2 (c'est ce qui rend « les tickets sans ordre de dépendance ne se heurtent jamais » vérifiable, et c'est le périmètre de l'exécuteur). Les plans sans ordre de dépendance avec des chemins qui se chevauchent échouent également à la Porte 2 ; résolvez avec une dépendance ou une redécoupe, jamais en élargissant des globs (un glob nu qui correspond à tout est signalé).

  5. Nommez ce qui fait déjà cela, avant de planifier de l'écrire. La section Contexte de chaque plan doit soit pointer vers l'implémentation existante que le ticket étend (chemin:ligne — le transformateur, le trieur, le middleware, l'assistant, le point de terminaison qu'il construit), soit enregistrer la vérification qui n'en a trouvé aucune : quel comportement vous avez recherché et les deux ou trois emplacements plausibles que vous avez consultés. Recherchez par COMPORTEMENT, pas par le nom que vous avez l'intention de donner au nouveau code — un doublon est presque toujours déjà appelé autrement, ce qui explique pourquoi il survit à la relecture. « Je n'en ai pas vu » n'est pas la même affirmation que « J'ai regardé » ; seule la seconde est un plan qu'un lecteur peut croire. C'est la porte la moins coûteuse du convoyage : un doublon non remarqué est découvert par l'intégrateur toute une phase plus tard, après que d'autres tickets ont déjà construit dessus, et à ce moment-là, le supprimer est son propre ticket. Contrairement au §4, cela ne peut pas être vérifié par machine à partir du frontmatter — la Porte 2 ne le voit jamais, la vérification de dérive ne fait que rattraper les tickets qu'elle rejuge, donc l'écrire est le contrôle.

  6. Les commandes de vérification sont limitées au ticket, pas au projet. Écrivez les commandes les plus restreintes qui couvrent réellement files_modified — les fichiers de test ou filtres spécifiques, la vérification de type et le lint sur les chemins touchés. Un simple npm test / make test / toute la suite e2e n'est PAS une commande de vérification ici : elle appartient à l'IC, qui l'exécute une fois par push sur du matériel conçu pour cela. L'exécuteur lance celles-ci à CHAQUE tentative et les rôles de correction les relancent à chaque tour, donc une commande non limitée n'est pas lente une fois — c'est la cadence de tout le convoyage, multipliée par chaque ticket exécuté en parallèle dans son propre worktree. Deux propriétés rendent une commande utilisable : elle doit s'exécuter dans un worktree nu sans services externes, et elle doit échouer pour les erreurs de CE ticket. Une commande qui ne peut pas être limitée (une suite qui nécessite une base de données active, un navigateur, un environnement déployé) est une vérification réservée à l'IC — dites-le sous Stratégie de test et laissez-la en dehors des commandes de vérification plutôt que de donner à l'exécuteur quelque chose qu'il ne peut pas exécuter.

  7. depends_on pilote la cascade, pas seulement l'ordre. Sous une livraison empilée par épopée (par défaut), un ticket racine (depends_on vide) PR dans la branche de l'épopée de phase ; un ticket dépendant cascade — il PR dans la branche de son parent principal SANS attendre une fusion, donc le flux ne se bloque jamais. Déclarez les dépendances avec précision : une dépendance parasite sérialise le flux, une dépendance manquante donne à l'exécuteur une base incomplète. Le validateur dérive l'épopée (epic/<phase-dir>), le parent principal, et pr_base ; plusieurs parents de même phase (un diamant) reçoivent un avertissement — linéarisez lorsque c'est pratique. Gardez les dépendances à l'intérieur d'une seule phase. Une dépendance inter-phase ne peut pas cascader — il n'y a pas de branche partagée sur laquelle s'empiler — donc le ticket dépendant reste bloqué jusqu'à ce que toute la phase du parent atterrisse sur la branche par défaut. Le validateur avertit pour chacune d'elles ; recoupez plutôt.

  8. Les identifiants sont canoniques : T-<2 chiffres phase>-<2 chiffres plan>. Écrivez T-01-02, jamais T-1-2 — le validateur normalise les deux, mais les branches, les titres de PR et les libellés Jira sont comparés par chaîne partout ailleurs.

  9. Pas de commentaire # en fin de valeur. Placez un commentaire sur sa propre ligne. files_modified: [a.ts] # note avait l'habitude de plier le commentaire dans le dernier chemin ; l'analyseur le supprime maintenant correctement, mais la Porte 2 rejette encore toute valeur qui contient # car c'est presque toujours une fuite.

  10. La Porte 2 est mécanique : elle réussit uniquement lorsque le validateur de graphe existe 0. Les problèmes Jira/GitHub, ROLLOUT.md, ou les résumés en prose ne remplacent jamais les fichiers PLAN matérialisés.

  11. Jira est une projection, pas la source de vérité. Par défaut (sauf si pipeline.jira.enabled: false ou aucun MCP Jira n'est connecté) l'étape de décomposition exporte le graphe validé vers Jira (une Épopée par phase, un problème par ticket) en anglais, après la Porte 2 — jamais avant, jamais à la place. Le projet est résolu automatiquement et mis en cache ; un échec Jira ne doit pas bloquer la décomposition ; les fichiers PLAN restent canoniques.

Pour les exécuteurs (implémentation d'un ticket)

  1. Restez à l'intérieur de files_modified. Les modifications hors périmètre appartiennent à un autre ticket — escaladez plutôt que d'étendre le périmètre en silence.
  2. Lisez l'implémentation existante avant d'en écrire une nouvelle. Tout ce que le plan a nommé au §5, plus les éventuels reuse_candidates que le convoyage vous a remis depuis la vérification de dérive : lisez chacun d'abord et étendez-le plutôt que d'ajouter une couche parallèle à côté. Si un candidat ne convient vraiment pas, dites pourquoi dans votre preuve — c'est un résultat légitime, l'ignorer en silence ne l'est pas. La réutilisation ne donne jamais le droit de quitter files_modified : si construire dessus vous emmènerait hors périmètre, il s'agit d'une escalade hors périmètre (§1), pas d'un diff plus large.
  3. Commits atomiques préfixés par l'identifiant du ticket : feat(T-01-02): ….
  4. Exécutez localement les commandes de vérification du plan jusqu'au vert avant de déclarer terminé ; ne prétendez jamais à une vérification sans sortie de commande. Exécutez ces commandes — ne soyez pas « exhaustif » en les élargissant à toute la suite (§6) : l'IC possède l'exécution complète, et une suite que vous lancez ici bloque votre propre worktree et chaque autre exécuteur partageant la machine. Si les commandes du plan sont cassées ou ne couvrent clairement pas la modification, corrigez-les ou réduisez-les dans le plan et dites-le dans votre preuve ; remplacer en silence par npm test n'est pas une correction.
  5. Worktree et branche proviennent du convoyage (tickets.json) — ne créez pas de branches ou de worktrees ad hoc. Votre base PR est également résolue par le convoyage (delivery-state.json → base : la branche de l'épopée pour un ticket racine, la branche parente pour un ticket dépendant) — n'ouvrez jamais une PR directement dans main/master sous une pile d'épopées.
  6. Arrêtez-vous au commit. Ne faites pas push, n'ouvrez pas la pull request, ne touchez pas aux réviseurs. L'orchestrateur vérifie le worktree mécaniquement (git log <base>..HEAD) avant de publier quoi que ce soit — cette vérification est ce qui détecte « l'agent a signalé un succès et n'a rien changé », et elle ne fonctionne que si la publication n'est pas entre les mains de l'agent vérifié. Remettez plutôt votre preuve de vérification et un corps de PR.

Skills associés