spec-lite — spec local durable + docs synchés par changement
Une sous-procédure partagée pour les skills de l'étape Chorus (proposal, develop, yolo) — le mode spec léger, modelé sur superpowers (une spec durable qui persiste, plus des artefacts par effort) :
une spec locale durable par capacité (<slug>/spec.md, éditée sur place, jamais synchée — l'historique git en est la trace), plus un dossier daté par effort de changement (<slug>/<YYYY-MM-DD>-<change-slug>/
contenant des docs typés Chorus — prd.md, … — qui sont mirrorés 1:1 dans les Documents Chorus persistants).
Aucune nouvelle CLI, aucun outil MCP, backend ou schéma — le mirroring réutilise les outils de document existants.
Mode (comment tu es arrivé ici)
Le mode spec est calculé par le hook SessionStart (hooks/resolve-spec-mode.sh), pas par toi — la
section ## Spec Mode de ton contexte indique 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 — reviens à l'appelant. (Pour la
forme, la règle du hook : un CHORUS_SPEC_MODE explicite l'emporte, sinon OpenSpec si utilisable, sinon lite.)
La spec locale durable — <slug>/spec.md
.chorus/specs/<slug>/spec.md — <slug> (kebab-case) désigne une capacité/feature, pas un seul changement.
C'est la source unique, cumulative, lisible par humain de la capacité : éditée sur place
par chaque changement, jamais mirrorée vers Chorus, sans IDs Chorus. Frontmatter minimal uniquement
(slug, title, status: draft|active|done, created), puis prose — ## Intent,
## Requirements (prose + points d'acceptation en - [ ], pas de grammaire SHALL/scenario), ## Non-goals.
Pars du template durable spec.md en ligne ci-dessous. Son historique git est l'enregistrement complet — pas de section changelog,
pas d'aller-retour Chorus. Ce fichier N'ENTRE JAMAIS dans la boucle de mirror.
status décrit la capacité, pas un seul changement : active tant qu'un changement est en cours,
done quand le changement actuel est livré et aucun n'est ouvert. Un nouveau changement contre une capacité done
la rouvre à active, revient à 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/), par ex.
.chorus/specs/<slug>/2026-09-08-add-export/. La date + slug pour éviter les collisions de changements le même jour et
trier les dossiers 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 synchés — chacun mappe à un Document Chorus persistent de son type. Leur
frontmatter porte les IDs de sync proposalUuid et documentUuid (le type est implicite dans le
nom de fichier). Pars du template de document pour dossier daté en ligne ci-dessous. Un changement différent de la même
capacité 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 restent gelés —
tu n'édites pas en arrière un changement passé.
Deux fichiers nommés
spec.md, rôles différents. Le<slug>/spec.mddurable (local uniquement, sans IDs) n'est PAS le même qu'un doc de typespecpar changement, qui vivrait à<slug>/<date>-<slug>/spec.md(synchéé, porte les IDs). Préfèreprd.mdcomme doc principal par changement pour éviter la confusion.
Template — un document du dossier daté
Le type du document est implicite dans le nom de 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 que mode =
lite(sinon no-op). - Crée le dossier daté
<slug>/<YYYY-MM-DD>-<change-slug>/et écris ses docs synchés —prd.md(requis),tech_design.mdetc. seulement si justifié (utilise le template de document pour dossier daté ci-dessus). - Met à jour
<slug>/spec.mdsur place à la nouvelle vérité cumulative (Requirements, points d'acceptation,status) — local uniquement, pas de sync. - Crée le conteneur de proposal avec une ligne locator littérale dans
description(sa propre ligne, sans ponctuation de fin) pour que develop trouve le changement :Spec-lite: .chorus/specs/<slug>/<YYYY-MM-DD>-<change-slug>/ - Mirror 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 du changement, re-mirrorant les docs du changement au fur et à mesure que le travail arrive et en cochant les points d'acceptation. À la livraison, mets lestatus: doneduspec.mddurable.
Mirror — uniquement les docs du dossier daté (jamais spec.md)
Chaque <type>.md du dossier daté mappe à un Document Chorus persistent de ce type, tracé par
documentUuid dans le frontmatter du fichier. Remplis content à partir des bytes du fichier avec --arg-file —
ne retape jamais le corps (dérive, brûle ~20k tokens). Un appel par fichier ; résout 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 ? Reviens à chorus-mcp-call.sh + json_encode_file (openspec-aware §3.6).
<slug>/spec.md n'est JAMAIS dans cette boucle.
- Première fois qu'un doc est écrit (son dossier daté est nouveau) : écris
proposalUuiddans frontmatter, mirror 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(draftUuidretourné) avant approbation. À l'approbation, il se matérialise en Document persistant — résout par(proposalUuid, type)viachorus_get_documents, enregistredocumentUuiddans frontmatter, re-mirror une fois pour que local == Chorus. - Éditions ultérieures (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 versions est l'enregistrement du doc du 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 du changement de chaque dossier daté ; les versions auto-incrémentées des Documents mirrorés sont l'enregistrement 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'orchestrateur / agent principal
édite + re-mirror ; les workers parallèles signalent via chorus_report_work uniquement, 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.