spec-lite — spec durable local + docs synchronisés par changement
Une sous-procédure partagée pour les skills de stage Chorus (proposal, develop, yolo) — le mode
spec léger, inspiré par superpowers (un spec durable qui persiste, plus des artefacts par effort) :
un spec durable local par capacité (<slug>/spec.md, édité sur place, jamais synchronisé — l'historique git est sa piste d'audit), plus un dossier daté par effort de changement (<slug>/<YYYY-MM-DD>-<change-slug>/
de docs typés Chorus — prd.md, … — qui sont mirrorés 1:1 dans Chorus Documents persistants).
Aucun CLI, outil MCP, backend ou schéma nouveau — le mirroring réutilise les outils de document existants.
Mode (comment tu es arrivé ici)
Le mode spec est calculé par le check-in session-start du plugin Chorus Hermes (pre_llm_call)
(spec_mode.py), pas par toi — la section ## Spec Mode de ton contexte injecté énonce le
CHORUS_SPEC_MODE résolu. Tu es ici parce qu'il a résolu à lite ; s'il est autre chose, ce skill est un no-op — retourne à l'appelant. (Pour info, la règle : un CHORUS_SPEC_MODE explicite gagne, sinon OpenSpec quand possible, sinon lite.)
Le spec durable local — <slug>/spec.md
.chorus/specs/<slug>/spec.md — <slug> (kebab-case) nomme une capacité/feature, pas un changement.
C'est la source unique, cumulative, lisible humainement de la capacité : éditée sur place
par chaque changement, jamais mirrorée vers Chorus, ne porte aucun id Chorus. Frontmatter minimal seulement
(slug, title, status: draft|active|done, created), puis prose — ## Intent,
## Requirements (prose + - [ ] points d'acceptation, pas de grammaire SHALL/scénario), ## Non-goals.
Commence par le template spec.md durable inline ci-dessous. Son historique git est le registre complet — pas de section changelog, pas d'aller-retour Chorus. Ce fichier N'ENTRE JAMAIS dans la boucle de mirroring.
status décrit la capacité, pas un changement unique : active tant qu'un changement est en cours,
done quand le changement courant est livré et aucun n'est ouvert. Un nouveau changement sur une capacité done la rouvre à active, retour à done à la livraison.
Template — le spec.md durable
---
slug: <kebab-case-capability>
title: <Capability title>
status: draft # draft | active | done
created: <YYYY-MM-DD>
---
## Intent
<what this capability is for, in prose>
## Requirements
<prose, no SHALL/scenario grammar>
- [ ] <acceptance point>
## Non-goals
- <explicitly out of scope>
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/), p. 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 vers un Chorus Document persistant de son type. Leur
frontmatter porte les ids de sync proposalUuid et documentUuid (le type est implicite au nom du fichier).
Commence par le template de document de dossier daté ci-dessous. Un changement différent à la même
capacité est un dossier daté différent. Le dossier du changement courant est édité et re-mirroré
tout au long de son effort (jusqu'à la livraison) ; seuls les dossiers datés précédemment livrés restent gelés —
tu ne réécrits pas un changement passé.
Deux fichiers nommés
spec.md, rôles différents. Le<slug>/spec.mddurable (local seulement, 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èreprd.mdcomme doc principal par changement pour éviter la confusion.
Template — un document de dossier daté
Le type de document est implicite au nom du fichier (prd.md → prd, tech_design.md → tech_design, …),
PAS une clé frontmatter.
---
title: <Document title as it appears in Chorus>
proposalUuid: <uuid> # written on first mirror
documentUuid: # empty until the draft materializes on approval
---
# <Document title>
<body — this file's bytes are the source of truth for the Chorus Document>
Flow (un changement)
- Confirme mode =
lite(sinon no-op). - Crée le dossier daté
<slug>/<YYYY-MM-DD>-<change-slug>/et écris ses docs de changement synchronisés —prd.md(requis),tech_design.mdetc. seulement si justifié (utilise le template de document de dossier daté ci-dessus). - Mets à jour
<slug>/spec.mdsur place vers la nouvelle vérité cumulative (Requirements, points d'acceptation,status) — local seulement, pas de sync. - Crée le conteneur de proposal avec une ligne de localisateur littérale dans
description(ligne propre, pas de ponctuation traînante) pour que develop trouve le changement :Spec-lite: .chorus/specs/<slug>/<YYYY-MM-DD>-<change-slug>/ - Mirrore les docs du dossier daté vers Chorus (ci-dessous). Ajoute des tâches via
chorus_pm_add_task_draft— pas detasks.md, pas de CLI / validate / archive, pas de grammaire delta. Les tâches vivent dans Chorus. - Develop → continue à éditer
spec.md+ les docs de changement, re-mirrorant les docs de changement au fur et à mesure que le travail avance et cochant les points d'acceptation. À la livraison, définis lestatus: doneduspec.mddurable.
Mirroring — seulement les docs de dossier daté (jamais spec.md)
Chaque <type>.md de dossier daté mappe vers un Chorus Document persistant de ce type, suivi par
documentUuid dans le frontmatter du fichier. Remplis content depuis les bytes du fichier avec --arg-file —
ne retype jamais le corps (dérive, brûle ~20k tokens). Un appel par fichier ; résous l'identité par
documentUuid / (proposalUuid, type), jamais par title seul (une lookup trouvant zéro ou >1 DOIT
halter). Garde chaque appel avec le helper chorus_check_response halt-on-error (openspec-aware
§6). Pas de chorus sur PATH ? Bascule vers l'outil MCP natif (mcp__chorus__chorus_pm_add_document_draft /
mcp__chorus__chorus_pm_update_document) avec content lu depuis le fichier via read_file (openspec-aware
§3.6) — il n'y a pas de wrapper shell bundlé sur Hermes.
<slug>/spec.md N'EST JAMAIS dans cette boucle.
- Première fois qu'un doc est créé (son dossier daté est nouveau) : écris
proposalUuiddans le frontmatter, mirrore dans un draft 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". Édite le draft viachorus_pm_update_document_draft(retournédraftUuid) avant approbation. À l'approbation il se matérialise en un Document persistant — résous par(proposalUuid, type)viachorus_get_documents, enregistredocumentUuiddans le frontmatter, re-mirrore une fois pour que local == Chorus. - Édits ultérieurs (un doc qui a déjà un
documentUuid) : édite 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 registre du doc de changement dans Chorus, aux côtés de git.
Piste d'audit : historique git + versions de Document
git log -- .chorus/specs/$SLUG/ est la piste d'audit — les diffs du spec.md durable sur place plus chaque dossier daté de changement ; les versions auto-incrémentées des Documents mirrorés sont le registre parallèle dans Chorus. Aucune section changelog à maintenir. Seul .chorus/specs/ est versionné (.chorus/* +
!.chorus/specs/).
Writer unique : le dossier est partagé — dans une vague multi-tâche seul l'orchestrateur / agent principal
édite + re-mirrore ; les workers parallèles rapportent via chorus_report_work seulement, relisant avant toute écriture.
L'état des tâches vit dans Chorus, pas dans les docs — les points - [ ] sont l'intention d'acceptation, pas un tracker.