ma-agents 3.17.1 → 3.18.0-beta.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 +214 -1
- package/bin/cli.js +4409 -279
- package/docs/architecture.md +11 -0
- package/docs/technical-notes/enforcement-hooks-research.md +10 -1
- package/lib/agents.js +81 -3
- package/lib/bmad-extension/skills/add-sprint/SKILL.md +112 -0
- package/lib/bmad-extension/skills/add-to-sprint/SKILL.md +112 -0
- package/lib/bmad-extension/skills/bmad-dev-epic/SKILL.md +112 -0
- package/lib/bmad-extension/skills/bmad-dev-story/workflow.md +112 -0
- package/lib/bmad-extension/skills/bmad-knowledge/SKILL.md +112 -0
- package/lib/bmad-extension/skills/bmad-sprint-planning/workflow.md +161 -0
- package/lib/bmad-extension/skills/bmad-sprint-status/workflow.md +112 -0
- package/lib/bmad-extension/skills/cleanup-done/SKILL.md +112 -0
- package/lib/bmad-extension/skills/close-sprint/SKILL.md +112 -0
- package/lib/bmad-extension/skills/generate-backlog/SKILL.md +163 -1
- package/lib/bmad-extension/skills/ma-agent-cyber/SKILL.md +2 -2
- package/lib/bmad-extension/skills/ma-agent-devops/SKILL.md +2 -2
- package/lib/bmad-extension/skills/ma-agent-sqa/SKILL.md +2 -2
- package/lib/bmad-extension/skills/ma-agent-sre/SKILL.md +2 -2
- package/lib/bmad-extension/skills/mil498-ocd/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension/skills/mil498-sdd/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension/skills/mil498-sdp/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension/skills/mil498-srs/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension/skills/mil498-ssdd/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension/skills/mil498-sss/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension/skills/mil498-std/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension/skills/modify-sprint/SKILL.md +112 -0
- package/lib/bmad-extension/skills/prioritize-backlog/SKILL.md +163 -1
- package/lib/bmad-extension/skills/remove-from-sprint/SKILL.md +112 -0
- package/lib/bmad-extension/skills/sprint-status-view/SKILL.md +112 -0
- package/lib/bmad-extension/skills/sqa-audit/SKILL.md +6 -2
- package/lib/bmad-extension/skills/sqa-ieee12207/SKILL.md +2 -2
- package/lib/bmad-extension/skills/sqa-requirements-quality/SKILL.md +1 -1
- package/lib/bmad-extension/workflows/add-sprint/workflow.md +112 -0
- package/lib/bmad-extension/workflows/add-to-sprint/workflow.md +112 -0
- package/lib/bmad-extension/workflows/modify-sprint/workflow.md +112 -0
- package/lib/bmad-extension/workflows/remove-from-sprint/workflow.md +112 -0
- package/lib/bmad-extension/workflows/sprint-status-view/workflow.md +112 -0
- package/lib/bmad-extension-plugin/.claude-plugin/marketplace.json +1 -1
- package/lib/bmad-extension-plugin/skills/add-sprint/SKILL.md +112 -0
- package/lib/bmad-extension-plugin/skills/add-to-sprint/SKILL.md +112 -0
- package/lib/bmad-extension-plugin/skills/bmad-dev-epic/SKILL.md +112 -0
- package/lib/bmad-extension-plugin/skills/bmad-dev-story/workflow.md +112 -0
- package/lib/bmad-extension-plugin/skills/bmad-knowledge/SKILL.md +112 -0
- package/lib/bmad-extension-plugin/skills/bmad-sprint-planning/workflow.md +161 -0
- package/lib/bmad-extension-plugin/skills/bmad-sprint-status/workflow.md +112 -0
- package/lib/bmad-extension-plugin/skills/cleanup-done/SKILL.md +112 -0
- package/lib/bmad-extension-plugin/skills/close-sprint/SKILL.md +112 -0
- package/lib/bmad-extension-plugin/skills/generate-backlog/SKILL.md +163 -1
- package/lib/bmad-extension-plugin/skills/ma-agent-cyber/SKILL.md +2 -2
- package/lib/bmad-extension-plugin/skills/ma-agent-devops/SKILL.md +2 -2
- package/lib/bmad-extension-plugin/skills/ma-agent-sqa/SKILL.md +2 -2
- package/lib/bmad-extension-plugin/skills/ma-agent-sre/SKILL.md +2 -2
- package/lib/bmad-extension-plugin/skills/mil498-ocd/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension-plugin/skills/mil498-sdd/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension-plugin/skills/mil498-sdp/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension-plugin/skills/mil498-srs/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension-plugin/skills/mil498-ssdd/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension-plugin/skills/mil498-sss/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension-plugin/skills/mil498-std/prompts/01-discover-project-artifacts.md +2 -2
- package/lib/bmad-extension-plugin/skills/modify-sprint/SKILL.md +112 -0
- package/lib/bmad-extension-plugin/skills/prioritize-backlog/SKILL.md +163 -1
- package/lib/bmad-extension-plugin/skills/remove-from-sprint/SKILL.md +112 -0
- package/lib/bmad-extension-plugin/skills/sprint-status-view/SKILL.md +112 -0
- package/lib/bmad-extension-plugin/skills/sqa-audit/SKILL.md +6 -2
- package/lib/bmad-extension-plugin/skills/sqa-ieee12207/SKILL.md +2 -2
- package/lib/bmad-extension-plugin/skills/sqa-requirements-quality/SKILL.md +1 -1
- package/lib/bmad.js +283 -15
- package/lib/bound-projects.js +265 -0
- package/lib/confluence-page-tree.js +925 -0
- package/lib/confluence-publish-hook.js +1781 -0
- package/lib/custom-marketplace.js +28 -18
- package/lib/installer.js +489 -20
- package/lib/store-backends.js +64 -0
- package/lib/templates/instruction-block-git.template.md +25 -25
- package/lib/templates/instruction-block-onprem.template.md +86 -86
- package/lib/templates/instruction-block-universal.template.md +29 -29
- package/package.json +2 -2
- package/skills/add-sprint/SKILL.md +112 -0
- package/skills/add-to-sprint/SKILL.md +112 -0
- package/skills/bmad-knowledge/SKILL.md +112 -0
- package/skills/bmad-sprint-planning/SKILL.md +176 -3
- package/skills/bmad-sprint-status/SKILL.md +112 -0
- package/skills/cleanup-done/SKILL.md +112 -0
- package/skills/close-sprint/SKILL.md +112 -0
- package/skills/generate-backlog/SKILL.md +164 -2
- package/skills/modify-sprint/SKILL.md +112 -0
- package/skills/prioritize-backlog/SKILL.md +163 -1
- package/skills/remove-from-sprint/SKILL.md +112 -0
- package/skills/sprint-status-view/SKILL.md +112 -0
- package/skills/story-status-lookup/SKILL.md +112 -0
|
@@ -62,7 +62,7 @@ Load the selected documents. Note presence or absence — missing documents resu
|
|
|
62
62
|
|
|
63
63
|
| Source | Path |
|
|
64
64
|
|--------|------|
|
|
65
|
-
| PRD | `{output_folder}/planning-artifacts/prd.md` |
|
|
65
|
+
| PRD | `{output_folder}/planning-artifacts/prd.md` — plus `{output_folder}/planning-artifacts/prd/**/*.md` when that file is a shard index |
|
|
66
66
|
| Epics & Stories | `{output_folder}/planning-artifacts/epics.md` |
|
|
67
67
|
|
|
68
68
|
Inform the user which documents were found and which were missing before proceeding.
|
|
@@ -2,6 +2,118 @@
|
|
|
2
2
|
|
|
3
3
|
Guided workflow to create a new sprint entry in the `sprints` section of `sprint-status.yaml` with capacity limits, optional ISO dates, and auto-incremented sprint ID.
|
|
4
4
|
|
|
5
|
+
## Knowledge Store Binding Preflight
|
|
6
|
+
|
|
7
|
+
**Gateway check — run this before anything else in this skill.** Before any read, any write, any user prompt, and before any other routing or configuration step below. No other step of this skill executes until this preflight returns PROCEED.
|
|
8
|
+
|
|
9
|
+
`_bmad/bmm/config.yaml` is a GENERATED file. `ma-agents` derives it from the committed binding in `_bmad-output/project-layout.yaml` on install and on `ma-agents bind`, and records which binding it was generated from in its `project_layout_stamp:` field. If the binding has moved since — the usual cause is a `git pull` that relocated a knowledge store — every path this skill would resolve from `config.yaml` points at where the stores used to be. This preflight refuses to let that happen silently.
|
|
10
|
+
|
|
11
|
+
**This preflight is read-only.** Whatever it finds, do NOT regenerate, repair, edit or create `config.yaml`, `_bmad-output/project-layout.yaml`, or any other file, and do not offer to. Regenerating the config belongs to the installer and to `ma-agents bind`, never to a skill.
|
|
12
|
+
|
|
13
|
+
**Compare content, never timestamps.** Never decide staleness from file modification times: mtime ordering is not preserved by `git pull`, `git checkout` or a fresh clone, so it both misses real drift and reports drift on a clean checkout.
|
|
14
|
+
|
|
15
|
+
Work through the steps below IN ORDER and stop at the first branch that matches. The order is load-bearing — `_bmad-output/project-layout.yaml` is the fact, and the stamp only ever corroborates it.
|
|
16
|
+
|
|
17
|
+
### Step P1 — Read `_bmad-output/project-layout.yaml`
|
|
18
|
+
|
|
19
|
+
- **Missing, or present but blank / comments-only** → go to **Step P2**.
|
|
20
|
+
- **Present but not cleanly readable** — it is not valid YAML, it carries unresolved merge-conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`), it yields no readable fields, its `schema_version:` is greater than `2`, its `schema_version:` is present but is not a number, it names a `backend:` or a `mode:` this build does not recognise, or any store record in it cannot be read → **HALT** and report:
|
|
21
|
+
|
|
22
|
+
> **ma-agents — stopping: the committed knowledge binding cannot be read.**
|
|
23
|
+
> `_bmad-output/project-layout.yaml` exists but this build cannot use it: {say exactly what is wrong}.
|
|
24
|
+
> Every knowledge-store path in `_bmad/bmm/config.yaml` is derived from that file, so nothing this skill would resolve can be trusted. Fix the binding by hand — if this is a merge conflict, resolve it; the file is committed, so conflicts are ordinary — then run `ma-agents bind` to regenerate `_bmad/bmm/config.yaml` from it.
|
|
25
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
26
|
+
|
|
27
|
+
That list of faults is illustrative, not exhaustive. **Default-deny:** the only two ways out of this step without halting are "absent, or blank / comments-only" (→ Step P2) and "resolves cleanly" (→ Step P3). Anything else takes this HALT, including a fault not named above. Do not fall back to defaults and do not treat this as "no binding". A binding that cannot be read is a different fact from a project that has none.
|
|
28
|
+
- **Present and resolves cleanly** → go to **Step P3**.
|
|
29
|
+
|
|
30
|
+
### Step P2 — There is no committed binding
|
|
31
|
+
|
|
32
|
+
No `_bmad-output/project-layout.yaml`. That is the pre-F26 shape and by itself it is NOT drift — but corroborate it instead of trusting it, because "a binding was never written here" and "the binding was deleted, ignored, or not pulled" look identical from the missing file alone. Read `_bmad/bmm/config.yaml`:
|
|
33
|
+
|
|
34
|
+
- **`config.yaml` does not exist either** → **HALT** and report:
|
|
35
|
+
|
|
36
|
+
> **ma-agents — stopping: this project is not configured.**
|
|
37
|
+
> Neither `_bmad-output/project-layout.yaml` nor `_bmad/bmm/config.yaml` exists, so nothing states where this project's knowledge stores live. Run `npx ma-agents install` to configure the project, or `ma-agents bind` if ma-agents is already installed and only the binding is missing.
|
|
38
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
39
|
+
|
|
40
|
+
- **`config.yaml` exists and carries, at column 0, any of `project_layout_stamp:`, `system_requirements_path:` or `software_requirements_path:`** (a commented-out or indented one does not count — it is not the field) → **HALT** and report:
|
|
41
|
+
|
|
42
|
+
> **ma-agents — stopping: the committed knowledge binding is missing.**
|
|
43
|
+
> `_bmad/bmm/config.yaml` carries {name the fields you found}, which only an F26 generation writes — so this project HAS been bound — but `_bmad-output/project-layout.yaml` is not here. The binding was deleted, is untracked or ignored, or has not been pulled. This is not a pre-F26 project, so proceeding would mean trusting generated paths against a binding that no longer exists.
|
|
44
|
+
> Restore the file (for example `git checkout -- _bmad-output/project-layout.yaml`), or run `ma-agents bind` to write a fresh one.
|
|
45
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
46
|
+
|
|
47
|
+
Those three fields are the discriminator and they are reliable: a genuine pre-F26 `config.yaml` carries none of them. Do not skip this check. An absent stamp on its own is never evidence that a project predates the stamp.
|
|
48
|
+
|
|
49
|
+
- **`config.yaml` exists and carries none of those three fields at column 0** → this is genuinely a pre-F26 project. **PROCEED** with the rest of this skill exactly as it behaved before F26, and say nothing at all about the binding — no warning, no prompt, no offer to bind. Nothing has moved, so there is nothing to re-bind. The existence of `config.yaml` is NOT on its own a reason to take this branch: all three fields must be absent.
|
|
50
|
+
|
|
51
|
+
### Step P3 — The binding is readable: check what `config.yaml` was generated from
|
|
52
|
+
|
|
53
|
+
Read `_bmad/bmm/config.yaml`.
|
|
54
|
+
|
|
55
|
+
- **`config.yaml` does not exist** → **HALT** and report:
|
|
56
|
+
|
|
57
|
+
> **ma-agents — stopping: the generated config is missing.**
|
|
58
|
+
> `_bmad-output/project-layout.yaml` commits this project's knowledge binding, but `_bmad/bmm/config.yaml` — the file this skill resolves its paths from — has never been generated from it. Run `npx ma-agents install` to install into this project, or `ma-agents bind` if ma-agents is already installed, to generate `_bmad/bmm/config.yaml` from the committed binding.
|
|
59
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
60
|
+
|
|
61
|
+
- **No `project_layout_stamp:` line at column 0 of `config.yaml`** (a commented-out or indented one does not count — it is not the field) → **HALT** and report:
|
|
62
|
+
|
|
63
|
+
> **ma-agents — stopping: `_bmad/bmm/config.yaml` does not record which binding it came from.**
|
|
64
|
+
> `_bmad-output/project-layout.yaml` exists, but `config.yaml` carries no `project_layout_stamp:`, so there is no evidence its paths were generated from the committed binding. Run `ma-agents bind` to regenerate it.
|
|
65
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
66
|
+
|
|
67
|
+
- **`project_layout_stamp:` is present but its value is not `sha256:` followed by exactly 64 lowercase hexadecimal characters** — truncated, uppercased, a different algorithm, unbalanced quotes, or trailing content after the digest → **HALT** and report:
|
|
68
|
+
|
|
69
|
+
> **ma-agents — stopping: `_bmad/bmm/config.yaml` claims to have been generated and the claim cannot be read.**
|
|
70
|
+
> Its `project_layout_stamp:` is {quote the value you found}, which is not a stamp ma-agents wrote (expected `sha256:` followed by 64 lowercase hex characters) — merge damage, a hand-edit, or a truncated write. Treat this config as unverified; it is NOT a config that predates the stamp. Run `ma-agents bind` to regenerate it from `_bmad-output/project-layout.yaml`.
|
|
71
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
72
|
+
|
|
73
|
+
- **`project_layout_stamp:` is well-formed** → go to **Step P4**.
|
|
74
|
+
|
|
75
|
+
### Step P4 — Compare the committed binding against the generated fields
|
|
76
|
+
|
|
77
|
+
Derive, from `_bmad-output/project-layout.yaml`, what each generated field in `config.yaml` WOULD be if it were regenerated right now, and compare it to what `config.yaml` actually carries. This is a content comparison of the two files — never a timestamp comparison.
|
|
78
|
+
|
|
79
|
+
A schema-2 binding holds three records: `system_requirements_store:`, `software_requirements_store:` and `sprint_management:`. A legacy schema-1 binding holds a single `knowledgebase:` record, which stands for BOTH requirement stores.
|
|
80
|
+
|
|
81
|
+
The table below IS the whole comparison: every field named in its right-hand column is compared, and no field outside that column is. Read each field only from a line at column 0, and compare VALUES rather than bytes — the generator quotes its scalars (`sprint_backend: "jira"`, `knowledgebase_path: "."`), so strip one balanced pair of surrounding quotes from each side first.
|
|
82
|
+
|
|
83
|
+
| When | Binding record it is derived from | Field(s) it generates in `config.yaml` |
|
|
84
|
+
| --- | --- | --- |
|
|
85
|
+
| always | `software_requirements_store` → its `path:` (a store whose `backend:` is not `file-system` has no `path:` at all, and so generates `.`); the artifacts field is that same path, except that a path of `.` gives `{project-root}/_bmad-output/planning-artifacts`; its resolved `backend:` (an absent or empty `backend:` resolves to `file-system`), and, when that backend is `confluence`, its `space_key:` — the generated space-key field is empty for every other backend, so a store re-bound away from Confluence does not keep the old space | `software_requirements_path:`, `knowledgebase_path:`, `planning_artifacts:`, `software_requirements_backend:`, `software_requirements_space_key:` |
|
|
86
|
+
| always | `system_requirements_store` → its `path:` (a store whose `backend:` is not `file-system` has no `path:` at all, and so generates `.`); its resolved `backend:` (an absent or empty `backend:` resolves to `file-system`), and, when that backend is `confluence`, its `space_key:` — the generated space-key field is empty for every other backend, so a store re-bound away from Confluence does not keep the old space | `system_requirements_path:`, `system_requirements_backend:`, `system_requirements_space_key:` |
|
|
87
|
+
| `sprint_management` has `mode: jira` | `sprint_management` → its `jira_url:` and `jira_project_key:`; the backend field is the literal `jira`; the artifacts field is always `{project-root}/_bmad-output/implementation-artifacts`, because a Jira sprint store has no path | `sprint_backend:`, `jira_url:`, `jira_project_key:`, `implementation_artifacts:` |
|
|
88
|
+
| `sprint_management` has any other mode | `sprint_management` → its `path:`; the backend field is the literal `file-system`; the artifacts field is that same path, except that a path of `.` gives `{project-root}/_bmad-output/implementation-artifacts` | `sprint_backend:`, `sprint_management_path:`, `implementation_artifacts:` |
|
|
89
|
+
|
|
90
|
+
**When the binding says `mode: jira`, `sprint_management_path:` is not compared at all.** The generator writes no `sprint_management_path:` in that mode — and it never DELETES a field, it only updates or appends one. So a project that was bound to the file system and later re-bound to Jira still carries its old `sprint_management_path:` line in a freshly generated `config.yaml`. That leftover line is not drift, and comparing it would halt every Jira project that was ever file-system-bound.
|
|
91
|
+
|
|
92
|
+
Not every field in that table is a path. Where a store's `backend:` or `space_key:` is what disagrees, the comparison is the same and so is the halt — read the message template's `{path in …}` placeholders as "the value that disagrees", and name the two values you actually compared.
|
|
93
|
+
|
|
94
|
+
**Any disagreement is drift** → **HALT** and report, naming every store that moved and both of its paths:
|
|
95
|
+
|
|
96
|
+
> **ma-agents — stopping: `_bmad/bmm/config.yaml` is stale.**
|
|
97
|
+
> The committed binding in `_bmad-output/project-layout.yaml` no longer matches the state `_bmad/bmm/config.yaml` was generated from:
|
|
98
|
+
> - {store name}: was `{path in config.yaml}`, is now `{path in project-layout.yaml}`
|
|
99
|
+
> (one line per store that moved)
|
|
100
|
+
> Running this skill now would read and write artifacts where those stores used to be. Run `ma-agents bind` to regenerate `_bmad/bmm/config.yaml` from the committed binding, then run this skill again.
|
|
101
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
102
|
+
|
|
103
|
+
**If everything in the table agrees** → go to **Step P5**.
|
|
104
|
+
|
|
105
|
+
The stamp covers binding state that `config.yaml` does not carry — a Confluence `root_page:`, a `gitUrl:` — so the table alone cannot see every kind of move. If, and only if, a command shell is available to you and `ma-agents` resolves as a local dependency of this project, you may confirm the comparison exactly, without parsing the stamp yourself:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
node -e "const c=require('ma-agents/bin/cli.js'),f=require('fs'),p=process.cwd();const t=c.resolveProjectTopology(p);if(!t.ok){console.log('binding:'+t.reason)}else{const s=c.readProjectLayoutStamp(f.readFileSync('_bmad/bmm/config.yaml','utf8'));console.log(s.ok?(s.value===c.computeProjectLayoutStamp(t.topology,p)?'MATCH':'DRIFT'):'stamp:'+s.reason)}"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`DRIFT` is authoritative: HALT with the stale-config message above even when the table found nothing, and say that the binding changed in a way `config.yaml` does not record. Never treat a failure to run this command as a result — if it does not run, the table is the check, and you say nothing about the stamp.
|
|
112
|
+
|
|
113
|
+
### Step P5 — PROCEED
|
|
114
|
+
|
|
115
|
+
The generated config matches the committed binding. Say NOTHING about the binding, the stamp or this preflight — a matched project gets no message — and continue with the rest of this skill.
|
|
116
|
+
|
|
5
117
|
## Backend Routing
|
|
6
118
|
|
|
7
119
|
Before executing any file-system operations, determine and route to the correct backend:
|
|
@@ -4,6 +4,118 @@ Guided workflow to move backlog items to a sprint in the unified `sprint-status.
|
|
|
4
4
|
|
|
5
5
|
**Movement semantics:** Each item exists in exactly one location — either the `backlog` array OR a sprint's `items` array, never both. This skill atomically removes items from `backlog` and appends them to the target sprint's `items` array in a single file write.
|
|
6
6
|
|
|
7
|
+
## Knowledge Store Binding Preflight
|
|
8
|
+
|
|
9
|
+
**Gateway check — run this before anything else in this skill.** Before any read, any write, any user prompt, and before any other routing or configuration step below. No other step of this skill executes until this preflight returns PROCEED.
|
|
10
|
+
|
|
11
|
+
`_bmad/bmm/config.yaml` is a GENERATED file. `ma-agents` derives it from the committed binding in `_bmad-output/project-layout.yaml` on install and on `ma-agents bind`, and records which binding it was generated from in its `project_layout_stamp:` field. If the binding has moved since — the usual cause is a `git pull` that relocated a knowledge store — every path this skill would resolve from `config.yaml` points at where the stores used to be. This preflight refuses to let that happen silently.
|
|
12
|
+
|
|
13
|
+
**This preflight is read-only.** Whatever it finds, do NOT regenerate, repair, edit or create `config.yaml`, `_bmad-output/project-layout.yaml`, or any other file, and do not offer to. Regenerating the config belongs to the installer and to `ma-agents bind`, never to a skill.
|
|
14
|
+
|
|
15
|
+
**Compare content, never timestamps.** Never decide staleness from file modification times: mtime ordering is not preserved by `git pull`, `git checkout` or a fresh clone, so it both misses real drift and reports drift on a clean checkout.
|
|
16
|
+
|
|
17
|
+
Work through the steps below IN ORDER and stop at the first branch that matches. The order is load-bearing — `_bmad-output/project-layout.yaml` is the fact, and the stamp only ever corroborates it.
|
|
18
|
+
|
|
19
|
+
### Step P1 — Read `_bmad-output/project-layout.yaml`
|
|
20
|
+
|
|
21
|
+
- **Missing, or present but blank / comments-only** → go to **Step P2**.
|
|
22
|
+
- **Present but not cleanly readable** — it is not valid YAML, it carries unresolved merge-conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`), it yields no readable fields, its `schema_version:` is greater than `2`, its `schema_version:` is present but is not a number, it names a `backend:` or a `mode:` this build does not recognise, or any store record in it cannot be read → **HALT** and report:
|
|
23
|
+
|
|
24
|
+
> **ma-agents — stopping: the committed knowledge binding cannot be read.**
|
|
25
|
+
> `_bmad-output/project-layout.yaml` exists but this build cannot use it: {say exactly what is wrong}.
|
|
26
|
+
> Every knowledge-store path in `_bmad/bmm/config.yaml` is derived from that file, so nothing this skill would resolve can be trusted. Fix the binding by hand — if this is a merge conflict, resolve it; the file is committed, so conflicts are ordinary — then run `ma-agents bind` to regenerate `_bmad/bmm/config.yaml` from it.
|
|
27
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
28
|
+
|
|
29
|
+
That list of faults is illustrative, not exhaustive. **Default-deny:** the only two ways out of this step without halting are "absent, or blank / comments-only" (→ Step P2) and "resolves cleanly" (→ Step P3). Anything else takes this HALT, including a fault not named above. Do not fall back to defaults and do not treat this as "no binding". A binding that cannot be read is a different fact from a project that has none.
|
|
30
|
+
- **Present and resolves cleanly** → go to **Step P3**.
|
|
31
|
+
|
|
32
|
+
### Step P2 — There is no committed binding
|
|
33
|
+
|
|
34
|
+
No `_bmad-output/project-layout.yaml`. That is the pre-F26 shape and by itself it is NOT drift — but corroborate it instead of trusting it, because "a binding was never written here" and "the binding was deleted, ignored, or not pulled" look identical from the missing file alone. Read `_bmad/bmm/config.yaml`:
|
|
35
|
+
|
|
36
|
+
- **`config.yaml` does not exist either** → **HALT** and report:
|
|
37
|
+
|
|
38
|
+
> **ma-agents — stopping: this project is not configured.**
|
|
39
|
+
> Neither `_bmad-output/project-layout.yaml` nor `_bmad/bmm/config.yaml` exists, so nothing states where this project's knowledge stores live. Run `npx ma-agents install` to configure the project, or `ma-agents bind` if ma-agents is already installed and only the binding is missing.
|
|
40
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
41
|
+
|
|
42
|
+
- **`config.yaml` exists and carries, at column 0, any of `project_layout_stamp:`, `system_requirements_path:` or `software_requirements_path:`** (a commented-out or indented one does not count — it is not the field) → **HALT** and report:
|
|
43
|
+
|
|
44
|
+
> **ma-agents — stopping: the committed knowledge binding is missing.**
|
|
45
|
+
> `_bmad/bmm/config.yaml` carries {name the fields you found}, which only an F26 generation writes — so this project HAS been bound — but `_bmad-output/project-layout.yaml` is not here. The binding was deleted, is untracked or ignored, or has not been pulled. This is not a pre-F26 project, so proceeding would mean trusting generated paths against a binding that no longer exists.
|
|
46
|
+
> Restore the file (for example `git checkout -- _bmad-output/project-layout.yaml`), or run `ma-agents bind` to write a fresh one.
|
|
47
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
48
|
+
|
|
49
|
+
Those three fields are the discriminator and they are reliable: a genuine pre-F26 `config.yaml` carries none of them. Do not skip this check. An absent stamp on its own is never evidence that a project predates the stamp.
|
|
50
|
+
|
|
51
|
+
- **`config.yaml` exists and carries none of those three fields at column 0** → this is genuinely a pre-F26 project. **PROCEED** with the rest of this skill exactly as it behaved before F26, and say nothing at all about the binding — no warning, no prompt, no offer to bind. Nothing has moved, so there is nothing to re-bind. The existence of `config.yaml` is NOT on its own a reason to take this branch: all three fields must be absent.
|
|
52
|
+
|
|
53
|
+
### Step P3 — The binding is readable: check what `config.yaml` was generated from
|
|
54
|
+
|
|
55
|
+
Read `_bmad/bmm/config.yaml`.
|
|
56
|
+
|
|
57
|
+
- **`config.yaml` does not exist** → **HALT** and report:
|
|
58
|
+
|
|
59
|
+
> **ma-agents — stopping: the generated config is missing.**
|
|
60
|
+
> `_bmad-output/project-layout.yaml` commits this project's knowledge binding, but `_bmad/bmm/config.yaml` — the file this skill resolves its paths from — has never been generated from it. Run `npx ma-agents install` to install into this project, or `ma-agents bind` if ma-agents is already installed, to generate `_bmad/bmm/config.yaml` from the committed binding.
|
|
61
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
62
|
+
|
|
63
|
+
- **No `project_layout_stamp:` line at column 0 of `config.yaml`** (a commented-out or indented one does not count — it is not the field) → **HALT** and report:
|
|
64
|
+
|
|
65
|
+
> **ma-agents — stopping: `_bmad/bmm/config.yaml` does not record which binding it came from.**
|
|
66
|
+
> `_bmad-output/project-layout.yaml` exists, but `config.yaml` carries no `project_layout_stamp:`, so there is no evidence its paths were generated from the committed binding. Run `ma-agents bind` to regenerate it.
|
|
67
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
68
|
+
|
|
69
|
+
- **`project_layout_stamp:` is present but its value is not `sha256:` followed by exactly 64 lowercase hexadecimal characters** — truncated, uppercased, a different algorithm, unbalanced quotes, or trailing content after the digest → **HALT** and report:
|
|
70
|
+
|
|
71
|
+
> **ma-agents — stopping: `_bmad/bmm/config.yaml` claims to have been generated and the claim cannot be read.**
|
|
72
|
+
> Its `project_layout_stamp:` is {quote the value you found}, which is not a stamp ma-agents wrote (expected `sha256:` followed by 64 lowercase hex characters) — merge damage, a hand-edit, or a truncated write. Treat this config as unverified; it is NOT a config that predates the stamp. Run `ma-agents bind` to regenerate it from `_bmad-output/project-layout.yaml`.
|
|
73
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
74
|
+
|
|
75
|
+
- **`project_layout_stamp:` is well-formed** → go to **Step P4**.
|
|
76
|
+
|
|
77
|
+
### Step P4 — Compare the committed binding against the generated fields
|
|
78
|
+
|
|
79
|
+
Derive, from `_bmad-output/project-layout.yaml`, what each generated field in `config.yaml` WOULD be if it were regenerated right now, and compare it to what `config.yaml` actually carries. This is a content comparison of the two files — never a timestamp comparison.
|
|
80
|
+
|
|
81
|
+
A schema-2 binding holds three records: `system_requirements_store:`, `software_requirements_store:` and `sprint_management:`. A legacy schema-1 binding holds a single `knowledgebase:` record, which stands for BOTH requirement stores.
|
|
82
|
+
|
|
83
|
+
The table below IS the whole comparison: every field named in its right-hand column is compared, and no field outside that column is. Read each field only from a line at column 0, and compare VALUES rather than bytes — the generator quotes its scalars (`sprint_backend: "jira"`, `knowledgebase_path: "."`), so strip one balanced pair of surrounding quotes from each side first.
|
|
84
|
+
|
|
85
|
+
| When | Binding record it is derived from | Field(s) it generates in `config.yaml` |
|
|
86
|
+
| --- | --- | --- |
|
|
87
|
+
| always | `software_requirements_store` → its `path:` (a store whose `backend:` is not `file-system` has no `path:` at all, and so generates `.`); the artifacts field is that same path, except that a path of `.` gives `{project-root}/_bmad-output/planning-artifacts`; its resolved `backend:` (an absent or empty `backend:` resolves to `file-system`), and, when that backend is `confluence`, its `space_key:` — the generated space-key field is empty for every other backend, so a store re-bound away from Confluence does not keep the old space | `software_requirements_path:`, `knowledgebase_path:`, `planning_artifacts:`, `software_requirements_backend:`, `software_requirements_space_key:` |
|
|
88
|
+
| always | `system_requirements_store` → its `path:` (a store whose `backend:` is not `file-system` has no `path:` at all, and so generates `.`); its resolved `backend:` (an absent or empty `backend:` resolves to `file-system`), and, when that backend is `confluence`, its `space_key:` — the generated space-key field is empty for every other backend, so a store re-bound away from Confluence does not keep the old space | `system_requirements_path:`, `system_requirements_backend:`, `system_requirements_space_key:` |
|
|
89
|
+
| `sprint_management` has `mode: jira` | `sprint_management` → its `jira_url:` and `jira_project_key:`; the backend field is the literal `jira`; the artifacts field is always `{project-root}/_bmad-output/implementation-artifacts`, because a Jira sprint store has no path | `sprint_backend:`, `jira_url:`, `jira_project_key:`, `implementation_artifacts:` |
|
|
90
|
+
| `sprint_management` has any other mode | `sprint_management` → its `path:`; the backend field is the literal `file-system`; the artifacts field is that same path, except that a path of `.` gives `{project-root}/_bmad-output/implementation-artifacts` | `sprint_backend:`, `sprint_management_path:`, `implementation_artifacts:` |
|
|
91
|
+
|
|
92
|
+
**When the binding says `mode: jira`, `sprint_management_path:` is not compared at all.** The generator writes no `sprint_management_path:` in that mode — and it never DELETES a field, it only updates or appends one. So a project that was bound to the file system and later re-bound to Jira still carries its old `sprint_management_path:` line in a freshly generated `config.yaml`. That leftover line is not drift, and comparing it would halt every Jira project that was ever file-system-bound.
|
|
93
|
+
|
|
94
|
+
Not every field in that table is a path. Where a store's `backend:` or `space_key:` is what disagrees, the comparison is the same and so is the halt — read the message template's `{path in …}` placeholders as "the value that disagrees", and name the two values you actually compared.
|
|
95
|
+
|
|
96
|
+
**Any disagreement is drift** → **HALT** and report, naming every store that moved and both of its paths:
|
|
97
|
+
|
|
98
|
+
> **ma-agents — stopping: `_bmad/bmm/config.yaml` is stale.**
|
|
99
|
+
> The committed binding in `_bmad-output/project-layout.yaml` no longer matches the state `_bmad/bmm/config.yaml` was generated from:
|
|
100
|
+
> - {store name}: was `{path in config.yaml}`, is now `{path in project-layout.yaml}`
|
|
101
|
+
> (one line per store that moved)
|
|
102
|
+
> Running this skill now would read and write artifacts where those stores used to be. Run `ma-agents bind` to regenerate `_bmad/bmm/config.yaml` from the committed binding, then run this skill again.
|
|
103
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
104
|
+
|
|
105
|
+
**If everything in the table agrees** → go to **Step P5**.
|
|
106
|
+
|
|
107
|
+
The stamp covers binding state that `config.yaml` does not carry — a Confluence `root_page:`, a `gitUrl:` — so the table alone cannot see every kind of move. If, and only if, a command shell is available to you and `ma-agents` resolves as a local dependency of this project, you may confirm the comparison exactly, without parsing the stamp yourself:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
node -e "const c=require('ma-agents/bin/cli.js'),f=require('fs'),p=process.cwd();const t=c.resolveProjectTopology(p);if(!t.ok){console.log('binding:'+t.reason)}else{const s=c.readProjectLayoutStamp(f.readFileSync('_bmad/bmm/config.yaml','utf8'));console.log(s.ok?(s.value===c.computeProjectLayoutStamp(t.topology,p)?'MATCH':'DRIFT'):'stamp:'+s.reason)}"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`DRIFT` is authoritative: HALT with the stale-config message above even when the table found nothing, and say that the binding changed in a way `config.yaml` does not record. Never treat a failure to run this command as a result — if it does not run, the table is the check, and you say nothing about the stamp.
|
|
114
|
+
|
|
115
|
+
### Step P5 — PROCEED
|
|
116
|
+
|
|
117
|
+
The generated config matches the committed binding. Say NOTHING about the binding, the stamp or this preflight — a matched project gets no message — and continue with the rest of this skill.
|
|
118
|
+
|
|
7
119
|
## Backend Routing
|
|
8
120
|
|
|
9
121
|
Before executing any file-system operations, determine and route to the correct backend:
|
|
@@ -5,6 +5,118 @@ Guided workflow to modify an existing sprint's metadata (name, capacity, dates,
|
|
|
5
5
|
> **Scope:** This skill modifies sprint **metadata only** — name, capacity, start date, end date, and status.
|
|
6
6
|
> To assign items to a sprint, use `/add-to-sprint`. To remove items, use `/remove-from-sprint`.
|
|
7
7
|
|
|
8
|
+
## Knowledge Store Binding Preflight
|
|
9
|
+
|
|
10
|
+
**Gateway check — run this before anything else in this skill.** Before any read, any write, any user prompt, and before any other routing or configuration step below. No other step of this skill executes until this preflight returns PROCEED.
|
|
11
|
+
|
|
12
|
+
`_bmad/bmm/config.yaml` is a GENERATED file. `ma-agents` derives it from the committed binding in `_bmad-output/project-layout.yaml` on install and on `ma-agents bind`, and records which binding it was generated from in its `project_layout_stamp:` field. If the binding has moved since — the usual cause is a `git pull` that relocated a knowledge store — every path this skill would resolve from `config.yaml` points at where the stores used to be. This preflight refuses to let that happen silently.
|
|
13
|
+
|
|
14
|
+
**This preflight is read-only.** Whatever it finds, do NOT regenerate, repair, edit or create `config.yaml`, `_bmad-output/project-layout.yaml`, or any other file, and do not offer to. Regenerating the config belongs to the installer and to `ma-agents bind`, never to a skill.
|
|
15
|
+
|
|
16
|
+
**Compare content, never timestamps.** Never decide staleness from file modification times: mtime ordering is not preserved by `git pull`, `git checkout` or a fresh clone, so it both misses real drift and reports drift on a clean checkout.
|
|
17
|
+
|
|
18
|
+
Work through the steps below IN ORDER and stop at the first branch that matches. The order is load-bearing — `_bmad-output/project-layout.yaml` is the fact, and the stamp only ever corroborates it.
|
|
19
|
+
|
|
20
|
+
### Step P1 — Read `_bmad-output/project-layout.yaml`
|
|
21
|
+
|
|
22
|
+
- **Missing, or present but blank / comments-only** → go to **Step P2**.
|
|
23
|
+
- **Present but not cleanly readable** — it is not valid YAML, it carries unresolved merge-conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`), it yields no readable fields, its `schema_version:` is greater than `2`, its `schema_version:` is present but is not a number, it names a `backend:` or a `mode:` this build does not recognise, or any store record in it cannot be read → **HALT** and report:
|
|
24
|
+
|
|
25
|
+
> **ma-agents — stopping: the committed knowledge binding cannot be read.**
|
|
26
|
+
> `_bmad-output/project-layout.yaml` exists but this build cannot use it: {say exactly what is wrong}.
|
|
27
|
+
> Every knowledge-store path in `_bmad/bmm/config.yaml` is derived from that file, so nothing this skill would resolve can be trusted. Fix the binding by hand — if this is a merge conflict, resolve it; the file is committed, so conflicts are ordinary — then run `ma-agents bind` to regenerate `_bmad/bmm/config.yaml` from it.
|
|
28
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
29
|
+
|
|
30
|
+
That list of faults is illustrative, not exhaustive. **Default-deny:** the only two ways out of this step without halting are "absent, or blank / comments-only" (→ Step P2) and "resolves cleanly" (→ Step P3). Anything else takes this HALT, including a fault not named above. Do not fall back to defaults and do not treat this as "no binding". A binding that cannot be read is a different fact from a project that has none.
|
|
31
|
+
- **Present and resolves cleanly** → go to **Step P3**.
|
|
32
|
+
|
|
33
|
+
### Step P2 — There is no committed binding
|
|
34
|
+
|
|
35
|
+
No `_bmad-output/project-layout.yaml`. That is the pre-F26 shape and by itself it is NOT drift — but corroborate it instead of trusting it, because "a binding was never written here" and "the binding was deleted, ignored, or not pulled" look identical from the missing file alone. Read `_bmad/bmm/config.yaml`:
|
|
36
|
+
|
|
37
|
+
- **`config.yaml` does not exist either** → **HALT** and report:
|
|
38
|
+
|
|
39
|
+
> **ma-agents — stopping: this project is not configured.**
|
|
40
|
+
> Neither `_bmad-output/project-layout.yaml` nor `_bmad/bmm/config.yaml` exists, so nothing states where this project's knowledge stores live. Run `npx ma-agents install` to configure the project, or `ma-agents bind` if ma-agents is already installed and only the binding is missing.
|
|
41
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
42
|
+
|
|
43
|
+
- **`config.yaml` exists and carries, at column 0, any of `project_layout_stamp:`, `system_requirements_path:` or `software_requirements_path:`** (a commented-out or indented one does not count — it is not the field) → **HALT** and report:
|
|
44
|
+
|
|
45
|
+
> **ma-agents — stopping: the committed knowledge binding is missing.**
|
|
46
|
+
> `_bmad/bmm/config.yaml` carries {name the fields you found}, which only an F26 generation writes — so this project HAS been bound — but `_bmad-output/project-layout.yaml` is not here. The binding was deleted, is untracked or ignored, or has not been pulled. This is not a pre-F26 project, so proceeding would mean trusting generated paths against a binding that no longer exists.
|
|
47
|
+
> Restore the file (for example `git checkout -- _bmad-output/project-layout.yaml`), or run `ma-agents bind` to write a fresh one.
|
|
48
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
49
|
+
|
|
50
|
+
Those three fields are the discriminator and they are reliable: a genuine pre-F26 `config.yaml` carries none of them. Do not skip this check. An absent stamp on its own is never evidence that a project predates the stamp.
|
|
51
|
+
|
|
52
|
+
- **`config.yaml` exists and carries none of those three fields at column 0** → this is genuinely a pre-F26 project. **PROCEED** with the rest of this skill exactly as it behaved before F26, and say nothing at all about the binding — no warning, no prompt, no offer to bind. Nothing has moved, so there is nothing to re-bind. The existence of `config.yaml` is NOT on its own a reason to take this branch: all three fields must be absent.
|
|
53
|
+
|
|
54
|
+
### Step P3 — The binding is readable: check what `config.yaml` was generated from
|
|
55
|
+
|
|
56
|
+
Read `_bmad/bmm/config.yaml`.
|
|
57
|
+
|
|
58
|
+
- **`config.yaml` does not exist** → **HALT** and report:
|
|
59
|
+
|
|
60
|
+
> **ma-agents — stopping: the generated config is missing.**
|
|
61
|
+
> `_bmad-output/project-layout.yaml` commits this project's knowledge binding, but `_bmad/bmm/config.yaml` — the file this skill resolves its paths from — has never been generated from it. Run `npx ma-agents install` to install into this project, or `ma-agents bind` if ma-agents is already installed, to generate `_bmad/bmm/config.yaml` from the committed binding.
|
|
62
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
63
|
+
|
|
64
|
+
- **No `project_layout_stamp:` line at column 0 of `config.yaml`** (a commented-out or indented one does not count — it is not the field) → **HALT** and report:
|
|
65
|
+
|
|
66
|
+
> **ma-agents — stopping: `_bmad/bmm/config.yaml` does not record which binding it came from.**
|
|
67
|
+
> `_bmad-output/project-layout.yaml` exists, but `config.yaml` carries no `project_layout_stamp:`, so there is no evidence its paths were generated from the committed binding. Run `ma-agents bind` to regenerate it.
|
|
68
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
69
|
+
|
|
70
|
+
- **`project_layout_stamp:` is present but its value is not `sha256:` followed by exactly 64 lowercase hexadecimal characters** — truncated, uppercased, a different algorithm, unbalanced quotes, or trailing content after the digest → **HALT** and report:
|
|
71
|
+
|
|
72
|
+
> **ma-agents — stopping: `_bmad/bmm/config.yaml` claims to have been generated and the claim cannot be read.**
|
|
73
|
+
> Its `project_layout_stamp:` is {quote the value you found}, which is not a stamp ma-agents wrote (expected `sha256:` followed by 64 lowercase hex characters) — merge damage, a hand-edit, or a truncated write. Treat this config as unverified; it is NOT a config that predates the stamp. Run `ma-agents bind` to regenerate it from `_bmad-output/project-layout.yaml`.
|
|
74
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
75
|
+
|
|
76
|
+
- **`project_layout_stamp:` is well-formed** → go to **Step P4**.
|
|
77
|
+
|
|
78
|
+
### Step P4 — Compare the committed binding against the generated fields
|
|
79
|
+
|
|
80
|
+
Derive, from `_bmad-output/project-layout.yaml`, what each generated field in `config.yaml` WOULD be if it were regenerated right now, and compare it to what `config.yaml` actually carries. This is a content comparison of the two files — never a timestamp comparison.
|
|
81
|
+
|
|
82
|
+
A schema-2 binding holds three records: `system_requirements_store:`, `software_requirements_store:` and `sprint_management:`. A legacy schema-1 binding holds a single `knowledgebase:` record, which stands for BOTH requirement stores.
|
|
83
|
+
|
|
84
|
+
The table below IS the whole comparison: every field named in its right-hand column is compared, and no field outside that column is. Read each field only from a line at column 0, and compare VALUES rather than bytes — the generator quotes its scalars (`sprint_backend: "jira"`, `knowledgebase_path: "."`), so strip one balanced pair of surrounding quotes from each side first.
|
|
85
|
+
|
|
86
|
+
| When | Binding record it is derived from | Field(s) it generates in `config.yaml` |
|
|
87
|
+
| --- | --- | --- |
|
|
88
|
+
| always | `software_requirements_store` → its `path:` (a store whose `backend:` is not `file-system` has no `path:` at all, and so generates `.`); the artifacts field is that same path, except that a path of `.` gives `{project-root}/_bmad-output/planning-artifacts`; its resolved `backend:` (an absent or empty `backend:` resolves to `file-system`), and, when that backend is `confluence`, its `space_key:` — the generated space-key field is empty for every other backend, so a store re-bound away from Confluence does not keep the old space | `software_requirements_path:`, `knowledgebase_path:`, `planning_artifacts:`, `software_requirements_backend:`, `software_requirements_space_key:` |
|
|
89
|
+
| always | `system_requirements_store` → its `path:` (a store whose `backend:` is not `file-system` has no `path:` at all, and so generates `.`); its resolved `backend:` (an absent or empty `backend:` resolves to `file-system`), and, when that backend is `confluence`, its `space_key:` — the generated space-key field is empty for every other backend, so a store re-bound away from Confluence does not keep the old space | `system_requirements_path:`, `system_requirements_backend:`, `system_requirements_space_key:` |
|
|
90
|
+
| `sprint_management` has `mode: jira` | `sprint_management` → its `jira_url:` and `jira_project_key:`; the backend field is the literal `jira`; the artifacts field is always `{project-root}/_bmad-output/implementation-artifacts`, because a Jira sprint store has no path | `sprint_backend:`, `jira_url:`, `jira_project_key:`, `implementation_artifacts:` |
|
|
91
|
+
| `sprint_management` has any other mode | `sprint_management` → its `path:`; the backend field is the literal `file-system`; the artifacts field is that same path, except that a path of `.` gives `{project-root}/_bmad-output/implementation-artifacts` | `sprint_backend:`, `sprint_management_path:`, `implementation_artifacts:` |
|
|
92
|
+
|
|
93
|
+
**When the binding says `mode: jira`, `sprint_management_path:` is not compared at all.** The generator writes no `sprint_management_path:` in that mode — and it never DELETES a field, it only updates or appends one. So a project that was bound to the file system and later re-bound to Jira still carries its old `sprint_management_path:` line in a freshly generated `config.yaml`. That leftover line is not drift, and comparing it would halt every Jira project that was ever file-system-bound.
|
|
94
|
+
|
|
95
|
+
Not every field in that table is a path. Where a store's `backend:` or `space_key:` is what disagrees, the comparison is the same and so is the halt — read the message template's `{path in …}` placeholders as "the value that disagrees", and name the two values you actually compared.
|
|
96
|
+
|
|
97
|
+
**Any disagreement is drift** → **HALT** and report, naming every store that moved and both of its paths:
|
|
98
|
+
|
|
99
|
+
> **ma-agents — stopping: `_bmad/bmm/config.yaml` is stale.**
|
|
100
|
+
> The committed binding in `_bmad-output/project-layout.yaml` no longer matches the state `_bmad/bmm/config.yaml` was generated from:
|
|
101
|
+
> - {store name}: was `{path in config.yaml}`, is now `{path in project-layout.yaml}`
|
|
102
|
+
> (one line per store that moved)
|
|
103
|
+
> Running this skill now would read and write artifacts where those stores used to be. Run `ma-agents bind` to regenerate `_bmad/bmm/config.yaml` from the committed binding, then run this skill again.
|
|
104
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
105
|
+
|
|
106
|
+
**If everything in the table agrees** → go to **Step P5**.
|
|
107
|
+
|
|
108
|
+
The stamp covers binding state that `config.yaml` does not carry — a Confluence `root_page:`, a `gitUrl:` — so the table alone cannot see every kind of move. If, and only if, a command shell is available to you and `ma-agents` resolves as a local dependency of this project, you may confirm the comparison exactly, without parsing the stamp yourself:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
node -e "const c=require('ma-agents/bin/cli.js'),f=require('fs'),p=process.cwd();const t=c.resolveProjectTopology(p);if(!t.ok){console.log('binding:'+t.reason)}else{const s=c.readProjectLayoutStamp(f.readFileSync('_bmad/bmm/config.yaml','utf8'));console.log(s.ok?(s.value===c.computeProjectLayoutStamp(t.topology,p)?'MATCH':'DRIFT'):'stamp:'+s.reason)}"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`DRIFT` is authoritative: HALT with the stale-config message above even when the table found nothing, and say that the binding changed in a way `config.yaml` does not record. Never treat a failure to run this command as a result — if it does not run, the table is the check, and you say nothing about the stamp.
|
|
115
|
+
|
|
116
|
+
### Step P5 — PROCEED
|
|
117
|
+
|
|
118
|
+
The generated config matches the committed binding. Say NOTHING about the binding, the stamp or this preflight — a matched project gets no message — and continue with the rest of this skill.
|
|
119
|
+
|
|
8
120
|
## Backend Routing
|
|
9
121
|
|
|
10
122
|
Before executing any file-system operations, determine and route to the correct backend:
|
|
@@ -2,6 +2,118 @@
|
|
|
2
2
|
|
|
3
3
|
Guided workflow to move sprint items back to the backlog in the unified `sprint-status.yaml` using reverse movement semantics (inverse of `add-to-sprint`).
|
|
4
4
|
|
|
5
|
+
## Knowledge Store Binding Preflight
|
|
6
|
+
|
|
7
|
+
**Gateway check — run this before anything else in this skill.** Before any read, any write, any user prompt, and before any other routing or configuration step below. No other step of this skill executes until this preflight returns PROCEED.
|
|
8
|
+
|
|
9
|
+
`_bmad/bmm/config.yaml` is a GENERATED file. `ma-agents` derives it from the committed binding in `_bmad-output/project-layout.yaml` on install and on `ma-agents bind`, and records which binding it was generated from in its `project_layout_stamp:` field. If the binding has moved since — the usual cause is a `git pull` that relocated a knowledge store — every path this skill would resolve from `config.yaml` points at where the stores used to be. This preflight refuses to let that happen silently.
|
|
10
|
+
|
|
11
|
+
**This preflight is read-only.** Whatever it finds, do NOT regenerate, repair, edit or create `config.yaml`, `_bmad-output/project-layout.yaml`, or any other file, and do not offer to. Regenerating the config belongs to the installer and to `ma-agents bind`, never to a skill.
|
|
12
|
+
|
|
13
|
+
**Compare content, never timestamps.** Never decide staleness from file modification times: mtime ordering is not preserved by `git pull`, `git checkout` or a fresh clone, so it both misses real drift and reports drift on a clean checkout.
|
|
14
|
+
|
|
15
|
+
Work through the steps below IN ORDER and stop at the first branch that matches. The order is load-bearing — `_bmad-output/project-layout.yaml` is the fact, and the stamp only ever corroborates it.
|
|
16
|
+
|
|
17
|
+
### Step P1 — Read `_bmad-output/project-layout.yaml`
|
|
18
|
+
|
|
19
|
+
- **Missing, or present but blank / comments-only** → go to **Step P2**.
|
|
20
|
+
- **Present but not cleanly readable** — it is not valid YAML, it carries unresolved merge-conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`), it yields no readable fields, its `schema_version:` is greater than `2`, its `schema_version:` is present but is not a number, it names a `backend:` or a `mode:` this build does not recognise, or any store record in it cannot be read → **HALT** and report:
|
|
21
|
+
|
|
22
|
+
> **ma-agents — stopping: the committed knowledge binding cannot be read.**
|
|
23
|
+
> `_bmad-output/project-layout.yaml` exists but this build cannot use it: {say exactly what is wrong}.
|
|
24
|
+
> Every knowledge-store path in `_bmad/bmm/config.yaml` is derived from that file, so nothing this skill would resolve can be trusted. Fix the binding by hand — if this is a merge conflict, resolve it; the file is committed, so conflicts are ordinary — then run `ma-agents bind` to regenerate `_bmad/bmm/config.yaml` from it.
|
|
25
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
26
|
+
|
|
27
|
+
That list of faults is illustrative, not exhaustive. **Default-deny:** the only two ways out of this step without halting are "absent, or blank / comments-only" (→ Step P2) and "resolves cleanly" (→ Step P3). Anything else takes this HALT, including a fault not named above. Do not fall back to defaults and do not treat this as "no binding". A binding that cannot be read is a different fact from a project that has none.
|
|
28
|
+
- **Present and resolves cleanly** → go to **Step P3**.
|
|
29
|
+
|
|
30
|
+
### Step P2 — There is no committed binding
|
|
31
|
+
|
|
32
|
+
No `_bmad-output/project-layout.yaml`. That is the pre-F26 shape and by itself it is NOT drift — but corroborate it instead of trusting it, because "a binding was never written here" and "the binding was deleted, ignored, or not pulled" look identical from the missing file alone. Read `_bmad/bmm/config.yaml`:
|
|
33
|
+
|
|
34
|
+
- **`config.yaml` does not exist either** → **HALT** and report:
|
|
35
|
+
|
|
36
|
+
> **ma-agents — stopping: this project is not configured.**
|
|
37
|
+
> Neither `_bmad-output/project-layout.yaml` nor `_bmad/bmm/config.yaml` exists, so nothing states where this project's knowledge stores live. Run `npx ma-agents install` to configure the project, or `ma-agents bind` if ma-agents is already installed and only the binding is missing.
|
|
38
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
39
|
+
|
|
40
|
+
- **`config.yaml` exists and carries, at column 0, any of `project_layout_stamp:`, `system_requirements_path:` or `software_requirements_path:`** (a commented-out or indented one does not count — it is not the field) → **HALT** and report:
|
|
41
|
+
|
|
42
|
+
> **ma-agents — stopping: the committed knowledge binding is missing.**
|
|
43
|
+
> `_bmad/bmm/config.yaml` carries {name the fields you found}, which only an F26 generation writes — so this project HAS been bound — but `_bmad-output/project-layout.yaml` is not here. The binding was deleted, is untracked or ignored, or has not been pulled. This is not a pre-F26 project, so proceeding would mean trusting generated paths against a binding that no longer exists.
|
|
44
|
+
> Restore the file (for example `git checkout -- _bmad-output/project-layout.yaml`), or run `ma-agents bind` to write a fresh one.
|
|
45
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
46
|
+
|
|
47
|
+
Those three fields are the discriminator and they are reliable: a genuine pre-F26 `config.yaml` carries none of them. Do not skip this check. An absent stamp on its own is never evidence that a project predates the stamp.
|
|
48
|
+
|
|
49
|
+
- **`config.yaml` exists and carries none of those three fields at column 0** → this is genuinely a pre-F26 project. **PROCEED** with the rest of this skill exactly as it behaved before F26, and say nothing at all about the binding — no warning, no prompt, no offer to bind. Nothing has moved, so there is nothing to re-bind. The existence of `config.yaml` is NOT on its own a reason to take this branch: all three fields must be absent.
|
|
50
|
+
|
|
51
|
+
### Step P3 — The binding is readable: check what `config.yaml` was generated from
|
|
52
|
+
|
|
53
|
+
Read `_bmad/bmm/config.yaml`.
|
|
54
|
+
|
|
55
|
+
- **`config.yaml` does not exist** → **HALT** and report:
|
|
56
|
+
|
|
57
|
+
> **ma-agents — stopping: the generated config is missing.**
|
|
58
|
+
> `_bmad-output/project-layout.yaml` commits this project's knowledge binding, but `_bmad/bmm/config.yaml` — the file this skill resolves its paths from — has never been generated from it. Run `npx ma-agents install` to install into this project, or `ma-agents bind` if ma-agents is already installed, to generate `_bmad/bmm/config.yaml` from the committed binding.
|
|
59
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
60
|
+
|
|
61
|
+
- **No `project_layout_stamp:` line at column 0 of `config.yaml`** (a commented-out or indented one does not count — it is not the field) → **HALT** and report:
|
|
62
|
+
|
|
63
|
+
> **ma-agents — stopping: `_bmad/bmm/config.yaml` does not record which binding it came from.**
|
|
64
|
+
> `_bmad-output/project-layout.yaml` exists, but `config.yaml` carries no `project_layout_stamp:`, so there is no evidence its paths were generated from the committed binding. Run `ma-agents bind` to regenerate it.
|
|
65
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
66
|
+
|
|
67
|
+
- **`project_layout_stamp:` is present but its value is not `sha256:` followed by exactly 64 lowercase hexadecimal characters** — truncated, uppercased, a different algorithm, unbalanced quotes, or trailing content after the digest → **HALT** and report:
|
|
68
|
+
|
|
69
|
+
> **ma-agents — stopping: `_bmad/bmm/config.yaml` claims to have been generated and the claim cannot be read.**
|
|
70
|
+
> Its `project_layout_stamp:` is {quote the value you found}, which is not a stamp ma-agents wrote (expected `sha256:` followed by 64 lowercase hex characters) — merge damage, a hand-edit, or a truncated write. Treat this config as unverified; it is NOT a config that predates the stamp. Run `ma-agents bind` to regenerate it from `_bmad-output/project-layout.yaml`.
|
|
71
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
72
|
+
|
|
73
|
+
- **`project_layout_stamp:` is well-formed** → go to **Step P4**.
|
|
74
|
+
|
|
75
|
+
### Step P4 — Compare the committed binding against the generated fields
|
|
76
|
+
|
|
77
|
+
Derive, from `_bmad-output/project-layout.yaml`, what each generated field in `config.yaml` WOULD be if it were regenerated right now, and compare it to what `config.yaml` actually carries. This is a content comparison of the two files — never a timestamp comparison.
|
|
78
|
+
|
|
79
|
+
A schema-2 binding holds three records: `system_requirements_store:`, `software_requirements_store:` and `sprint_management:`. A legacy schema-1 binding holds a single `knowledgebase:` record, which stands for BOTH requirement stores.
|
|
80
|
+
|
|
81
|
+
The table below IS the whole comparison: every field named in its right-hand column is compared, and no field outside that column is. Read each field only from a line at column 0, and compare VALUES rather than bytes — the generator quotes its scalars (`sprint_backend: "jira"`, `knowledgebase_path: "."`), so strip one balanced pair of surrounding quotes from each side first.
|
|
82
|
+
|
|
83
|
+
| When | Binding record it is derived from | Field(s) it generates in `config.yaml` |
|
|
84
|
+
| --- | --- | --- |
|
|
85
|
+
| always | `software_requirements_store` → its `path:` (a store whose `backend:` is not `file-system` has no `path:` at all, and so generates `.`); the artifacts field is that same path, except that a path of `.` gives `{project-root}/_bmad-output/planning-artifacts`; its resolved `backend:` (an absent or empty `backend:` resolves to `file-system`), and, when that backend is `confluence`, its `space_key:` — the generated space-key field is empty for every other backend, so a store re-bound away from Confluence does not keep the old space | `software_requirements_path:`, `knowledgebase_path:`, `planning_artifacts:`, `software_requirements_backend:`, `software_requirements_space_key:` |
|
|
86
|
+
| always | `system_requirements_store` → its `path:` (a store whose `backend:` is not `file-system` has no `path:` at all, and so generates `.`); its resolved `backend:` (an absent or empty `backend:` resolves to `file-system`), and, when that backend is `confluence`, its `space_key:` — the generated space-key field is empty for every other backend, so a store re-bound away from Confluence does not keep the old space | `system_requirements_path:`, `system_requirements_backend:`, `system_requirements_space_key:` |
|
|
87
|
+
| `sprint_management` has `mode: jira` | `sprint_management` → its `jira_url:` and `jira_project_key:`; the backend field is the literal `jira`; the artifacts field is always `{project-root}/_bmad-output/implementation-artifacts`, because a Jira sprint store has no path | `sprint_backend:`, `jira_url:`, `jira_project_key:`, `implementation_artifacts:` |
|
|
88
|
+
| `sprint_management` has any other mode | `sprint_management` → its `path:`; the backend field is the literal `file-system`; the artifacts field is that same path, except that a path of `.` gives `{project-root}/_bmad-output/implementation-artifacts` | `sprint_backend:`, `sprint_management_path:`, `implementation_artifacts:` |
|
|
89
|
+
|
|
90
|
+
**When the binding says `mode: jira`, `sprint_management_path:` is not compared at all.** The generator writes no `sprint_management_path:` in that mode — and it never DELETES a field, it only updates or appends one. So a project that was bound to the file system and later re-bound to Jira still carries its old `sprint_management_path:` line in a freshly generated `config.yaml`. That leftover line is not drift, and comparing it would halt every Jira project that was ever file-system-bound.
|
|
91
|
+
|
|
92
|
+
Not every field in that table is a path. Where a store's `backend:` or `space_key:` is what disagrees, the comparison is the same and so is the halt — read the message template's `{path in …}` placeholders as "the value that disagrees", and name the two values you actually compared.
|
|
93
|
+
|
|
94
|
+
**Any disagreement is drift** → **HALT** and report, naming every store that moved and both of its paths:
|
|
95
|
+
|
|
96
|
+
> **ma-agents — stopping: `_bmad/bmm/config.yaml` is stale.**
|
|
97
|
+
> The committed binding in `_bmad-output/project-layout.yaml` no longer matches the state `_bmad/bmm/config.yaml` was generated from:
|
|
98
|
+
> - {store name}: was `{path in config.yaml}`, is now `{path in project-layout.yaml}`
|
|
99
|
+
> (one line per store that moved)
|
|
100
|
+
> Running this skill now would read and write artifacts where those stores used to be. Run `ma-agents bind` to regenerate `_bmad/bmm/config.yaml` from the committed binding, then run this skill again.
|
|
101
|
+
> Nothing has been read or written on your behalf. Stopping rather than guessing.
|
|
102
|
+
|
|
103
|
+
**If everything in the table agrees** → go to **Step P5**.
|
|
104
|
+
|
|
105
|
+
The stamp covers binding state that `config.yaml` does not carry — a Confluence `root_page:`, a `gitUrl:` — so the table alone cannot see every kind of move. If, and only if, a command shell is available to you and `ma-agents` resolves as a local dependency of this project, you may confirm the comparison exactly, without parsing the stamp yourself:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
node -e "const c=require('ma-agents/bin/cli.js'),f=require('fs'),p=process.cwd();const t=c.resolveProjectTopology(p);if(!t.ok){console.log('binding:'+t.reason)}else{const s=c.readProjectLayoutStamp(f.readFileSync('_bmad/bmm/config.yaml','utf8'));console.log(s.ok?(s.value===c.computeProjectLayoutStamp(t.topology,p)?'MATCH':'DRIFT'):'stamp:'+s.reason)}"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`DRIFT` is authoritative: HALT with the stale-config message above even when the table found nothing, and say that the binding changed in a way `config.yaml` does not record. Never treat a failure to run this command as a result — if it does not run, the table is the check, and you say nothing about the stamp.
|
|
112
|
+
|
|
113
|
+
### Step P5 — PROCEED
|
|
114
|
+
|
|
115
|
+
The generated config matches the committed binding. Say NOTHING about the binding, the stamp or this preflight — a matched project gets no message — and continue with the rest of this skill.
|
|
116
|
+
|
|
5
117
|
<workflow>
|
|
6
118
|
|
|
7
119
|
<step n="0" goal="Load configuration and validate file existence">
|