@sylad/cadence
v1.3.0
Published
A small, repo-native working method: a versioned plan linked to your commits, a changelog with screenshots, session rituals and deliveries proven by their effect.
Readme
cadence
A small working method that lives in your repository. Solo developers and AI-assisted sessions lose track of what is left to do and what each commit was for; cadence keeps both in plain files next to the code.
Four tools:
- raf (French reste à faire, "what is left to do"): the plan, linked to your commits;
- news: a user-facing changelog with screenshots, tied to the plan;
- session: the facts to start and to close a work session;
- deliver: wait for the CI of the pushed commit, deploy, then verify the effect.
And four Claude Code skills that turn them
into rituals — session-start, session-close, deliver, and lead to pilot
several projects through subagents — plus three reviewer agents: ux-reviewer
(no user-facing change is done before its usability review) and code-reviewer
(no lot with commits is done before its code review), each behind an opt-in
gate, and qa-reviewer, which walks the delivered app in a real browser and
reports a page left empty or in error.
And a second plugin, cadence-hud: a status band above the Claude
Code prompt that shows the session's context, quota, cost and the orchestrate waves running.
Spec step (design, first steps delivered)
For a visible lot that adds a page (screen: page; a component or a journey follows the ordinary path since L209), orchestrate gets a step
before the code: a static HTML mockup in the project's own style (1440 and 390 px; empty, loading and
error states) and a machine-readable screen sheet (fields, numbered rules R1… each marked sourced
or hypothesis, actions → API calls). The ux-reviewer agent reads the mockup before any code; the
acceptance tests are written from the sheet, red, by a session other than the implementer's; the
implementation gets the sheet, the code review checks rule → test → green, the hypotheses go into the
lot's news entry, and a human is asked only about a choice that is costly to undo. The design is in
docs/superpowers/specs/2026-10-10-etape-spec-design.md (with an example sheet and the plan of the
lots that deliver it). Delivered so far: the sheet templates templates/fiche.yaml (screen) and templates/fiche-back.yaml (a lot without a screen: sujet, cas, regles, contrats, donnees), cadence spec check
(the sheet's invariants) and cadence spec qa (the screen's docs/qa/expectations.md section, derived
from the sheet), see spec below, and the spec step of orchestrate itself (the spec-writer agent, the
render at 1440 and 390 px, the commit of the spec), see The spec step in orchestrate; the accept step (red acceptance tests and the lock that protects them), see The accept step; the UX review of
the mockup (the ux-reviewer agent in mockup mode), see The mockup review; and the downstream briefs (the sheet given to implement, rule → test → green in the code review, a light UX conformity pass, the ## Hypothèses section of the news entry), see The downstream briefs.
What's new
1.3.0: the spec step's threshold is narrowed to screen: page after the measure of 2026-10-12 (no row of the success table reached, about 570 k tokens per lot): component and journey lots follow the ordinary path again (L176, L209, L210); cadence spec reseal … --porteur <lot> re-seals the unstable sealed test of a delivered lot whose contract does not change (L212); the session cap shown and followed is the human's (CADENCE_MAX_SESSIONS, L208); cadence orchestrate --waits measures slot waits (L206); a third correction pass when the review converges (L205); "e2e": true acceptations stay out of the unit runner (L203); a dropped lot fully reverted no longer blocks npm run service (L207). 1.2.0: the spec step reaches lots without a screen: a lot that declares spec: true (raf add --spec, raf spec) gets a back-end sheet of cases, rules, contracts and data (cadence spec check), reviewed before any code, then acceptance tests locked before the implementation, and raf screen lets a plan already written adopt the step; orchestrate.accept may be a list of runners (front and back), each run under its own root; cadence spec reseal <lot> <test> --reason is the lead's way out when a sealed test contradicts its unchanged sheet; lead.ux: lead lets the lead form the UX verdict itself; cadence lead tour --depth n looks for projects deeper in the folder; the budgets of a wave are recalibrated on the measured runs (750 k for an ordinary lot of 0.5 to 1 day, 1.3 M for a lot with a screen); the code in service on the cadence repository is a separate worktree, updated only by npm run service, so a wave can no longer put unreviewed code in service (L185–L189, L191, L192, L194–L198, L200, L201). 1.1.0: the spec step of cadence orchestrate: a lot that declares screen: gets a machine-readable screen sheet (cadence spec check|qa), a mockup reviewed against it, acceptance tests committed red and locked before the implementation, and briefs that carry the sheet and rule → test → green to implement, fix and the code review; the news entry gains a Hypothèses section (L166, L169–L174, L177–L184). 1.0.0: the first major release, a stable contract: the commands and options, the keys of cadence.yaml, the plan file and the names of the skills and agents follow semantic versioning, and the README's Stability section lists what is guaranteed and what is not (L164). 0.28.0: orchestrate.precheck: local runs the « deliverable already present? » pre-check of cadence orchestrate on the local model (claude-local, Ollama), off the Anthropic quota, Sonnet staying the default and the fallback (L146); the qa-reviewer agent walks only the pages a lot touched, with a Scope line in its report (L123); the sub-tasks a review closes are also read in a lot's neighbouring repositories (L156) and a commit's sub-task list is read with the plan's left guard (L155); an unstable test is fixed (L90). 0.27.1: cadence orchestrate no longer leaves a session's child processes alive: a dev server started in its own process group, or orphaned by a shell that exits (nohup srv &), is killed with the session through its process tree and its CADENCE_SESSION mark, a tmux server, screen, gpg-agent or dirmngr started on demand being spared; a session that exits with code 0 while a descendant holds its output open is no longer reported as « délai dépassé » (L83); the ux-reviewer and qa-reviewer agents carry the briefs' Playwright rule outside cadence orchestrate (L84). 0.27.0: a compliant review of cadence orchestrate settles the open sub-tasks that commits of the lot cite (feat(L3/t2): …, comma lists included), closed in the same plan commit as the verdict or, on a read-only plan, returned as [sous-tâche clore] proposals, so raf done no longer refuses a lot over sub-tasks whose work is done; on a foreign-format plan the ids are read as the plan reads them (L82); the test suite stays green with two full suites running in parallel (L150). 0.26.0: cadence orchestrate raises the floor of a lot's budget from 200 k to 450 k tokens, enough to pay a write pass, its review, one fix pass and the short review that follows, so a lot of 0.5 or 1 day is no longer handed back at its second or third pass; a --continue wave draws fewer lots as a result (L128). 0.25.0: the project line of the plans' progress in the cadence-hud band names the lots in progress after their count, three at most then … (L153, cadence-hud 0.4.2); the progress follows the folder the session was launched from, so a cd into a sub-project no longer shrinks the band, and the session context keeps the session.start folder (L154). 0.24.0: cadence orchestrate --drop <project:lot> and --stop-after-current steer a live wave from another terminal, --resume --drop removes a lot before replaying a stopped wave (L79); the final table of a wave says « livrable jusqu'à » for a ready lot stacked under a lot handed back, with git push origin <sha>:main && cadence deliver --sha <sha> (L76); a version commit (version fields, CHANGELOG.md, the README's « What's new ») no longer asks for a new code review (L72). 0.23.0: the progress bar of each project in the cadence-hud band is coloured by the share of lots done, red below 33 %, orange below 66 %, green beyond (L152, cadence-hud 0.4.1); cadence deliver under a wave lock refuses only when a lot of the wave still works in that very repository, a linked worktree included (L127). 0.22.0: cadence orchestrate --continue draws the next ready lot of the plan itself, in the declared priority, until the budget, the time window or a question stops it (L147); cadence session context prints the context of the session, which the cadence-hud band publishes, and the lead skill chains lots without the human while it stays under 60 % (L148); the band shows the progress of each project's plan, and cadence lead tour --json gains progress (L149, cadence-hud 0.4.0); the final review of a lot is always played, the lot's own budget bounding the writing passes only, with 65 k tokens reserved for it (L145); the cause « tests rouges après … » names the pass whose tests were red (L151). 0.21.0: cadence orchestrate --status and cadence lead tour print the free session slots, which the lead skill reads (L141); orchestrate.effort sets the effort level of each pass of a wave (L137); docs.sync makes raf check, lead tour and the review brief report a document that does not follow the code (L143); docs.articles opens, after a green cadence deliver, a lot Article <project> à rafraîchir in the neighbouring repository (L144). 0.20.0: cadence-hud no longer misleads once the work is over: /hud cmd lists the background commands it counts (id, tool, origin, age, name), any other argument answers argument inconnu instead of hiding the band, commands with no end seen for an hour or no record go to a grey N cmd sans fin vue, a finished subagent takes its commands with it, two races that left a 1 cmd counted forever are closed, and a finished wave shows grey without its budget then disappears after 30 minutes (L142); the qa-reviewer and ux-reviewer agents are read-only for real, their frontmatter listing Read, Grep, Glob, Bash and the Playwright tools (L140). 0.19.1: cadence-hud's N cmd counter goes back down when a Monitor expires, when the background commands a subagent started end with it, and at session start or plugin reload (L135); its tool.call and prompt.submit guard hooks carry a .catch on registration, which clears the claude plugin validate warning (L136). 0.19.0: cadence orchestrate lifts a repository's lock and pre-push guard as soon as every lot of the wave that touches it is finished, so cadence deliver works there while the wave continues elsewhere (L132); a review that leaves a repository dirty hands back that lot only, suspends the lots still queued in that repository and keeps the other repositories running, its verdict reported instead of lost (L133); cadence session close re-run without a session start keeps the window since the last opening (L131); cadence-hud draws the lot rows of a wave in aligned columns on every surface (L134). 0.18.0: cadence session next prints what it records (issue #6); cadence session close covers the period since the last session start (or the last close) and says so in its title, --since still wins (issue #7). 0.17.0: cadence-hud shows an N cmd segment next to the agents, the background commands of the session (Bash run in the background and Monitor, subagents' included), tracked from the tool results and ended by the task's notification or TaskStop. 0.16.0: a lot can declare neighbouring repositories (repos: key of the lot, { path, cite } for a repository shared between projects): cadence orchestrate refuses, locks and guards them, gives them to every session as --add-dir, and raf commits, raf show and the review verdict read the commits that cite the lot there too. 0.15.0: hook.autostart in cadence.yaml (warn by default, refuse or start): a pre-commit hook that refuses, or starts in the same commit, a lot still todo that the commit cites; cadence session start|close --all [--depth n], one section per project under a folder. 0.14.0: cadence lead tour, the lead's morning table of every project in a folder, printed by a program (one line per project: lots in progress, gaps, last notes, next ready lot, repository) in place of one subagent per project; the lead skill calls it. 0.13.1: cadence-hud takes back the segments that fit once a big one has dropped (reset times, then the per-model consumption, now short: opus 1.2M sonnet 800k); CADENCE_HUD_AMBIGUOUS=1 for a terminal that draws ▰ ▱ ⚙ │ ↻ in one cell. 0.13.0: cadence orchestrate --status --watch (a wave's table redrawn in the terminal, which
stops with the wave) and the lead skill that names the wave and follows its journal; lot ids with /
(sub-tasks of a read-only plan) accepted by orchestrate; cadence-hud's first line measured in
terminal cells and kept to ASCII; publish.yml on the v5 actions. 0.12.0: the cadence-hud plugin (a status band above the Claude Code prompt),
raf ignore to acknowledge a commit without a lot, waves that size the review to the lot,
hand back a lot whose deliverable is already there and start the app themselves for the UX
review (orchestrate.ux), and briefs that require the README to follow the change. 0.11.0: waves on different repositories run side by side under a shared cap of
simultaneous sessions (--max-sessions, 2 by default), and every release now has its
changelog section and GitHub release. 0.10.1: the QA expectations file (docs/qa/expectations.md) is kept with the plan —
a commit that only touches it no longer has to cite a lot. 0.10.0: cadence orchestrate
sends an already-committed lot straight to review, and sessions only ask questions that
name what they would change.
Every version, with what it brings and since when: CHANGELOG.md.
raf
- The plan is a YAML file in the repo (
docs/plan/raf.yaml), edited by the CLI. Your comments and hand edits are preserved. - A commit belongs to a lot when its message cites the id:
feat(L3): …,fix: L3/t1 …. The link is computed fromgit log, never stored, so committing never dirties the plan. The id is read as a whole word:XL3,L3xandL3.4do not citeL3, whileL3.at the end of a sentence does. When the subject has a scope that cites lots (feat(L3): …,chore(L31,L32): …), the scope alone decides: a passing mention (page équipe (L27)), a range (L28–L31,L45 à L48) or the body does not count. Without a scope citing a lot, the whole message is read as before. raf checkaudits drift between the plan and the history.- Plan upkeep needs no lot. A commit is plan upkeep when every file it
touches is a plan file: the plan itself, its Gantt page (only at its default place,
gantt.htmlnext to the plan — written elsewhere withraf gantt -o, declare it underplan.files), theplan:key of the config file in use (cadence.yaml, or the--configfile; a change todeliver:/session:is work), or a file the project lists underplan.filesincadence.yaml(a page it generates from the plan, a journal), or the QA expectations file (docs/qa/expectations.md, or the file named byqa.expectations; the lead commits theqa-reviewer's draft of it). Such a commit is never a "commit without a lot", and it does not count as work on the lots it cites: it is absent fromraf commits, does not start atodolot, does not make a code review stale, andcadence deliverdoes not announce the lots it cites as delivered. The files decide, never the subject: achore(plan): …commit that touches a source file is a commit like any other. raf ganttwrites a single self-contained HTML page (no server, no CDN).
npm install -g @sylad/cadence # or: npx -p @sylad/cadence raf …
raf init # docs/plan/raf.yaml + post-commit hook + .playwright-mcp/ in .gitignore
raf add "Monthly dedup on merge" --estimate 2
raf add "Typo in footer" --quickwin
raf add "Loan cache" --after L1
raf add "write the migration" --parent L1 # → L1/t1
raf start L1
git commit -m "feat(L1): dedup by calendar month"
raf now # in progress, next up (quickwins first), recently done
raf done L1/t1 && raf done L1
raf check # exit 1 on drift
raf gantt # docs/plan/gantt.htmlCommands
| Command | Effect |
|---|---|
| raf init [--project name] [--prefix L] [--no-hook] | create the plan, install the hook, add .playwright-mcp/ to .gitignore |
| raf add "title" [--estimate d] [--quickwin] [--visible [--screen page\|component\|journey]] [--spec] [--public "title"] [--after L2,L4] [--parent L3] | add a lot or a sub-task, print its id (--public: the lot's title in the public's words, written as public: right after title:; --screen: the screen a visible lot creates or changes — a new page, a new component or a modified journey — written as screen: right after visible:, shown by raf show; it requires --visible, and raf check reports a screen: without visible: or with another value as an error. Only page triggers the spec step of orchestrate (L209), never inferred from the title; --spec: the lot changes a behaviour (something a user, an API client or another service can observe), written as spec: true right after screen:, visible:, quickwin: or estimate: (whichever comes last), shown by raf show, refused on a sub-task. Also set by the lead at planning time, never inferred from the title) |
| raf add "title" --every <days> · raf did <id> ["text"] | recurring lot: every (days) and last (last time done) fields; the lot stays todo, raf now and session start list it under « Récurrent » with « dû depuis N j » / « prochain dans N j »; raf did resets the count (spec: docs/superpowers/specs/2026-10-04-L11-tache-recurrente.md) |
| raf screen <id> page\|component\|journey\|none | set, replace or remove screen: on an existing lot, to adopt the spec step on a plan already written (only page adopts the spec step; component and journey do not); refused on a lot without visible: (like raf add --screen) and on a sub-task; none removes the key and leaves visible: alone |
| raf spec <id> on\|off | set or remove spec: on an existing lot (a lot that changes a behaviour, for the back-end spec step of cadence orchestrate, see The spec step of a lot with spec: true); refused on a sub-task; off is refused on a lot that has screen: page (the page implies the spec: remove screen: first) and on there only says so and changes nothing; on component and journey (ordinary path since L209) both work and set or remove the back-end spec:. raf spec only takes on/off: cadence spec check\|qa <fiche.yaml> keeps its own subcommands. raf check reports a spec: that is neither true nor false (spec : true ou false attendu) |
| raf public <id> "title" · raf public <id> --clear | set, replace or remove the public title of a lot |
| raf start <id> · raf done <id> [--force] · raf drop <id> [--reason text] | dated transitions (done refuses open sub-tasks unless --force) |
| raf note <id> "text" | dated note — keep decisions next to the work |
| raf show <id> [--notes] | one lot: status, dates, after, public title, dated notes in order, then the counted commits (as raf commits, neighbouring repositories included); --notes prints the notes alone |
| raf commits <id> | the commits counted for a lot (the set the code review gate uses), one <sha> <subject> per line, oldest first; a lot that declares repos: (neighbouring repositories) gets, after them, one dépôt <path> : section per neighbour with the commits there that cite the lot and fall within the lot's period (started to finished) and, when the lot declares a cite: for that neighbour, contain that string (aucun commit du lot, or introuvable for a path that is not there) |
| raf now | what to do next |
| raf list [--status s] | flat list |
| raf ignore <sha> \| "exact subject" [--reason text] | acknowledge a commit without a lot (tooling chore, a plan commit citing an unknown id) without rewriting history: a dated, reasoned line in the plan's acknowledged: section; a sha is exact, a subject covers every commit carrying it |
| raf check --ignored | list the acknowledged commits with their date and reason |
| raf check [--since date] [--idle 7] | since the plan's adoption date by default (a visible lot without a public title is only a ⚠ warning: it never changes the exit code): commits without a lot (commits touching only plan files, or only version fields, CHANGELOG.md and the README's « What's new » section, are exempt), unknown ids, todo lots that already have commits, idle lots, done lots with open sub-tasks, bad or circular dependencies |
| raf gantt [-o file] | standalone Gantt page |
| raf hook install | add the post-commit hook (read-only, never blocks) and the pre-commit hook (does nothing unless hook.autostart says so, see below) |
A commit on a lot that is still todo
By default the post-commit hook only warns (L1 est encore todo — raf start L1). The hook.autostart
key of cadence.yaml changes what the pre-commit hook does when the message cites a todo lot
(a recurring lot, a lot already doing, a commit without a lot and a plan-upkeep commit are never concerned):
hook:
autostart: refuse # warn (default) | refuse | startwarn: today's behaviour, the commit goes through, the post-commit hook warns.refuse: the commit fails, loudly, withraf start <id>in the message (--no-verifystill bypasses it).start: the hook runsraf start <id>and stages the plan, so the plan change is in the same commit — no amend afterwards, no dirty plan left behind. Only whendocs/plan/raf.yamlis identical toHEAD(no uncommitted change to the plan, staged or not): otherwise nothing is started, the hook says why (plan modifié non commité : démarrage automatique sauté, raf start <id> à la main) and behaves likewarn.
The pre-commit hook reads the message from the command line of the git commit that runs it (-m, -am,
--message, -F; Linux, through /proc) or from CADENCE_COMMIT_MESSAGE. When the message is not known yet
(editor, --amend) it does nothing and the post-commit warning stays. Run raf hook install again to add the
pre-commit block to an existing repository. A read-only plan is never started by the hook. Only a refusal (exit code 3 of raf hook pre-commit) stops a commit: an older or broken raf lets it through.
Global options: --file path or RAF_FILE; RAF_TODAY=YYYY-MM-DD to freeze
the date. cadence raf … is the same as raf ….
Plan file
version: 1
project: my-app
prefix: L
since: 2026-09-28 # commits before this date are not audited
ignore: ['^chore\(batch\):'] # optional: subjects of automated commits, neither audited nor counted for a lot
lots:
- id: L1
title: Monthly dedup on merge
status: doing # todo | doing | done | dropped
estimate: 2 # working days
quickwin: false
visible: true # user-facing: a news entry is expected when done
after: [L0]
created: 2026-09-28
started: 2026-09-29
notes:
- { date: 2026-09-29, text: "keep the bank line when both sources exist" }
tasks:
- { id: t1, title: write the migration, status: done }A plan elsewhere, or in another format
cadence.yaml, at the repository root, can say where the plan is. The short form keeps raf's own
format, and the plan stays writable:
plan: planning/todo.yamlA project that publishes its plan (a JSON generated from it and committed with it) declares that file, so a commit touching only the plan and its published copy is plan upkeep; the plan keeps raf's format and stays writable:
plan:
files: [frontend/public/plan-data/plan.json]Until the file is declared, such a commit is reported as a "commit without a lot" when it cites none, and counts as work on the lots it cites.
A project that already keeps its plan with its own tool is read without migrating it: describe
the file, and raf now, raf list, raf commits, raf check, raf gantt and
cadence session start|close work on it. Such a plan is read-only —
raf add|start|done|note|ux|review refuse and leave the file to the project's tool, and the two
review gates do not apply to it (a uxSince or reviewSince written in it is ignored).
plan:
path: docs/plan/taches.yaml
project: my-app # what the file does not say itself: project, since, ignore
since: 2026-10-02
ignore: ['^plan: ']
files: [docs/plan/journal.ndjson] # kept with the plan: a commit touching only these is a plan commit
lots: taches # root key holding the list (default: lots)
fields: # raf field: key in the file (a list = first one present)
title: titre
public: titre_public # the lot's title for the public; read when it is text, else ignored
screen: ecran # page, component or journey; only on a visible lot (only `page` enters the spec step)
spec: fiche # true or false: the lot changes a behaviour
status: etat
estimate: effort
created: cree_le
started: demarre_le
finished: [livre_le, ferme_le]
notes: note
repos: depots # the lot's neighbouring repositories (a list of paths and/or { path, cite }, or one of them)
parent: parent
statuses: # raf status: their states
todo: [prevu, specifie]
doing: [en_cours, teste]
done: [deploye, valide]
dropped: caduc
estimates: { S: 0.5, M: 1, L: 3 } # their effort labels, in working days- Fields:
id,title,status,estimate,quickwin,visible,screen,spec,public,every,last,after,created,started,finished,notes,repos,parent; one left out is read under its own name. A timestamp counts for its day; a note written as plain text is one note. specis the exception to « a left-out field is read under its own name »: a read-only plan'sspec:is often the path of a spec document, so it is read only whenplan.fields.specmaps it, and then onlytruecounts (any other value is neither an error nor a spec step). Natively,spec:staystrueorfalse(L198).parent: an entryB33/t1-fusionwhose parent isB33becomes the sub-taskt1-fusionofB33.- Ids need no prefix: a commit belongs to a lot when its message cites one of the plan's ids as a
whole word (
E-A2,NC2.4,B33/t1-fusion). An id that is not in the plan cannot be told from ordinary text: such a commit counts as "without a lot", never as an unknown reference. - A state missing from
statuses, or an effort label missing fromestimates, is reported byraf check.
Gantt scheduling
One lane of work. Finished lots use their real dates (or their commits' dates);
lots in progress run until max(start + estimate, today); lots to do follow in
file order, after their dependencies, on working days.
news
What changed for the user, one entry per visible lot, each with a screenshot.
- Mark a lot as user-facing with
raf add … --visible(orvisible: truein the YAML).raf doneand the post-commit hook remind you to write its entry;raf checkfails while a visible lot is done without one. - An entry is a Markdown file in
docs/nouveautes/, with a YAML header. Screenshots are files you take yourself, stored next to the entries. cadence news buildwritesnouveautes.jsonfor your app to display, a self-containedindex.html, and copies the screenshots.
raf add "Amounts like 3.000 read as three thousand" --visible # → L8
raf start L8 && git commit -m "fix(L8): thousands separator" && raf done L8
cadence news new L8 # docs/nouveautes/2026-09-29-amounts-like-3-000-….md (title: the lot's public title if any)
# add docs/nouveautes/captures/l8.png, list it under `captures:`, write the text
cadence news check # exit 1 on drift (also part of raf check)
cadence news build -o frontend/public/nouveautes---
title: Amounts like 3.000 read as three thousand
date: 2026-09-29
created: 2026-09-29T14:32+02:00
lots: [L8]
captures: [captures/l8.png]
# nocapture: reason, when a screenshot makes no sense
---
Imported statements now read **3.000** as three thousand, not three.A screenshot can say what it shows: write it as { file, alt } instead of a
bare path, one text per screenshot.
captures:
- { file: captures/l8-before.png, alt: "Statement total read as 3 instead of 3,000" }
- captures/l8-after.png # a bare path still works: no alternative text| Command | Effect |
|---|---|
| cadence news new <lot…> [--title t] | entry skeleton, dated and timed now (date, created), titled after the lot's public title (public), else its title; --title wins |
| cadence news list | entries, newest first (see Order below) |
| cadence news check | visible lots done without entry, unknown lots, missing or undeclared screenshots, entries without creation time, bad headers, a lot whose screen sheet has hypotheses and whose entry lacks the ## Hypothèses section (or a line for one of them) |
| cadence news stamp | migration: writes created: into entries without one (or with an empty one), from the author date of the commit that added the file under its current name (now if not committed yet) |
| cadence news build [-o dir] | nouveautes.json + index.html + screenshots (default docs/nouveautes/site) |
--dir changes the entries folder (default docs/nouveautes at the git root).
The Markdown is deliberately small: headings (# to ######, rendered one level lower, <h2> to <h6>; a heading takes its own line and cuts the paragraph or list around it), paragraphs, - lists (a bullet may continue on the next lines, indented), **bold**,
`code`, [links](url); everything else is escaped text. The JSON holds
{ project, generated, entries: [{ slug, title, date, lots, captures, html }] },
with screenshot paths relative to the JSON file. captures is always a list of
paths; an entry that gives at least one alternative text also carries alts,
the texts in the same order ("" for a screenshot without one) — an entry
without any keeps exactly the shape above. The built page puts the text in the
image's alt, and falls back to "Capture : ".
Order. Everywhere (list, build, the JSON), entries are strictly newest
first: by date, then, on the same day, by creation time. Every entry carries
it to the minute in its created header, which cadence news new writes as
local time with an explicit offset (2026-09-29T14:32+02:00, or Z). The
offset is required, so the order does not depend on the machine's time zone:
news check (and raf check) flags a value without it, an impossible one, an
empty created:, and an entry without created. cadence news stamp fills
it in older entries (or replaces an empty one) from the author date of the
commit that added the file under its current name; until then, that date is
used for sorting (an entry not committed yet counts as the newest). Renames
are not followed: a renamed entry counts as added on the day of the rename,
so stamp it before renaming it. The file name only breaks the remaining ties,
since it follows the title, not the chronology. The page and the JSON still
show the day only.
UX review
raf ux enable # from today, a --visible lot needs a UX review before done
raf ux L4 "compliant after 2 fixes" # record the verdict (from the ux-reviewer agent)
raf ux L8 "no screen: calculation fix"With the rule on, raf done refuses a visible lot without a review (--force
to override) and raf check reports visible lots finished after the uxSince
day without one. An empty verdict is refused, and one left empty or blank by hand
in the YAML counts as no review. Plans without uxSince are not affected.
Code review
raf review enable # from today, a lot with commits needs a code review before done
raf commits L4 # what there is to review: the commits the gate counts for the lot
raf review L4 "compliant after 2 fixes" # record the verdict (from the code-reviewer agent)The counterpart of the UX review, off by default. With the rule on, raf done
refuses a lot that has at least one commit citing it and no recorded verdict
(--force to override), and raf check reports such lots finished after the
reviewSince day. A lot with no commit has nothing to review; neither does a
lot whose only commits touch plan files alone (the plan, a file listed under
plan.files, or the QA expectations file), are version commits (see Releasing), predate the plan's since or match an ignore: pattern — raf commits <id> prints exactly the counted set.
The verdict is tied to what was reviewed: raf review stores it on the lot with
the sha of the lot's latest counted commit (review: { date, verdict, commit },
commit: null when the lot had none). A counted commit made after that one
makes the review stale: raf done refuses (--force to override), and
raf check reports a finished lot, until the lot is reviewed again and
raf review is rerun. A verdict
written by hand without a commit field is not checked for staleness. An empty
verdict is refused, and one left empty or blank by hand in the YAML counts as no
review. Plans without reviewSince are not affected.
A lot that works in neighbouring repositories (repos:, see orchestrate)
has its verdict tied to each of them: raf review also stores, under repos, the sha of the latest counted commit of the
lot in each neighbour (the one raf commits lists last: it cites the lot, falls within the lot's period and contains the cite: string if any) (review: { date, verdict, commit, repos: { ../aetherwx-gitops: <sha> } }, null when a
neighbour has none), and refuses to record when a listed repository cannot be read. raf check does not audit the
neighbours: their staleness is not checked, only the project's own commits are.
Documentation that follows the code
A stale README misleads. cadence.yaml can declare which documents must follow which code:
docs:
sync:
- paths: [src/**, bin/*.js] # what changes…
docs: [README.md, docs/usage.md] # …must change one of these, in the same lot
- paths: [templates/]
docs: [CLAUDE.md]
- paths: [frontend/src/**, '!**/*.test.tsx'] # a pattern starting with ! leaves files out
docs: [README.md]
since: 2026-10-09 # optional: also audit lots finished on or after this dayA pattern is an exact path, with * (inside a folder), ** (across folders), ?, or a trailing / for
a whole folder. raf check takes the work commits of every lot in progress (plan-only commits and
version commits do not count — so a "What's new" line written in the version commit is not documentation; a lot finished on or after docs.since is audited too) and, for each pair, reports the lot when
those commits touch paths without any of them touching a file of docs:
✗ L7 : documentation en retard — src/a.ts, src/b.ts sans toucher README.md ou docs/usage.md (docs.sync)It counts as drift: exit code 1, shown in the dérive column of cadence lead tour, and the review
brief of cadence orchestrate (review and review-small) carries the list the program computed,
to be reported as one major finding per line — a stale document is not left to the reviewer's
memory of a sentence. Touching a document is what the program checks; whether its text is true is
still the review's reading. The commits of neighbouring repositories (repos:) are not audited.
An article elsewhere that follows the delivery
A case study that lives in a neighbouring repository (the project's article on a showcase site) goes stale
the same way. docs.articles names it:
docs:
articles:
- repo: ../claude-code-codex # neighbouring repository, relative to the project
file: src/pages/cas/demo.md # the article in it
name: demo # optional: the name in the lot title (default: the plan's project)After a green cadence deliver, for the lots it lists as delivered that have a public title (public:, or
the title of their Nouveautés entry), cadence opens in this repository's plan the lot
Article demo à rafraîchir (todo, estimate 0.5, repos: [{ path: ../claude-code-codex, cite: demo }]), with a note
that quotes the delivery, the public titles delivered, the article and the sections to read again: the headings
(# lines, or <h1>…<h6> of an Astro page) that share a word of five letters or more with a delivered title,
else all the ## headings. The lot is then played like any other, in an ordinary wave (cadence orchestrate: an
implementer rewrites the article in the neighbouring repository, the review checks it against the note). If a lot
of that title is still open, it receives a note instead of a duplicate. Two entries with the same name (the same
project told in two neighbouring repositories) share one lot, which declares both repositories in repos:. Internal lots (no public title) open nothing;
a red delivery opens nothing; cadence deliver --dry-run announces the articles. The plan is written but not
committed (deliver never commits): the line article à rafraîchir : L9 … says so. With a plan kept by another
tool (read-only), the same line carries the instruction to open the lot with that tool. This replaces the manual
sync-site-docs skill.
QA review
No gate and no command here: the QA review comes after a delivery, and
raf done does not wait for it. It follows any delivery that changes what a
page shows or what it is served (screen, API, data source, configuration of
either) — in practice every delivery except docs-, plan- or tests-only ones: a
backend-only lot can empty a page without touching a screen, and the agent then
walks the pages that call the changed endpoints. It also walks the pages that consume the services the lot changed; when the diff changes no route and no screen, or cannot be linked to pages, it walks every page and says so. The qa-reviewer agent
opens each page of the running app in a real browser and judges it from the
user's side. A page can be empty while everything else is green — no code
changed, a data source went down upstream, the unit tests replace the network,
/api/health answers ok, and the "nothing found" on screen is the message the
code was written to show.
The agent cannot tell such an empty state from a normal one by itself: the
project says what each page must show, in docs/qa/expectations.md — one
## <route> section per page, three kinds of lines:
# QA expectations
## *
- shows: the header and the navigation links
- never: "Loading failed", "Too Many Requests"
- api: /api/live/current — may be empty when no match is within 24 hours
## /players
- shows: the squad of the last match — at least 11 players
- shows: the season statistics table, 8 columns — 1440 only
- never: "No recent line-up found"
- api: /api/squad/last — a non-empty list
## /fixtures/:id (the first match linked from /fixtures)
- shows: both team names, the date, the score once the match is played
- never: "Unknown match"
- api: /api/fixtures/:idshows:— content that must be present and non-empty, with a count where one exists;never:— texts that must not appear: error messages, and empty-state messages that mean missing data;api:— the calls the page depends on: each must answer 2xx with a non-empty body (a 200 with[],{}ornullis a failure, unless its line saysmay be empty when …).
An optional ## * section holds what every page must show, never show and call. A line may end
with a condition in plain words, which the agent honours: may be empty when …, 1440 only,
390 only (a line without a width holds at both). Content hidden on the phone by design is not a
defect unless a shows: line requires it at 390; content pushed outside the visible area (it
needs a sideways scroll) is reported as suspect and handed to ux-reviewer in one line.
The rest is free text, written for a reader: a line can be repeated, and a route with a parameter names a real value to visit or says where to find one. The file can live elsewhere:
# cadence.yaml
qa:
expectations: docs/quality/pages.mdThe agent reads that key, and so does raf check: a commit touching only that file is plan upkeep (no lot to cite, see above). Without an expectations file the agent walks
the routes it discovers and still runs its universal checks: an error shown, a failed API call
whose content is missing on screen, a broken or missing content image are defects with or without a
file; an empty 2xx body, like whatever else would need an expectation to judge, is suspect at most
(it may be a normal absence). For a route with a
parameter, it finds a real value in the app's links or its API responses and says how it built the
URL. The agent then returns a draft for you to correct — it never writes the file itself.
session
cadence session start # notes from the last close, lots in progress (silent ones flagged),
# work done since yesterday by lot, drift, repo state, 3 proposals
cadence session start --since "3 days ago" --idle 2
cadence session close # commits by lot since the last `session start`,
# commits without a lot, lots in progress with no commit in that window,
# drift, uncommitted / unpushed work; exit 1 while something is still open
cadence session close --since "2 days ago" # --since overrides the window
cadence session start --all # from a folder that is not a repository: one "## project" section per
cadence session close --all --depth 2 # sub-folder holding a plan (--depth n: n levels down, 1 by default);
# exit = the worst code of the projects (2 error, 1 open, 0 closed)
cadence session next "finish L3" "review L4" # shown by the next session start; replaces the previous notes
cadence session next --clear # erase those notes, on purpose
cadence session context # `ctx 42 % (84000/200000)`: the context of YOUR session, as the cadence-hud band publishes
# it: the one named by $CLAUDE_CODE_SESSION_ID (set in Claude Code's Bash); --session <id>
# overrides it; with no variable, the folder decides only if a single session publishes for it
# (two sessions in one folder = exit 2, "pass --session"); exit 2 too when no fresh figure
# (band not loaded) = treat as at the thresholdsession start records its time in the worktree's state (session.json, under the git dir); the next
session close takes it as its window and names it in the section title: Commits de la période (depuis
l'ouverture de 09:12) (with the date when it is not today). A close never moves the boundary, refused
or not: run again without a session start in between (the session-close skill does, after fixing a
point), it still reports since that opening instead of an empty period. With no recorded opening, or an
unreadable file, the window is the current day, said as such (depuis 2026-09-28 00:00); --since is
quoted as given. (A session.json written by 0.18.0 after a close, depuis la clôture de …, is still read.)
On success cadence session next prints what it recorded (2 lignes enregistrées pour la prochaine
ouverture, then the lines as written, blank ones dropped), so session-close can report
them without running session start again.
--all runs the same command inside each project found under the current folder —
docs/plan/raf.yaml, or a cadence.yaml with plan: — and never enters a project
to look for another. --since and --idle go to every project; an error in one
project is printed in its section and the others still run. It replaces the shell
loop over the sub-folders. A project that is not the root of its own git repository gets a ✗ line
(and exit 2) instead of the parent repository's plan. --all and --depth are refused outside session (--depth is also read by cadence lead tour),
and --all refuses --file, --config and RAF_FILE: each project reads its own plan. For a one-line-per-project overview, cadence lead tour.
cadence session next without a line refuses (exit 2) and leaves the notes of the
last close as they are — it used to erase them silently; erasing is --clear.
Proposals come from the plan only: lots in progress, then ready lots (dependencies
done), quick wins first. Local state lives in the git directory, never committed:
the close notes per worktree, the delivery lock and log in .git/cadence/, shared
by all the worktrees of a clone.
A project that already has its own morning and evening scripts keeps them: name
them in cadence.yaml and their output is added to the report, under "Faits
propres au projet", before the proposals (start) or the verdict (close).
session:
start: ./scripts/morning.sh "$CADENCE_SINCE" # sh, at the repo root, 120 s at most
close: ./scripts/evening.sh "$CADENCE_SINCE"session:
clean: [ "~/projects/tmp/*", "tmp/*", "test-output-*" ] # working files to propose for removal at close
cleanDays: 7 # older than this many days (default 7)cadence session close then lists, under "Nettoyage proposé", the entries matching these
patterns (* stands for part of a name and never crosses a /; ~ is the home folder, a
relative pattern starts at the repo root) that were not modified for more than cleanDays
days, oldest first — a folder's age is that of the most recent entry it contains, at any depth,
and an entry's age runs from the later of its modification time and its status-change time (ctime):
what tar xf, cp -a or rsync -a just brought in with an old modification time is not old.
An entry is proposed only if it could be measured entirely. Never proposed:
- a git repository, a folder that contains one at any depth, and anything under a
.gitfolder; - a git directory without a
.gitentry — a bare repository (git init --bare,git clone --mirror,backup.git/), a--separate-git-dir, a worktree's admin folder —, recognised by its content as git does (HEADwithobjectsandrefs, orHEADwithcommondir): neither it, nor anything inside it, nor a folder that contains one; - anything
gittracks, in any repository that has a.gitentry above it. One limit, stated plainly: a bare repository driven with an external work tree (git --git-dir=~/.dotfiles --work-tree=~) leaves no.gitbeside the files, so its tracked files cannot be recognised and can be proposed — never point a pattern at such a work tree; - a name starting with
.unless the pattern itself starts that name with.(as in the shell,tmp/*does not matchtmp/.env;tmp/.cache-*does); - anything reached through a symbolic link matched by a
*segment: unlike the shell, the walk never descends into such a link (tmp/*/*lists nothing behindtmp/link → ../outside), and a folder's age never looks behind a link; the link itself can be proposed, as a link — removing it leaves its target alone. Only segments written in full before the first*follow a link, ascdwould (~/shared/*with~/shareda link lists the target's entries); once a*has been crossed no link is followed any more, even on a segment written in full (tmp/*/out/*withtmp/run1/out → /elsewherelists nothing behindout); - anything that could not be read entirely: a folder that cannot be listed — nor anything
inside it, even named in full —, an entry that cannot be examined or vanished during the
walk, an entry under a
.gitthatgitcould not answer for. These are listed apart, under "Nettoyage : N élément(s) illisible(s), jamais proposé(s)"; - the repository itself, or a folder that contains it.
The command deletes nothing, never fails on the cleanup and does not change the exit code: the
session-close skill shows the list and removes the entries only after the human agrees.
The commands get CADENCE_SINCE and CADENCE_TODAY. CADENCE_SINCE is the --since as given; on session close without --since it is the instant of the last session start as an ISO 8601 UTC string (2026-09-28T07:12:00.000Z), or <today> 00:00 when no mark exists.
The commands add facts and decide nothing: a failing command is reported and changes neither
the exit code nor the verdict.
lead tour
cadence lead tour [folder] [--idle 3] [--depth n] [--json] is the lead's morning table, with no model in
the loop. From a parent folder (default: the current one) it takes every direct sub-folder that
holds docs/plan/raf.yaml, or a cadence.yaml with a plan: key (a plan kept by another tool
included), and for each one reads the same facts as cadence session start — in-process, no
sub-process, no call to claude — then prints one line per project:
alpha · en cours L1 (silencieux 4j) · dérive 1 (✗ L2 a 1 commit(s) mais est encore todo) · notes : finir L1 puis livrer · prochain L3 Typo · dépôt non commité, non poussé
beta · en cours rien · dérive aucune · notes : aucune · prochain T2 Second · dépôt propre| Column | Content |
|---|---|
| en cours | ids of the lots in progress; (aucune activité) when it has none at all, (silencieux Nj) when the lot's last activity (commit, note or start) is more than --idle days old (default 3) |
| dérive | the gaps raf check reports (a lot whose commits leave a document behind, docs.sync, included), counted and the first two shown |
| notes | the notes left by the last session close, joined with / and cut at 120 characters |
| prochain | the first ready lot (quick wins first) — id and title cut at 60 characters |
| dépôt | non commité (modified or untracked files), non poussé (commits ahead of the upstream), livraison en cours (live delivery lock); propre otherwise |
When an orchestrated wave is live, one more line closes the tour (not part of --json): vagues en cours : 1 · sessions en cours : 0 · créneaux libres : 1 sur 2 — the lead reads the free slots there instead of computing them (L141). The sur M is the cap the human set (CADENCE_MAX_SESSIONS, 2 by default), not a fixed 2 (L208); an invalid value falls back to 2 in this display.
--json prints the same content as an array of objects (project, doing, drift, notes,
next, repo, and error when the project could not be read), plus progress — { done, doing, todo, added7 },
the lots done / in progress / to do (dropped and recurring lots left out) and those created in the last 7 days (L149), which
cadence-hud draws as one progress bar per project. Projects come in the order of the
priority: key of the folder's cadence.yaml (the one orchestrate --continue reads), the others after, alphabetically; an unreadable cadence.yaml or
a priority: that is not a list of names (priority: ol, priority: []) keeps the alphabetical order and adds a first row cadence.yaml · ✗ erreur : <cause> (project: "cadence.yaml" with error in --json).
Sub-projects are looked for one level down by default. --depth n goes n levels down (same meaning as in cadence session start --all --depth n:
a folder that is a project is not entered; an integer ≥ 1, otherwise refused), and the depth: key of the folder's cadence.yaml, next to priority:, sets it once for all
(depth: 2); --depth wins over the key, and a depth: that is not an integer ≥ 1 adds the same first row cadence.yaml · ✗ erreur : … and leaves one level read.
cadence-hud asks the tour from the folder of the session, so it follows the key with no change. A project is named by its folder's name; one found below the first level is named by its path from the folder (groupe/gamma), unique and ready for cadence orchestrate groupe/gamma:L1 run from there, while priority: and the alphabetical order read the folder's own name.
"Created in the last 7 days" means today and the six days before. When the folder has no sub-project but is itself a project, the tour is that project's single line
(this is what cadence-hud asks from a session opened inside a project). The tour is read-only: it changes
no plan. It exits 0 even when a project is in error — that project's line reads
beta · ✗ erreur : <cause>. The lead skill runs it instead of one subagent per project.
corrections
cadence corrections [folder] [--classify [--model m]] [--cache file] [--sample n] [--until date] [--json] measures how often a wave
has to correct itself. From the folder a wave was launched from (default: the current one) it reads the journals
<folder>/.cadence/runs/<wave>/<project>--<lot>.json of every project and prints:
- the lots with a correction: of the lots that went through a successful write session, the share with at least one
and at least two
fixpasses, per project and for visible versus non-visible lots (61 %and29 %of 263 lots in the 10-10 baseline); - the passes by cause, in total, per project and per visibility (visible lots apart from the others, with the share of
spec-floue,regle-inventeeandtest-manquantamong each one's passes — the reference an evolution aimed at screens is compared to is that of the visible lots, not « all lots »: 16 % of 45 passes against 31 % overall in the 10-10 baseline). The cause of a pass is read from the findings of the review that precedes it, among: unclear spec or missing criterion (spec-floue), invented business rule (regle-inventee), architecture drift (derive-architecture), data / SQL (donnees-sql), code bug (bug-code), missing test (test-manquant), false review finding (faux-constat). One cause per pass: the root of what forced the fix. A pass with no review finding to read (triggered by red tests right after the write session) is counted apart assans-constatand never sent to the model.
Without --classify the command calls no model: the passes not yet classified count as non classé. With --classify
each pass is classified by a local model served by Ollama (OLLAMA_HOST, default http://localhost:11434;
--model, default mistral-small3.2:24b; temperature 0, output constrained to the seven causes), off the Anthropic quota.
The classification is cached in <folder>/.cadence/corrections.json (or --cache file): a re-run classifies only the
new passes, and a pass the model could not answer stays out of the cache. --sample n prints n passes with findings spread
evenly over the sorted keys, with their findings and the model's cause, to be read by hand; a manual field written
beside a pass in the cache file (one of the seven causes, else the command refuses the file) overrides the model's cause in every table and gives the agreement rate of the model
on the reviewed sample. --until date (ISO, e.g. 2026-10-10T18:31Z) reads only the waves created up to then (created in the wave's wave.json) and, in them, only the steps ended by then (ended), so that neither later waves nor a wave still running at that time change a published baseline; a wave or a step with no readable date is left out. --json prints the measure as data. The command reads the journals and writes nothing but the cache.
The first baseline is in docs/mesures/corrections-2026-10-10.md; test/corrections-mesure.test.ts replays its command on the journals and checks the document's results word for word (skipped when the journals are not there). The measure of the screen-sheet step against the visible lots of this baseline (L176: 8 lots with a sheet, verdict per row of the success table, token cost beside the passes avoided) is in docs/mesures/etape-spec-2026-10-12.md; the target of its third row is ≤ 8 %, half the 16 % reference.
spec
cadence spec check <fiche.yaml> checks a sheet (fiche.yaml, the machine-readable output of the spec step): a screen sheet (a lot with screen:), a back-end sheet (a lot that changes a behaviour without a screen) or a mixed sheet with both parts. The screen part is designed in
docs/superpowers/specs/2026-10-10-etape-spec-design.md). Start from the template
templates/fiche.yaml (it passes the check as is), a worked example sits next to the design. It prints one
✗ … line per violation and exits 0 when the sheet is valid, 1 with violations, 2 when the file is missing, is not YAML or the usage is wrong. The invariants:
ecranhasid,titre,route(starts with/),lot,maquette, andlargeurs: [1440, 390];etatsholds at leastvide,chargement,erreur, none twice;champs[]: a unique kebab-caseid(it is also the mockup'sdata-testid),libelle,type,source, and a booleanobligatoire;regles[]are numberedR1,R2… in order with no gap; each has anetatthat is one ofetats, anenonce, amessage(the exact text on screen, ornull), astatut—sourceewith thesourceit comes from, orhypothesewith thesi_fauxthat says what would change — and at least one planned test, namedRn — …;masque(optional, only on a rule of statevide) lists the fields the rule makes disappear: every id must be a field of the sheet and none may be one the rule shows inchamps;actions[]are numberedA1… in order, theirdeclencheuris a field id (ornullfor the page load), theirappelreadsVERB /path, and thereglesthey carry exist.
Back-end sheet (L187; design: docs/superpowers/specs/2026-10-11-etape-spec-back-design.md). Start from templates/fiche-back.yaml (it passes the check as is); a worked example, a real lot of ol-companion, sits next to the design. The sheet has sujet instead of ecran (no etats, champs, mockup), and the same regles. The back-end invariants, one ✗ … line each:
sujethasid(kebab-case, the folder namedocs/specs/<id>/),titre,lot, and aperimetrewithmodules,endpointsandjobs(lists of texts, at least one entry in the three) and an optionalhors_perimetre;cas[]are numberedC1,C2… with no gap, each withtitre,acteur,declencheur,preconditions,nominal(a non-empty list of steps),resultat, andalternatives— a list of{ si, alors, regles }, each citing at least one existing rule — oralternatives: []with its reason insans_alternative; every case is cited by at least one rule;- a back-end rule has
cas(at least one existing case id) instead ofetat, plus the screen rule'senonce,statut(sourcee+source, orhypothese+si_faux) and tests namedRn — …;message,champsandmasqueonly make sense on a rule attached to a state; contrats[]are numberedA1… with no gap, each with anappel(VERB /path,job <name>orcommande <name>),entree,sortie,erreurs— a list of{ code, message }wherecodeisHTTP <n>orlog debug|log|warn|warning|error|info|critical|fatal|verboseandmessagethe exact text — orerreurs: []with its reason insans_erreur, and thereglesit carries exist;donnees[]are numberedD1…, each withobjet,note, a booleanexistantand amodification(aucune,ajoutorchangement); an existing object that is modified carries thedecisionof the lead (the answer to the targeted question). The list may be empty ([]: the lot touches no data).
Mixed sheet (a lot with screen: and a back-end part): sujet and ecran side by side, with the same id (the folder name) and the same lot. A rule is attached to a state (etat, a screen rule) or to cases (cas), at least one of the two. The A ids are shared: the actions of the screen and the contrats are numbered A1…An with no gap over the whole, and an action that calls an API already listed in contrats points to it with contrat: Ax instead of repeating its appel. An action that has its own appel equal to the appel of a contract is reported (it must point to the contract). A sheet without ecran refuses actions, etats and champs (they only make sense with a screen part), and a rule with etat there gets that single report. A sheet that only has ecran stays valid as it is (no migration); sujet is required as soon as the lot is back-end or mixed.
cadence spec check prints the same summary line for each kind (N cas, N règles (N hypothèses), N contrats, N données for a back-end sheet) and keeps its exit codes: 0 valid, 1 violations, 2 usage.
cadence spec reseal <lot> <test> --reason texte is the lead's way to correct one sealed acceptance test of the lot in progress that contradicts its (unchanged) sheet (of a delivered lot: add --porteur <lot in progress>), see The accept step.
cadence spec qa <fiche.yaml> derives from a valid sheet the section of docs/qa/expectations.md for its screen and prints it on the standard output
(it never writes the file: you paste the section, and the lead commits it like the rest of the plan files). A sheet with violations prints them on the
error output, nothing on the standard one, and exits 1. The derivation is built so that the planned empty and error states are never reported as defects:
## <route>is the screen's route;shows:— one line per mandatory field (itslibelle), except the fields that belong to a state (listed inchampsof a rule of statevideorerreur, like the empty-state message); the line of a field listed in themasqueof asourceerule of statevideends with— unless <the rule's statement>; the other fields (a static title) never get one;never:— the messages of the rules of stateerreur, on one line; the message of a rule of statevideis a planned display and never goes there;api:— the load actions only (declencheur: null) inGET(the QA pass never sends a POST); the line ends withmay be empty when <the rule's statement>when asourceerule of statevidecarries the action. Actions triggered by a field stay with the acceptance tests.
spec qa only derives the screen part: a back-end sheet, which has no ecran, is refused (exit 2, « la fiche n'a pas de partie écran »); on a mixed sheet it reads the actions' calls through their contrat.
deliver
A delivery is done when its checks pass, not when a tool says "success".
# cadence.yaml, at the repository root
deliver:
ci: github # github | none | { command: "…" } (default: none)
ciTimeout: 1800 # seconds
deploy: # sh commands, in order, at the repo root
- ./scripts/deploy.sh "$CADENCE_SHORT"
verify: # at least one; retried every 10 s until verifyTimeout
- url: https://app.example.com/api/health
status: 200 # default 200
- url: https://app.example.com/version.txt
contains: "${SHORT}"
- command: kubectl rollout status deploy/app --timeout=60s
verifyTimeout: 300
deployTimeout: 1800 # seconds, per deploy commandA public title (public:) longer than the site's Plan page accepts fails its build. Declare the limit
in cadence.yaml and it is caught before the push:
news:
publicTitleMax: 80 # characte