@evolvehq/docflow 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -80,8 +80,10 @@ set keeps numbering contiguous **per repo** while a federation-wide
80
80
  identity is the cross-repo key. The `rollup` skill aggregates every
81
81
  member's catalogue into one product-wide view, and `audit` gains
82
82
  cross-repo checks (membership, identity collisions, dangling references,
83
- roll-up drift). No tool writes across a repo boundary; consistency is
84
- declared at the edges and enforced by audit. See the
83
+ roll-up drift, convention drift). Work and status cross repos the same way:
84
+ a cross-repo decision is one plan item per affected repo, and its aggregate
85
+ status ("2 of 3 repos") surfaces in the roll-up. No tool writes across a
86
+ repo boundary; consistency is declared at the edges and enforced by audit. See the
85
87
  [methodology](https://evolvehq.github.io/docflow/methodology/#5-scaling-to-many-repositories)
86
88
  for the full model.
87
89
 
package/USAGE.md CHANGED
@@ -239,6 +239,7 @@ picks; a fully-specified request lets you skip straight through.
239
239
  | `/audit` | Lints the repo against its own conventions and reports a punch list — numbering, INDEX sync, plan coverage, section completeness, status validity, cross-refs, language mandate, and **ADR-privacy leaks into user-visible code**. Offers to fix the mechanical issues. |
240
240
  | `/brainstorm` | Decomposes a problem into candidate ADRs + plan items with dependency edges and ordering. Proposes drafts only; writes nothing until approved, then hands off to `/new-adr` and `/new-plan`. |
241
241
  | `/agent-wave` | Orchestrates parallel worktree subagents over the queue. Asks wave width, budget (items/waves; hours as a soft cap), and supervision (checkpoint vs. continuous). Requires multi-agent mode; refuses mode 1. |
242
+ | `/rollup` | For a **multi-repo product**: from the home repo, aggregate every member repo's `INDEX` into one derived, product-wide roll-up. Members not checked out are listed as "not aggregated this run". |
242
243
 
243
244
  ### agent-wave: what it can and can't do
244
245
 
@@ -254,6 +255,40 @@ It requires a multi-agent mode (Q5 mode 2 or 3) and works best in mode
254
255
  Continuous-unsupervised runs are recommended only with PR-based
255
256
  integration, so CI gates each merge.
256
257
 
258
+ ### Multi-repo products (federation)
259
+
260
+ A single product spread across several repos runs as a **federation**.
261
+ Bootstrap asks whether the repo is standalone or part of a multi-repo
262
+ product, and — if the latter — whether it is **establishing** a new
263
+ federation or **joining** an existing one. A joining repo writes only its
264
+ own `federation.md` back-pointer; it never writes into another repo, and
265
+ it inherits the topology and identity scheme rather than re-choosing them.
266
+
267
+ - **Topology** (chosen at establishment): a central decisions repo · a
268
+ distributed set · or a home repo with local decisions alongside (the
269
+ default).
270
+ - **Identity & numbering.** Numbering stays contiguous *per repo*; a
271
+ federation-wide identity — by default a repo-prefixed slug
272
+ `<repo-id>/NNNN-slug` — is the cross-repo key, so two repos never
273
+ collide.
274
+ - **References.** Cross-repo links use the logical identity, resolved via
275
+ the home's `federation-index.md`; same-repo links stay relative.
276
+ - **Work & status.** A cross-repo decision is one plan item **per affected
277
+ repo**, each tracing to the owning ADR by its federation identity (no
278
+ umbrella record); the decision's aggregate status ("2 of 3 repos") is a
279
+ derived roll-up column, `Implemented` only when every per-repo item ships.
280
+ - **`/rollup`** aggregates every member's catalogue into one product-wide
281
+ view; **`/audit`** gains cross-repo checks (bidirectional membership,
282
+ identity collisions, dangling references, roll-up drift, convention
283
+ drift).
284
+ - **Conventions** are copied at bootstrap and kept honest by audit
285
+ drift-detection — referenceable from the home, never force-pushed.
286
+
287
+ No tool writes across a repo boundary: consistency is declared at the
288
+ edges and enforced by audit. See the
289
+ [methodology](https://evolvehq.github.io/docflow/methodology/#5-scaling-to-many-repositories)
290
+ for the formal model.
291
+
257
292
  ### Enabling an optional convention later (worked example: TDD)
258
293
 
259
294
  docflow's bootstrap is deliberately lean — practices such as
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@evolvehq/docflow",
3
- "version": "0.9.0",
4
- "description": "ADR-driven documentation workflow: scaffold an Architecture Decision Record (ADR) catalogue, a plan/ queue, and AGENTS.md conventions into any repo, then author, queue, ship, and audit ADRs with lifecycle skills. Works with the pi coding agent and Claude Code.",
3
+ "version": "0.9.2",
4
+ "description": "ADR-driven documentation workflow: scaffold an Architecture Decision Record (ADR) catalogue, a plan/ queue, and AGENTS.md conventions into any repo, then author, queue, ship, audit, and roll up ADRs with lifecycle skills — across one repo or a multi-repo product. Works on Claude Code, Claude Cowork, pi, Codex, and OpenCode.",
5
5
  "keywords": [
6
6
  "pi-package",
7
7
  "adr",
8
8
  "architecture-decision-records",
9
9
  "documentation",
10
- "claude-code"
10
+ "claude-code",
11
+ "multi-repo"
11
12
  ],
12
13
  "license": "MIT",
13
14
  "author": "Eugenio Minardi",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: audit
3
- description: Audit a documentation-led repo against its own conventions — contiguous ADR numbering, INDEX sync, plan/ coverage, required sections, status validity, cross-reference resolution, language mandate, ADR-privacy leaks into user-visible code, cross-worktree collisions (duplicate numbers, duplicate plan ownership, same ADR edited on two branches), and — for a multi-repo product — cross-repo federation checks (bidirectional membership, identity collisions, dangling cross-repo references, roll-up drift). Reports a punch list and offers to fix the mechanical issues. Use when the user says "audit the ADRs", "lint the conventions", "check repo consistency", "are the ADRs in sync", or invokes /audit.
3
+ description: Audit a documentation-led repo against its own conventions — contiguous ADR numbering, INDEX sync, plan/ coverage, required sections, status validity, cross-reference resolution, language mandate, ADR-privacy leaks into user-visible code, cross-worktree collisions (duplicate numbers, duplicate plan ownership, same ADR edited on two branches), and — for a multi-repo product — cross-repo federation checks (bidirectional membership, identity collisions, dangling cross-repo references, roll-up drift, convention drift). Reports a punch list and offers to fix the mechanical issues. Use when the user says "audit the ADRs", "lint the conventions", "check repo consistency", "are the ADRs in sync", or invokes /audit.
4
4
  ---
5
5
 
6
6
  # audit
@@ -16,9 +16,10 @@ This is the enforcement `AGENTS.md` cannot guarantee on its own.
16
16
  language mandate, optional artefacts present (GLOSSARY, domains/),
17
17
  and any Q10 domain hard rules.
18
18
  3. If a `federation.md` exists, this repo is part of a multi-repo
19
- product. Note whether it is the **home** or a **member** and read the
20
- recorded identity scheme; the cross-repo checks (check 12) run from
21
- the home repo.
19
+ product. Note its `Role` (`central` / `home` / `coordinator`
20
+ index-holder, or a plain `member`) and read the recorded identity
21
+ scheme; the cross-repo checks (check 12) run from the index-holding
22
+ repo.
22
23
 
23
24
  ## Step 1 — Run the checks (read-only)
24
25
 
@@ -67,22 +68,35 @@ relevant):
67
68
  Cross-check against `_agent/IN_FLIGHT.md`: every collision should
68
69
  correspond to a reservation/ownership violation recorded there.
69
70
  12. **Cross-repo (federation) checks** — only when a `federation.md`
70
- exists; run from the **home** repo. Reach each member through the
71
- local checkout named in `federation-index.md`. A member not checked
71
+ exists; run from the **index-holding** repo (`Role: central`, `home`,
72
+ or `coordinator` whichever holds `federation-index.md`). Reach each
73
+ member through the local checkout named in `federation-index.md`. A member not checked
72
74
  out locally is reported **"unverified this run"** — never silently
73
75
  passed, never a hard failure.
74
76
  - **Bidirectional membership.** Every repo listed in the member index
75
- carries a `federation.md` back-pointer to this home, and every repo
76
- whose back-pointer names this home is listed in the index. Flag
77
- either half-edge (in-index-without-back-pointer, or
78
- points-home-but-unlisted).
79
- - **Identity collisions.** No two ADRs across the federation resolve
80
- to the same identity under the recorded identity scheme.
81
- - **Dangling cross-repo references.** Every cross-repo link resolves
82
- to a real ADR in the named member; flag a target that does not
83
- exist. (Same-repo relative links are check 7.)
77
+ carries a `federation.md` back-pointer to this index-holder, and
78
+ every repo whose back-pointer names this repo is listed in the
79
+ index. Flag either half-edge (in-index-without-back-pointer, or
80
+ points-here-but-unlisted).
81
+ - **Identity collisions.** Under the repo-prefixed scheme an identity
82
+ is `repo-id` + local number, so the only reachable collision is a
83
+ **duplicate `repo-id`**. Flag any repo-id that appears on more than
84
+ one `federation-index.md` row or in two members' `federation.md`
85
+ back-pointers.
86
+ - **Dangling cross-repo references.** Resolve each cross-repo link
87
+ along `repo-id → Pointer → adr/NNNN-*.md` — look up the repo-id's
88
+ Pointer in `federation-index.md`, then the ADR file under that repo.
89
+ A repo-id with **no index row** is a dangling reference. If the row
90
+ exists but the **checkout is absent**, report it **"unverified this
91
+ run"** (not dangling); only an **absent ADR in a present checkout**
92
+ is a true dangling reference. (Same-repo relative links are
93
+ check 7.)
84
94
  - **Roll-up drift.** The roll-up agrees with each member's `INDEX.md`
85
95
  metadata; flag rows that are stale, missing, or extra.
96
+ - **Convention drift.** Compare each member's **shared** conventions
97
+ against the index-holder's authoritative copy; flag a member whose
98
+ shared conventions have drifted from the source. Members' **local-only**
99
+ conventions are exempt.
86
100
 
87
101
  ## Step 2 — Report
88
102
 
@@ -60,8 +60,10 @@ questions.
60
60
  For a **multi-repo product** (one product spread across several repos —
61
61
  see Q11), two extra files appear: `federation.md`, a small back-pointer
62
62
  every member repo carries, and `federation-index.md`, the authoritative
63
- member list that lives only in the home/establishing repo. A standalone
64
- repo has neither.
63
+ member list that lives only in the home/establishing repo. All federation
64
+ artefacts `federation.md`, `federation-index.md`, and the derived
65
+ roll-up `ROLLUP.md` — are placed under the **configured artefact root**.
66
+ A standalone repo has none of them.
65
67
 
66
68
  ## Step 3 — Conventions to install
67
69
 
@@ -246,12 +248,14 @@ lines and ask for sign-off before writing any files.
246
248
  The scheme is recorded in the federation config and applied by the
247
249
  authoring skills.
248
250
 
249
- **Establish** designates this repo as the home/central repo, writes
250
- the member index here, and records the topology **and identity
251
- scheme** in the federation config. **Join** asks for the home pointer **you confirm it; the
252
- skill performs no cross-repo read and no host API call** then
253
- writes **only this repo's** back-pointer config and inherits the
254
- topology without re-asking it. Joining never writes into any other
251
+ **Establish** sets this repo's role from the chosen topology
252
+ **central** (A), **coordinator** (B), or **home** (C) writes the
253
+ member index here, and records the topology **and identity scheme**
254
+ in the federation config. **Join** asks for the home pointer **and the federation's topology +
255
+ identity scheme** **you supply them; the skill performs no
256
+ cross-repo read and no host API call** — then writes **only this
257
+ repo's** back-pointer config, recording those values (it does not
258
+ re-choose the topology). Joining never writes into any other
255
259
  repo; adding this repo to the member index is a deliberate edit in
256
260
  the home repo. A standalone repo (Q11 = No) writes none of these
257
261
  files and behaves exactly as a single-repo bootstrap.
@@ -326,18 +330,30 @@ write it into the repo.
326
330
  configured artefact root (repository root by default).
327
331
  - **Establish:** write `federation-index.md` (the member index, a
328
332
  Markdown table) from `templates/federation-index.md` into this
329
- repo, seeded with this repo as the home member; and write
330
- `federation.md` from `templates/federation-config.md` with
331
- `Role: home`, the chosen topology, and the chosen identity scheme
332
- (default repo-prefixed slug). Record the identity scheme in both
333
- files so it is the same on every read.
333
+ repo, seeded with this repo as the first member; and write
334
+ `federation.md` from `templates/federation-config.md` with the
335
+ chosen topology, the chosen identity scheme (default repo-prefixed
336
+ slug), and this repo's **`Role` set from the topology**:
337
+ `central` for **A** (this repo holds all product-wide ADRs),
338
+ `coordinator` for **B** (this repo holds only the member index —
339
+ product-wide decisions are distributed and the roll-up is the
340
+ product-wide view), or `home` for **C** (this repo holds
341
+ product-wide ADRs; members keep local ADRs alongside). Record the
342
+ identity scheme in both files so it is the same on every read.
334
343
  - **Join:** write **only** `federation.md` from
335
344
  `templates/federation-config.md` with `Role: member`, the
336
345
  confirmed home pointer, and the topology **and identity scheme**
337
- inherited from the federation (read them from the home, do not
338
- re-ask). Write nothing into any other repo, and do **not** create a
339
- member index. Tell the user to add this repo to the home repo's
340
- `federation-index.md` (a deliberate edit there).
346
+ for the federation, **supplied by the operator at join** (recorded
347
+ into this repo's `federation.md`; no cross-repo read). Then apply
348
+ the **topology's member rule**: for **A**, this
349
+ repo references the central repo and does **not** hold product-wide
350
+ ADRs locally (its `adr/` is for local-implementation decisions
351
+ only); for **B**, this repo owns its own catalogue in full; for
352
+ **C**, this repo keeps local ADRs and references the home for
353
+ product-wide ones. Write nothing into any other repo, and do **not**
354
+ create a member index. Tell the user to add this repo to the
355
+ **index-holding repo's** `federation-index.md` — the home (C),
356
+ central (A), or coordinator (B) repo — a deliberate edit there.
341
357
 
342
358
  Commit each file (or logical group) with a Conventional Commit message;
343
359
  no `Co-Authored-By` trailer unless Q6 asked for one.
@@ -177,13 +177,27 @@ This repo belongs to the **<product>** federation. Topology and the
177
177
  identity scheme are recorded in `federation.md`; the home repo's
178
178
  `federation-index.md` is the authoritative member list.
179
179
 
180
+ - **Where product-wide decisions live depends on the topology** (recorded
181
+ in `federation.md`):
182
+ - **A — central:** a single central repo holds **all** product-wide
183
+ ADRs; every other repo references them and never duplicates a
184
+ product-wide decision locally.
185
+ - **B — distributed:** **no** repo holds product-wide ADRs; each repo
186
+ owns its own catalogue and the roll-up is the product-wide view.
187
+ - **C — home + local:** the home repo holds product-wide ADRs; members
188
+ keep purely-local ADRs alongside and reference the home for
189
+ product-wide ones.
180
190
  - **Numbering is per-repo contiguous.** Each member repo numbers its own
181
191
  ADRs contiguously from `0001`; numbers are **not** unique across the
182
192
  federation. The cross-federation key is the **identity scheme** recorded
183
193
  in `federation.md` — default repo-prefixed slug `<repo-id>/NNNN-slug`.
184
194
  - **Cross-repo references use the logical identity**, resolved through the
185
- member index (`repo-id → location`); they survive a target repo move
186
- (edit one index row, not the references). **Same-repo references stay
195
+ member index along `repo-id → Pointer (repo root) adr/NNNN-*.md`: look
196
+ up the repo-id's `Pointer` in `federation-index.md`, then find
197
+ `adr/NNNN-*.md` under that repo. They survive a target repo move (edit
198
+ one index row, not the references). A **member repo holds no index**, so
199
+ it first reaches `federation-index.md` via its own `federation.md`
200
+ `Home` pointer, then resolves as above. **Same-repo references stay
187
201
  relative paths** (`adr/NNNN-*.md`).
188
202
  - `supersedes:` / `superseded-by:` may point across repos using the
189
203
  logical identity.
@@ -191,6 +205,24 @@ identity scheme are recorded in `federation.md`; the home repo's
191
205
  `federation.md` back-pointer; adding it to the home's
192
206
  `federation-index.md` is a deliberate edit there. The two must agree —
193
207
  audit cross-checks both directions.
208
+ - **Cross-repo work is one plan item per repo.** A decision implemented in
209
+ several repos gets one `plan/todo` item **per affected repo**, each in
210
+ the repo whose code it changes and naming the owning ADR by its
211
+ federation identity. The owning ADR is the single grouping point — its
212
+ per-repo items are discoverable from it; there is **no umbrella record**.
213
+ Per-repo "lower numbers first" ordering is unchanged.
214
+ - **Aggregate status is derived in the roll-up.** A cross-repo decision is
215
+ `Implemented` only when **every** owning per-repo plan item has shipped
216
+ (each under its own repo's completion event); until then it is partially
217
+ implemented. The aggregate ("2 of 3 repos") is a **derived column in the
218
+ roll-up**, computed from per-repo plan-item state — never hand-written
219
+ into the ADR, so no cross-repo writes.
220
+ - **Shared conventions come from one source.** Shared conventions and
221
+ templates are authoritative in the index-holding repo; members **copy
222
+ them at bootstrap** and may keep **local-only** conventions alongside.
223
+ Updates are **not** force-pushed — drift between a member's copy and the
224
+ source is **detected by audit**. Referenceable, not enforced; no
225
+ cross-repo writes.
194
226
  -->
195
227
 
196
228
  ## Audit Trail Policy
@@ -9,7 +9,7 @@ is my home?"; the home repo's `federation-index.md` is the answer to
9
9
  - **Topology:** <A — central decisions repo | B — distributed + federation | C — home repo + local>
10
10
  - **Identity scheme:** <repo-prefixed slug `<repo-id>/NNNN-slug` (default) | other scheme chosen at establishment>
11
11
  - **Home:** <pointer to the home/central repo — URL or path; for the home repo itself, `this repo`>
12
- - **Role:** <home | member>
12
+ - **Role:** <central | home | coordinator | member — the establishing repo's role is set by the topology (central for A, coordinator for B, home for C); every joining repo is `member`>
13
13
  - **Repo id:** <short identifier for this repo, used to qualify its records across the federation>
14
14
 
15
15
  <!-- Hand-maintained. Membership is declared, not auto-discovered: a
@@ -11,7 +11,12 @@ skills read this to enumerate the product's repos.
11
11
 
12
12
  | Repo id | Repo | Role | Pointer |
13
13
  |---------|------|------|---------|
14
- | <id> | <this repo> | home | this repo |
14
+ | <id> | <this repo> | <central\|home\|coordinator> | this repo |
15
+
16
+ <!-- Role values: the establishing repo is `central` (topology A),
17
+ `coordinator` (B), or `home` (C); every other member is `member`.
18
+ Pointer `this repo` means the repo that holds this index (the
19
+ index-holder); resolve every other Pointer relative to it. -->
15
20
 
16
21
  <!-- Each row should have a matching federation.md back-pointer in the
17
22
  named repo, and vice versa. The audit step cross-checks both directions. -->
@@ -84,8 +84,8 @@ If this ADR replaces an existing one:
84
84
  History row noting the successor.
85
85
  - **Same-repo** links use relative paths (`adr/NNNN-*.md`). **In a
86
86
  federation**, a link to an ADR in another repo uses the logical
87
- identity (`<repo-id>/NNNN-slug`), resolved via the member index — not
88
- a relative path.
87
+ identity (`<repo-id>/NNNN-slug`), resolved via the member index along
88
+ `repo-id → Pointer → adr/NNNN-*.md` — not a relative path.
89
89
  - A pure deprecation (no successor) sets the target to `Deprecated`
90
90
  with a Revision History row — and is usually done directly, not via
91
91
  this skill.
@@ -52,6 +52,12 @@ Questions (skip any the request already answers):
52
52
  still `Proposed`, warn — you can queue ahead of acceptance, but the
53
53
  work is not yet authorised. If it has no ADR at all, suggest running
54
54
  the **new-adr** skill first; plan items should trace to a decision.
55
+ - **In a federation** (a `federation.md` exists): the owning ADR may live
56
+ in **another** repo (the home/central). Name it by its **federation
57
+ identity** (`<repo-id>/NNNN-slug`); the plan item itself lives in **this**
58
+ repo — the one whose code the work changes. A decision spanning several
59
+ repos gets **one item per affected repo**, each tracing to the same
60
+ owning ADR (the grouping point — no umbrella record).
55
61
 
56
62
  ## Step 2 — Pick number and position
57
63
 
@@ -12,11 +12,13 @@ from source, never hand-edited — treat it exactly like a repo's own
12
12
 
13
13
  ## Step 0 — Preconditions
14
14
 
15
- 1. This skill runs in the **home repo** of a federation. Confirm a
16
- `federation-index.md` (the authoritative member list) and a
17
- `federation.md` with `Role: home` exist. If they do not, stop: either
18
- this repo is standalone (nothing to roll up) or it is a member, not the
19
- home point the user at the home repo.
15
+ 1. This skill runs in the **index-holding repo** of a federation the one
16
+ that carries `federation-index.md` (its `Role` is `central` for
17
+ topology A, `coordinator` for B, or `home` for C). Confirm
18
+ `federation-index.md` and a `federation.md` whose `Role` is `central`,
19
+ `home`, or `coordinator` exist. If they do not, stop: either this repo
20
+ is standalone (nothing to roll up) or it is a plain member — point the
21
+ user at the index-holding repo.
20
22
  2. Read `federation.md` to learn the **identity scheme** (default
21
23
  repo-prefixed slug `<repo-id>/NNNN-slug`); roll-up rows use it.
22
24
 
@@ -38,6 +40,12 @@ For every member whose checkout is **locally available** at its pointer:
38
40
  A member's own `INDEX.md` stays authoritative for that member; this skill
39
41
  only reads it.
40
42
 
43
+ For the **aggregate status** of a product-wide decision (one with owning
44
+ per-repo plan items across several members), also scan each member's
45
+ `plan/todo/` (pending) and `plan/done/` (shipped) for items naming that
46
+ decision's federation identity — that per-repo state feeds the aggregate
47
+ column in Step 4.
48
+
41
49
  ## Step 3 — Handle unreachable members
42
50
 
43
51
  A member named in the index whose checkout is **not locally available** is
@@ -47,12 +55,17 @@ visible rather than silent.
47
55
 
48
56
  ## Step 4 — Write the roll-up
49
57
 
50
- Write the aggregate to a derived file in the home repo (e.g. `ROLLUP.md`):
58
+ Write the aggregate to **`ROLLUP.md`** at the configured artefact root (the
59
+ same root as `INDEX.md`), so every re-run overwrites the same file:
51
60
 
52
61
  - A header stating it is **generated — do not hand-edit**, with the run
53
62
  date and the set of members aggregated.
54
63
  - One table across the whole product: federation identity, title, status,
55
64
  owning repo, date. Group or sort by owning repo for readability.
65
+ - For product-wide decisions, an **aggregate status** column **derived**
66
+ from per-repo plan-item state: `Implemented` only when every owning
67
+ per-repo plan item is in a member's `plan/done/`, otherwise `N of M
68
+ repos` shipped. This column is derived — never written back into any ADR.
56
69
  - The "Not aggregated this run" list from Step 3.
57
70
 
58
71
  Do not alter any member's `INDEX.md` and do not write into any other repo.