spec-lite — spec local durable + docs synchronisés par changement
Une sous-procédure partagée pour les skills de la phase Chorus (proposal, develop, yolo) — le mode spec léger, modélisé sur les superpowers (un spec durable qui perdure, plus des artefacts par effort) : un spec local durable par capability (.chorus/specs/<slug>/spec.md, édité sur place, jamais synchronisé — l'historique git en est la 留痕), plus un dossier daté par effort de changement (.chorus/specs/<slug>/<YYYY-MM-DD>-<change-slug>/ de docs typés Chorus — prd.md, … — qui sont mirrorés 1:1 dans Chorus Documents persistants). Aucune nouvelle CLI, outil MCP, backend, ou schema — le mirroring réutilise les outils de document existants.
Mode (comment vous êtes arrivé ici)
Le mode spec est calculé par le handler session_start de l'extension chorus-pi (resolveSpecMode), pas par vous — la section ## Spec Mode de votre contexte injecté indique le CHORUS_SPEC_MODE résolu. Vous êtes ici parce qu'il s'est résolu à lite ; s'il est différent, ce skill est un no-op — retournez à l'appelant. (Pour info, la règle : un CHORUS_SPEC_MODE explicite gagne, sinon OpenSpec si utilisable, sinon lite.)
Le spec local durable — <slug>/spec.md
.chorus/specs/<slug>/spec.md — <slug> (kebab-case) nomme une capability/feature, pas un changement. C'est la vérité « actuelle » unique, cumulative et lisible par l'humain de la capability : éditée sur place par chaque changement, jamais mirrorée à Chorus, ne porte aucun id Chorus. Frontmatter minimal uniquement (slug, title, status: draft|active|done, created), puis prose simple — ## Intent, ## Requirements (prose + points d'acceptation - [ ], pas de grammaire SHALL/scenario), ## Non-goals. Partez du template spec.md durable inline ci-dessous. Son historique git est le record complet — aucune section changelog, aucun aller-retour Chorus. Ce fichier N'ENTRE JAMAIS dans la boucle de mirror.
status décrit la capability, pas un changement unique : active tant que un changement est en cours, done quand le changement actuel est livré et aucun n'est ouvert. Un changement nouveau sur une capability done la réouvre à active, retour à done à la livraison.
Template — le spec.md durable
---
slug: <capability-en-kebab-case>
title: <Titre de la capability>
status: draft # draft | active | done
created: <YYYY-MM-DD>
---
## Intent
<à quoi sert cette capability, en prose>
## Requirements
<prose, pas de grammaire SHALL/scenario>
- [ ] <point d'acceptation>
## Non-goals
- <explicitement hors de portée>
Dossiers datés par changement — <slug>/<YYYY-MM-DD>-<change-slug>/
Chaque effort de changement est un dossier daté directement sous <slug>/ (pas de wrapper changes/), par ex. .chorus/specs/<slug>/2026-09-08-add-export/. Date + slug pour que les changements du même jour ne se heurtent pas et les dossiers se trient par date. Il contient les docs typés Chorus pour CE changement — un fichier par type de Document :
| Fichier | Document.type |
Requis ? |
|---|---|---|
prd.md |
prd |
oui — le doc principal par changement |
tech_design.md |
tech_design |
optionnel — le « comment » |
adr.md / guide.md / spec.md |
adr / guide / spec |
optionnel |
Ces fichiers SONT synchronisés — chacun mappe à un Document Chorus persistant de son type. Leur frontmatter porte les ids de sync proposalUuid et documentUuid (le type est impliqué par le nom de fichier). Partez du template de document dossier daté ci-dessous. Un changement différent à la même capability est un dossier daté différent. Le dossier du changement actuel est édité et re-mirroré tout au long de son effort (jusqu'à la livraison) ; seuls les dossiers datés précédemment livrés sont laissés gelés — vous ne revenez pas en arrière et ne réécrivez pas un changement passé.
Deux fichiers nommés
spec.md, rôles différents. Le<slug>/spec.mddurable (local uniquement, pas d'ids) N'EST PAS le même qu'un docspec-type par changement, qui vivrait à<slug>/<date>-<slug>/spec.md(synchronisé, porte des ids). Préférezprd.mdcomme doc principal par changement pour éviter la confusion.
Template — un document de dossier daté
Le type de document est impliqué par le nom de fichier (prd.md → prd, tech_design.md → tech_design, …), PAS une clé frontmatter.
---
title: <Titre du document tel qu'il apparaît dans Chorus>
proposalUuid: <uuid> # écrit au premier mirror
documentUuid: # vide jusqu'à ce que le brouillon se matérialise à l'approbation
---
# <Titre du document>
<body — les bytes de ce fichier sont la source de vérité pour le Document Chorus>
Flow (un changement)
- Confirmez mode =
lite(sinon no-op). - Créez le dossier daté
<slug>/<YYYY-MM-DD>-<change-slug>/et écrivez ses docs de changement synchronisés —prd.md(requis),tech_design.mdetc. seulement si justifié (utilisez le template de document dossier daté ci-dessus). - Mettez à jour
<slug>/spec.mdsur place avec la nouvelle vérité cumulative (Requirements, points d'acceptation,status) — local uniquement, pas de sync. - Créez le conteneur de proposal avec une ligne de localisateur littérale dans
description(propre ligne, pas de ponctuation finale) pour que develop trouve le changement :Spec-lite: .chorus/specs/<slug>/<YYYY-MM-DD>-<change-slug>/ - Mirrorez les docs du dossier daté à Chorus (ci-dessous). Ajoutez des tasks via
chorus_pm_add_task_draft— pas detasks.md, pas de CLI / validate / archive, pas de grammaire delta. Les tasks vivent dans Chorus. - Develop → continuez à éditer
spec.md+ les docs du changement, en re-mirrorant les docs du changement à mesure que le travail avance et en cochant les points d'acceptation. À la livraison, réglez lestatus: doneduspec.mddurable.
Mirror — seulement les docs du dossier daté (jamais spec.md)
Chaque <type>.md du dossier daté mappe à un Document Chorus persistant de ce type, tracé par documentUuid dans le frontmatter du fichier. Remplissez content à partir des bytes du fichier avec --arg-file — ne retapez jamais le body (dérive, brûle ~20k tokens). Un appel par fichier ; résolvez l'identité par documentUuid / (proposalUuid, type), jamais par title seul (une recherche trouvant zéro ou >1 DOIT s'arrêter). Gardez chaque appel avec le helper chorus_check_response halt-on-error (openspec-aware §6). Pas de chorus sur PATH ? Revenez à chorus-mcp-call.sh + json_encode_file (openspec-aware §3.6) ; l'extension résout le wrapper regroupé et expose son chemin dans le contexte session_start. <slug>/spec.md N'EST JAMAIS dans cette boucle.
- Première fois qu'un doc est écrit (son dossier daté est nouveau) : écrivez
proposalUuiddans le frontmatter, mirrorez dans un brouillon de proposal —chorus mcp call chorus_pm_add_document_draft "{\"proposalUuid\":\"$P\",\"type\":\"prd\",\"title\":\"PRD: $TITLE\"}" --arg-file content=".chorus/specs/$SLUG/$DATED/prd.md". Éditez le brouillon viachorus_pm_update_document_draft(draftUuidretourné) avant approbation. À l'approbation, il se matérialise en Document persistant — résolvez par(proposalUuid, type)viachorus_get_documents, enregistrezdocumentUuiddans le frontmatter, re-mirrorez une fois pour que local == Chorus. - Éditions ultérieures (un doc qui a déjà un
documentUuid) : éditez le fichier, puischorus mcp call chorus_pm_update_document "{\"documentUuid\":\"$D\"}" --arg-file content=".chorus/specs/$SLUG/$DATED/<type>.md". Chaque update auto-incrémente la version du Document — cet historique de version est le record du doc de changement dans Chorus, aux côtés de git.
留痕 : historique git + versions de Document
git log -- .chorus/specs/$SLUG/ est la piste d'audit — les diffs sur place du spec.md durable plus les docs de changement de chaque dossier daté ; les versions auto-incrémentées des Documents mirrorés sont le record parallèle dans Chorus. Aucune section changelog à maintenir. Seul .chorus/specs/ est versionné (.chorus/* + !.chorus/specs/).
Single-writer : le dossier est partagé — dans une vague multi-tâche, seul l'orchestrator / agent principal édite + re-mirroe ; les workers parallèles rapportent via chorus_report_work uniquement, en relisant avant chaque write. L'état de la task vit dans Chorus, pas dans les docs — les points - [ ] sont l'intention d'acceptation, pas un tracker.