Compare commits
9 Commits
3e2085975a
...
3970ace793
| Author | SHA1 | Date |
|---|---|---|
|
|
3970ace793 | |
|
|
77628f0055 | |
|
|
4104598460 | |
|
|
c8784a167b | |
|
|
47cf70f0e8 | |
|
|
242dc6ef75 | |
|
|
560a2e3a6f | |
|
|
fbb48ed711 | |
|
|
b9431d6d99 |
|
|
@ -26,6 +26,9 @@ design-artifacts/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
|
|
||||||
|
# BMad run artifacts (memlogs are per-run working memory, never committed)
|
||||||
|
.memlog.md
|
||||||
|
|
||||||
# System files
|
# System files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
|
||||||
16
README_KR.md
16
README_KR.md
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
[](https://www.npmjs.com/package/bmad-method)
|
[](https://www.npmjs.com/package/bmad-method)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](https://nodejs.org)
|
[](https://nodejs.org)
|
||||||
[](https://www.python.org)
|
[](https://www.python.org)
|
||||||
[](https://docs.astral.sh/uv/)
|
[](https://docs.astral.sh/uv/)
|
||||||
[](https://discord.gg/gk8jAdXWmj)
|
[](https://discord.gg/gk8jAdXWmj)
|
||||||
|
|
||||||
[English](README.md) | [简体中文](README_CN.md) | [Tiếng Việt](README_VN.md) | 한국어
|
[English](README.md) | [简体中文](README_CN.md) | [Tiếng Việt](README_VN.md) | 한국어
|
||||||
|
|
||||||
**Build More Architect Dreams** - BMad Method 모듈 생태계를 위한 AI 기반 애자일 개발 모듈입니다. 버그 수정부터 엔터프라이즈 시스템까지, 프로젝트 규모와 도메인에 맞춰 계획 깊이를 조절하는 포괄적인 프레임워크입니다.
|
**Build More Architect Dreams** - BMad Method 모듈 생태계를 위한 포괄적인 AI 기반 애자일 개발 프레임워크입니다. 버그 수정부터 엔터프라이즈 시스템까지, 프로젝트 규모와 도메인에 맞춰 계획 깊이를 조절합니다.
|
||||||
|
|
||||||
**100% 무료 오픈 소스입니다.** 유료 장벽도, 잠긴 콘텐츠도, 폐쇄형 Discord도 없습니다. 우리는 닫힌 커뮤니티나 강좌 비용을 낼 수 있는 사람만이 아니라 모두가 더 나은 도구를 쓸 수 있어야 한다고 믿습니다.
|
**100% 무료 오픈 소스입니다.** 유료 장벽도, 잠긴 콘텐츠도, 폐쇄형 Discord도 없습니다. 우리는 닫힌 커뮤니티나 강좌 비용을 낼 수 있는 사람만이 아니라 모두가 더 나은 도구를 쓸 수 있어야 한다고 믿습니다.
|
||||||
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
## 빠른 시작
|
## 빠른 시작
|
||||||
|
|
||||||
**필수 조건**: [Node.js](https://nodejs.org) v20+ · [Python](https://www.python.org) 3.10+ · [uv](https://docs.astral.sh/uv/)
|
**필수 조건**: [Node.js](https://nodejs.org) v20.12+ · [Python](https://www.python.org) 3.10+ · [uv](https://docs.astral.sh/uv/)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npx bmad-method install
|
npx bmad-method install
|
||||||
|
|
@ -75,6 +75,16 @@ BMad Method는 전문 도메인을 위한 공식 모듈로 확장됩니다. 설
|
||||||
| **[게임 개발 스튜디오(BMGD)](https://github.com/bmad-code-org/bmad-module-game-dev-studio)** | Unity, Unreal, Godot 워크플로 |
|
| **[게임 개발 스튜디오(BMGD)](https://github.com/bmad-code-org/bmad-module-game-dev-studio)** | Unity, Unreal, Godot 워크플로 |
|
||||||
| **[창의적 지능 제품군(CIS)](https://github.com/bmad-code-org/bmad-module-creative-intelligence-suite)** | 혁신, 브레인스토밍, 디자인 사고 |
|
| **[창의적 지능 제품군(CIS)](https://github.com/bmad-code-org/bmad-module-creative-intelligence-suite)** | 혁신, 브레인스토밍, 디자인 사고 |
|
||||||
|
|
||||||
|
## Web Bundles
|
||||||
|
|
||||||
|
V4에도 Web bundle이 있었습니다. V6에서는 새롭게 개선된 형태로 다시 돌아왔습니다.
|
||||||
|
|
||||||
|
Web bundle은 선택한 BMad 스킬을 **Google Gemini Gem**과 **ChatGPT Custom GPT**로 설치할 수 있게 패키징합니다. 브레인스토밍, 제품 개요, PRD, PRFAQ, UX 사양, 시장 및 산업 리서치 같은 앞단 계획 작업은 웹 LLM 구독 환경에서 진행하고, 다듬어진 산출물은 IDE로 가져와 구현에 사용하세요. 계획 작업을 사용량 과금형 IDE 토큰 대신 정액 구독 환경에서 처리하므로 긴 작업에서는 비용을 줄이는 데 도움이 됩니다. Gemini나 ChatGPT에서 사용할 수 있는 가장 좋은 모델을 선택하면 됩니다.
|
||||||
|
|
||||||
|
현재 제공되는 번들은 브레인스토밍, 제품 개요, PRFAQ, PRD, UX, 시장 및 산업 리서치입니다.
|
||||||
|
|
||||||
|
**[bmadcode.com/web-bundles](https://bmadcode.com/web-bundles/)에서 찾아보고 설치하세요.** 번들마다 카드가 하나씩 있고, Gemini와 ChatGPT 설치 단계가 페이지 안에 안내되며, ZIP 파일도 바로 다운로드할 수 있습니다. 개념 설명은 [Web bundle 가이드](https://docs.bmad-method.org/ko-kr/explanation/web-bundles/)를 참고하세요.
|
||||||
|
|
||||||
## 문서
|
## 문서
|
||||||
|
|
||||||
[BMad Method 문서 사이트](https://docs.bmad-method.org/ko-kr/) - 튜토리얼, 가이드, 개념 설명, 참조 문서
|
[BMad Method 문서 사이트](https://docs.bmad-method.org/ko-kr/) - 튜토리얼, 가이드, 개념 설명, 참조 문서
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ description: Google 스타일과 Diataxis 구조를 바탕으로 한 프로젝
|
||||||
| 스킬 | 에이전트 | 목적 |
|
| 스킬 | 에이전트 | 목적 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `bmad-brainstorming` | 분석가 | 새 프로젝트 브레인스토밍 |
|
| `bmad-brainstorming` | 분석가 | 새 프로젝트 브레인스토밍 |
|
||||||
| `bmad-create-prd` | PM | 제품 요구사항 문서 생성 |
|
| `bmad-prd` | PM | 제품 요구사항 문서 생성 |
|
||||||
```
|
```
|
||||||
|
|
||||||
## 폴더 구조 블록
|
## 폴더 구조 블록
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
title: "고급 도출"
|
title: "고급 도출"
|
||||||
description: 구조화된 추론 방법으로 LLM이 자신의 작업을 다시 생각하게 합니다
|
description: 구조화된 추론 방법으로 LLM이 자신의 작업을 다시 생각하게 합니다
|
||||||
sidebar:
|
sidebar:
|
||||||
order: 9
|
order: 4
|
||||||
---
|
---
|
||||||
|
|
||||||
LLM이 방금 생성한 결과를 다시 검토하게 만드세요. 추론 방법을 선택하면 LLM이 그 방법을 자신의 출력에 적용하고, 사용자는 개선 사항을 유지할지 결정합니다.
|
LLM이 방금 생성한 결과를 다시 검토하게 만드세요. 추론 방법을 선택하면 LLM이 그 방법을 자신의 출력에 적용하고, 사용자는 개선 사항을 유지할지 결정합니다.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
title: "적대적 리뷰"
|
title: "적대적 리뷰"
|
||||||
description: “괜찮아 보이네”라는 식의 대충 넘어가는 검토를 방지하는 논리적 추론 기법
|
description: “괜찮아 보이네”라는 식의 대충 넘어가는 검토를 방지하는 논리적 추론 기법
|
||||||
sidebar:
|
sidebar:
|
||||||
order: 8
|
order: 9
|
||||||
---
|
---
|
||||||
|
|
||||||
문제를 반드시 찾게 만들어 더 깊은 분석을 강제합니다.
|
문제를 반드시 찾게 만들어 더 깊은 분석을 강제합니다.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
title: "분석 단계: 아이디어에서 기반까지"
|
title: "분석 단계: 아이디어에서 기반까지"
|
||||||
description: 브레인스토밍, 리서치, 제품 개요, PRFAQ가 무엇이며 언제 쓰는지 설명합니다
|
description: 브레인스토밍, 리서치, 제품 개요, PRFAQ가 무엇이며 언제 쓰는지 설명합니다
|
||||||
sidebar:
|
sidebar:
|
||||||
order: 1
|
order: 2
|
||||||
---
|
---
|
||||||
|
|
||||||
분석 단계(단계 1)는 제품을 만들기로 확정하기 전에 명확하게 생각하도록 돕습니다. 이 단계의 모든 도구는 선택 사항이지만, 분석을 완전히 건너뛰면 PRD가 인사이트가 아니라 가정 위에 세워집니다.
|
분석 단계(단계 1)는 제품을 만들기로 확정하기 전에 명확하게 생각하도록 돕습니다. 이 단계의 모든 도구는 선택 사항이지만, 분석을 완전히 건너뛰면 PRD가 인사이트가 아니라 가정 위에 세워집니다.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
title: "체크포인트 미리보기"
|
title: "체크포인트 미리보기"
|
||||||
description: 목적에서 세부 사항에 이르기까지의 변경 과정을 단계별로 안내하는, LLM을 활용한 인간 중심 검토
|
description: 목적에서 세부 사항에 이르기까지의 변경 과정을 단계별로 안내하는, LLM을 활용한 인간 중심 검토
|
||||||
sidebar:
|
sidebar:
|
||||||
order: 5
|
order: 8
|
||||||
---
|
---
|
||||||
|
|
||||||
`bmad-checkpoint-preview`는 LLM이 보조하는 대화형 human-in-the-loop 리뷰 워크플로입니다. 코드 변경을 목적과 컨텍스트에서 세부 사항까지 안내해, 출시할지, 다시 작업할지, 더 파고들지에 대해 충분한 정보를 바탕으로 판단할 수 있게 합니다.
|
`bmad-checkpoint-preview`는 LLM이 보조하는 대화형 human-in-the-loop 리뷰 워크플로입니다. 코드 변경을 목적과 컨텍스트에서 세부 사항까지 안내해, 출시할지, 다시 작업할지, 더 파고들지에 대해 충분한 정보를 바탕으로 판단할 수 있게 합니다.
|
||||||
|
|
|
||||||
|
|
@ -55,11 +55,11 @@ sidebar:
|
||||||
|
|
||||||
이것이 포렌식 감각입니다. 목격자 진술은 데이터이지 진실이 아닙니다. 때로 보고된 버그는 진짜지만 이름표가 틀립니다. 때로 설명된 증상은 다른 원인의 파생 결과입니다. 전제를 절대적 진실로 받아들이는 조사는 잘못된 결함을 진단하고, 버그는 약간 다른 형태로 돌아옵니다.
|
이것이 포렌식 감각입니다. 목격자 진술은 데이터이지 진실이 아닙니다. 때로 보고된 버그는 진짜지만 이름표가 틀립니다. 때로 설명된 증상은 다른 원인의 파생 결과입니다. 전제를 절대적 진실로 받아들이는 조사는 잘못된 결함을 진단하고, 버그는 약간 다른 형태로 돌아옵니다.
|
||||||
|
|
||||||
## 보정된 진행
|
## 상황에 맞춘 조사 흐름
|
||||||
|
|
||||||
스킬은 두 가지 모드가 아니라 하나의 절차입니다. 입력이 요구하는 결함 추적과 영역 탐색의 비율을 계속 보정합니다.
|
스킬은 두 가지 모드가 아니라 하나의 절차입니다. 입력이 요구하는 결함 추적과 영역 탐색의 비율을 계속 맞춥니다.
|
||||||
|
|
||||||
증상 기반 사례(티켓, 충돌, 오류 메시지, "예전엔 됐다")는 가설 추적, 타임라인 재구성, 수정 방향에 기울어집니다. 증상 없는 사례(만지기 전 모듈 이해, 재사용성 평가, 정신 모델 구축)는 I/O 매핑, 제어 흐름 필터링, 검증 계획에 기울어집니다. 실제 사례 대부분은 그 사이 어딘가에 있고, 사례 파일은 증거가 요구한 균형을 반영합니다.
|
증상 기반 사례(티켓, 충돌, 오류 메시지, "예전엔 됐다")는 가설 추적, 타임라인 재구성, 수정 방향에 무게를 둡니다. 증상 없는 사례(만지기 전 모듈 이해, 재사용성 평가, 정신 모델 구축)는 I/O 매핑, 제어 흐름 필터링, 검증 계획에 무게를 둡니다. 실제 사례 대부분은 그 사이 어딘가에 있고, 사례 파일은 증거가 요구한 균형을 반영합니다.
|
||||||
|
|
||||||
사례가 어디에 있든 원칙은 같습니다. 먼저 기준점 확보, 증거 등급화, 가설 추적, 절대 지우지 않기입니다. 출력은 항상 `{implementation_artifacts}/investigations/{slug}-investigation.md`이며, 해당 사례에 적용되지 않는 섹션은 비어 있거나 생략됩니다.
|
사례가 어디에 있든 원칙은 같습니다. 먼저 기준점 확보, 증거 등급화, 가설 추적, 절대 지우지 않기입니다. 출력은 항상 `{implementation_artifacts}/investigations/{slug}-investigation.md`이며, 해당 사례에 적용되지 않는 섹션은 비어 있거나 생략됩니다.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
title: "이름 있는 에이전트"
|
title: "이름 있는 에이전트"
|
||||||
description: BMad 에이전트가 이름, 페르소나, 커스터마이징 영역을 갖는 이유와 메뉴 기반 또는 프롬프트 기반 대안보다 무엇을 가능하게 하는지
|
description: BMad 에이전트가 이름, 페르소나, 커스터마이징 영역을 갖는 이유와 메뉴 기반 또는 프롬프트 기반 대안보다 무엇을 가능하게 하는지
|
||||||
sidebar:
|
sidebar:
|
||||||
order: 2
|
order: 1
|
||||||
---
|
---
|
||||||
|
|
||||||
"Mary, 브레인스토밍하자"라고 말하면 Mary가 활성화됩니다. 그녀는 설정한 언어로 당신의 이름을 부르고, 고유한 페르소나로 인사합니다. `bmad-help`가 언제나 가능하다고 알려줍니다. 그리고 의도가 명확했기 때문에 메뉴를 건너뛰고 바로 브레인스토밍으로 들어갑니다.
|
"Mary, 브레인스토밍하자"라고 말하면 Mary가 활성화됩니다. 그녀는 설정한 언어로 당신의 이름을 부르고, 고유한 페르소나로 인사합니다. `bmad-help`가 언제나 가능하다고 알려줍니다. 그리고 의도가 명확했기 때문에 메뉴를 건너뛰고 바로 브레인스토밍으로 들어갑니다.
|
||||||
|
|
@ -67,7 +67,7 @@ BMad는 BMad Method의 단계에 맞춘 여섯 이름 있는 에이전트를 제
|
||||||
|
|
||||||
빈 프롬프트는 사용자가 마법 단어를 안다고 가정합니다. "브레인스토밍을 도와줘"는 될 수 있지만 "내 SaaS 아이디어를 같이 발전시켜 보자"는 안 될 수 있고, 결과는 표현 방식에 의존합니다. 사용자가 프롬프트 엔지니어링을 책임지게 됩니다.
|
빈 프롬프트는 사용자가 마법 단어를 안다고 가정합니다. "브레인스토밍을 도와줘"는 될 수 있지만 "내 SaaS 아이디어를 같이 발전시켜 보자"는 안 될 수 있고, 결과는 표현 방식에 의존합니다. 사용자가 프롬프트 엔지니어링을 책임지게 됩니다.
|
||||||
|
|
||||||
이름 있는 에이전트는 자유를 닫지 않고 구조를 더합니다. 페르소나는 일관되고, 기능은 발견 가능하며, `bmad-help`는 항상 한 명령 거리에 있습니다. 에이전트가 무엇을 할 수 있는지 추측할 필요도, 사용 설명서가 필요하지도 않습니다.
|
이름 있는 에이전트는 자유를 제한하지 않으면서 구조를 제공합니다. 페르소나는 일관되고, 기능은 발견하기 쉬우며, `bmad-help`는 명령 하나로 언제든 호출할 수 있습니다. 에이전트가 무엇을 할 수 있는지 추측할 필요도, 사용 설명서가 필요하지도 않습니다.
|
||||||
|
|
||||||
## 커스터마이징은 일급 기능입니다
|
## 커스터마이징은 일급 기능입니다
|
||||||
|
|
||||||
|
|
@ -84,7 +84,7 @@ BMad는 BMad Method의 단계에 맞춘 여섯 이름 있는 에이전트를 제
|
||||||
전체 커스터마이징 영역과 작동 예시는 다음을 참고하세요.
|
전체 커스터마이징 영역과 작동 예시는 다음을 참고하세요.
|
||||||
|
|
||||||
- [BMad 커스터마이징 방법](../how-to/customize-bmad.md) - 무엇을 커스터마이즈할 수 있고 병합이 어떻게 동작하는지의 참조
|
- [BMad 커스터마이징 방법](../how-to/customize-bmad.md) - 무엇을 커스터마이즈할 수 있고 병합이 어떻게 동작하는지의 참조
|
||||||
- [조직을 위해 BMad 확장하기](../how-to/expand-bmad-for-your-org.md) - 에이전트 전반 규칙, 워크플로 관례, 외부 게시, 템플릿 교체, 에이전트 명단 커스터마이징을 다루는 실전 레시피
|
- [조직을 위해 BMad 확장하기](../how-to/expand-bmad-for-your-org.md) - 에이전트 전반 규칙, 워크플로 관례, 외부 게시, 템플릿 교체, 에이전트 명단 커스터마이징을 다루는 여섯 가지 실전 레시피
|
||||||
- `bmad-customize` 스킬 - 의도를 올바른 위치의 검증된 오버라이드 파일로 바꿔 주는 안내형 작성 도우미
|
- `bmad-customize` 스킬 - 의도를 올바른 위치의 검증된 오버라이드 파일로 바꿔 주는 안내형 작성 도우미
|
||||||
|
|
||||||
## 더 큰 아이디어
|
## 더 큰 아이디어
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ sidebar:
|
||||||
|
|
||||||
## 파티 모드란?
|
## 파티 모드란?
|
||||||
|
|
||||||
`bmad-party-mode`를 실행하면 PM, 아키텍트, 개발자, UX 디자이너 등 필요한 AI 팀 전체가 한 방에 모입니다. BMad Master가 조율하고 메시지마다 관련 에이전트를 선택합니다. 에이전트들은 각 페르소나에 맞게 답하고, 동의하거나 반대하며, 서로의 아이디어를 이어받아 발전시킵니다.
|
`bmad-party-mode`를 실행하면 PM, 아키텍트, 개발자, UX 디자이너 등 필요한 AI 팀 전체가 한 대화방에 모입니다. 파티 모드가 논의를 조율하고 메시지마다 설치된 에이전트 중 적합한 에이전트를 선택합니다. 에이전트들은 각 페르소나에 맞게 답하고, 동의하거나 반대하며, 서로의 아이디어를 이어받아 발전시킵니다.
|
||||||
|
|
||||||
대화는 원하는 만큼 계속됩니다. 후속 질문을 묻고, 답에 반박하고, 토론 방향을 바꿀 수 있습니다. 끝날 때까지 에이전트들과 실제 주고받는 대화를 합니다.
|
대화는 원하는 만큼 계속됩니다. 후속 질문을 묻고, 답에 반박하고, 토론 방향을 바꿀 수 있습니다. 끝날 때까지 에이전트들과 실제 주고받는 대화를 합니다.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
title: "에이전트 충돌 방지"
|
title: "에이전트 충돌 방지"
|
||||||
description: 여러 에이전트가 시스템을 구현할 때 아키텍처가 충돌을 방지하는 방법
|
description: 여러 에이전트가 시스템을 구현할 때 아키텍처가 충돌을 방지하는 방법
|
||||||
sidebar:
|
sidebar:
|
||||||
order: 7
|
order: 6
|
||||||
---
|
---
|
||||||
|
|
||||||
여러 AI 에이전트가 시스템의 서로 다른 부분을 구현하면 충돌하는 기술 결정을 내릴 수 있습니다. 아키텍처 문서화는 공유 표준을 세워 이를 방지합니다.
|
여러 AI 에이전트가 시스템의 서로 다른 부분을 구현하면 충돌하는 기술 결정을 내릴 수 있습니다. 아키텍처 문서화는 공유 표준을 세워 이를 방지합니다.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
title: "빠른 개발"
|
title: "빠른 개발"
|
||||||
description: 출력 품질을 보호하는 체크포인트를 포기하지 않고 사람이 개입하는 검토의 마찰을 줄입니다
|
description: 출력 품질을 보호하는 체크포인트를 포기하지 않고 사람이 개입하는 검토의 마찰을 줄입니다
|
||||||
sidebar:
|
sidebar:
|
||||||
order: 4
|
order: 7
|
||||||
---
|
---
|
||||||
|
|
||||||
의도를 넣으면 코드 변경이 나오고, 사람이 개입하는 검토 단계는 가능한 한 적게 사용합니다. 품질은 희생하지 않습니다.
|
의도를 넣으면 코드 변경이 나오고, 사람이 개입하는 검토 단계는 가능한 한 적게 사용합니다. 품질은 희생하지 않습니다.
|
||||||
|
|
@ -68,6 +68,6 @@ sidebar:
|
||||||
|
|
||||||
빠른 개발은 리뷰를 분류 작업으로 다뤄 둘 다 해결합니다.
|
빠른 개발은 리뷰를 분류 작업으로 다뤄 둘 다 해결합니다.
|
||||||
|
|
||||||
어떤 발견 사항은 현재 변경에 속합니다. 어떤 발견 사항은 그렇지 않습니다. 발견 사항이 현재 작업과 인과적으로 연결되지 않은 부수적 이슈라면, 워크플로는 즉시 처리하도록 강제하지 않고 미룰 수 있습니다. 이렇게 하면 실행이 집중되고 무작위 곁가지가 주의력 예산을 소비하지 않습니다.
|
어떤 발견 사항은 현재 변경에 속합니다. 어떤 발견 사항은 그렇지 않습니다. 발견 사항이 현재 작업과 인과적으로 연결되지 않은 부수적 이슈라면, 워크플로는 즉시 처리하도록 강제하지 않고 미룰 수 있습니다. 이렇게 하면 실행이 집중되고, 무작위로 뻗는 곁가지가 검토 여력을 소모하지 않습니다.
|
||||||
|
|
||||||
분류는 때때로 완벽하지 않습니다. 괜찮습니다. 수천 개의 낮은 가치 리뷰 댓글로 사람을 압도하는 것보다 일부 발견 사항을 잘못 판단하는 편이 보통 낫습니다. 이 시스템은 모든 이슈를 빠짐없이 회수하는 것보다 신호 품질을 최적화합니다.
|
분류는 때때로 완벽하지 않습니다. 괜찮습니다. 수천 개의 낮은 가치 리뷰 댓글로 사람을 압도하는 것보다 일부 발견 사항을 잘못 판단하는 편이 보통 낫습니다. 이 시스템은 모든 이슈를 빠짐없이 회수하는 것보다 신호 품질을 최적화합니다.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
---
|
||||||
|
title: 'Web Bundles'
|
||||||
|
description: Google Gemini Gems와 ChatGPT Custom GPT용으로 패키징된 BMad 스킬
|
||||||
|
---
|
||||||
|
|
||||||
|
BMad의 계획 작업은 웹 LLM 구독 환경에서 실행하고, 만들어진 산출물은 IDE로 가져오세요.
|
||||||
|
|
||||||
|
## Web Bundle이란?
|
||||||
|
|
||||||
|
Web bundle은 **Google Gemini Gem** 또는 **ChatGPT Custom GPT**로 설치할 수 있게 다시 패키징한 BMad 스킬입니다. 각 번들에는 지식 파일로 업로드하는 `SKILL.md` 프로토콜, Gem 또는 GPT 지침에 붙여 넣는 `INSTRUCTIONS.md` 블록, 그리고 스킬에 필요한 데이터 파일(CSV, 템플릿, 검증 체크리스트, 추가로 점진 공개되는 콘텐츠)이 포함됩니다. 페르소나는 붙여 넣은 지침에 있고, 프로토콜은 지식 파일에 있습니다. 프로토콜을 건드리지 않고도 페르소나를 바꿀 수 있습니다.
|
||||||
|
|
||||||
|
설치가 원클릭은 아니지만 단계는 안내됩니다. **[bmadcode.com/web-bundles](https://bmadcode.com/web-bundles/)에서 설치하세요**. 이 사이트는 모든 번들을 카드 그리드로 보여 주고, Gemini와 ChatGPT 설치 단계를 페이지 안에서 안내하며, ZIP 다운로드를 제공합니다. 이것이 지원되는 설치 경로입니다. 전체 카탈로그에서 패턴이 같으므로 하나만 설치해 보면 다음 번들은 기계적으로 진행할 수 있습니다.
|
||||||
|
|
||||||
|
BMad V4에도 web bundle이 있었습니다. V6에서는 현재 Gem과 Custom GPT 플랫폼, Canvas, Deep Research, 이미지 생성을 염두에 두고 다시 작성해 되살렸습니다.
|
||||||
|
|
||||||
|
## 사용하는 이유
|
||||||
|
|
||||||
|
계획 작업과 구현 작업에는 서로 다른 도구가 어울립니다. Web bundle은 각 작업을 가장 잘 맞는 곳에서 하게 해 줍니다.
|
||||||
|
|
||||||
|
| 관심사 | Web LLM(Gem 또는 GPT) | IDE(Claude Code, Cursor) |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 비용 모델 | 정액 구독 | 토큰 사용량 과금 |
|
||||||
|
| 강점 | 대화, Canvas, Deep Research, 이미지 | 파일, 터미널, 코드베이스 컨텍스트 |
|
||||||
|
| 가장 적합한 작업 | 브레인스토밍, brief, PRD, 리서치 | 구현, 리팩터링, 코드 리뷰 |
|
||||||
|
|
||||||
|
전체 PRD나 시장 리서치 대화를 IDE에서 진행하면 토큰을 많이 쓰지만, Gem이나 Custom GPT에서는 이미 가진 구독 비용 안에서 처리할 수 있습니다. 다듬어진 산출물은 저장소에 넣고 Claude Code나 Cursor가 이어받으면 됩니다.
|
||||||
|
|
||||||
|
:::tip[웹에서 계획하고 IDE에서 빌드하세요]
|
||||||
|
작업이 길어질수록 비용 절감 효과가 커집니다. Gem에서 PRFAQ 한 번과 리서치 세 라운드를 돌리는 것은 추가 비용이 없지만, 같은 작업을 IDE에서 하면 실제 지출이 됩니다.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 카탈로그에 있는 것
|
||||||
|
|
||||||
|
현재 번들 세트는 분석과 계획 단계를 다룹니다.
|
||||||
|
|
||||||
|
| Bundle | Phase | Persona lineage |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Brainstorming Coach | Analysis | Osborn(기본), Minto(교체) |
|
||||||
|
| Product Brief Coach | Analysis | Mary(BMad 분석가) |
|
||||||
|
| PRFAQ Coach | Analysis | Working Backwards(Bezos) |
|
||||||
|
| PRD Coach | Planning | Cagan |
|
||||||
|
| UX Coach | Planning | Norman |
|
||||||
|
| Market & Industry Research | Analysis | Porter와 Christensen |
|
||||||
|
|
||||||
|
각 번들은 소유 BMad 에이전트가 있는 경우 그 에이전트에서 물려받은 기본 페르소나와, 목소리 변경 패턴을 보여 주는 대비용 교체 예시를 함께 담고 있습니다.
|
||||||
|
|
||||||
|
## 세션 작동 방식
|
||||||
|
|
||||||
|
1. **Gem 또는 Custom GPT를 엽니다.** 페르소나가 캐릭터에 맞게 인사하고 대화형 발견을 시작합니다.
|
||||||
|
2. **범위를 발견합니다.** 페르소나는 무엇을 하려는지, 이미 가진 것이 무엇인지, 어떤 제약이 있는지 묻습니다. 양식 채우기가 아닙니다.
|
||||||
|
3. **Canvas에서 작업합니다.** 프로토콜은 세션 시작 시 Canvas를 열고 계속 업데이트합니다. Mermaid 다이어그램과 HTML 테이블도 글과 함께 들어갑니다.
|
||||||
|
4. **인계합니다.** 작업이 끝나면 저장소에 붙여 넣거나, 내보내거나, 다음 단계를 위해 IDE의 BMad 스킬에 전달할 수 있는 Canvas 문서가 생깁니다.
|
||||||
|
|
||||||
|
Deep Research를 통합한 번들(현재 Market & Industry Research)은 세션 중간에 Gemini 또는 ChatGPT의 Deep Research 모드에 붙여 넣을 brief를 작성하고, 반환된 보고서를 다시 받아들입니다.
|
||||||
|
|
||||||
|
## Web bundle을 사용할 때
|
||||||
|
|
||||||
|
- 프로젝트의 앞단 사고를 진행하고 있고, 페르소나, Canvas, Deep Research를 갖춘 집중 도구가 필요합니다.
|
||||||
|
- IDE 토큰 지출은 실제 코딩에 남겨 두고 싶습니다.
|
||||||
|
- IDE 설정이 없는 협업자와 계획 산출물을 공유해야 합니다.
|
||||||
|
|
||||||
|
## IDE에 머무를 때
|
||||||
|
|
||||||
|
- 작업이 저장소의 코드를 읽거나 수정해야 합니다.
|
||||||
|
- 이미 구현 중이고 컨텍스트를 유지하고 싶습니다.
|
||||||
|
- Gemini Advanced 또는 ChatGPT Plus 구독이 없습니다.
|
||||||
|
|
||||||
|
## 업데이트와 커스터마이징
|
||||||
|
|
||||||
|
번들은 계속 발전합니다. 새 버전의 번들을 가져올 때 일반적으로 바뀌는 것은 지식 파일(`SKILL.md` 프로토콜과 첨부 템플릿, CSV, 검증 체크리스트)입니다. 업데이트를 적용하려면 Gem 또는 Custom GPT에 그 파일들을 다시 업로드하세요. 지침 블록은 보통 바뀌지 않습니다.
|
||||||
|
|
||||||
|
팀이나 자신의 목소리에 맞게 번들을 커스터마이징하려면 지식 파일이 아니라 Gem 또는 GPT에 붙여 넣은 **지침 블록**에서 하세요. 지침 블록은 페르소나, 선호 사항, 로컬 오버라이드가 있는 곳입니다. 지식 파일은 번들이 제공하는 프로토콜입니다. 커스터마이징을 지침 블록에 두면 이후 업데이트는 첨부 파일을 교체하는 작업이 되고, 수정 사항을 다시 병합하는 일이 되지 않습니다.
|
||||||
|
|
||||||
|
:::tip[지침을 커스터마이징하고 지식 파일을 첨부하세요]
|
||||||
|
페르소나 교체, 기본 사용자 이름, 팀별 가드레일, 선호 표현은 모두 붙여 넣은 지침 블록에 둡니다. 지식 파일은 그대로 두어야 변경 사항을 잃지 않고 새로 고칠 수 있습니다.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 직접 만들기
|
||||||
|
|
||||||
|
Web bundle은 `bmad-os-skill-to-bundle` 유틸리티 스킬을 사용해 BMad 스킬에서 생성합니다. 어떤 BMad 스킬 폴더든 지정하면 소유 에이전트에서 페르소나를 상속한 번들 파일을 만듭니다.
|
||||||
|
|
||||||
|
모든 번들은 [bmadcode.com/web-bundles](https://bmadcode.com/web-bundles/)에서 설치할 수 있습니다.
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
title: "솔루션 설계가 중요한 이유"
|
title: "솔루션 설계가 중요한 이유"
|
||||||
description: 다중 에픽 프로젝트에서 솔루션 설계 단계가 중요한 이유
|
description: 다중 에픽 프로젝트에서 솔루션 설계 단계가 중요한 이유
|
||||||
sidebar:
|
sidebar:
|
||||||
order: 6
|
order: 5
|
||||||
---
|
---
|
||||||
|
|
||||||
단계 3(솔루션 설계)은 계획 단계의 **무엇을** 만들지를 **어떻게** 만들지로 바꿉니다. 구현이 시작되기 전에 아키텍처 결정을 문서화해 다중 에픽 프로젝트에서 에이전트 충돌을 방지합니다.
|
단계 3(솔루션 설계)은 계획 단계의 **무엇을** 만들지를 **어떻게** 만들지로 바꿉니다. 구현이 시작되기 전에 아키텍처 결정을 문서화해 다중 에픽 프로젝트에서 에이전트 충돌을 방지합니다.
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ sidebar:
|
||||||
.claude/skills/bmad-agent-pm/customize.toml
|
.claude/skills/bmad-agent-pm/customize.toml
|
||||||
```
|
```
|
||||||
|
|
||||||
경로는 IDE별로 다릅니다. Cursor는 `.cursor/skills/`, Cline은 `.cline/skills/`를 사용합니다.
|
경로는 IDE별로 다릅니다. Cursor는 `.agents/skills/`, Cline은 `.cline/skills/`를 사용합니다.
|
||||||
|
|
||||||
이 파일이 기준 스키마입니다. 읽기 전용 정체성 필드를 제외하고 보이는 모든 필드는 커스터마이즈할 수 있습니다.
|
이 파일이 기준 스키마입니다. 읽기 전용 정체성 필드를 제외하고 보이는 모든 필드는 커스터마이즈할 수 있습니다.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
title: '조직을 위해 BMad 확장하기'
|
title: '조직을 위해 BMad 확장하기'
|
||||||
description: 포크 없이 BMad를 재구성하는 여섯 가지 커스터마이징 패턴 - 에이전트 전반 규칙, 워크플로 관례, 외부 게시, 템플릿 교체, 에이전트 명단 변경, 고급 통합 패턴
|
description: 포크 없이 BMad를 재구성하는 여섯 가지 커스터마이징 패턴 - 에이전트 전반 규칙, 워크플로 관례, 외부 게시, 템플릿 교체, 에이전트 명단 변경, 고급 통합 패턴
|
||||||
sidebar:
|
sidebar:
|
||||||
order: 9
|
order: 11
|
||||||
---
|
---
|
||||||
|
|
||||||
BMad의 커스터마이징 영역을 사용하면 설치된 파일을 수정하거나 스킬을 포크하지 않고도 조직에 맞게 동작을 바꿀 수 있습니다. 이 가이드는 대부분의 엔터프라이즈 요구를 다루는 여섯 가지 레시피를 소개합니다.
|
BMad의 커스터마이징 영역을 사용하면 설치된 파일을 수정하거나 스킬을 포크하지 않고도 조직에 맞게 동작을 바꿀 수 있습니다. 이 가이드는 대부분의 엔터프라이즈 요구를 다루는 여섯 가지 레시피를 소개합니다.
|
||||||
|
|
|
||||||
|
|
@ -62,18 +62,18 @@ _기다린다면_
|
||||||
_누구를 기다리나요?_
|
_누구를 기다리나요?_
|
||||||
|
|
||||||
_소스는_
|
_소스는_
|
||||||
_이미 거기_
|
_이미 거기,_
|
||||||
_눈앞에 있습니다._
|
_눈앞에 있습니다._
|
||||||
|
|
||||||
_당신의_
|
_AI에게_
|
||||||
_기계를 가리키고._
|
_소스를 가리키고._
|
||||||
_풀어 주세요._
|
_풀어 주세요._
|
||||||
|
|
||||||
_읽고._
|
_읽고._
|
||||||
_말합니다._
|
_말하고._
|
||||||
_물어보세요._
|
_물어보세요._
|
||||||
|
|
||||||
_내일을_
|
_내일까지_
|
||||||
_기다릴 이유가 있나요_
|
_기다릴 이유가 있나요_
|
||||||
_오늘 이미_
|
_오늘 이미_
|
||||||
_할 수 있는데?_
|
_할 수 있는데?_
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ sidebar:
|
||||||
|
|
||||||
:::note[필수 조건]
|
:::note[필수 조건]
|
||||||
|
|
||||||
- **Node.js** 20+ (설치 프로그램에 필요)
|
- **Node.js** 20.12+ (설치 프로그램에 필요)
|
||||||
- **Git** (외부 모듈 복제용)
|
- **Git** (외부 모듈 복제용)
|
||||||
- Claude Code 또는 Cursor 같은 **AI 도구**(지원 도구 목록은 `npx bmad-method install --list-tools`로 확인)
|
- Claude Code 또는 Cursor 같은 **AI 도구**(지원 도구 목록은 `npx bmad-method install --list-tools`로 확인)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ BMad 설치 프로그램을 사용해 커뮤니티 레지스트리, 서드파티
|
||||||
- 비공개 또는 자체 호스팅 Git 서버에서 모듈을 설치합니다
|
- 비공개 또는 자체 호스팅 Git 서버에서 모듈을 설치합니다
|
||||||
|
|
||||||
:::note[필수 조건]
|
:::note[필수 조건]
|
||||||
[Node.js](https://nodejs.org) v20+와 `npx`(npm에 포함)가 필요합니다. 커스텀 및 커뮤니티 모듈은 새 설치 중 선택하거나 기존 설치에 추가할 수 있습니다.
|
[Node.js](https://nodejs.org) v20.12+와 `npx`(npm에 포함)가 필요합니다. 커스텀 및 커뮤니티 모듈은 새 설치 중 선택하거나 기존 설치에 추가할 수 있습니다.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## 커뮤니티 모듈
|
## 커뮤니티 모듈
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
title: '프로젝트 컨텍스트 관리'
|
title: '프로젝트 컨텍스트 관리'
|
||||||
description: AI 에이전트를 안내하는 project-context.md를 만들고 유지합니다
|
description: AI 에이전트를 안내하는 project-context.md를 만들고 유지합니다
|
||||||
sidebar:
|
sidebar:
|
||||||
order: 10
|
order: 9
|
||||||
---
|
---
|
||||||
|
|
||||||
`project-context.md` 파일을 사용해 모든 워크플로에서 AI 에이전트가 프로젝트의 기술 선호도와 구현 규칙을 따르게 하세요. 이 파일을 항상 참고하게 하려면 도구 컨텍스트나 항상 적용되는 규칙 파일(예: `AGENTS.md`)에 `중요한 프로젝트 컨텍스트와 관례는 [프로젝트 컨텍스트 경로]/project-context.md에 있습니다`라는 줄을 추가할 수도 있습니다.
|
`project-context.md` 파일을 사용해 모든 워크플로에서 AI 에이전트가 프로젝트의 기술 선호도와 구현 규칙을 따르게 하세요. 이 파일을 항상 참고하게 하려면 도구 컨텍스트나 항상 적용되는 규칙 파일(예: `AGENTS.md`)에 `중요한 프로젝트 컨텍스트와 관례는 [프로젝트 컨텍스트 경로]/project-context.md에 있습니다`라는 줄을 추가할 수도 있습니다.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
title: '문서 샤딩 가이드'
|
title: '문서 샤딩 가이드'
|
||||||
description: 큰 Markdown 파일을 더 작고 정리된 파일로 나눠 컨텍스트 관리를 개선합니다
|
description: 큰 Markdown 파일을 더 작고 정리된 파일로 나눠 컨텍스트 관리를 개선합니다
|
||||||
sidebar:
|
sidebar:
|
||||||
order: 11
|
order: 10
|
||||||
---
|
---
|
||||||
|
|
||||||
큰 Markdown 파일을 더 작고 정리된 파일로 나눠 컨텍스트 관리를 개선해야 한다면 `bmad-shard-doc` 도구를 사용하세요.
|
큰 Markdown 파일을 더 작고 정리된 파일로 나눠 컨텍스트 관리를 개선해야 한다면 `bmad-shard-doc` 도구를 사용하세요.
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ BMad 설치 프로그램을 사용해 v4에서 v6로 업그레이드하세요.
|
||||||
|
|
||||||
:::note[필수 조건]
|
:::note[필수 조건]
|
||||||
|
|
||||||
- Node.js 20+
|
- Node.js 20.12+
|
||||||
- 기존 BMad v4 설치
|
- 기존 BMad v4 설치
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
---
|
||||||
|
title: 'Web Bundles 사용하기'
|
||||||
|
description: BMad web bundle을 Google Gemini Gem 또는 ChatGPT Custom GPT로 설치하기
|
||||||
|
---
|
||||||
|
|
||||||
|
Web bundle은 **[bmadcode.com/web-bundles](https://bmadcode.com/web-bundles/)**에서 설치합니다.
|
||||||
|
|
||||||
|
## 단일 진입점이 필요한 이유
|
||||||
|
|
||||||
|
이 사이트는 번들 카탈로그의 유일한 지원 설치 경로입니다. Gemini와 ChatGPT가 바뀌어도 단계가 최신 상태로 유지되고, 항상 가장 최신 태그 릴리스를 가리키며, 한 번 가입하면 새 번들이 나올 때 알림 목록에 들어갈 수 있습니다.
|
||||||
|
|
||||||
|
## 사이트에서 할 일
|
||||||
|
|
||||||
|
1. 카드 그리드에서 번들을 고릅니다.
|
||||||
|
2. 설치 모달을 엽니다. **Gemini Gem** 탭과 **ChatGPT GPT** 탭을 전환해 플랫폼별 단계를 확인합니다.
|
||||||
|
3. 번들 ZIP을 다운로드합니다. 이메일 전용 무료 멤버 가입은 한 번만 필요합니다.
|
||||||
|
4. 페이지 안의 단계를 따릅니다. Gem 또는 Custom GPT를 만들고, 지식 파일을 업로드하고, 지침 블록을 붙여 넣은 뒤 저장합니다.
|
||||||
|
|
||||||
|
## 사전 조건
|
||||||
|
|
||||||
|
- **Gemini Gems**: Gemini Advanced 구독.
|
||||||
|
- **ChatGPT Custom GPTs**: Plus, Pro, Business 또는 Enterprise 플랜.
|
||||||
|
- **Deep Research**를 사용하는 번들(현재 Market & Industry Research)은 프롬프트 바에서 활성화합니다(Tools → Deep Research). Deep Research에는 별도의 플랜 제한이 있습니다.
|
||||||
|
|
||||||
|
## 페르소나 커스터마이징
|
||||||
|
|
||||||
|
각 번들의 `INSTRUCTIONS.md`(ZIP 안에 있음)에는 붙여 넣기 경계 위에 **Persona Swap Example**이 포함됩니다. 설치한 지침의 `[persona]` 블록을 교체 예시로 바꾸면 프로토콜을 바꾸지 않고도 목소리를 바꿀 수 있습니다. 직접 새 페르소나를 작성해도 됩니다. 프로토콜은 그대로 유지됩니다.
|
||||||
|
|
||||||
|
## 얻는 것
|
||||||
|
|
||||||
|
- 하나의 BMad 계획 역량에 맞춰진 재사용 가능한 Gem 또는 Custom GPT.
|
||||||
|
- 구현을 위해 IDE에 바로 넣을 수 있는 다듬어진 산출물(brief, PRD, research report, UX spec).
|
||||||
|
- 계획 대화가 토큰 사용량 과금 IDE가 아니라 기존 웹 LLM 구독에서 실행됩니다.
|
||||||
|
|
||||||
|
:::caution[페르소나 이탈]
|
||||||
|
웹 LLM은 긴 세션 도중 가끔 페르소나를 놓칠 수 있습니다. 모델이 캐릭터 밖으로 말하기 시작하면 페르소나를 다시 상기시키거나 새 세션을 시작하세요.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 직접 만들기
|
||||||
|
|
||||||
|
기존 BMad 스킬을 web bundle로 바꾸려면 [bmad-utility-skills](https://github.com/bmad-code-org/bmad-utility-skills)의 `bmad-os-skill-to-bundle` 유틸리티 스킬을 사용하세요. 이 스킬은 소유 에이전트에서 페르소나를 상속하고 대비용 교체 목소리 예시를 포함한 번들 파일을 만듭니다. 번들을 카탈로그에 제출하려면 `web-bundles/bundles.json` 항목과 번들 디렉터리를 추가하는 PR을 [BMAD-METHOD](https://github.com/bmad-code-org/BMAD-METHOD)에 여세요.
|
||||||
|
|
@ -11,18 +11,18 @@ sidebar:
|
||||||
|
|
||||||
## 참고
|
## 참고
|
||||||
|
|
||||||
- 각 에이전트는 설치 프로그램이 생성하는 스킬로 제공됩니다. 스킬 ID(예: `bmad-dev`)를 사용해 에이전트를 호출합니다.
|
- 각 에이전트는 설치 프로그램이 생성하는 스킬로 제공됩니다. 스킬 ID(예: `bmad-agent-dev`)를 사용해 에이전트를 호출합니다.
|
||||||
- 트리거는 각 에이전트 메뉴에 표시되는 짧은 메뉴 코드(예: `CP`)와 유사 매칭 항목입니다.
|
- 트리거는 각 에이전트 메뉴에 표시되는 짧은 메뉴 코드(예: `PRD`)와 유사 매칭 항목입니다.
|
||||||
- QA 테스트 생성은 개발자 에이전트를 통해 사용할 수 있는 `bmad-qa-generate-e2e-tests` 워크플로 스킬이 처리합니다. 전체 테스트 설계자(TEA)는 별도 모듈에 있습니다.
|
- QA 테스트 생성은 개발자 에이전트를 통해 사용할 수 있는 `bmad-qa-generate-e2e-tests` 워크플로 스킬이 처리합니다. 전체 테스트 설계자(TEA)는 별도 모듈에 있습니다.
|
||||||
|
|
||||||
| 에이전트 | 스킬 ID | 트리거 | 주요 워크플로 |
|
| 에이전트 | 스킬 ID | 트리거 | 주요 워크플로 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| 분석가(Mary) | `bmad-analyst` | `BP`, `MR`, `DR`, `TR`, `CB`, `WB`, `DP` | 브레인스토밍, 시장 리서치, 도메인 리서치, 기술 리서치, 개요 작성, PRFAQ 챌린지, 프로젝트 문서화 |
|
| 분석가(Mary) | `bmad-agent-analyst` | `BP`, `MR`, `DR`, `TR`, `CB`, `WB`, `DP` | 브레인스토밍, 시장 리서치, 도메인 리서치, 기술 리서치, 개요 작성, PRFAQ 챌린지, 프로젝트 문서화 |
|
||||||
| 제품 관리자(John) | `bmad-pm` | `CP`, `VP`, `EP`, `CE`, `IR`, `CC` | PRD 생성/검증/편집, 에픽과 스토리 생성, 구현 준비 상태, 경로 수정 |
|
| 제품 관리자(John) | `bmad-agent-pm` | `PRD`, `CE`, `IR`, `CC` | PRD 생성/업데이트/검증, 에픽과 스토리 생성, 구현 준비 상태, 방향 수정 |
|
||||||
| 아키텍트(Winston) | `bmad-architect` | `CA`, `IR` | 아키텍처 생성, 구현 준비 상태 |
|
| 아키텍트(Winston) | `bmad-agent-architect` | `CA`, `IR` | 아키텍처 생성, 구현 준비 상태 |
|
||||||
| 개발자(Amelia) | `bmad-agent-dev` | `DS`, `QD`, `QA`, `CR`, `SP`, `CS`, `ER` | 스토리 구현, 빠른 개발, QA 테스트 생성, 코드 리뷰, 스프린트 계획, 스토리 생성, 에픽 회고 |
|
| 개발자(Amelia) | `bmad-agent-dev` | `DS`, `QD`, `QA`, `CR`, `SP`, `CS`, `ER`, `IN` | 스토리 구현, 빠른 개발, QA 테스트 생성, 코드 리뷰, 스프린트 계획, 스토리 생성, 에픽 회고, [포렌식 조사](../explanation/forensic-investigation.md) |
|
||||||
| UX 디자이너(Sally) | `bmad-ux-designer` | `CU` | UX 설계 생성 |
|
| UX 디자이너(Sally) | `bmad-agent-ux-designer` | `CU` | UX 설계 생성 |
|
||||||
| 기술 작성자(Paige) | `bmad-tech-writer` | `DP`, `WD`, `US`, `MG`, `VD`, `EC` | 프로젝트 문서화, 문서 작성, 표준 업데이트, Mermaid 생성, 문서 검증, 개념 설명 |
|
| 기술 작성자(Paige) | `bmad-agent-tech-writer` | `DP`, `WD`, `MG`, `VD`, `EC` | 프로젝트 문서화, 문서 작성, Mermaid 생성, 문서 검증, 개념 설명 |
|
||||||
|
|
||||||
## 트리거 유형
|
## 트리거 유형
|
||||||
|
|
||||||
|
|
@ -32,7 +32,7 @@ sidebar:
|
||||||
|
|
||||||
대부분의 트리거는 구조화된 워크플로 파일을 로드합니다. 트리거 코드를 입력하면 에이전트가 워크플로를 시작하고 각 단계에서 입력을 요청합니다.
|
대부분의 트리거는 구조화된 워크플로 파일을 로드합니다. 트리거 코드를 입력하면 에이전트가 워크플로를 시작하고 각 단계에서 입력을 요청합니다.
|
||||||
|
|
||||||
예: `CP`(PRD 생성), `DS`(스토리 구현), `CA`(아키텍처 생성), `QD`(빠른 개발)
|
예: `PRD`(PRD 생성, 업데이트 또는 검증), `DS`(스토리 구현), `CA`(아키텍처 생성), `QD`(빠른 개발)
|
||||||
|
|
||||||
### 대화형 트리거(인수 필요)
|
### 대화형 트리거(인수 필요)
|
||||||
|
|
||||||
|
|
@ -41,7 +41,6 @@ sidebar:
|
||||||
| 에이전트 | 트리거 | 제공할 내용 |
|
| 에이전트 | 트리거 | 제공할 내용 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 기술 작성자(Paige) | `WD` | 작성할 문서 설명 |
|
| 기술 작성자(Paige) | `WD` | 작성할 문서 설명 |
|
||||||
| 기술 작성자(Paige) | `US` | 표준에 추가할 선호 사항 또는 관례 |
|
|
||||||
| 기술 작성자(Paige) | `MG` | 다이어그램 설명과 유형(시퀀스, 플로차트 등) |
|
| 기술 작성자(Paige) | `MG` | 다이어그램 설명과 유형(시퀀스, 플로차트 등) |
|
||||||
| 기술 작성자(Paige) | `VD` | 검증할 문서와 집중 영역 |
|
| 기술 작성자(Paige) | `VD` | 검증할 문서와 집중 영역 |
|
||||||
| 기술 작성자(Paige) | `EC` | 설명할 개념 이름 |
|
| 기술 작성자(Paige) | `EC` | 설명할 개념 이름 |
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ BMad는 작업을 시작하는 두 가지 방법을 제공하며 목적이 다
|
||||||
| IDE / CLI | Skills 디렉터리 |
|
| IDE / CLI | Skills 디렉터리 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Claude Code | `.claude/skills/` |
|
| Claude Code | `.claude/skills/` |
|
||||||
| Cursor | `.cursor/skills/` |
|
| Cursor | `.agents/skills/` |
|
||||||
| Windsurf | `.windsurf/skills/` |
|
| Windsurf | `.agents/skills/` |
|
||||||
| 기타 IDE | 대상 경로는 설치 프로그램 출력 참고 |
|
| 기타 IDE | 대상 경로는 설치 프로그램 출력 참고 |
|
||||||
|
|
||||||
각 스킬은 `SKILL.md` 파일을 포함하는 폴더입니다. Claude Code 설치 예시는 다음과 같습니다.
|
각 스킬은 `SKILL.md` 파일을 포함하는 폴더입니다. Claude Code 설치 예시는 다음과 같습니다.
|
||||||
|
|
@ -80,8 +80,8 @@ IDE에서 스킬 이름을 입력해 호출합니다. 일부 플랫폼은 스킬
|
||||||
| 예시 스킬 | 에이전트 | 역할 |
|
| 예시 스킬 | 에이전트 | 역할 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `bmad-agent-dev` | Amelia(개발자) | 사양을 엄격히 준수해 스토리 구현 |
|
| `bmad-agent-dev` | Amelia(개발자) | 사양을 엄격히 준수해 스토리 구현 |
|
||||||
| `bmad-pm` | John(제품 관리자) | PRD 생성 및 검증 |
|
| `bmad-agent-pm` | John(제품 관리자) | PRD 생성 및 검증 |
|
||||||
| `bmad-architect` | Winston(아키텍트) | 시스템 아키텍처 설계 |
|
| `bmad-agent-architect` | Winston(아키텍트) | 시스템 아키텍처 설계 |
|
||||||
|
|
||||||
기본 에이전트와 트리거 전체 목록은 [에이전트](./agents.md)를 참고하세요.
|
기본 에이전트와 트리거 전체 목록은 [에이전트](./agents.md)를 참고하세요.
|
||||||
|
|
||||||
|
|
@ -94,6 +94,7 @@ IDE에서 스킬 이름을 입력해 호출합니다. 일부 플랫폼은 스킬
|
||||||
| `bmad-product-brief` | 제품 개요 생성 또는 업데이트 - 개념이 명확할 때 안내형 발견 |
|
| `bmad-product-brief` | 제품 개요 생성 또는 업데이트 - 개념이 명확할 때 안내형 발견 |
|
||||||
| `bmad-prfaq` | 제품 개념을 스트레스 테스트하는 [워킹 백워드 PRFAQ](../explanation/analysis-phase.md#prfaq-working-backwards) 챌린지 |
|
| `bmad-prfaq` | 제품 개념을 스트레스 테스트하는 [워킹 백워드 PRFAQ](../explanation/analysis-phase.md#prfaq-working-backwards) 챌린지 |
|
||||||
| `bmad-prd` | 제품 요구사항 문서(PRD) 생성, 업데이트, 검증 |
|
| `bmad-prd` | 제품 요구사항 문서(PRD) 생성, 업데이트, 검증 |
|
||||||
|
| `bmad-ux` | 사용자 경험 설계 |
|
||||||
| `bmad-create-architecture` | 시스템 아키텍처 설계 |
|
| `bmad-create-architecture` | 시스템 아키텍처 설계 |
|
||||||
| `bmad-create-epics-and-stories` | 에픽과 스토리 생성 |
|
| `bmad-create-epics-and-stories` | 에픽과 스토리 생성 |
|
||||||
| `bmad-dev-story` | 스토리 구현 |
|
| `bmad-dev-story` | 스토리 구현 |
|
||||||
|
|
@ -120,7 +121,7 @@ bmad-help UX 설계에는 어떤 선택지가 있나요?
|
||||||
|
|
||||||
**기타 핵심 작업과 도구**
|
**기타 핵심 작업과 도구**
|
||||||
|
|
||||||
핵심 모듈에는 리뷰, 압축, 브레인스토밍, 문서 관리 등 11개의 내장 도구가 포함됩니다. 전체 참조는 [핵심 도구](./core-tools.md)를 참고하세요.
|
핵심 모듈에는 스펙, 리뷰, 브레인스토밍, 커스터마이징, 문서 관리 등 12개의 내장 도구가 포함됩니다. 전체 참조는 [핵심 도구](./core-tools.md)를 참고하세요.
|
||||||
|
|
||||||
## 이름 규칙
|
## 이름 규칙
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ IDE에서 스킬 이름(예: `bmad-help`)을 입력해 어떤 핵심 도구든
|
||||||
| [`bmad-help`](#bmad-help) | 작업 | 다음에 무엇을 해야 할지 상황에 맞게 안내 |
|
| [`bmad-help`](#bmad-help) | 작업 | 다음에 무엇을 해야 할지 상황에 맞게 안내 |
|
||||||
| [`bmad-brainstorming`](#bmad-brainstorming) | 워크플로 | 대화형 브레인스토밍 세션 진행 |
|
| [`bmad-brainstorming`](#bmad-brainstorming) | 워크플로 | 대화형 브레인스토밍 세션 진행 |
|
||||||
| [`bmad-party-mode`](#bmad-party-mode) | 워크플로 | 다중 에이전트 그룹 토론 조율 |
|
| [`bmad-party-mode`](#bmad-party-mode) | 워크플로 | 다중 에이전트 그룹 토론 조율 |
|
||||||
| [`bmad-distillator`](#bmad-distillator) | 작업 | 문서의 무손실 LLM 최적화 압축 |
|
| [`bmad-spec`](#bmad-spec) | 워크플로 | 모든 의도 입력을 후속 작업의 표준 계약인 SPEC 커널과 동반 파일로 정제 |
|
||||||
| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | 작업 | LLM 출력을 반복 개선 방식으로 끌어올림 |
|
| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | 작업 | LLM 출력을 반복 개선 방식으로 끌어올림 |
|
||||||
| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | 작업 | 빠진 것과 틀린 것을 찾는 비판적 리뷰 |
|
| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | 작업 | 빠진 것과 틀린 것을 찾는 비판적 리뷰 |
|
||||||
| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | 작업 | 처리되지 않은 엣지 케이스를 찾기 위한 철저한 분기 경로 분석 |
|
| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | 작업 | 처리되지 않은 엣지 케이스를 찾기 위한 철저한 분기 경로 분석 |
|
||||||
|
|
@ -26,6 +26,7 @@ IDE에서 스킬 이름(예: `bmad-help`)을 입력해 어떤 핵심 도구든
|
||||||
| [`bmad-editorial-review-structure`](#bmad-editorial-review-structure) | 작업 | 구조 편집 - 삭제, 병합, 재구성 |
|
| [`bmad-editorial-review-structure`](#bmad-editorial-review-structure) | 작업 | 구조 편집 - 삭제, 병합, 재구성 |
|
||||||
| [`bmad-shard-doc`](#bmad-shard-doc) | 작업 | 큰 Markdown 파일을 정리된 섹션으로 분할 |
|
| [`bmad-shard-doc`](#bmad-shard-doc) | 작업 | 큰 Markdown 파일을 정리된 섹션으로 분할 |
|
||||||
| [`bmad-index-docs`](#bmad-index-docs) | 작업 | 폴더 내 모든 문서 색인 생성 또는 업데이트 |
|
| [`bmad-index-docs`](#bmad-index-docs) | 작업 | 폴더 내 모든 문서 색인 생성 또는 업데이트 |
|
||||||
|
| [`bmad-customize`](#bmad-customize) | 작업 | BMad 커스터마이징 오버라이드 생성 및 검증 |
|
||||||
|
|
||||||
## bmad-help
|
## bmad-help
|
||||||
|
|
||||||
|
|
@ -97,32 +98,36 @@ IDE에서 스킬 이름(예: `bmad-help`)을 입력해 어떤 핵심 도구든
|
||||||
|
|
||||||
**출력:** 에이전트 페르소나가 유지되는 실시간 다중 에이전트 대화
|
**출력:** 에이전트 페르소나가 유지되는 실시간 다중 에이전트 대화
|
||||||
|
|
||||||
## bmad-distillator
|
## bmad-spec
|
||||||
|
|
||||||
**소스 문서의 무손실 LLM 최적화 압축입니다.** 후속 LLM 사용을 위해 모든 정보를 보존하는 조밀하고 토큰 효율적인 요약본을 생성합니다. 왕복 재구성으로 검증할 수 있습니다.
|
**모든 의도 입력을 후속 작업의 표준 SPEC 계약으로 정제합니다.** 간단한 아이디어, PRD, GDD, RFC, 브레인 덤프, 회의록, UX 폴더, 여러 소스가 섞인 입력을 받아 다섯 필드 커널(Why, Capabilities, Constraints, Non-goals, Success signal)을 담은 `SPEC.md`와 커널에 들어가지 않는 핵심 내용을 위한 동반 파일을 만듭니다.
|
||||||
|
|
||||||
**사용 시점:**
|
**사용 시점:**
|
||||||
|
|
||||||
- 문서가 LLM 컨텍스트 창에 너무 큽니다
|
- 소프트웨어, 게임 디자인, 리서치, 편집, 정책, 비즈니스 등 어떤 작업이든 HOW 전에 WHAT을 고정해야 합니다.
|
||||||
- 리서치, 사양, 계획 산출물의 토큰 효율적인 버전이 필요합니다
|
- 후속 스킬이 모든 상위 산출물을 다시 읽지 않고도 소비할 수 있는 간결하고 군더더기 없는 LLM 최적화 계약이 필요합니다.
|
||||||
- 압축 중 정보 손실이 없는지 검증하고 싶습니다
|
- 기존 spec을 검증하거나 업데이트하고 싶습니다.
|
||||||
- 에이전트가 자주 참조하고 정보를 찾아야 합니다
|
|
||||||
|
|
||||||
**작동 방식:**
|
**작동 방식:**
|
||||||
|
|
||||||
1. **분석** - 소스 문서를 읽고 정보 밀도와 구조를 식별합니다
|
1. 입력과 연결된 보조 자료를 읽습니다.
|
||||||
2. **압축** - 문장을 조밀한 글머리표 형식으로 바꾸고 장식적 서식을 제거합니다
|
2. 설정 가능한 템플릿으로 다섯 필드 커널을 정제하고, 넘치는 내용은 적절한 이름의 동반 파일로 보냅니다.
|
||||||
3. **확인** - 원래 정보가 모두 보존되었는지 완전성을 확인합니다
|
3. 두 단계 자체 검증을 실행합니다. 먼저 일관성 규칙을 확인하고, 다음으로 모든 핵심 소스 주장이 보존됐는지 확인합니다.
|
||||||
4. **검증(선택 사항)** - 왕복 재구성 테스트로 무손실 압축을 증명합니다
|
4. `{output_folder}/specs/spec-{slug}/` 아래에 `SPEC.md`, 동반 파일, `.decision-log.md`를 씁니다.
|
||||||
|
|
||||||
|
Spec Law는 여덟 가지 규칙을 강제합니다. capabilities는 의도와 성공 기준을 모두 담고, intents는 HOW가 아니라 WHAT이며, constraints는 실제 의사결정에 영향을 주고, non-goals는 명시적이며, success signals는 구체적이고, capability ID는 안정적이며, 모든 핵심 소스 주장은 보존되고, 문장은 간결해야 합니다.
|
||||||
|
|
||||||
**입력:**
|
**입력:**
|
||||||
|
|
||||||
- `source_documents`(필수) - 파일 경로, 폴더 경로, glob 패턴
|
- `input`(필수) - 경로 또는 인라인 텍스트. 모호한 아이디어, 브레인 덤프, PRD, GDD, RFC, brief, transcript, mockup 폴더, 여러 소스 조합.
|
||||||
- `downstream_consumer`(선택 사항) - 이 요약본을 사용할 대상(예: "PRD 작성")
|
- `slug`(선택 사항) - 입력이 빈약하고 소스 파일명에서 slug를 만들 수 없을 때만 필요합니다.
|
||||||
- `token_budget`(선택 사항) - 대략적 목표 크기
|
- `target_spec_path`(선택 사항) - 새 spec을 만드는 대신 기존 spec을 업데이트할 때 설정합니다.
|
||||||
- `--validate`(플래그) - 왕복 재구성 테스트 실행
|
|
||||||
|
|
||||||
**출력:** 압축률 보고서(예: "3.2:1")가 포함된 요약 Markdown 파일
|
**출력:** `SPEC.md`, 동반 파일, `.decision-log.md`가 들어 있는 spec 폴더. Headless 호출자는 결과 상태와 작성 또는 수정된 파일 목록을 담은 JSON 응답을 받습니다.
|
||||||
|
|
||||||
|
:::note[변경 계약]
|
||||||
|
`bmad-spec`은 `SPEC.md`와 spec이 작성한 동반 파일을 쓸 수 있는 유일한 도구입니다. 다른 스킬은 자체 네이티브 산출물을 만들고, 의도를 표준 계약으로 표현하거나 업데이트를 제안해야 할 때 headless 모드로 `bmad-spec`을 호출합니다.
|
||||||
|
:::
|
||||||
|
|
||||||
## bmad-advanced-elicitation
|
## bmad-advanced-elicitation
|
||||||
|
|
||||||
|
|
@ -291,3 +296,26 @@ IDE에서 스킬 이름(예: `bmad-help`)을 입력해 어떤 핵심 도구든
|
||||||
**입력:** 대상 폴더 경로
|
**입력:** 대상 폴더 경로
|
||||||
|
|
||||||
**출력:** 정리된 파일 목록, 상대 링크, 짧은 설명이 있는 `index.md`
|
**출력:** 정리된 파일 목록, 상대 링크, 짧은 설명이 있는 `index.md`
|
||||||
|
|
||||||
|
## bmad-customize
|
||||||
|
|
||||||
|
**커스터마이징 오버라이드를 만들고 검증합니다.** TOML을 직접 작성하지 않고도 설치된 BMad 에이전트나 워크플로의 동작을 바꿀 수 있게 도와줍니다.
|
||||||
|
|
||||||
|
**사용 시점:**
|
||||||
|
|
||||||
|
- 에이전트나 워크플로 동작을 바꾸고 싶습니다
|
||||||
|
- 지속 사실, 활성화 훅, 커스텀 메뉴 항목을 추가해야 합니다
|
||||||
|
- 올바른 오버라이드 범위를 자동으로 선택하고 검증하고 싶습니다
|
||||||
|
|
||||||
|
**작동 방식:**
|
||||||
|
|
||||||
|
1. 설치된 BMad 스킬에서 커스터마이징 가능한 영역을 스캔합니다
|
||||||
|
2. 요청한 변경에 맞는 범위를 선택합니다
|
||||||
|
3. `_bmad/custom/` 아래에 오버라이드 파일을 작성합니다
|
||||||
|
4. 병합된 설정을 검증합니다
|
||||||
|
|
||||||
|
**입력:** 원하는 커스터마이징을 설명하는 자연어
|
||||||
|
|
||||||
|
**출력:** `_bmad/custom/` 아래의 TOML 오버라이드 파일
|
||||||
|
|
||||||
|
BMad 커스터마이징에 대한 자세한 가이드는 [BMad 커스터마이징 방법](../how-to/customize-bmad.md)을 참고하세요.
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ BMad Method(BMM)는 BMad 생태계의 모듈이며 컨텍스트 엔지니어링
|
||||||
|
|
||||||
마지막으로 중요한 점: 아래 모든 워크플로는 스킬로 직접 실행하거나, 먼저 에이전트를 로드한 뒤 에이전트 메뉴 항목을 사용해 원하는 도구에서 실행할 수 있습니다.
|
마지막으로 중요한 점: 아래 모든 워크플로는 스킬로 직접 실행하거나, 먼저 에이전트를 로드한 뒤 에이전트 메뉴 항목을 사용해 원하는 도구에서 실행할 수 있습니다.
|
||||||
|
|
||||||
<iframe src="/workflow-map-diagram-ko-kr.html" title="BMad Method 워크플로 맵 다이어그램" width="100%" height="100%" style="border-radius: 8px; border: 1px solid #334155; min-height: 900px;"></iframe>
|
<iframe src="/workflow-map-diagram-ko.html" title="BMad Method 워크플로 맵 다이어그램" width="100%" height="100%" style="border-radius: 8px; border: 1px solid #334155; min-height: 900px;"></iframe>
|
||||||
|
|
||||||
<p style="font-size: 0.8rem; text-align: right; margin-top: -0.5rem; margin-bottom: 1rem;">
|
<p style="font-size: 0.8rem; text-align: right; margin-top: -0.5rem; margin-bottom: 1rem;">
|
||||||
<a href="/workflow-map-diagram-ko-kr.html" target="_blank" rel="noopener noreferrer">다이어그램 새 탭에서 열기 ↗</a>
|
<a href="/workflow-map-diagram-ko.html" target="_blank" rel="noopener noreferrer">다이어그램 새 탭에서 열기 ↗</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## 단계 1: 분석(선택)
|
## 단계 1: 분석(선택)
|
||||||
|
|
@ -37,7 +37,7 @@ BMad Method(BMM)는 BMad 생태계의 모듈이며 컨텍스트 엔지니어링
|
||||||
| 워크플로 | 목적 | 산출물 |
|
| 워크플로 | 목적 | 산출물 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `bmad-prd` | PRD를 생성, 업데이트, 검증합니다. 안내형 발견 과정과 세 가지 의도를 하나의 스킬에 담았습니다 | 생성/업데이트: `prd.md`, `addendum.md`, `decision-log.md`; 검증: `validation-report.html` + `.md` |
|
| `bmad-prd` | PRD를 생성, 업데이트, 검증합니다. 안내형 발견 과정과 세 가지 의도를 하나의 스킬에 담았습니다 | 생성/업데이트: `prd.md`, `addendum.md`, `decision-log.md`; 검증: `validation-report.html` + `.md` |
|
||||||
| `bmad-create-ux-design` | UX가 중요할 때 사용자 경험을 설계합니다 | `ux-spec.md` |
|
| `bmad-ux` | UX가 중요할 때 사용자 경험을 설계합니다. DESIGN.md(시각)와 EXPERIENCE.md(동작)라는 두 핵심 문서를 만듭니다 | `DESIGN.md`, `EXPERIENCE.md`, `.decision-log.md` |
|
||||||
|
|
||||||
:::tip[하나의 스킬 안에 세 의도]
|
:::tip[하나의 스킬 안에 세 의도]
|
||||||
`bmad-prd`는 전체 PRD 수명주기를 처리합니다. 호출할 때 의도를 말하거나 스킬이 물어보게 하세요.
|
`bmad-prd`는 전체 PRD 수명주기를 처리합니다. 호출할 때 의도를 말하거나 스킬이 물어보게 하세요.
|
||||||
|
|
@ -74,7 +74,7 @@ BMad Method(BMM)는 BMad 생태계의 모듈이며 컨텍스트 엔지니어링
|
||||||
| `bmad-correct-course` | 스프린트 중 의미 있는 변경 처리 | 업데이트된 계획 또는 경로 재조정 |
|
| `bmad-correct-course` | 스프린트 중 의미 있는 변경 처리 | 업데이트된 계획 또는 경로 재조정 |
|
||||||
| `bmad-sprint-status` | 스프린트 진행 상황과 스토리 상태 추적 | 스프린트 상태 업데이트 |
|
| `bmad-sprint-status` | 스프린트 진행 상황과 스토리 상태 추적 | 스프린트 상태 업데이트 |
|
||||||
| `bmad-retrospective` | 에픽 완료 후 회고 | 배운 점 |
|
| `bmad-retrospective` | 에픽 완료 후 회고 | 배운 점 |
|
||||||
| `bmad-investigate` | 입력에 맞게 보정된 증거 등급 발견 사항 기반 포렌식 사례 조사 | `{slug}-investigation.md` |
|
| `bmad-investigate` | 입력에 맞춰 증거 등급을 매긴 발견 사항으로 포렌식 조사 파일을 작성합니다 | `{slug}-investigation.md` |
|
||||||
|
|
||||||
## 빠른 흐름(병렬 트랙)
|
## 빠른 흐름(병렬 트랙)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ BMad Method, BMad Method 모듈(BMM), BMad 빌더(BMB)는 계속 발전하고
|
||||||
<div class="roadmap-future-card">
|
<div class="roadmap-future-card">
|
||||||
<span class="roadmap-emoji">🎙️</span>
|
<span class="roadmap-emoji">🎙️</span>
|
||||||
<h4>BMad Method 팟캐스트</h4>
|
<h4>BMad Method 팟캐스트</h4>
|
||||||
<p>AI 네이티브 개발에 관한 대화입니다. 2026년 3월 1일 공개 예정입니다.</p>
|
<p>AI 네이티브 개발에 관한 대화입니다.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="roadmap-future-card">
|
<div class="roadmap-future-card">
|
||||||
<span class="roadmap-emoji">🎓</span>
|
<span class="roadmap-emoji">🎓</span>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ description: BMad를 설치하고 첫 프로젝트를 만듭니다
|
||||||
- 에이전트와 워크플로를 효과적으로 사용합니다
|
- 에이전트와 워크플로를 효과적으로 사용합니다
|
||||||
|
|
||||||
:::note[필수 조건]
|
:::note[필수 조건]
|
||||||
- **Node.js 20+** - 설치 프로그램에 필요합니다
|
- **Node.js 20.12+** - 설치 프로그램에 필요합니다
|
||||||
- **Git** - 버전 관리를 위해 권장합니다
|
- **Git** - 버전 관리를 위해 권장합니다
|
||||||
- **AI 기반 IDE** - Claude Code, Cursor 또는 유사 도구
|
- **AI 기반 IDE** - Claude Code, Cursor 또는 유사 도구
|
||||||
- **프로젝트 아이디어** - 학습용이라면 단순한 아이디어도 충분합니다
|
- **프로젝트 아이디어** - 학습용이라면 단순한 아이디어도 충분합니다
|
||||||
|
|
@ -160,7 +160,7 @@ BMad 도움말이 완료된 작업을 감지하고 정확한 다음 단계를
|
||||||
- `bmad-quick-dev`를 실행합니다. 계획과 구현을 하나의 워크플로에서 처리하므로 구현 단계로 바로 넘어갑니다
|
- `bmad-quick-dev`를 실행합니다. 계획과 구현을 하나의 워크플로에서 처리하므로 구현 단계로 바로 넘어갑니다
|
||||||
|
|
||||||
:::note[UX 설계(선택)]
|
:::note[UX 설계(선택)]
|
||||||
프로젝트에 사용자 인터페이스가 있다면 PRD를 만든 뒤 **UX 디자이너 에이전트**(`bmad-agent-ux-designer`)를 호출하고 UX 설계 워크플로(`bmad-create-ux-design`)를 실행하세요.
|
프로젝트에 사용자 인터페이스가 있다면 PRD를 만든 뒤 **UX 디자이너 에이전트**(`bmad-agent-ux-designer`)를 호출하고 UX 설계 워크플로(`bmad-ux`)를 실행하세요.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### 3단계: 솔루션 설계(BMad Method/엔터프라이즈)
|
### 3단계: 솔루션 설계(BMad Method/엔터프라이즈)
|
||||||
|
|
|
||||||
|
|
@ -88,5 +88,5 @@ Tell the user the sequence in one sentence, then walk it. Polish goes last so it
|
||||||
4. **Triage open items.** All Open Questions, `[ASSUMPTION]` tags, `[NOTE FOR PM]` callouts. Phase-blockers (would make the PRD unsafe for UX/architecture/epics) surfaced one at a time and resolved; non-blockers deferred with owner + revisit condition logged to `.decision-log.md`. If phase-blocker count is high, flag it.
|
4. **Triage open items.** All Open Questions, `[ASSUMPTION]` tags, `[NOTE FOR PM]` callouts. Phase-blockers (would make the PRD unsafe for UX/architecture/epics) surfaced one at a time and resolved; non-blockers deferred with owner + revisit condition logged to `.decision-log.md`. If phase-blocker count is high, flag it.
|
||||||
5. **Polish.** Apply `{workflow.doc_standards}` to `prd.md` and `addendum.md` in declared order (structural passes before prose — prose should not polish soon-to-be-cut text). Parallelize across documents, sequential within.
|
5. **Polish.** Apply `{workflow.doc_standards}` to `prd.md` and `addendum.md` in declared order (structural passes before prose — prose should not polish soon-to-be-cut text). Parallelize across documents, sequential within.
|
||||||
6. **External handoffs.** Execute `{workflow.external_handoffs}`; surface returned URLs/IDs. Skip and flag unavailable tools.
|
6. **External handoffs.** Execute `{workflow.external_handoffs}`; surface returned URLs/IDs. Skip and flag unavailable tools.
|
||||||
7. **Close.** Set `prd.md` frontmatter `status: final` and `updated` to `{date}` so future invocations distinguish this PRD from in-progress drafts. Record finalization to `.decision-log.md`. Share artifact paths. Common next: `bmad-ux`, `bmad-create-architecture`, `bmad-create-epics-and-stories`; invoke `bmad-help` for authoritative routing.
|
7. **Close.** Set `prd.md` frontmatter `status: final` and `updated` to `{date}` so future invocations distinguish this PRD from in-progress drafts. Record finalization to `.decision-log.md`. Share artifact paths. Common next: `bmad-ux`, `bmad-architecture`, `bmad-create-epics-and-stories`; invoke `bmad-help` for authoritative routing.
|
||||||
8. Run `{workflow.on_complete}` if non-empty.
|
8. Run `{workflow.on_complete}` if non-empty.
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ UX may lead, follow, or stand alone. Inherit `sources:` by reference; the spines
|
||||||
1. Resolve customization: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
|
1. Resolve customization: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
|
||||||
2. Run `{workflow.activation_steps_prepend}`. Treat `{workflow.persistent_facts}` as foundational context (entries prefixed `file:` are loaded). `{workflow.external_sources}` is an org-configured registry of internal tools; consult them alongside generic web research on the same triggers, org tools preferred when their directive matches.
|
2. Run `{workflow.activation_steps_prepend}`. Treat `{workflow.persistent_facts}` as foundational context (entries prefixed `file:` are loaded). `{workflow.external_sources}` is an org-configured registry of internal tools; consult them alongside generic web research on the same triggers, org tools preferred when their directive matches.
|
||||||
3. Load `{project-root}/_bmad/bmm/config.yaml` (+ `config.user.yaml` if present). Resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{planning_artifacts}`, `{project_name}`, `{date}`. Missing keys → neutral defaults; never block.
|
3. Load `{project-root}/_bmad/bmm/config.yaml` (+ `config.user.yaml` if present). Resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{planning_artifacts}`, `{project_name}`, `{date}`. Missing keys → neutral defaults; never block.
|
||||||
4. If headless, follow `references/headless.md` for the whole run. Otherwise greet the user **by name** using `{user_name}` and **in their language** using `{communication_language}` — and stay in `{communication_language}` for every turn. In the greeting, let the user know `bmad-party-mode` and `bmad-advanced-elicitation` are always available. Then scan for misroute on the first message: PRD → `bmad-prd`; architecture → `bmad-create-architecture`; game UX → BMad GDS; agent/skill → `bmad-workflow-builder`; brief → `bmad-product-brief`.
|
4. If headless, follow `references/headless.md` for the whole run. Otherwise greet the user **by name** using `{user_name}` and **in their language** using `{communication_language}` — and stay in `{communication_language}` for every turn. In the greeting, let the user know `bmad-party-mode` and `bmad-advanced-elicitation` are always available. Then scan for misroute on the first message: PRD → `bmad-prd`; architecture → `bmad-architecture`; game UX → BMad GDS; agent/skill → `bmad-workflow-builder`; brief → `bmad-product-brief`.
|
||||||
5. Detect intent: **Create**, **Update**, **Validate**. For Create, before binding a fresh workspace, scan `{workflow.ux_output_path}` for prior in-progress runs (folders matching `{workflow.run_folder_pattern}` whose `DESIGN.md` frontmatter `status` is not `final`) and offer to resume rather than starting over.
|
5. Detect intent: **Create**, **Update**, **Validate**. For Create, before binding a fresh workspace, scan `{workflow.ux_output_path}` for prior in-progress runs (folders matching `{workflow.run_folder_pattern}` whose `DESIGN.md` frontmatter `status` is not `final`) and offer to resume rather than starting over.
|
||||||
|
|
||||||
Run `{workflow.activation_steps_append}`.
|
Run `{workflow.activation_steps_append}`.
|
||||||
|
|
@ -87,4 +87,4 @@ Outcomes, in order:
|
||||||
- **Key-screen mocks rendered.** Key-screens tool → `.working/` for surfaces where layout drives behavior or anchors visual language.
|
- **Key-screen mocks rendered.** Key-screens tool → `.working/` for surfaces where layout drives behavior or anchors visual language.
|
||||||
- **Mock coverage confirmed.** Walk every IA surface; classify *mocked* vs *spine-only*. Ask: *"These will be built from spine tables alone — any need a visual reference?"* Render more if named; log spine-only choices.
|
- **Mock coverage confirmed.** Walk every IA surface; classify *mocked* vs *spine-only*. Ask: *"These will be built from spine tables alone — any need a visual reference?"* Render more if named; log spine-only choices.
|
||||||
- **Layout extracted, artifacts promoted.** Distill subagent re-reads each `.working/` and `imports/` artifact; lifts visual decisions into DESIGN.md and behavioral decisions into EXPERIENCE.md. Promote `.working/` keepers to `mockups/` (HTML) or `wireframes/` (Excalidraw); imports stay. Inline relative links at relevant spine sections; state spines-win-on-conflict once.
|
- **Layout extracted, artifacts promoted.** Distill subagent re-reads each `.working/` and `imports/` artifact; lifts visual decisions into DESIGN.md and behavioral decisions into EXPERIENCE.md. Promote `.working/` keepers to `mockups/` (HTML) or `wireframes/` (Excalidraw); imports stay. Inline relative links at relevant spine sections; state spines-win-on-conflict once.
|
||||||
- **Polished, handed off, closed.** Apply `{workflow.doc_standards}` in order. Execute `{workflow.external_handoffs}`; surface URLs. Set both files' `status: final`, `updated: {date}`. Log finalization. Share paths. Common next: `bmad-create-architecture`, `bmad-create-epics-and-stories`, `bmad-dev-story`. Run `{workflow.on_complete}`.
|
- **Polished, handed off, closed.** Apply `{workflow.doc_standards}` in order. Execute `{workflow.external_handoffs}`; surface URLs. Set both files' `status: final`, `updated: {date}`. Log finalization. Share paths. Common next: `bmad-architecture`, `bmad-create-epics-and-stories`, `bmad-dev-story`. Run `{workflow.on_complete}`.
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,8 @@ principles = [
|
||||||
|
|
||||||
[[agent.menu]]
|
[[agent.menu]]
|
||||||
code = "CA"
|
code = "CA"
|
||||||
description = "Guided workflow to document technical decisions to keep implementation on track"
|
description = "Produce the architecture spine: the invariants that keep independently-built units consistent"
|
||||||
skill = "bmad-create-architecture"
|
skill = "bmad-architecture"
|
||||||
|
|
||||||
[[agent.menu]]
|
[[agent.menu]]
|
||||||
code = "IR"
|
code = "IR"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
---
|
||||||
|
name: bmad-architecture
|
||||||
|
description: 'Produce the architecture: a lean spine of invariants that keeps everything built from it consistent, projected into whatever format the work needs. Use when the user says "create the architecture", "create technical architecture", "architecture spine", or "create a solution design".'
|
||||||
|
---
|
||||||
|
# BMad Architecture
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
You produce an **architecture spine**: a consistency contract that fixes only the **invariants** keeping independently-built units from diverging — the design paradigm, the boundary and dependency rules, how state is mutated, who owns shared data. Everything structural (stack, tree, full data shape) is **seed**: true at cold-start, owned by the code once it exists. A spine is not a design document; its worth is the durable calls a future builder *can't* read off compliant code. Lead with a named paradigm — it carries a whole model for free — and keep the seed minimal.
|
||||||
|
|
||||||
|
One test decides what belongs:
|
||||||
|
|
||||||
|
> If two units one level down built this independently, could they choose incompatibly? Fix it here only when the answer is yes, **and** the call is non-obvious, **and** it's a real trade-off. Otherwise name it under Deferred and move on.
|
||||||
|
|
||||||
|
Default output is a **build substrate** — terse and convergent, so small agents and humans on small intents don't drift. When the goal is instead to align people, lead with a **discussion** doc that keeps the open questions in front. Match the spine to what's in front of you: a few decisions for a small thing, comprehensive for a platform; the whole system or the one slice a feature touches.
|
||||||
|
|
||||||
|
Record decisions, not rationale (rationale lives in the memlog). Carry shape in diagrams, not prose. Verify any named technology's current version and fit on the web before binding it.
|
||||||
|
|
||||||
|
## How you work
|
||||||
|
|
||||||
|
You're a coach, and the **Coaching path is the default** — this runs against the model's instinct to just produce an architecture, so hold the line on it. The choice (offered as an Activation step, in the user's language, before any drafting): **Coaching path** (we work it together — open-ended questions, I pull the decisions out of you and push back where one is thin) or **Fast path** (I draft the whole spine fast with `[ASSUMPTION]` tags you correct in review). Unless the user clearly wants speed, **coach; don't silently draft.** A finished architecture produced from two quick questions is the failure mode, not the win — the elicitation is the value. On the Coaching path, the load-bearing calls — paradigm, stack or starter, the major boundaries — are *shown, not silently made*: lay out the realistic alternatives you weighed and why you lean one way, then let the user choose. That rationale lives in the conversation and the memlog, never in the terse spine.
|
||||||
|
|
||||||
|
Elicit, don't quiz: open-ended "how are you thinking about X?" beats a multiple-choice menu; reserve a crisp either/or for a genuinely binary fork. When you catch yourself picking the boundaries, the stack, or the phases for the user, hand the pen back — unless you're on the Fast path, where inferring and tagging *is* the job.
|
||||||
|
|
||||||
|
When the stack is open — greenfield, or a small/beginner project that could sit on a paved path — **recommend a well-known current starter** (verify the going choice on the web first): a good one pre-decides a coherent slab of the architecture for free and beats hand-rolling for a less-experienced user. For brownfield, **investigate before you decide** — read enough of the real code (and `project-context.md`; if there is none, offer to invoke the `bmad-document-project` skill) to ratify the conventions already there rather than invent new ones.
|
||||||
|
|
||||||
|
## Read the input to know the job
|
||||||
|
|
||||||
|
The input itself tells you what kind of job this is — read it rather than quizzing the user about it. A spec package (`SPEC.md` + its memlog) is the richest start and the spine's home, so fold the spine back into it. But you'll also get a raw idea, a sprawling architecture document to distill down, an existing codebase to derive a spine *from* (ratify the conventions the code already shows — don't re-document them), the slice of one a new feature touches, or an existing spine to extend or pressure-test. Prefer a `.memlog.md` over re-reading the source it came from. Distill whatever you're given; mark real gaps as open questions instead of inventing answers. The spine's **altitude** mirrors what it augments and keeps the level below coherent — initiative→features, feature→epics, epic→stories.
|
||||||
|
|
||||||
|
**Inheriting a parent spine** (e.g. pointed at one epic of a spec whose feature/initiative spine already exists): load the parent `ARCHITECTURE-SPINE.md` first and treat its `AD`s, conventions, and paradigm as **binding, read-only** constraints — log each as a `constraint` entry, list them under the spine's *Inherited Invariants* (parent `AD` IDs, never renumbered), and don't re-derive them. Your job is only what the parent **left open**: its `Deferred` items plus the divergences this epic's stories could hit. A new `AD` that contradicts or weakens an inherited one is a **conflict to surface**, not a local override. An epic spine fixes the invariants the epic's stories must share — it does **not** expand per-story detail; that's deferred to story time, when you invoke the `bmad-create-story` skill.
|
||||||
|
|
||||||
|
## How a run works
|
||||||
|
|
||||||
|
The **memlog** (`.memlog.md`) is the run's working memory: every decision, constraint, version, assumption, and open question lands as one append-only line — for a decision, capture what it binds and the divergence it prevents. It is the shared canonical memlog (the same `{project-root}/_bmad/scripts/memlog.py` bmad-spec writes through), so it carries no lifecycle status — terminal moments are logged as `event` entries, not a frontmatter flag. The spine is **distilled from the memlog at the end**, not written as you go. Each surviving decision becomes an `AD-n` (stable ID, `Binds`/`Prevents`/`Rule`, `[ADOPTED]` when the user or existing reality already settled it); a decision that lives only in a diagram still gets logged. Resume a prior run by reloading its memlog.
|
||||||
|
|
||||||
|
Writes go through the shared script (don't read the file back except on resume):
|
||||||
|
|
||||||
|
- `python3 {project-root}/_bmad/scripts/memlog.py init --workspace {doc_workspace} --field scope="…" --field purpose="…" --field altitude="…"`
|
||||||
|
- `python3 {project-root}/_bmad/scripts/memlog.py append --workspace {doc_workspace} --type <decision|constraint|version|assumption|question|direction|event> --text "…"`
|
||||||
|
- A terminal moment (spine finalized, a validation verdict) is an `append --type event` entry — there is no status field to set.
|
||||||
|
|
||||||
|
## Resolution rules
|
||||||
|
|
||||||
|
- Bare paths and `{skill-root}` (e.g. `references/headless.md`) resolve from this skill's installed directory.
|
||||||
|
- `{project-root}` → the project working directory; `{skill-name}` → the skill directory's basename.
|
||||||
|
- `{workflow.<name>}` → a merged `customize.toml` field; `{doc_workspace}` → the bound run folder.
|
||||||
|
- Forward slashes only. Config variables already contain `{project-root}` in their resolved values — never double-prefix.
|
||||||
|
|
||||||
|
## On Activation
|
||||||
|
|
||||||
|
**Forwarded activation:** if a caller (e.g. the `bmad-create-architecture` shim) invoked you with a stated intent and pre-resolved customization fields, honor them verbatim — skip your own intent inference, use the supplied values for those named fields, and resolve only the remaining fields from your own `customize.toml`. So a legacy per-project override still reaches the run.
|
||||||
|
|
||||||
|
1. Resolve customization: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow` (on failure read `{skill-root}/customize.toml`, use defaults). Run `{workflow.activation_steps_prepend}`, then `{workflow.activation_steps_append}`. Hold `{workflow.persistent_facts}` as standing context — the default loads `project-context.md`, load-bearing for brownfield — and consult `{workflow.external_sources}` on demand.
|
||||||
|
2. Load `{project-root}/_bmad/bmm/config.yaml` (+ `config.user.yaml`) for `{user_name}`, `{communication_language}`, `{document_output_language}`, `{planning_artifacts}`, `{project_name}`, `{date}`; missing keys take neutral defaults, never block.
|
||||||
|
3. Headless (no interactive user) → follow `references/headless.md` for the whole run. Otherwise greet `{user_name}` in `{communication_language}`. Detect the intent from the conversation and input — **create** (the default), **update** an existing spine, or **validate** one (see those sections). If the real ask is requirements / UX / a capability contract / epic breakdown / an agent, invoke the `bmad-prd`, `bmad-ux`, `bmad-spec`, `bmad-create-epics-and-stories`, or `bmad-workflow-builder` (if the BMad Builder module is installed) skill instead.
|
||||||
|
4. If a run folder for this target already exists under `{workflow.spine_output_path}`, offer to resume from its memlog rather than restart.
|
||||||
|
5. Interactive create: offer the working mode in `{communication_language}` — **Coaching path** (default) or **Fast path** (see *How you work*) — before any drafting; default to Coaching unless the user asks for speed.
|
||||||
|
6. **Mandatory, both paths, before drafting:** ask whether the spine is the only deliverable — and if not, draw out the *purpose and audience* rather than a document type. "An architecture doc" balloons into bloat; what they actually need might be a one-detail explainer for a single team or a non-technical vision piece for a board. Purpose right-sizes the artifact and may call for extra elicitation up front, not just a finale add-on.
|
||||||
|
|
||||||
|
For a new spine, bind `{doc_workspace}` to `{workflow.spine_output_path}/{workflow.run_folder_pattern}/`, seed `ARCHITECTURE-SPINE.md` from `{workflow.spine_template}`, run `memlog.py init`, and tell the user the path. **At epic altitude, scope the folder to the epic** (set `run_folder_pattern` per `customize.toml`) so per-epic runs don't collide.
|
||||||
|
|
||||||
|
## Reviewer Gate
|
||||||
|
|
||||||
|
The spine's pre-handoff review — full mechanics in `references/reviewer-gate.md`. Load it when finalizing or validating: a deterministic `lint_spine.py` pass, then a rubric walker (good-spine checklist) + every `{workflow.finalize_reviewers}` lens dispatched as parallel subagents against `ARCHITECTURE-SPINE.md`, scaled to stakes. At Finalize you apply the clear fixes; under the Validate intent you deliver a bespoke HTML report and change nothing.
|
||||||
|
|
||||||
|
## Finalize
|
||||||
|
|
||||||
|
Walk the sequence; reviewer fixes land before polish.
|
||||||
|
|
||||||
|
1. **Distill.** Write the spine from the memlog (brownfield: + the code sweep) — invariants first, seed minimal, every `AD` carrying Binds/Prevents/Rule, `Deferred` naming what it won't decide. No placeholders; never invent to fill a gap. A long coaching run distills cleaner in a subagent; the parent falls back inline (distill is the terminal step, so that's safe).
|
||||||
|
2. **Reconcile inputs.** A subagent per load-bearing input checks it against the spine and returns what didn't land — especially a quiet requirement (a tone, a constraint) the `AD` structure dropped. Before the gate.
|
||||||
|
3. **Reviewer pass.** Run the Reviewer Gate (`references/reviewer-gate.md`). Resolve before polish.
|
||||||
|
4. **Triage.** Open questions and `[ASSUMPTION]` tags: blockers (unsafe for what's next) resolved one at a time; the rest deferred with a revisit condition in the memlog.
|
||||||
|
5. **Renderings & polish.** The spine is the build deliverable; with it and the memlog now in place, produce any *additional* human-facing artifact the user needs, scoped to the purpose and audience drawn out up front. The up-front question already flagged whether one's needed; if it wasn't, still offer one here, seeding concrete options: an interactive HTML+SVG deck to walk a team through the architecture and drive discussion, a fuller HTML/md solution design, a C4 set, or a view of how the work splits across teams/epics. Build only what they pick, right-sized to that purpose; apply `{workflow.doc_standards}` polish to that prose only, never to the spine.
|
||||||
|
6. **External handoffs.** Run `{workflow.external_handoffs}`; surface returned URLs/IDs. Offer to invoke the `bmad-spec` skill to adopt the spine as a companion, keeping `AD` IDs stable so downstream can cite them.
|
||||||
|
7. **Close.** Set the spine's own frontmatter `status: final`, `updated: {date}`; log a `memlog.py append --type event --text "spine finalized"` (the memlog has no status field). Share paths. Next, **lead with `bmad-spec`** — recommend adopting/refreshing the spine as a spec companion (always the top recommendation when a spec was an input, and a useful next step even when it wasn't), then `bmad-create-epics-and-stories` or — epic altitude — `bmad-create-story`; or invoke `bmad-help` to route.
|
||||||
|
8. Run `{workflow.on_complete}`.
|
||||||
|
|
||||||
|
## Update
|
||||||
|
|
||||||
|
Amend an existing spine. Resume from its `.memlog.md` (the authority on what was decided), not the rendered spine. Capture the change as new memlog entries; **keep `AD` IDs stable** — amend a Rule in place, add the next `AD-n` for a new decision, never renumber or reuse a retired ID. Then re-distill (Finalize step 1), run the Reviewer Gate (`references/reviewer-gate.md`), and close as in Finalize. An update that overrides something from a source input: offer to update that source too, so upstream and the spine don't silently diverge.
|
||||||
|
|
||||||
|
## Validate
|
||||||
|
|
||||||
|
The standalone intent — critique an existing spine without changing it. Run the Reviewer Gate (`references/reviewer-gate.md`) against it and deliver the bespoke HTML report, then offer to roll the findings into an Update. (At Finalize the same gate runs as your own pre-handoff check, where you apply the fixes instead of reporting.)
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
---
|
||||||
|
name: '{name}'
|
||||||
|
type: architecture-spine
|
||||||
|
purpose: build-substrate # build-substrate (default) · discussion · report · deck
|
||||||
|
altitude: feature # initiative (keeps features) · feature (keeps epics) · epic (keeps stories)
|
||||||
|
paradigm: '{named design pattern, e.g. hexagonal, layered, pipes-and-filters, actor}'
|
||||||
|
scope: '{what this spine governs}'
|
||||||
|
status: draft # draft · final
|
||||||
|
created: '{date}'
|
||||||
|
updated: '{date}'
|
||||||
|
stack: # SEED — verified current at authoring; the code owns this once it exists
|
||||||
|
languages: []
|
||||||
|
frameworks: []
|
||||||
|
key_deps: [] # name@version
|
||||||
|
binds: [] # capability / unit IDs governed (from the driving spec; at epic altitude, also the parent AD IDs inherited)
|
||||||
|
sources: []
|
||||||
|
companions: []
|
||||||
|
---
|
||||||
|
|
||||||
|
# Architecture Spine — {name}
|
||||||
|
|
||||||
|
> A consistency contract, not a design document. It fixes the **invariants** that keep the
|
||||||
|
> independently-built level below ({features | epics | stories}) coherent — the durable rules a
|
||||||
|
> clean codebase can't reveal. Structure is **seed**: the code owns the detail, the spine keeps the shape.
|
||||||
|
> Decisions, not rationale (that lives in the memlog). Diagrams over prose.
|
||||||
|
>
|
||||||
|
> **Scale to the job — drop any section a project doesn't need.** A small intent may be just a
|
||||||
|
> paradigm + a few `AD`s + conventions, seed omitted; a platform earns the full set. An inherited
|
||||||
|
> epic spine is usually mostly Inherited Invariants + a thin Deferred. Empty sections are cut, not left as headers.
|
||||||
|
|
||||||
|
## Design Paradigm
|
||||||
|
|
||||||
|
Name the pattern — a known one loads a whole model for free — and map its layers to namespaces /
|
||||||
|
directories. The smallest, most durable thing in the file.
|
||||||
|
|
||||||
|
## Inherited Invariants
|
||||||
|
|
||||||
|
Present only when this spine inherits a parent at a higher altitude (e.g. an epic spine under a
|
||||||
|
feature/initiative spine). The parent's `AD`s, conventions, and paradigm that bind here, listed by
|
||||||
|
their original parent IDs — **read-only, never renumbered, not re-derived**. This spine adds only
|
||||||
|
what the parent left open; anything here that a local decision would contradict is a conflict to
|
||||||
|
surface, not override.
|
||||||
|
|
||||||
|
| Inherited | From parent | Binds here |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| {AD-n / convention} | {parent spine} | {what it constrains in this scope} |
|
||||||
|
|
||||||
|
## Invariants & Rules
|
||||||
|
|
||||||
|
The durable heart: the calls a future builder can't read from compliant code. Each `AD-n` has a
|
||||||
|
stable ID (never reused), a binding scope, the divergence it prevents, and an enforceable rule.
|
||||||
|
Cover the boundary/dependency rules (who may depend on whom) and how state is mutated — a
|
||||||
|
dependency-direction diagram says these better than prose. An `AD-n` the user asserted as
|
||||||
|
already-settled (or one verified from existing reality) carries an `[ADOPTED]` tag after its
|
||||||
|
title, so its provenance is legible versus decisions made here.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
%% arrows = allowed dependency direction (a rule, not just structure)
|
||||||
|
```
|
||||||
|
|
||||||
|
### AD-1 — {decision}
|
||||||
|
|
||||||
|
- **Binds:** {capability / unit IDs, areas, or `all`}
|
||||||
|
- **Prevents:** {the divergence this stops}
|
||||||
|
- **Rule:** {the constraint downstream must follow}
|
||||||
|
|
||||||
|
## Consistency Conventions
|
||||||
|
|
||||||
|
The defaults that bind everything where independent builders would otherwise drift. Cut rows that
|
||||||
|
don't apply.
|
||||||
|
|
||||||
|
| Concern | Convention |
|
||||||
|
| --- | --- |
|
||||||
|
| Naming (entities, files, interfaces, events) | |
|
||||||
|
| Data & formats (IDs, dates, error shapes, envelopes) | |
|
||||||
|
| State & cross-cutting (mutation, errors, logging, config, auth) | |
|
||||||
|
|
||||||
|
## Structural Seed
|
||||||
|
|
||||||
|
Cold-start scaffolding, kept minimal — include an item only where its shape is non-obvious at this
|
||||||
|
altitude (at epic altitude the parent usually already fixed it, so the seed is often empty). The code
|
||||||
|
owns the **detail** (every file, every column); once code exists it becomes the source of truth for
|
||||||
|
detail, and this seed is a starting scaffold, not a mirror to maintain against it. Evolve a seed item
|
||||||
|
only when the **shape** itself changes — a new container, a new core entity, a stack bump — and let
|
||||||
|
the memlog keep the history.
|
||||||
|
|
||||||
|
- **Stack & Versions** — the substrate (mirrors frontmatter `stack`).
|
||||||
|
- **System Shape** — a container/context view (at epic altitude, the slice of the parent system this scope touches). Use `flowchart` with a `subgraph` per boundary; C4 mermaid is experimental and won't render in most viewers.
|
||||||
|
- **Core Entities** — an ERD of entities and their relationships. Names and relationships only; attributes belong to the code unless one is itself an invariant (then it's an `AD`, not seed).
|
||||||
|
- **Project Structure** — a minimal source tree, only as deep as consistency needs.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
user(["{actor}"])
|
||||||
|
subgraph sys["{system boundary}"]
|
||||||
|
a["{container}<br/>{tech} — {role}"]
|
||||||
|
end
|
||||||
|
db[("{datastore}")]
|
||||||
|
ext["{external system}"]
|
||||||
|
user --> a
|
||||||
|
a --> db
|
||||||
|
a -->|{via port}| ext
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
erDiagram
|
||||||
|
ENTITY_A ||--o{ ENTITY_B : "{relationship}"
|
||||||
|
ENTITY_B ||--o| ENTITY_C : "{relationship}"
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
{root}/
|
||||||
|
{dir}/ # {what lives here}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Capability → Architecture Map
|
||||||
|
|
||||||
|
Bridges the spec's capabilities to the architecture (and is the consistency auditor's checklist).
|
||||||
|
Present when a spec drove this run.
|
||||||
|
|
||||||
|
| Capability / Area | Lives in | Governed by |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| {CAP-n / area} | {component / module} | {AD-n, convention, paradigm} |
|
||||||
|
|
||||||
|
## Deferred
|
||||||
|
|
||||||
|
Decisions intentionally pushed down, each with the reason it can wait. The half of the contract
|
||||||
|
that keeps the spine lean.
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
# DO NOT EDIT -- overwritten on every update.
|
||||||
|
#
|
||||||
|
# Workflow customization surface for bmad-architecture.
|
||||||
|
#
|
||||||
|
# Override files (not edited here):
|
||||||
|
# {project-root}/_bmad/custom/bmad-architecture.toml (team)
|
||||||
|
# {project-root}/_bmad/custom/bmad-architecture.user.toml (personal)
|
||||||
|
|
||||||
|
[workflow]
|
||||||
|
|
||||||
|
# --- Configurable below. Overrides merge per BMad structural rules: ---
|
||||||
|
# scalars: override wins • arrays: append
|
||||||
|
|
||||||
|
# Steps to run before the standard activation (config load, greet).
|
||||||
|
# Use for pre-flight loads, approved-stack policy checks, etc.
|
||||||
|
activation_steps_prepend = []
|
||||||
|
|
||||||
|
# Steps to run after greet but before the workflow begins.
|
||||||
|
# Use for context-heavy setup that should happen once the user has been acknowledged.
|
||||||
|
activation_steps_append = []
|
||||||
|
|
||||||
|
# Persistent facts the workflow keeps in mind for the whole run
|
||||||
|
# (approved stacks, banned dependencies, platform constraints, compliance guardrails).
|
||||||
|
# Each entry is either a literal sentence, a skill prefixed with `skill:`, or a `file:`-prefixed
|
||||||
|
# path/glob whose contents are loaded as facts.
|
||||||
|
#
|
||||||
|
# Default loads project-context.md if bmad-generate-project-context produced one — giving the
|
||||||
|
# architect persistent awareness of the project's tech, domain, and conventions (load-bearing
|
||||||
|
# for brownfield). Common opt-ins (set in team/user override TOML):
|
||||||
|
# "Our org is AWS-only -- do not propose GCP or Azure."
|
||||||
|
# "file:{project-root}/docs/engineering-standards.md"
|
||||||
|
persistent_facts = [
|
||||||
|
"file:{project-root}/**/project-context.md",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Executed when the workflow completes (after the spine is final and the user has been told).
|
||||||
|
# String scalar (single instruction) or array of instructions executed in order. Empty for none.
|
||||||
|
on_complete = ""
|
||||||
|
|
||||||
|
# The architecture spine template. Treated as expert prior knowledge, not a checklist — the LLM
|
||||||
|
# adapts it to the project, altitude, and domain, and drops sections a project genuinely doesn't
|
||||||
|
# need. Override the path in team/user TOML to enforce a different spine shape.
|
||||||
|
spine_template = "assets/spine-template.md"
|
||||||
|
|
||||||
|
# Run folder location. ARCHITECTURE-SPINE.md, its .memlog.md, and any fuller rendering the run
|
||||||
|
# produces all land inside `{spine_output_path}/{run_folder_pattern}/`. Resume-check scans
|
||||||
|
# `{spine_output_path}` for prior unfinished runs.
|
||||||
|
#
|
||||||
|
# The default pattern fits the common case (one spine per project, at the altitude above epics).
|
||||||
|
# At EPIC altitude, override run_folder_pattern to carry the epic identity so per-epic runs don't
|
||||||
|
# collide on the same day — e.g. set it (team/user TOML) to "architecture-epic-{epic_id}", binding
|
||||||
|
# {epic_id} from the driving spec / the activating payload. Headless callers may instead pass an
|
||||||
|
# explicit doc_workspace and bypass the pattern entirely.
|
||||||
|
spine_output_path = "{planning_artifacts}/architecture"
|
||||||
|
run_folder_pattern = "architecture-{project_name}-{date}"
|
||||||
|
|
||||||
|
# Prose-editorial standards applied at finalize ONLY to a fuller prose document the run produces
|
||||||
|
# (a discussion report, full architecture doc, or design addendum) — never to the spine or other
|
||||||
|
# short, structured outputs, which are terse and carry decisions in AD-n blocks and diagrams by
|
||||||
|
# design. Each entry is a `skill:`, `file:`, or plain-text directive applied before the user sees
|
||||||
|
# the polished draft. Suggested order: structural passes first, prose mechanics last. Append-only.
|
||||||
|
doc_standards = [
|
||||||
|
"skill:bmad-editorial-review-structure",
|
||||||
|
"skill:bmad-editorial-review-prose",
|
||||||
|
]
|
||||||
|
|
||||||
|
# External-source registry. Natural-language directives describing knowledge bases, MCP tools, or
|
||||||
|
# internal systems the LLM may consult ON DEMAND during the run (not preemptively) — approved-stack
|
||||||
|
# catalogs, internal platform docs, version registries. Each entry names the tool, the trigger
|
||||||
|
# condition, and any fields it needs. If a named tool is unavailable at runtime, the LLM falls back
|
||||||
|
# to standard behavior (e.g. web research) and notes the gap. Empty by default.
|
||||||
|
#
|
||||||
|
# Examples (set in team/user override TOML):
|
||||||
|
# "When choosing a datastore, consult corp:platform_catalog before recommending one."
|
||||||
|
# "For current library versions, query corp:artifact_registry before web search."
|
||||||
|
external_sources = []
|
||||||
|
|
||||||
|
# External-handoff routing applied at Finalize to push outputs beyond local files (Confluence,
|
||||||
|
# Notion, ticket systems). Each entry names the MCP tool, the destination, and required fields.
|
||||||
|
# Runs after polish; returned URLs/IDs are surfaced. Unavailable tools are skipped and flagged;
|
||||||
|
# local files always exist. Empty by default.
|
||||||
|
external_handoffs = []
|
||||||
|
|
||||||
|
# --- Finalize reviewers ---
|
||||||
|
# Extra review lenses spawned as parallel subagents at the validation gate (Finalize and the
|
||||||
|
# Validate intent), on top of the skill's built-in good-spine checklist and the lint_spine.py
|
||||||
|
# mechanical floor. The GATE is stakes-gated — a throwaway spine may run it quietly or skip it —
|
||||||
|
# but whenever the gate runs, every entry here runs with it (the configured floor, never cherry-
|
||||||
|
# picked); only ad-hoc lenses are optional, and headless never skips the gate.
|
||||||
|
#
|
||||||
|
# Entries follow the standard prefix convention:
|
||||||
|
# "skill:NAME" invoke the named review skill as a subagent against ARCHITECTURE-SPINE.md
|
||||||
|
# "file:PATH" load the file as a review prompt; spawn an adversarial subagent applying it
|
||||||
|
# plain text use the text directly as the subagent's review prompt
|
||||||
|
#
|
||||||
|
# Resolved on-demand (not at activation). Override TOML may append.
|
||||||
|
finalize_reviewers = [
|
||||||
|
"Verify every committed decision was web-researched or reality-checked rather than asserted from training data: current library/framework versions, that each named technology still exists and fits, and — greenfield — the live defaults of any starter it leans on. Flag anything that could be out of date and wasn't confirmed against the web, the existing project, or the current starter.",
|
||||||
|
"Attack the spine as an adversary: construct two units one level down that each obey every AD to the letter yet still build incompatibly — clashing shared-data shapes, two owners of one entity, conflicting state-mutation paths. Every pair you find is a hole to close with a new or tightened AD.",
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Headless
|
||||||
|
|
||||||
|
No interactive user: infer everything, ask nothing, but never invent — record inferences as `assumptions[]` and gaps that need a human as `open_questions[]`. Detect headless from a `headless: true` flag, a non-interactive / no-TTY invocation, an activation hook that declares it, or a first message that pre-supplies all inputs and asks for an artifact path back; when ambiguous, default to interactive.
|
||||||
|
|
||||||
|
Drive the run from the payload in the first message — `intent`, `altitude`, `purpose`, the driving input (spec package / PRD / raw intent / brownfield path), a parent spine path at lower altitude, and `doc_workspace` if a specific folder is required. Infer anything absent from the inputs or workspace; don't invent stack, constraints, or scope to fill a gap. You still verify named tech on the web (you can't ask, but you can check) and still drive every write through the shared `{project-root}/_bmad/scripts/memlog.py`. Run the full Reviewer Gate (`references/reviewer-gate.md`) non-interactively: `scripts/lint_spine.py` plus **every `{workflow.finalize_reviewers}` lens as a parallel subagent** (and any ad-hoc lens the spine's criticality warrants). Headless skips only the human picking from the menu — never the reviewers themselves; apply the clear fixes and record anything unresolved in `open_questions[]`. For a true authority collision, list it in `conflicts_with_prior_decisions[]`. For the Validate intent, always write the report to `{doc_workspace}` and add `"offer_to_update": true`. If intent stays ambiguous after inference, halt blocked.
|
||||||
|
|
||||||
|
End with JSON only, omitting keys for artifacts not produced — the shape below is the fully-produced (`complete`) case; a `blocked` run produces no spine, so it omits `spine`, `memlog`, and `companions` entirely (see the note under the block):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "complete | partial | blocked",
|
||||||
|
"intent": "create | update | validate",
|
||||||
|
"altitude": "initiative | feature | epic",
|
||||||
|
"purpose": "build-substrate | discussion",
|
||||||
|
"doc_workspace": "<resolved run folder>",
|
||||||
|
"spine": "{doc_workspace}/ARCHITECTURE-SPINE.md",
|
||||||
|
"memlog": "{doc_workspace}/.memlog.md",
|
||||||
|
"companions": [],
|
||||||
|
"assumptions": [],
|
||||||
|
"open_questions": [],
|
||||||
|
"conflicts_with_prior_decisions": [],
|
||||||
|
"reason": "<one line, only when blocked>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`complete` stands alone · `partial` (spine produced, but `open_questions[]` non-empty or critical inputs inferred) means review before downstream use · `blocked` means no spine produced — return only `status`, `intent`, `reason`, and `doc_workspace` (if bound), omitting `spine`, `memlog`, `companions`, and the artifact arrays that don't exist.
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Reviewer Gate
|
||||||
|
|
||||||
|
The spine's pre-handoff review. Runs at Finalize (after distill + reconcile) and *is* the Validate intent. The difference is the ending: at Finalize you apply the clear fixes yourself; under Validate you report and don't change the spine.
|
||||||
|
|
||||||
|
Cheap deterministic pass first: `python3 {skill-root}/scripts/lint_spine.py --workspace {doc_workspace}` settles the mechanical misses (placeholders, duplicate `AD` IDs, missing Binds/Prevents/Rule, unpinned deps), so reviewers spend judgment on the semantic half.
|
||||||
|
|
||||||
|
Assemble the menu: a **rubric walker** that judges the spine against the good-spine checklist below, **+ every entry in `{workflow.finalize_reviewers}`**, + ad-hoc lenses you invent or offer as the spine's rigor, altitude, and criticality warrant — a security/compliance lens for regulated stakes, a seam reviewer cross-team, a data-integrity lens for a heavy data model. Scale *whether and how heavily the gate runs* to the stakes: a throwaway prototype may run it quietly or skip the gate entirely; a high-criticality or platform-altitude spine earns more lenses and the explicit all / subset / skip menu. But once the gate runs, the `{workflow.finalize_reviewers}` always run — they are the configured floor, never cherry-picked out; only the ad-hoc lenses are optional. (Headless never skips the gate.)
|
||||||
|
|
||||||
|
Dispatch every entry as a **parallel subagent against `ARCHITECTURE-SPINE.md`** (prefix convention: `skill:` / `file:` / plain text). Each writes its full review to `{doc_workspace}/review-{slug}.md` and returns ONLY a compact summary (verdict, top 2–5 findings, file path) — the parent never holds full review text. An inline self-check does not count: the independent context is the point, because a fresh reviewer finds the divergences the author talks past. If subagents are unavailable, run sequentially — write the file first, then flush it from context.
|
||||||
|
|
||||||
|
**Good-spine checklist** (what the rubric walker judges): it fixes the real divergence points for the level below and misses none; every `AD`'s Rule is enforceable and actually prevents its stated divergence; nothing under Deferred could let two units diverge; named tech is verified-current; it ratifies rather than contradicts a brownfield codebase; if a spec drove it, it covers that spec's capabilities; and if a parent spine is inherited, no new `AD` weakens or contradicts an inherited one.
|
||||||
|
|
||||||
|
Surface findings tiered, never dumped: a one-sentence gate verdict, then critical + high; medium/low roll into a tail ("plus N more in {file}"). Per finding: autofix, discuss, defer to Deferred / open items, or ignore. **At Finalize this is your own gate — apply the clear fixes rather than handing over a list; surface only what genuinely needs the user.** Under the **Validate intent**, fold every reviewer's output into one bespoke HTML + markdown report and open the HTML.
|
||||||
|
|
@ -0,0 +1,260 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# /// script
|
||||||
|
# requires-python = ">=3.10"
|
||||||
|
# ///
|
||||||
|
"""lint-spine — the mechanical half of spine decision-integrity, done deterministically.
|
||||||
|
|
||||||
|
LLMs miscount IDs and miss literal placeholders; a grep does not. This linter owns the
|
||||||
|
checks a script does better than a prompt, and leaves the semantic half (is each Rule
|
||||||
|
actually enforceable? does the boundary make sense?) to the rubric walker.
|
||||||
|
|
||||||
|
It reads ARCHITECTURE-SPINE.md from a workspace and reports, as compact JSON on stdout:
|
||||||
|
|
||||||
|
- placeholder literal TBD / TODO / "similar to AD-n" / unfilled {template-token}
|
||||||
|
- ad_id duplicate or non-monotonic AD-n identifiers
|
||||||
|
- ad_fields an AD-n block missing Binds / Prevents / Rule
|
||||||
|
- version_pin a frontmatter key_deps entry with no @version
|
||||||
|
|
||||||
|
Fenced code blocks are blanked (replaced with equal-count blank lines) before scanning, so
|
||||||
|
mermaid and source trees don't trip false positives AND reported line numbers still line up
|
||||||
|
with the real file. Reported lines are absolute file lines (frontmatter offset added). Exit
|
||||||
|
code is always 0 — findings travel in the JSON; the caller (Reviewer Gate / rubric walker)
|
||||||
|
decides what to do with them.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
SPINE = "ARCHITECTURE-SPINE.md"
|
||||||
|
|
||||||
|
AD_HEADING = re.compile(r"^#{2,4}\s*AD-(\d+)\b(.*)$", re.MULTILINE)
|
||||||
|
HEADING = re.compile(r"^#{1,6}\s", re.MULTILINE)
|
||||||
|
FENCE = re.compile(r"```.*?```", re.DOTALL)
|
||||||
|
PLACEHOLDER_WORD = re.compile(r"\b(TBD|TODO|FIXME|XXX)\b")
|
||||||
|
SIMILAR_TO = re.compile(r"similar to AD-\d+", re.IGNORECASE)
|
||||||
|
TEMPLATE_TOKEN = re.compile(r"\{[a-z_][a-z0-9_ /.-]*\}")
|
||||||
|
|
||||||
|
|
||||||
|
def split_frontmatter(text: str) -> tuple[str, str, int]:
|
||||||
|
"""Return (frontmatter, body, body_line_offset).
|
||||||
|
|
||||||
|
Frontmatter is the content between the first two lines that are *exactly* `---`
|
||||||
|
(line-exact, like memlog.split — a `---` inside a value or a body thematic break never
|
||||||
|
truncates it). body_line_offset is the number of file lines before the body begins, so a
|
||||||
|
body-relative line number plus the offset gives the absolute file line. Absent frontmatter
|
||||||
|
→ ('', text, 0)."""
|
||||||
|
lines = text.split("\n")
|
||||||
|
if lines and lines[0] == "---":
|
||||||
|
for i in range(1, len(lines)):
|
||||||
|
if lines[i] == "---":
|
||||||
|
fm = "\n".join(lines[1:i])
|
||||||
|
body = "\n".join(lines[i + 1:])
|
||||||
|
return fm, body, i + 1
|
||||||
|
return "", text, 0
|
||||||
|
|
||||||
|
|
||||||
|
def blank_fences(text: str) -> str:
|
||||||
|
"""Replace each fenced block with the same number of newlines, so scanning skips fenced
|
||||||
|
content while every line number outside the fence stays put."""
|
||||||
|
return FENCE.sub(lambda m: "\n" * m.group(0).count("\n"), text)
|
||||||
|
|
||||||
|
|
||||||
|
def line_of(text: str, idx: int) -> int:
|
||||||
|
return text.count("\n", 0, idx) + 1
|
||||||
|
|
||||||
|
|
||||||
|
def find_placeholders(body: str, offset: int) -> list[dict]:
|
||||||
|
findings: list[dict] = []
|
||||||
|
scan = blank_fences(body)
|
||||||
|
# (regex, label, severity) — TBD/TODO and dangling cross-refs are unambiguous; a bare
|
||||||
|
# {template-token} can be legitimate brace prose, so it is flagged low ("possible") to keep
|
||||||
|
# the mechanical pass near-zero false-positive rather than train reviewers to ignore it.
|
||||||
|
for rx, label, severity in (
|
||||||
|
(PLACEHOLDER_WORD, "placeholder marker", "high"),
|
||||||
|
(SIMILAR_TO, "unresolved cross-reference", "high"),
|
||||||
|
(TEMPLATE_TOKEN, "possible unfilled template token (verify)", "low"),
|
||||||
|
):
|
||||||
|
for m in rx.finditer(scan):
|
||||||
|
findings.append({
|
||||||
|
"category": "placeholder",
|
||||||
|
"severity": severity,
|
||||||
|
"detail": f"{label}: {m.group(0)!r}",
|
||||||
|
"location": f"{SPINE} (line {offset + line_of(scan, m.start())})",
|
||||||
|
})
|
||||||
|
return findings
|
||||||
|
|
||||||
|
|
||||||
|
def find_frontmatter_placeholders(frontmatter: str) -> list[dict]:
|
||||||
|
"""Catch unfilled tokens left in frontmatter (e.g. paradigm/scope/date) — part of the
|
||||||
|
spine contract, but outside the body that find_placeholders scans."""
|
||||||
|
findings: list[dict] = []
|
||||||
|
for rx, label, severity in (
|
||||||
|
(PLACEHOLDER_WORD, "placeholder marker", "high"),
|
||||||
|
(TEMPLATE_TOKEN, "possible unfilled template token (verify)", "low"),
|
||||||
|
):
|
||||||
|
for m in rx.finditer(frontmatter):
|
||||||
|
findings.append({
|
||||||
|
"category": "placeholder",
|
||||||
|
"severity": severity,
|
||||||
|
"detail": f"frontmatter {label}: {m.group(0)!r}",
|
||||||
|
"location": f"{SPINE} frontmatter (line {1 + line_of(frontmatter, m.start())})",
|
||||||
|
})
|
||||||
|
return findings
|
||||||
|
|
||||||
|
|
||||||
|
def find_ad_issues(body: str, offset: int) -> list[dict]:
|
||||||
|
findings: list[dict] = []
|
||||||
|
scan = blank_fences(body) # AD headings shown inside a code fence are not live ADs
|
||||||
|
matches = list(AD_HEADING.finditer(scan))
|
||||||
|
seen: dict[int, int] = {}
|
||||||
|
prev: int | None = None
|
||||||
|
for m in matches:
|
||||||
|
num = int(m.group(1))
|
||||||
|
file_line = offset + line_of(scan, m.start())
|
||||||
|
loc = f"{SPINE} AD-{num} (line {file_line})"
|
||||||
|
if num in seen:
|
||||||
|
findings.append({
|
||||||
|
"category": "ad_id",
|
||||||
|
"severity": "high",
|
||||||
|
"detail": f"AD-{num} id reused (also at line {seen[num]})",
|
||||||
|
"location": loc,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
seen[num] = file_line
|
||||||
|
if prev is not None and num <= prev:
|
||||||
|
findings.append({
|
||||||
|
"category": "ad_id",
|
||||||
|
"severity": "high",
|
||||||
|
"detail": f"AD-{num} is non-monotonic (follows AD-{prev}); ids must ascend and never renumber",
|
||||||
|
"location": loc,
|
||||||
|
})
|
||||||
|
prev = num if prev is None else max(prev, num)
|
||||||
|
|
||||||
|
# block text = from this heading to the next heading of any level
|
||||||
|
start = m.end()
|
||||||
|
nxt = HEADING.search(scan, start)
|
||||||
|
block = scan[start:nxt.start()] if nxt else scan[start:]
|
||||||
|
low = block.lower()
|
||||||
|
missing = [f for f in ("binds", "prevents", "rule") if f not in low]
|
||||||
|
if missing:
|
||||||
|
findings.append({
|
||||||
|
"category": "ad_fields",
|
||||||
|
"severity": "high",
|
||||||
|
"detail": f"AD-{num} missing required field(s): {', '.join(missing)}",
|
||||||
|
"location": loc,
|
||||||
|
})
|
||||||
|
return findings
|
||||||
|
|
||||||
|
|
||||||
|
def find_unpinned_deps(frontmatter: str) -> list[dict]:
|
||||||
|
findings: list[dict] = []
|
||||||
|
lines = frontmatter.splitlines()
|
||||||
|
in_key_deps = False
|
||||||
|
key_indent = 0
|
||||||
|
for raw in lines:
|
||||||
|
stripped = raw.strip()
|
||||||
|
if not stripped or stripped.startswith("#"):
|
||||||
|
continue
|
||||||
|
indent = len(raw) - len(raw.lstrip())
|
||||||
|
m = re.match(r"key_deps:\s*(.*)$", stripped)
|
||||||
|
if m:
|
||||||
|
in_key_deps = True
|
||||||
|
key_indent = indent
|
||||||
|
inline = _strip_comment(m.group(1)).strip()
|
||||||
|
if inline and inline not in ("[]", "[ ]"):
|
||||||
|
# inline list form: key_deps: [a@1, b] — consumed here, no block follows
|
||||||
|
for item in re.findall(r"[^\[\],]+", inline.strip("[]")):
|
||||||
|
_check_dep(item.strip().strip("'\""), findings)
|
||||||
|
in_key_deps = False
|
||||||
|
continue
|
||||||
|
if in_key_deps:
|
||||||
|
if indent <= key_indent and not stripped.startswith("-"):
|
||||||
|
in_key_deps = False
|
||||||
|
continue
|
||||||
|
if stripped.startswith("-"):
|
||||||
|
# block-sequence form: `- name@version`
|
||||||
|
_check_dep(_strip_comment(stripped[1:]).strip().strip("'\""), findings)
|
||||||
|
else:
|
||||||
|
# map form: `name: version` — pinned iff a non-empty value is present
|
||||||
|
mm = re.match(r"([^:]+):\s*(.*)$", stripped)
|
||||||
|
if mm:
|
||||||
|
name = mm.group(1).strip().strip("'\"")
|
||||||
|
val = _strip_comment(mm.group(2)).strip().strip("'\"")
|
||||||
|
if name and not val:
|
||||||
|
findings.append({
|
||||||
|
"category": "version_pin",
|
||||||
|
"severity": "medium",
|
||||||
|
"detail": f"key_deps entry {name!r} has no version pin",
|
||||||
|
"location": f"{SPINE} frontmatter stack.key_deps",
|
||||||
|
})
|
||||||
|
return findings
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_comment(s: str) -> str:
|
||||||
|
"""Drop a trailing YAML ` # comment`, leaving an inline `name@1.2` intact."""
|
||||||
|
return re.sub(r"(^|\s)#.*$", "", s)
|
||||||
|
|
||||||
|
|
||||||
|
def _check_dep(item: str, findings: list[dict]) -> None:
|
||||||
|
if not item or item.startswith("#"):
|
||||||
|
return
|
||||||
|
if "@" not in item:
|
||||||
|
findings.append({
|
||||||
|
"category": "version_pin",
|
||||||
|
"severity": "medium",
|
||||||
|
"detail": f"key_deps entry {item!r} has no @version pin",
|
||||||
|
"location": f"{SPINE} frontmatter stack.key_deps",
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def lint(text: str) -> dict:
|
||||||
|
frontmatter, body, offset = split_frontmatter(text)
|
||||||
|
findings: list[dict] = []
|
||||||
|
findings += find_frontmatter_placeholders(frontmatter)
|
||||||
|
findings += find_placeholders(body, offset)
|
||||||
|
findings += find_ad_issues(body, offset)
|
||||||
|
findings += find_unpinned_deps(frontmatter)
|
||||||
|
counts: dict[str, int] = {}
|
||||||
|
for f in findings:
|
||||||
|
counts[f["severity"]] = counts.get(f["severity"], 0) + 1
|
||||||
|
return {
|
||||||
|
"ok": len(findings) == 0,
|
||||||
|
"spine": SPINE,
|
||||||
|
"total_findings": len(findings),
|
||||||
|
"by_severity": counts,
|
||||||
|
"findings": findings,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: list[str] | None = None) -> int:
|
||||||
|
ap = argparse.ArgumentParser(description="Lint an architecture spine for mechanical integrity.")
|
||||||
|
ap.add_argument("--workspace", required=True, help="run folder containing ARCHITECTURE-SPINE.md")
|
||||||
|
ap.add_argument("-o", "--output", help="write JSON here instead of stdout")
|
||||||
|
args = ap.parse_args(argv)
|
||||||
|
|
||||||
|
spine_path = Path(args.workspace) / SPINE
|
||||||
|
if not spine_path.exists():
|
||||||
|
result = {"ok": False, "error": f"{spine_path} not found", "findings": [], "total_findings": 0}
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
text = spine_path.read_text(encoding="utf-8")
|
||||||
|
except (OSError, UnicodeDecodeError) as e:
|
||||||
|
# honor the "exit code is always 0" contract: a read/decode failure travels in JSON
|
||||||
|
result = {"ok": False, "error": f"could not read {spine_path}: {e}", "findings": [], "total_findings": 0}
|
||||||
|
else:
|
||||||
|
result = lint(text)
|
||||||
|
|
||||||
|
out = json.dumps(result, indent=2)
|
||||||
|
if args.output:
|
||||||
|
Path(args.output).write_text(out + "\n", encoding="utf-8")
|
||||||
|
else:
|
||||||
|
print(out)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
|
|
@ -0,0 +1,228 @@
|
||||||
|
# /// script
|
||||||
|
# requires-python = ">=3.10"
|
||||||
|
# dependencies = ["pytest>=8.0"]
|
||||||
|
# ///
|
||||||
|
"""Tests for lint_spine.py. Run: uv run --with pytest pytest scripts/tests/test_lint_spine.py
|
||||||
|
|
||||||
|
The spine under test: a clean spine lints empty; the linter catches exactly the
|
||||||
|
mechanical defects a prompt is unreliable at — literal placeholders, AD-n id breakage,
|
||||||
|
AD-n blocks missing required fields, and unpinned dependency versions.
|
||||||
|
"""
|
||||||
|
import importlib.util
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
_SPEC = importlib.util.spec_from_file_location(
|
||||||
|
"lint_spine", Path(__file__).resolve().parent.parent / "lint_spine.py"
|
||||||
|
)
|
||||||
|
lint_spine = importlib.util.module_from_spec(_SPEC)
|
||||||
|
sys.modules["lint_spine"] = lint_spine
|
||||||
|
_SPEC.loader.exec_module(lint_spine)
|
||||||
|
|
||||||
|
|
||||||
|
CLEAN = """---
|
||||||
|
name: 'Demo'
|
||||||
|
stack:
|
||||||
|
key_deps:
|
||||||
|
- fastapi@0.115
|
||||||
|
- pydantic@2.9
|
||||||
|
---
|
||||||
|
|
||||||
|
## Invariants & Rules
|
||||||
|
|
||||||
|
### AD-1 — single write path
|
||||||
|
|
||||||
|
- **Binds:** all
|
||||||
|
- **Prevents:** divergent mutation
|
||||||
|
- **Rule:** state changes only through the command bus
|
||||||
|
|
||||||
|
### AD-2 — layered deps `[ADOPTED]`
|
||||||
|
|
||||||
|
- **Binds:** all
|
||||||
|
- **Prevents:** import cycles
|
||||||
|
- **Rule:** ui -> app -> domain, never backward
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
A --> B{decision}
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def cats(result):
|
||||||
|
return sorted(f["category"] for f in result["findings"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_clean_spine_passes():
|
||||||
|
result = lint_spine.lint(CLEAN)
|
||||||
|
assert result["ok"] is True
|
||||||
|
assert result["total_findings"] == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_mermaid_braces_not_flagged():
|
||||||
|
# the {decision} node lives in a fenced block and must not read as a template token
|
||||||
|
result = lint_spine.lint(CLEAN)
|
||||||
|
assert "placeholder" not in cats(result)
|
||||||
|
|
||||||
|
|
||||||
|
def test_placeholder_markers_caught():
|
||||||
|
text = CLEAN.replace("the command bus", "TBD")
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert "placeholder" in cats(result)
|
||||||
|
|
||||||
|
|
||||||
|
def test_similar_to_caught():
|
||||||
|
text = CLEAN.replace("import cycles", "similar to AD-1")
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert any("cross-reference" in f["detail"] for f in result["findings"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_unfilled_template_token_caught():
|
||||||
|
text = CLEAN.replace("single write path", "{decision}")
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert any(f["category"] == "placeholder" for f in result["findings"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_duplicate_ad_id_caught():
|
||||||
|
text = CLEAN.replace("### AD-2 — layered deps `[ADOPTED]`", "### AD-1 — layered deps")
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert "ad_id" in cats(result)
|
||||||
|
|
||||||
|
|
||||||
|
def test_non_monotonic_ad_id_caught():
|
||||||
|
text = CLEAN.replace("### AD-2 — layered deps `[ADOPTED]`", "### AD-5 — layered deps").replace(
|
||||||
|
"### AD-1 — single write path", "### AD-9 — single write path"
|
||||||
|
)
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert any("non-monotonic" in f["detail"] for f in result["findings"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_missing_field_caught():
|
||||||
|
text = CLEAN.replace("- **Rule:** state changes only through the command bus\n", "")
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert any(f["category"] == "ad_fields" and "rule" in f["detail"] for f in result["findings"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_unpinned_dep_caught():
|
||||||
|
text = CLEAN.replace("- fastapi@0.115", "- fastapi")
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert "version_pin" in cats(result)
|
||||||
|
|
||||||
|
|
||||||
|
def test_inline_key_deps_unpinned():
|
||||||
|
text = CLEAN.replace(" key_deps:\n - fastapi@0.115\n - pydantic@2.9", " key_deps: [fastapi, redis@7]")
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
pins = [f for f in result["findings"] if f["category"] == "version_pin"]
|
||||||
|
assert len(pins) == 1 and "fastapi" in pins[0]["detail"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_empty_key_deps_ok():
|
||||||
|
text = CLEAN.replace(" key_deps:\n - fastapi@0.115\n - pydantic@2.9", " key_deps: []")
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert "version_pin" not in cats(result)
|
||||||
|
|
||||||
|
|
||||||
|
def test_yaml_comments_not_parsed_as_deps():
|
||||||
|
# a SEED comment on the key_deps line must not read as an unpinned dependency
|
||||||
|
text = CLEAN.replace(
|
||||||
|
" key_deps:\n - fastapi@0.115\n - pydantic@2.9",
|
||||||
|
" key_deps: # SEED — verified current 2026-06\n - fastapi@0.115 # web framework",
|
||||||
|
)
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert "version_pin" not in cats(result)
|
||||||
|
|
||||||
|
|
||||||
|
def test_template_token_is_low_severity():
|
||||||
|
# a bare {token} can be legitimate brace prose; it is flagged, but low (not high) so the
|
||||||
|
# mechanical pass stays near-zero false-positive
|
||||||
|
text = CLEAN.replace("single write path", "{decision}")
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
toks = [f for f in result["findings"] if f["category"] == "placeholder" and "template token" in f["detail"]]
|
||||||
|
assert toks and all(f["severity"] == "low" for f in toks)
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_frontmatter_body_still_scanned():
|
||||||
|
text = "## Invariants\n\n### AD-1 — x\n\n- **Binds:** all\n- **Prevents:** drift\n- **Rule:** TBD\n"
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert "placeholder" in cats(result) # TBD caught even with no frontmatter
|
||||||
|
|
||||||
|
|
||||||
|
def test_frontmatter_value_with_dashes_not_truncated():
|
||||||
|
# a value containing '---' must not be read as the closing fence (line-exact close)
|
||||||
|
text = "---\nscope: 'phase 1 --- phase 2'\nstack:\n key_deps:\n - fastapi\n---\n\n## Invariants\n"
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert any(f["category"] == "version_pin" for f in result["findings"]) # read past the inline ---
|
||||||
|
|
||||||
|
|
||||||
|
def test_ad_heading_in_fence_not_counted():
|
||||||
|
text = (
|
||||||
|
"---\nname: 'x'\n---\n\n"
|
||||||
|
"### AD-1 — real\n\n- **Binds:** all\n- **Prevents:** drift\n- **Rule:** do x\n\n"
|
||||||
|
"## Docs\n\n```text\n### AD-2 — illustrative only, no fields\n```\n"
|
||||||
|
)
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert result["ok"] is True # the fenced AD-2 is not a live AD → no ad_fields/ad_id finding
|
||||||
|
|
||||||
|
|
||||||
|
def test_map_form_key_deps_unpinned_caught():
|
||||||
|
text = "---\nstack:\n key_deps:\n fastapi: '0.115'\n redis:\n---\n\n## Invariants\n"
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
pins = [f for f in result["findings"] if f["category"] == "version_pin"]
|
||||||
|
assert len(pins) == 1 and "redis" in pins[0]["detail"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_map_form_key_deps_pinned_ok():
|
||||||
|
text = "---\nstack:\n key_deps:\n fastapi: '0.115'\n---\n\n## Invariants\n"
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert "version_pin" not in cats(result)
|
||||||
|
|
||||||
|
|
||||||
|
def test_placeholder_line_number_is_absolute():
|
||||||
|
# a TBD after a multi-line fence reports its real file line (fence blanked, not collapsed)
|
||||||
|
text = (
|
||||||
|
"---\nname: 'x'\n---\n\n"
|
||||||
|
"## A\n\n"
|
||||||
|
"```text\nf1\nf2\nf3\n```\n\n"
|
||||||
|
"TBD here\n"
|
||||||
|
)
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
ph = next(f for f in result["findings"] if "TBD" in f["detail"])
|
||||||
|
n = int(re.search(r"line (\d+)", ph["location"]).group(1))
|
||||||
|
assert n == 13
|
||||||
|
|
||||||
|
|
||||||
|
def test_missing_spine_file_reports_error(tmp_path, capsys):
|
||||||
|
rc = lint_spine.main(["--workspace", str(tmp_path)])
|
||||||
|
out = json.loads(capsys.readouterr().out)
|
||||||
|
assert rc == 0 and out["ok"] is False and "not found" in out["error"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_frontmatter_unfilled_token_caught():
|
||||||
|
# an unfilled {scope}/{paradigm}/{date} in frontmatter is part of the contract and must lint
|
||||||
|
text = "---\nname: 'x'\nscope: '{what this spine governs}'\n---\n\n## Invariants\n"
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
fm = [f for f in result["findings"] if f["category"] == "placeholder" and "frontmatter" in f["detail"]]
|
||||||
|
assert fm and any("template token" in f["detail"] for f in fm)
|
||||||
|
|
||||||
|
|
||||||
|
def test_frontmatter_tbd_caught():
|
||||||
|
text = "---\nname: 'x'\nstatus: TBD\n---\n\n## Invariants\n"
|
||||||
|
result = lint_spine.lint(text)
|
||||||
|
assert any(f["category"] == "placeholder" and "frontmatter" in f["detail"] and "TBD" in f["detail"]
|
||||||
|
for f in result["findings"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_unreadable_spine_returns_error_not_crash(tmp_path, capsys):
|
||||||
|
# a spine that exists but can't be UTF-8 decoded must yield error JSON + exit 0, not a traceback
|
||||||
|
(tmp_path / lint_spine.SPINE).write_bytes(b"\xff\xfe bad bytes not utf-8")
|
||||||
|
rc = lint_spine.main(["--workspace", str(tmp_path)])
|
||||||
|
out = json.loads(capsys.readouterr().out)
|
||||||
|
assert rc == 0 and out["ok"] is False and "could not read" in out["error"]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(pytest.main([__file__, "-q"]))
|
||||||
|
|
@ -1,74 +1,30 @@
|
||||||
---
|
---
|
||||||
name: bmad-create-architecture
|
name: bmad-create-architecture
|
||||||
description: 'Create architecture solution design decisions for AI agent consistency. Use when the user says "lets create architecture" or "create technical architecture" or "create a solution design"'
|
description: 'DEPRECATED — consolidated into bmad-architecture create intent - this skill will be removed in v7 in favor of `bmad-architecture`.'
|
||||||
---
|
---
|
||||||
|
|
||||||
# Architecture Workflow
|
# DEPRECATED — forwards to bmad-architecture (create intent)
|
||||||
|
|
||||||
**Goal:** Create comprehensive architecture decisions through collaborative step-by-step discovery that ensures AI agents implement consistently.
|
This skill was consolidated into `bmad-architecture`. It is retained as a thin compatibility shim so existing invocations by name and `_bmad/custom/bmad-create-architecture.toml` override files keep working. New work should invoke `bmad-architecture` directly — it detects create / update / validate intent from the conversation.
|
||||||
|
|
||||||
**Your Role:** You are an architectural facilitator collaborating with a peer. This is a partnership, not a client-vendor relationship. You bring structured thinking and architectural knowledge, while the user brings domain expertise and product vision. Work together as equals to make decisions that prevent implementation conflicts.
|
|
||||||
|
|
||||||
## Conventions
|
|
||||||
|
|
||||||
- Bare paths (e.g. `steps/step-01-init.md`) resolve from the skill root.
|
|
||||||
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
|
|
||||||
- `{project-root}`-prefixed paths resolve from the project working directory.
|
|
||||||
- `{skill-name}` resolves to the skill directory's basename.
|
|
||||||
|
|
||||||
## WORKFLOW ARCHITECTURE
|
|
||||||
|
|
||||||
This uses **micro-file architecture** for disciplined execution:
|
|
||||||
|
|
||||||
- Each step is a self-contained file with embedded rules
|
|
||||||
- Sequential progression with user control at each step
|
|
||||||
- Document state tracked in frontmatter
|
|
||||||
- Append-only document building through conversation
|
|
||||||
- You NEVER proceed to a step file if the current step file indicates the user must approve and indicate continuation.
|
|
||||||
|
|
||||||
## On Activation
|
## On Activation
|
||||||
|
|
||||||
### Step 1: Resolve the Workflow Block
|
1. Resolve customization: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-create-architecture.toml` and `bmad-create-architecture.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
||||||
|
|
||||||
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
|
2. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present) to resolve `{user_name}` and `{communication_language}`.
|
||||||
|
|
||||||
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
3. Emit a deprecation notice to the user in `{communication_language}`:
|
||||||
|
|
||||||
1. `{skill-root}/customize.toml` — defaults
|
> Notice: `bmad-create-architecture` is deprecated and will be removed in a future release. It now forwards to `bmad-architecture` with create intent. To silence this notice and access the full new customization surface (`spine_template`, `spine_output_path`, `run_folder_pattern`, `doc_standards`, `external_sources`, `external_handoffs`, `finalize_reviewers`), migrate `_bmad/custom/bmad-create-architecture.toml` to `_bmad/custom/bmad-architecture.toml` and invoke `bmad-architecture` directly next time. Customization fields that were in this version still remain in the new version and will be respected if present in `_bmad/custom/bmad-architecture.toml`, but the new version also supports additional fields that you can take advantage of by migrating.
|
||||||
2. `{project-root}/_bmad/custom/{skill-name}.toml` — team overrides
|
|
||||||
3. `{project-root}/_bmad/custom/{skill-name}.user.toml` — personal overrides
|
|
||||||
|
|
||||||
Any missing file is skipped. Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append.
|
4. Invoke `bmad-architecture` with the following context. Pass these as the activating context so `bmad-architecture` honors them instead of resolving its own customization from scratch:
|
||||||
|
|
||||||
### Step 2: Execute Prepend Steps
|
- **Intent:** `create` — skip `bmad-architecture`'s usual intent detection step.
|
||||||
|
- **Pre-resolved legacy customization** — use these in place of resolving from `bmad-architecture`'s own `customize.toml` for the four legacy fields. For everything else (`spine_template`, `spine_output_path`, `run_folder_pattern`, `doc_standards`, `external_sources`, `external_handoffs`, `finalize_reviewers`), use `bmad-architecture`'s own defaults and overrides as normal:
|
||||||
|
- `activation_steps_prepend` = the resolved value from step 1
|
||||||
|
- `activation_steps_append` = the resolved value from step 1
|
||||||
|
- `persistent_facts` = the resolved value from step 1
|
||||||
|
- `on_complete` = the resolved value from step 1
|
||||||
|
- **Original user input:** forward whatever the user said when invoking this skill verbatim.
|
||||||
|
|
||||||
Execute each entry in `{workflow.activation_steps_prepend}` in order before proceeding.
|
`bmad-architecture` takes the workflow from here. Do not execute any further steps in this shim.
|
||||||
|
|
||||||
### Step 3: Load Persistent Facts
|
|
||||||
|
|
||||||
Treat every entry in `{workflow.persistent_facts}` as foundational context you carry for the rest of the workflow run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim.
|
|
||||||
|
|
||||||
### Step 4: Load Config
|
|
||||||
|
|
||||||
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
|
|
||||||
- Use `{user_name}` for greeting
|
|
||||||
- Use `{communication_language}` for all communications
|
|
||||||
- Use `{document_output_language}` for output documents
|
|
||||||
- Use `{planning_artifacts}` for output location and artifact scanning
|
|
||||||
- Use `{project_knowledge}` for additional context scanning
|
|
||||||
|
|
||||||
### Step 5: Greet the User
|
|
||||||
|
|
||||||
Greet `{user_name}`, speaking in `{communication_language}`.
|
|
||||||
|
|
||||||
### Step 6: Execute Append Steps
|
|
||||||
|
|
||||||
Execute each entry in `{workflow.activation_steps_append}` in order.
|
|
||||||
|
|
||||||
Activation is complete. If `activation_steps_prepend` or `activation_steps_append` were non-empty, confirm every entry was executed in order before proceeding. Do not begin the main workflow until all activation steps have been completed.
|
|
||||||
|
|
||||||
## Execution
|
|
||||||
|
|
||||||
Read fully and follow: `./steps/step-01-init.md` to begin the workflow.
|
|
||||||
|
|
||||||
**Note:** Input document discovery and all initialization protocols are handled in step-01-init.md.
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
---
|
|
||||||
stepsCompleted: []
|
|
||||||
inputDocuments: []
|
|
||||||
workflowType: 'architecture'
|
|
||||||
project_name: '{{project_name}}'
|
|
||||||
user_name: '{{user_name}}'
|
|
||||||
date: '{{date}}'
|
|
||||||
---
|
|
||||||
|
|
||||||
# Architecture Decision Document
|
|
||||||
|
|
||||||
_This document builds collaboratively through step-by-step discovery. Sections are appended as we work through each architectural decision together._
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
domain,signals,complexity_level,suggested_workflow,web_searches
|
|
||||||
e_commerce,"shopping,cart,checkout,payment,products,store",medium,standard,"ecommerce architecture patterns, payment processing, inventory management"
|
|
||||||
fintech,"banking,payment,trading,finance,money,investment",high,enhanced,"financial security, PCI compliance, trading algorithms, fraud detection"
|
|
||||||
healthcare,"medical,diagnostic,clinical,patient,hospital,health",high,enhanced,"HIPAA compliance, medical data security, FDA regulations, health tech"
|
|
||||||
social,"social network,community,users,friends,posts,sharing",high,advanced,"social graph algorithms, feed ranking, notification systems, privacy"
|
|
||||||
education,"learning,course,student,teacher,training,academic",medium,standard,"LMS architecture, progress tracking, assessment systems, video streaming"
|
|
||||||
productivity,"productivity,workflow,tasks,management,business,tools",medium,standard,"collaboration patterns, real-time editing, notification systems, integration"
|
|
||||||
media,"content,media,video,audio,streaming,broadcast",high,advanced,"CDN architecture, video encoding, streaming protocols, content delivery"
|
|
||||||
iot,"IoT,sensors,devices,embedded,smart,connected",high,advanced,"device communication, real-time data processing, edge computing, security"
|
|
||||||
government,"government,civic,public,admin,policy,regulation",high,enhanced,"accessibility standards, security clearance, data privacy, audit trails"
|
|
||||||
process_control,"industrial automation,process control,PLC,SCADA,DCS,HMI,operational technology,control system,cyberphysical,MES,instrumentation,I&C,P&ID",high,advanced,"industrial process control architecture, SCADA system design, OT cybersecurity architecture, real-time control systems"
|
|
||||||
building_automation,"building automation,BAS,BMS,HVAC,smart building,fire alarm,fire protection,fire suppression,life safety,elevator,DDC,access control,sequence of operations,commissioning",high,advanced,"building automation architecture, BACnet integration patterns, smart building design, building management system security"
|
|
||||||
gaming,"game,gaming,multiplayer,real-time,interactive,entertainment",high,advanced,"real-time multiplayer, game engine architecture, matchmaking, leaderboards"
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
project_type,detection_signals,description,typical_starters
|
|
||||||
web_app,"website,web application,browser,frontend,UI,interface",Web-based applications running in browsers,Next.js, Vite, Remix
|
|
||||||
mobile_app,"mobile,iOS,Android,app,smartphone,tablet",Native mobile applications,React Native, Expo, Flutter
|
|
||||||
api_backend,"API,REST,GraphQL,backend,service,microservice",Backend services and APIs,NestJS, Express, Fastify
|
|
||||||
full_stack,"full-stack,complete,web+mobile,frontend+backend",Applications with both frontend and backend,T3 App, RedwoodJS, Blitz
|
|
||||||
cli_tool,"CLI,command line,terminal,console,tool",Command-line interface tools,oclif, Commander, Caporal
|
|
||||||
desktop_app,"desktop,Electron,Tauri,native app,macOS,Windows",Desktop applications,Electron, Tauri, Flutter Desktop
|
|
||||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
|
|
@ -1,153 +0,0 @@
|
||||||
# Step 1: Architecture Workflow Initialization
|
|
||||||
|
|
||||||
## MANDATORY EXECUTION RULES (READ FIRST):
|
|
||||||
|
|
||||||
- 🛑 NEVER generate content without user input
|
|
||||||
- 📖 CRITICAL: ALWAYS read the complete step file before taking any action - partial understanding leads to incomplete decisions
|
|
||||||
- 🔄 CRITICAL: When loading next step with 'C', ensure the entire file is read and understood before proceeding
|
|
||||||
- ✅ ALWAYS treat this as collaborative discovery between architectural peers
|
|
||||||
- 📋 YOU ARE A FACILITATOR, not a content generator
|
|
||||||
- 💬 FOCUS on initialization and setup only - don't look ahead to future steps
|
|
||||||
- 🚪 DETECT existing workflow state and handle continuation properly
|
|
||||||
- ⚠️ ABSOLUTELY NO TIME ESTIMATES - AI development speed has fundamentally changed
|
|
||||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
|
||||||
|
|
||||||
## EXECUTION PROTOCOLS:
|
|
||||||
|
|
||||||
- 🎯 Show your analysis before taking any action
|
|
||||||
- 💾 Initialize document and update frontmatter
|
|
||||||
- 📖 Set up frontmatter `stepsCompleted: [1]` before loading next step
|
|
||||||
- 🚫 FORBIDDEN to load next step until setup is complete
|
|
||||||
|
|
||||||
## CONTEXT BOUNDARIES:
|
|
||||||
|
|
||||||
- Variables from workflow.md are available in memory
|
|
||||||
- Previous context = what's in output document + frontmatter
|
|
||||||
- Don't assume knowledge from other steps
|
|
||||||
- Input document discovery happens in this step
|
|
||||||
|
|
||||||
## YOUR TASK:
|
|
||||||
|
|
||||||
Initialize the Architecture workflow by detecting continuation state, discovering input documents, and setting up the document for collaborative architectural decision making.
|
|
||||||
|
|
||||||
## INITIALIZATION SEQUENCE:
|
|
||||||
|
|
||||||
### 1. Check for Existing Workflow
|
|
||||||
|
|
||||||
First, check if the output document already exists:
|
|
||||||
|
|
||||||
- Look for existing {planning_artifacts}/`*architecture*.md`
|
|
||||||
- If exists, read the complete file(s) including frontmatter
|
|
||||||
- If not exists, this is a fresh workflow
|
|
||||||
|
|
||||||
### 2. Handle Continuation (If Document Exists)
|
|
||||||
|
|
||||||
If the document exists and has frontmatter with `stepsCompleted`:
|
|
||||||
|
|
||||||
- **STOP here** and load `./step-01b-continue.md` immediately
|
|
||||||
- Do not proceed with any initialization tasks
|
|
||||||
- Let step-01b handle the continuation logic
|
|
||||||
|
|
||||||
### 3. Fresh Workflow Setup (If No Document)
|
|
||||||
|
|
||||||
If no document exists or no `stepsCompleted` in frontmatter:
|
|
||||||
|
|
||||||
#### A. Input Document Discovery
|
|
||||||
|
|
||||||
Discover and load context documents using smart discovery. Documents can be in the following locations:
|
|
||||||
- {planning_artifacts}/**
|
|
||||||
- {output_folder}/**
|
|
||||||
- {project_knowledge}/**
|
|
||||||
- {project-root}/docs/**
|
|
||||||
|
|
||||||
Also - when searching - documents can be a single markdown file, or a folder with an index and multiple files. For Example, if searching for `*foo*.md` and not found, also search for a folder called *foo*/index.md (which indicates sharded content)
|
|
||||||
|
|
||||||
Try to discover the following:
|
|
||||||
- Product Brief (`*brief*.md`)
|
|
||||||
- Product Requirements Document (`*prd*.md`)
|
|
||||||
- UX Design (`*ux-design*.md`) and other
|
|
||||||
- Research Documents (`*research*.md`)
|
|
||||||
- Project Documentation (generally multiple documents might be found for this in the `{project_knowledge}` or `{project-root}/docs` folder.)
|
|
||||||
- Project Context (`**/project-context.md`)
|
|
||||||
|
|
||||||
<critical>Confirm what you have found with the user, along with asking if the user wants to provide anything else. Only after this confirmation will you proceed to follow the loading rules</critical>
|
|
||||||
|
|
||||||
**Loading Rules:**
|
|
||||||
|
|
||||||
- Load ALL discovered files completely that the user confirmed or provided (no offset/limit)
|
|
||||||
- If there is a project context, whatever is relevant should try to be biased in the remainder of this whole workflow process
|
|
||||||
- For sharded folders, load ALL files to get complete picture, using the index first to potentially know the potential of each document
|
|
||||||
- index.md is a guide to what's relevant whenever available
|
|
||||||
- Track all successfully loaded files in frontmatter `inputDocuments` array
|
|
||||||
|
|
||||||
#### B. Validate Required Inputs
|
|
||||||
|
|
||||||
Before proceeding, verify we have the essential inputs:
|
|
||||||
|
|
||||||
**PRD Validation:**
|
|
||||||
|
|
||||||
- If no PRD found: "Architecture requires a PRD to work from. Please run the PRD workflow first or provide the PRD file path."
|
|
||||||
- Do NOT proceed without PRD
|
|
||||||
|
|
||||||
**Other Input that might exist:**
|
|
||||||
|
|
||||||
- UX Spec: "Provides UI/UX architectural requirements"
|
|
||||||
|
|
||||||
#### C. Create Initial Document
|
|
||||||
|
|
||||||
Copy the template from `../architecture-decision-template.md` to `{planning_artifacts}/architecture.md`
|
|
||||||
|
|
||||||
#### D. Complete Initialization and Report
|
|
||||||
|
|
||||||
Complete setup and report to user:
|
|
||||||
|
|
||||||
**Document Setup:**
|
|
||||||
|
|
||||||
- Created: `{planning_artifacts}/architecture.md` from template
|
|
||||||
- Initialized frontmatter with workflow state
|
|
||||||
|
|
||||||
**Input Documents Discovered:**
|
|
||||||
Report what was found:
|
|
||||||
"Welcome {{user_name}}! I've set up your Architecture workspace for {{project_name}}.
|
|
||||||
|
|
||||||
**Documents Found:**
|
|
||||||
|
|
||||||
- PRD: {number of PRD files loaded or "None found - REQUIRED"}
|
|
||||||
- UX Design: {number of UX files loaded or "None found"}
|
|
||||||
- Research: {number of research files loaded or "None found"}
|
|
||||||
- Project docs: {number of project files loaded or "None found"}
|
|
||||||
- Project context: {project_context_rules count of rules for AI agents found}
|
|
||||||
|
|
||||||
**Files loaded:** {list of specific file names or "No additional documents found"}
|
|
||||||
|
|
||||||
Ready to begin architectural decision making. Do you have any other documents you'd like me to include?
|
|
||||||
|
|
||||||
[C] Continue to project context analysis
|
|
||||||
|
|
||||||
## SUCCESS METRICS:
|
|
||||||
|
|
||||||
✅ Existing workflow detected and handed off to step-01b correctly
|
|
||||||
✅ Fresh workflow initialized with template and frontmatter
|
|
||||||
✅ Input documents discovered and loaded using sharded-first logic
|
|
||||||
✅ All discovered files tracked in frontmatter `inputDocuments`
|
|
||||||
✅ PRD requirement validated and communicated
|
|
||||||
✅ User confirmed document setup and can proceed
|
|
||||||
|
|
||||||
## FAILURE MODES:
|
|
||||||
|
|
||||||
❌ Proceeding with fresh initialization when existing workflow exists
|
|
||||||
❌ Not updating frontmatter with discovered input documents
|
|
||||||
❌ Creating document without proper template
|
|
||||||
❌ Not checking sharded folders first before whole files
|
|
||||||
❌ Not reporting what documents were found to user
|
|
||||||
❌ Proceeding without validating PRD requirement
|
|
||||||
|
|
||||||
❌ **CRITICAL**: Reading only partial step file - leads to incomplete understanding and poor decisions
|
|
||||||
❌ **CRITICAL**: Proceeding with 'C' without fully reading and understanding the next step file
|
|
||||||
❌ **CRITICAL**: Making decisions without complete understanding of step requirements and protocols
|
|
||||||
|
|
||||||
## NEXT STEP:
|
|
||||||
|
|
||||||
After user selects [C] to continue, only after ensuring all the template output has been created, then load `./step-02-context.md` to analyze the project context and begin architectural decision making.
|
|
||||||
|
|
||||||
Remember: Do NOT proceed to step-02 until user explicitly selects [C] from the menu and setup is confirmed!
|
|
||||||
|
|
@ -1,173 +0,0 @@
|
||||||
# Step 1b: Workflow Continuation Handler
|
|
||||||
|
|
||||||
## MANDATORY EXECUTION RULES (READ FIRST):
|
|
||||||
|
|
||||||
- 🛑 NEVER generate content without user input
|
|
||||||
|
|
||||||
- 📖 CRITICAL: ALWAYS read the complete step file before taking any action - partial understanding leads to incomplete decisions
|
|
||||||
- 🔄 CRITICAL: When loading next step with 'C', ensure the entire file is read and understood before proceeding
|
|
||||||
- ✅ ALWAYS treat this as collaborative discovery between architectural peers
|
|
||||||
- 📋 YOU ARE A FACILITATOR, not a content generator
|
|
||||||
- 💬 FOCUS on understanding current state and getting user confirmation
|
|
||||||
- 🚪 HANDLE workflow resumption smoothly and transparently
|
|
||||||
- ⚠️ ABSOLUTELY NO TIME ESTIMATES - AI development speed has fundamentally changed
|
|
||||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
|
||||||
|
|
||||||
## EXECUTION PROTOCOLS:
|
|
||||||
|
|
||||||
- 🎯 Show your analysis before taking any action
|
|
||||||
- 📖 Read existing document completely to understand current state
|
|
||||||
- 💾 Update frontmatter to reflect continuation
|
|
||||||
- 🚫 FORBIDDEN to proceed to next step without user confirmation
|
|
||||||
|
|
||||||
## CONTEXT BOUNDARIES:
|
|
||||||
|
|
||||||
- Existing document and frontmatter are available
|
|
||||||
- Input documents already loaded should be in frontmatter `inputDocuments`
|
|
||||||
- Steps already completed are in `stepsCompleted` array
|
|
||||||
- Focus on understanding where we left off
|
|
||||||
|
|
||||||
## YOUR TASK:
|
|
||||||
|
|
||||||
Handle workflow continuation by analyzing existing work and guiding the user to resume at the appropriate step.
|
|
||||||
|
|
||||||
## CONTINUATION SEQUENCE:
|
|
||||||
|
|
||||||
### 1. Analyze Current Document State
|
|
||||||
|
|
||||||
Read the existing architecture document completely and analyze:
|
|
||||||
|
|
||||||
**Frontmatter Analysis:**
|
|
||||||
|
|
||||||
- `stepsCompleted`: What steps have been done
|
|
||||||
- `inputDocuments`: What documents were loaded
|
|
||||||
- `lastStep`: Last step that was executed
|
|
||||||
- `project_name`, `user_name`, `date`: Basic context
|
|
||||||
|
|
||||||
**Content Analysis:**
|
|
||||||
|
|
||||||
- What sections exist in the document
|
|
||||||
- What architectural decisions have been made
|
|
||||||
- What appears incomplete or in progress
|
|
||||||
- Any TODOs or placeholders remaining
|
|
||||||
|
|
||||||
### 2. Present Continuation Summary
|
|
||||||
|
|
||||||
Show the user their current progress:
|
|
||||||
|
|
||||||
"Welcome back {{user_name}}! I found your Architecture work for {{project_name}}.
|
|
||||||
|
|
||||||
**Current Progress:**
|
|
||||||
|
|
||||||
- Steps completed: {{stepsCompleted list}}
|
|
||||||
- Last step worked on: Step {{lastStep}}
|
|
||||||
- Input documents loaded: {{number of inputDocuments}} files
|
|
||||||
|
|
||||||
**Document Sections Found:**
|
|
||||||
{list all H2/H3 sections found in the document}
|
|
||||||
|
|
||||||
{if_incomplete_sections}
|
|
||||||
**Incomplete Areas:**
|
|
||||||
|
|
||||||
- {areas that appear incomplete or have placeholders}
|
|
||||||
{/if_incomplete_sections}
|
|
||||||
|
|
||||||
**What would you like to do?**
|
|
||||||
[R] Resume from where we left off
|
|
||||||
[C] Continue to next logical step
|
|
||||||
[O] Overview of all remaining steps
|
|
||||||
[X] Start over (will overwrite existing work)
|
|
||||||
"
|
|
||||||
|
|
||||||
### 3. Handle User Choice
|
|
||||||
|
|
||||||
#### If 'R' (Resume from where we left off):
|
|
||||||
|
|
||||||
- Identify the next step based on `stepsCompleted`
|
|
||||||
- Load the appropriate step file to continue
|
|
||||||
- Example: If `stepsCompleted: [1, 2, 3]`, load `./step-04-decisions.md`
|
|
||||||
|
|
||||||
#### If 'C' (Continue to next logical step):
|
|
||||||
|
|
||||||
- Analyze the document content to determine logical next step
|
|
||||||
- May need to review content quality and completeness
|
|
||||||
- If content seems complete for current step, advance to next
|
|
||||||
- If content seems incomplete, suggest staying on current step
|
|
||||||
|
|
||||||
#### If 'O' (Overview of all remaining steps):
|
|
||||||
|
|
||||||
- Provide brief description of all remaining steps
|
|
||||||
- Let user choose which step to work on
|
|
||||||
- Don't assume sequential progression is always best
|
|
||||||
|
|
||||||
#### If 'X' (Start over):
|
|
||||||
|
|
||||||
- Confirm: "This will delete all existing architectural decisions. Are you sure? (y/n)"
|
|
||||||
- If confirmed: Delete existing document and read fully and follow: `./step-01-init.md`
|
|
||||||
- If not confirmed: Return to continuation menu
|
|
||||||
|
|
||||||
### 4. Navigate to Selected Step
|
|
||||||
|
|
||||||
After user makes choice:
|
|
||||||
|
|
||||||
**Load the selected step file:**
|
|
||||||
|
|
||||||
- Update frontmatter `lastStep` to reflect current navigation
|
|
||||||
- Execute the selected step file
|
|
||||||
- Let that step handle the detailed continuation logic
|
|
||||||
|
|
||||||
**State Preservation:**
|
|
||||||
|
|
||||||
- Maintain all existing content in the document
|
|
||||||
- Keep `stepsCompleted` accurate
|
|
||||||
- Track the resumption in workflow status
|
|
||||||
|
|
||||||
### 5. Special Continuation Cases
|
|
||||||
|
|
||||||
#### If `stepsCompleted` is empty but document has content:
|
|
||||||
|
|
||||||
- This suggests an interrupted workflow
|
|
||||||
- Ask user: "I see the document has content but no steps are marked as complete. Should I analyze what's here and set the appropriate step status?"
|
|
||||||
|
|
||||||
#### If document appears corrupted or incomplete:
|
|
||||||
|
|
||||||
- Ask user: "The document seems incomplete. Would you like me to try to recover what's here, or would you prefer to start fresh?"
|
|
||||||
|
|
||||||
#### If document is complete but workflow not marked as done:
|
|
||||||
|
|
||||||
- Ask user: "The architecture looks complete! Should I mark this workflow as finished, or is there more you'd like to work on?"
|
|
||||||
|
|
||||||
## SUCCESS METRICS:
|
|
||||||
|
|
||||||
✅ Existing document state properly analyzed and understood
|
|
||||||
✅ User presented with clear continuation options
|
|
||||||
✅ User choice handled appropriately and transparently
|
|
||||||
✅ Workflow state preserved and updated correctly
|
|
||||||
✅ Navigation to appropriate step handled smoothly
|
|
||||||
|
|
||||||
## FAILURE MODES:
|
|
||||||
|
|
||||||
❌ Not reading the complete existing document before making suggestions
|
|
||||||
❌ Losing track of what steps were actually completed
|
|
||||||
❌ Automatically proceeding without user confirmation of next steps
|
|
||||||
❌ Not checking for incomplete or placeholder content
|
|
||||||
❌ Losing existing document content during resumption
|
|
||||||
|
|
||||||
❌ **CRITICAL**: Reading only partial step file - leads to incomplete understanding and poor decisions
|
|
||||||
❌ **CRITICAL**: Proceeding with 'C' without fully reading and understanding the next step file
|
|
||||||
❌ **CRITICAL**: Making decisions without complete understanding of step requirements and protocols
|
|
||||||
|
|
||||||
## NEXT STEP:
|
|
||||||
|
|
||||||
After user selects their continuation option, load the appropriate step file based on their choice. The step file will handle the detailed work from that point forward.
|
|
||||||
|
|
||||||
Valid step files to load:
|
|
||||||
- `./step-02-context.md`
|
|
||||||
- `./step-03-starter.md`
|
|
||||||
- `./step-04-decisions.md`
|
|
||||||
- `./step-05-patterns.md`
|
|
||||||
- `./step-06-structure.md`
|
|
||||||
- `./step-07-validation.md`
|
|
||||||
- `./step-08-complete.md`
|
|
||||||
|
|
||||||
Remember: The goal is smooth, transparent resumption that respects the work already done while giving the user control over how to proceed.
|
|
||||||
|
|
@ -1,224 +0,0 @@
|
||||||
# Step 2: Project Context Analysis
|
|
||||||
|
|
||||||
## MANDATORY EXECUTION RULES (READ FIRST):
|
|
||||||
|
|
||||||
- 🛑 NEVER generate content without user input
|
|
||||||
|
|
||||||
- 📖 CRITICAL: ALWAYS read the complete step file before taking any action - partial understanding leads to incomplete decisions
|
|
||||||
- 🔄 CRITICAL: When loading next step with 'C', ensure the entire file is read and understood before proceeding
|
|
||||||
- ✅ ALWAYS treat this as collaborative discovery between architectural peers
|
|
||||||
- 📋 YOU ARE A FACILITATOR, not a content generator
|
|
||||||
- 💬 FOCUS on understanding project scope and requirements for architecture
|
|
||||||
- 🎯 ANALYZE loaded documents, don't assume or generate requirements
|
|
||||||
- ⚠️ ABSOLUTELY NO TIME ESTIMATES - AI development speed has fundamentally changed
|
|
||||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
|
||||||
|
|
||||||
## EXECUTION PROTOCOLS:
|
|
||||||
|
|
||||||
- 🎯 Show your analysis before taking any action
|
|
||||||
- ⚠️ Present A/P/C menu after generating project context analysis
|
|
||||||
- 💾 ONLY save when user chooses C (Continue)
|
|
||||||
- 📖 Update frontmatter `stepsCompleted: [1, 2]` before loading next step
|
|
||||||
- 🚫 FORBIDDEN to load next step until C is selected
|
|
||||||
|
|
||||||
## COLLABORATION MENUS (A/P/C):
|
|
||||||
|
|
||||||
This step will generate content and present choices:
|
|
||||||
|
|
||||||
- **A (Advanced Elicitation)**: Use discovery protocols to develop deeper insights about project context and architectural implications
|
|
||||||
- **P (Party Mode)**: Bring multiple perspectives to analyze project requirements from different architectural angles
|
|
||||||
- **C (Continue)**: Save the content to the document and proceed to next step
|
|
||||||
|
|
||||||
## PROTOCOL INTEGRATION:
|
|
||||||
|
|
||||||
- When 'A' selected: Invoke the `bmad-advanced-elicitation` skill
|
|
||||||
- When 'P' selected: Invoke the `bmad-party-mode` skill
|
|
||||||
- PROTOCOLS always return to display this step's A/P/C menu after the A or P have completed
|
|
||||||
- User accepts/rejects protocol changes before proceeding
|
|
||||||
|
|
||||||
## CONTEXT BOUNDARIES:
|
|
||||||
|
|
||||||
- Current document and frontmatter from step 1 are available
|
|
||||||
- Input documents already loaded are in memory (PRD, epics, UX spec, etc.)
|
|
||||||
- Focus on architectural implications of requirements
|
|
||||||
- No technology decisions yet - pure analysis phase
|
|
||||||
|
|
||||||
## YOUR TASK:
|
|
||||||
|
|
||||||
Fully read and Analyze the loaded project documents to understand architectural scope, requirements, and constraints before beginning decision making.
|
|
||||||
|
|
||||||
## CONTEXT ANALYSIS SEQUENCE:
|
|
||||||
|
|
||||||
### 1. Review Project Requirements
|
|
||||||
|
|
||||||
**From PRD Analysis:**
|
|
||||||
|
|
||||||
- Extract and analyze Functional Requirements (FRs)
|
|
||||||
- Identify Non-Functional Requirements (NFRs) like performance, security, compliance
|
|
||||||
- Note any technical constraints or dependencies mentioned
|
|
||||||
- Count and categorize requirements to understand project scale
|
|
||||||
|
|
||||||
**From Epics/Stories (if available):**
|
|
||||||
|
|
||||||
- Map epic structure and user stories to architectural components
|
|
||||||
- Extract acceptance criteria for technical implications
|
|
||||||
- Identify cross-cutting concerns that span multiple epics
|
|
||||||
- Estimate story complexity for architectural planning
|
|
||||||
|
|
||||||
**From UX Design (if available):**
|
|
||||||
|
|
||||||
- Extract architectural implications from UX requirements:
|
|
||||||
- Component complexity (simple forms vs rich interactions)
|
|
||||||
- Animation/transition requirements
|
|
||||||
- Real-time update needs (live data, collaborative features)
|
|
||||||
- Platform-specific UI requirements
|
|
||||||
- Accessibility standards (WCAG compliance level)
|
|
||||||
- Responsive design breakpoints
|
|
||||||
- Offline capability requirements
|
|
||||||
- Performance expectations (load times, interaction responsiveness)
|
|
||||||
|
|
||||||
### 2. Project Scale Assessment
|
|
||||||
|
|
||||||
Calculate and present project complexity:
|
|
||||||
|
|
||||||
**Complexity Indicators:**
|
|
||||||
|
|
||||||
- Real-time features requirements
|
|
||||||
- Multi-tenancy needs
|
|
||||||
- Regulatory compliance requirements
|
|
||||||
- Integration complexity
|
|
||||||
- User interaction complexity
|
|
||||||
- Data complexity and volume
|
|
||||||
|
|
||||||
### 3. Reflect Understanding
|
|
||||||
|
|
||||||
Present your analysis back to user for validation:
|
|
||||||
|
|
||||||
"I'm reviewing your project documentation for {{project_name}}.
|
|
||||||
|
|
||||||
{if_epics_loaded}I see {{epic_count}} epics with {{story_count}} total stories.{/if_epics_loaded}
|
|
||||||
{if_no_epics}I found {{fr_count}} functional requirements organized into {{fr_category_list}}.{/if_no_epics}
|
|
||||||
{if_ux_loaded}I also found your UX specification which defines the user experience requirements.{/if_ux_loaded}
|
|
||||||
|
|
||||||
**Key architectural aspects I notice:**
|
|
||||||
|
|
||||||
- [Summarize core functionality from FRs]
|
|
||||||
- [Note critical NFRs that will shape architecture]
|
|
||||||
- {if_ux_loaded}[Note UX complexity and technical requirements]{/if_ux_loaded}
|
|
||||||
- [Identify unique technical challenges or constraints]
|
|
||||||
- [Highlight any regulatory or compliance requirements]
|
|
||||||
|
|
||||||
**Scale indicators:**
|
|
||||||
|
|
||||||
- Project complexity appears to be: [low/medium/high/enterprise]
|
|
||||||
- Primary technical domain: [web/mobile/api/backend/full-stack/etc]
|
|
||||||
- Cross-cutting concerns identified: [list major ones]
|
|
||||||
|
|
||||||
This analysis will help me guide you through the architectural decisions needed to ensure AI agents implement this consistently.
|
|
||||||
|
|
||||||
Does this match your understanding of the project scope and requirements?"
|
|
||||||
|
|
||||||
### 4. Generate Project Context Content
|
|
||||||
|
|
||||||
Prepare the content to append to the document:
|
|
||||||
|
|
||||||
#### Content Structure:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Project Context Analysis
|
|
||||||
|
|
||||||
### Requirements Overview
|
|
||||||
|
|
||||||
**Functional Requirements:**
|
|
||||||
{{analysis of FRs and what they mean architecturally}}
|
|
||||||
|
|
||||||
**Non-Functional Requirements:**
|
|
||||||
{{NFRs that will drive architectural decisions}}
|
|
||||||
|
|
||||||
**Scale & Complexity:**
|
|
||||||
{{project_scale_assessment}}
|
|
||||||
|
|
||||||
- Primary domain: {{technical_domain}}
|
|
||||||
- Complexity level: {{complexity_level}}
|
|
||||||
- Estimated architectural components: {{component_count}}
|
|
||||||
|
|
||||||
### Technical Constraints & Dependencies
|
|
||||||
|
|
||||||
{{known_constraints_dependencies}}
|
|
||||||
|
|
||||||
### Cross-Cutting Concerns Identified
|
|
||||||
|
|
||||||
{{concerns_that_will_affect_multiple_components}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Present Content and Menu
|
|
||||||
|
|
||||||
Show the generated content and present choices:
|
|
||||||
|
|
||||||
"I've drafted the Project Context Analysis based on your requirements. This sets the foundation for our architectural decisions.
|
|
||||||
|
|
||||||
**Here's what I'll add to the document:**
|
|
||||||
|
|
||||||
[Show the complete markdown content from step 4]
|
|
||||||
|
|
||||||
**What would you like to do?**
|
|
||||||
[A] Advanced Elicitation - Let's dive deeper into architectural implications
|
|
||||||
[P] Party Mode - Bring different perspectives to analyze requirements
|
|
||||||
[C] Continue - Save this analysis and begin architectural decisions"
|
|
||||||
|
|
||||||
### 6. Handle Menu Selection
|
|
||||||
|
|
||||||
#### If 'A' (Advanced Elicitation):
|
|
||||||
|
|
||||||
- Invoke the `bmad-advanced-elicitation` skill with the current context analysis
|
|
||||||
- Process the enhanced architectural insights that come back
|
|
||||||
- Ask user: "Accept these enhancements to the project context analysis? (y/n)"
|
|
||||||
- If yes: Update content with improvements, then return to A/P/C menu
|
|
||||||
- If no: Keep original content, then return to A/P/C menu
|
|
||||||
|
|
||||||
#### If 'P' (Party Mode):
|
|
||||||
|
|
||||||
- Invoke the `bmad-party-mode` skill with the current project context
|
|
||||||
- Process the collaborative improvements to architectural understanding
|
|
||||||
- Ask user: "Accept these changes to the project context analysis? (y/n)"
|
|
||||||
- If yes: Update content with improvements, then return to A/P/C menu
|
|
||||||
- If no: Keep original content, then return to A/P/C menu
|
|
||||||
|
|
||||||
#### If 'C' (Continue):
|
|
||||||
|
|
||||||
- Append the final content to `{planning_artifacts}/architecture.md`
|
|
||||||
- Update frontmatter: `stepsCompleted: [1, 2]`
|
|
||||||
- Load `./step-03-starter.md`
|
|
||||||
|
|
||||||
## APPEND TO DOCUMENT:
|
|
||||||
|
|
||||||
When user selects 'C', append the content directly to the document using the structure from step 4.
|
|
||||||
|
|
||||||
## SUCCESS METRICS:
|
|
||||||
|
|
||||||
✅ All input documents thoroughly analyzed for architectural implications
|
|
||||||
✅ Project scope and complexity clearly assessed and validated
|
|
||||||
✅ Technical constraints and dependencies identified
|
|
||||||
✅ Cross-cutting concerns mapped for architectural planning
|
|
||||||
✅ User confirmation of project understanding
|
|
||||||
✅ A/P/C menu presented and handled correctly
|
|
||||||
✅ Content properly appended to document when C selected
|
|
||||||
|
|
||||||
## FAILURE MODES:
|
|
||||||
|
|
||||||
❌ Skimming documents without deep architectural analysis
|
|
||||||
❌ Missing or misinterpreting critical NFRs
|
|
||||||
❌ Not validating project understanding with user
|
|
||||||
❌ Underestimating complexity indicators
|
|
||||||
❌ Generating content without real analysis of loaded documents
|
|
||||||
❌ Not presenting A/P/C menu after content generation
|
|
||||||
|
|
||||||
❌ **CRITICAL**: Reading only partial step file - leads to incomplete understanding and poor decisions
|
|
||||||
❌ **CRITICAL**: Proceeding with 'C' without fully reading and understanding the next step file
|
|
||||||
❌ **CRITICAL**: Making decisions without complete understanding of step requirements and protocols
|
|
||||||
|
|
||||||
## NEXT STEP:
|
|
||||||
|
|
||||||
After user selects 'C' and content is saved to document, load `./step-03-starter.md` to evaluate starter template options.
|
|
||||||
|
|
||||||
Remember: Do NOT proceed to step-03 until user explicitly selects 'C' from the A/P/C menu and content is saved!
|
|
||||||
|
|
@ -1,329 +0,0 @@
|
||||||
# Step 3: Starter Template Evaluation
|
|
||||||
|
|
||||||
## MANDATORY EXECUTION RULES (READ FIRST):
|
|
||||||
|
|
||||||
- 🛑 NEVER generate content without user input
|
|
||||||
- ✅ ALWAYS treat this as collaborative discovery between architectural peers
|
|
||||||
- 📋 YOU ARE A FACILITATOR, not a content generator
|
|
||||||
- 💬 FOCUS on evaluating starter template options with current versions
|
|
||||||
- 🌐 ALWAYS search the web to verify current versions - NEVER trust hardcoded versions
|
|
||||||
- ⚠️ ABSOLUTELY NO TIME ESTIMATES - AI development speed has fundamentally changed
|
|
||||||
- 📖 CRITICAL: ALWAYS read the complete step file before taking any action - partial understanding leads to incomplete architecture
|
|
||||||
- 🔄 CRITICAL: When loading next step with 'C', ensure the entire file is read and understood before proceeding
|
|
||||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
|
||||||
|
|
||||||
## EXECUTION PROTOCOLS:
|
|
||||||
|
|
||||||
- 🎯 Show your analysis before taking any action
|
|
||||||
- 🌐 Search the web to verify current versions and options
|
|
||||||
- ⚠️ Present A/P/C menu after generating starter template analysis
|
|
||||||
- 💾 ONLY save when user chooses C (Continue)
|
|
||||||
- 📖 Update frontmatter `stepsCompleted: [1, 2, 3]` before loading next step
|
|
||||||
- 🚫 FORBIDDEN to load next step until C is selected
|
|
||||||
|
|
||||||
## COLLABORATION MENUS (A/P/C):
|
|
||||||
|
|
||||||
This step will generate content and present choices:
|
|
||||||
|
|
||||||
- **A (Advanced Elicitation)**: Use discovery protocols to explore unconventional starter options or custom approaches
|
|
||||||
- **P (Party Mode)**: Bring multiple perspectives to evaluate starter trade-offs for different use cases
|
|
||||||
- **C (Continue)**: Save the content to the document and proceed to next step
|
|
||||||
|
|
||||||
## PROTOCOL INTEGRATION:
|
|
||||||
|
|
||||||
- When 'A' selected: Invoke the `bmad-advanced-elicitation` skill
|
|
||||||
- When 'P' selected: Invoke the `bmad-party-mode` skill
|
|
||||||
- PROTOCOLS always return to display this step's A/P/C menu after the A or P have completed
|
|
||||||
- User accepts/rejects protocol changes before proceeding
|
|
||||||
|
|
||||||
## CONTEXT BOUNDARIES:
|
|
||||||
|
|
||||||
- Project context from step 2 is available and complete
|
|
||||||
- Project context file from step-01 may contain technical preferences
|
|
||||||
- No architectural decisions made yet - evaluating foundations
|
|
||||||
- Focus on technical preferences discovery and starter evaluation
|
|
||||||
- Consider project requirements and existing preferences when evaluating options
|
|
||||||
|
|
||||||
## YOUR TASK:
|
|
||||||
|
|
||||||
Discover technical preferences and evaluate starter template options, leveraging existing technical preferences and establishing solid architectural foundations.
|
|
||||||
|
|
||||||
## STARTER EVALUATION SEQUENCE:
|
|
||||||
|
|
||||||
### 0. Check Technical Preferences & Context
|
|
||||||
|
|
||||||
**Check Project Context for Existing Technical Preferences:**
|
|
||||||
"Before we dive into starter templates, let me check if you have any technical preferences already documented.
|
|
||||||
|
|
||||||
{{if_project_context_exists}}
|
|
||||||
I found some technical rules in your project context file:
|
|
||||||
{{extracted_technical_preferences_from_project_context}}
|
|
||||||
|
|
||||||
**Project Context Technical Rules Found:**
|
|
||||||
|
|
||||||
- Languages/Frameworks: {{languages_frameworks_from_context}}
|
|
||||||
- Tools & Libraries: {{tools_from_context}}
|
|
||||||
- Development Patterns: {{patterns_from_context}}
|
|
||||||
- Platform Preferences: {{platforms_from_context}}
|
|
||||||
|
|
||||||
{{else}}
|
|
||||||
No existing technical preferences found in project context file. We'll establish your technical preferences now.
|
|
||||||
{{/if_project_context}}"
|
|
||||||
|
|
||||||
**Discover User Technical Preferences:**
|
|
||||||
"Based on your project context, let's discuss your technical preferences:
|
|
||||||
|
|
||||||
{{primary_technology_category}} Preferences:
|
|
||||||
|
|
||||||
- **Languages**: Do you have preferences between TypeScript/JavaScript, Python, Go, Rust, etc.?
|
|
||||||
- **Frameworks**: Any existing familiarity or preferences (React, Vue, Angular, Next.js, etc.)?
|
|
||||||
- **Databases**: Any preferences or existing infrastructure (PostgreSQL, MongoDB, MySQL, etc.)?
|
|
||||||
|
|
||||||
**Development Experience:**
|
|
||||||
|
|
||||||
- What's your team's experience level with different technologies?
|
|
||||||
- Are there any technologies you want to learn vs. what you're comfortable with?
|
|
||||||
|
|
||||||
**Platform/Deployment Preferences:**
|
|
||||||
|
|
||||||
- Cloud provider preferences (AWS, Vercel, Railway, etc.)?
|
|
||||||
- Container preferences (Docker, Serverless, Traditional)?
|
|
||||||
|
|
||||||
**Integrations:**
|
|
||||||
|
|
||||||
- Any existing systems or APIs you need to integrate with?
|
|
||||||
- Third-party services you plan to use (payment, authentication, analytics, etc.)?
|
|
||||||
|
|
||||||
These preferences will help me recommend the most suitable starter templates and guide our architectural decisions."
|
|
||||||
|
|
||||||
### 1. Identify Primary Technology Domain
|
|
||||||
|
|
||||||
Based on project context analysis and technical preferences, identify the primary technology stack:
|
|
||||||
|
|
||||||
- **Web application** → Look for Next.js, Vite, Remix, SvelteKit starters
|
|
||||||
- **Mobile app** → Look for React Native, Expo, Flutter starters
|
|
||||||
- **API/Backend** → Look for NestJS, Express, Fastify, Supabase starters
|
|
||||||
- **CLI tool** → Look for CLI framework starters (oclif, commander, etc.)
|
|
||||||
- **Full-stack** → Look for T3, RedwoodJS, Blitz, Next.js starters
|
|
||||||
- **Desktop** → Look for Electron, Tauri starters
|
|
||||||
|
|
||||||
### 2. UX Requirements Consideration
|
|
||||||
|
|
||||||
If UX specification was loaded, consider UX requirements when selecting starter:
|
|
||||||
|
|
||||||
- **Rich animations** → Framer Motion compatible starter
|
|
||||||
- **Complex forms** → React Hook Form included starter
|
|
||||||
- **Real-time features** → Socket.io or WebSocket ready starter
|
|
||||||
- **Design system** → Storybook-enabled starter
|
|
||||||
- **Offline capability** → Service worker or PWA configured starter
|
|
||||||
|
|
||||||
### 3. Research Current Starter Options
|
|
||||||
|
|
||||||
Search the web to find current, maintained starter templates:
|
|
||||||
|
|
||||||
```
|
|
||||||
Search the web: "{{primary_technology}} starter template CLI create command latest"
|
|
||||||
Search the web: "{{primary_technology}} boilerplate generator latest options"
|
|
||||||
Search the web: "{{primary_technology}} production-ready starter best practices"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Investigate Top Starter Options
|
|
||||||
|
|
||||||
For each promising starter found, investigate details:
|
|
||||||
|
|
||||||
```
|
|
||||||
Search the web: "{{starter_name}} default setup technologies included latest"
|
|
||||||
Search the web: "{{starter_name}} project structure file organization"
|
|
||||||
Search the web: "{{starter_name}} production deployment capabilities"
|
|
||||||
Search the web: "{{starter_name}} recent updates maintenance status"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Analyze What Each Starter Provides
|
|
||||||
|
|
||||||
For each viable starter option, document:
|
|
||||||
|
|
||||||
**Technology Decisions Made:**
|
|
||||||
|
|
||||||
- Language/TypeScript configuration
|
|
||||||
- Styling solution (CSS, Tailwind, Styled Components, etc.)
|
|
||||||
- Testing framework setup
|
|
||||||
- Linting/Formatting configuration
|
|
||||||
- Build tooling and optimization
|
|
||||||
- Project structure and organization
|
|
||||||
|
|
||||||
**Architectural Patterns Established:**
|
|
||||||
|
|
||||||
- Code organization patterns
|
|
||||||
- Component structure conventions
|
|
||||||
- API layering approach
|
|
||||||
- State management setup
|
|
||||||
- Routing patterns
|
|
||||||
- Environment configuration
|
|
||||||
|
|
||||||
**Development Experience Features:**
|
|
||||||
|
|
||||||
- Hot reloading and development server
|
|
||||||
- TypeScript configuration
|
|
||||||
- Debugging setup
|
|
||||||
- Testing infrastructure
|
|
||||||
- Documentation generation
|
|
||||||
|
|
||||||
### 6. Present Starter Options
|
|
||||||
|
|
||||||
Based on user skill level and project needs:
|
|
||||||
|
|
||||||
**For Expert Users:**
|
|
||||||
"Found {{starter_name}} which provides:
|
|
||||||
{{quick_decision_list_of_key_decisions}}
|
|
||||||
|
|
||||||
This would establish our base architecture with these technical decisions already made. Use it?"
|
|
||||||
|
|
||||||
**For Intermediate Users:**
|
|
||||||
"I found {{starter_name}}, which is a well-maintained starter for {{project_type}} projects.
|
|
||||||
|
|
||||||
It makes these architectural decisions for us:
|
|
||||||
{{decision_list_with_explanations}}
|
|
||||||
|
|
||||||
This gives us a solid foundation following current best practices. Should we use it?"
|
|
||||||
|
|
||||||
**For Beginner Users:**
|
|
||||||
"I found {{starter_name}}, which is like a pre-built foundation for your project.
|
|
||||||
|
|
||||||
Think of it like buying a prefab house frame instead of cutting each board yourself.
|
|
||||||
|
|
||||||
It makes these decisions for us:
|
|
||||||
{{friendly_explanation_of_decisions}}
|
|
||||||
|
|
||||||
This is a great starting point that follows best practices and saves us from making dozens of small technical choices. Should we use it?"
|
|
||||||
|
|
||||||
### 7. Get Current CLI Commands
|
|
||||||
|
|
||||||
If user shows interest in a starter, get the exact current commands:
|
|
||||||
|
|
||||||
```
|
|
||||||
Search the web: "{{starter_name}} CLI command options flags latest"
|
|
||||||
Search the web: "{{starter_name}} create new project command examples"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 8. Generate Starter Template Content
|
|
||||||
|
|
||||||
Prepare the content to append to the document:
|
|
||||||
|
|
||||||
#### Content Structure:
|
|
||||||
|
|
||||||
````markdown
|
|
||||||
## Starter Template Evaluation
|
|
||||||
|
|
||||||
### Primary Technology Domain
|
|
||||||
|
|
||||||
{{identified_domain}} based on project requirements analysis
|
|
||||||
|
|
||||||
### Starter Options Considered
|
|
||||||
|
|
||||||
{{analysis_of_evaluated_starters}}
|
|
||||||
|
|
||||||
### Selected Starter: {{starter_name}}
|
|
||||||
|
|
||||||
**Rationale for Selection:**
|
|
||||||
{{why_this_starter_was_chosen}}
|
|
||||||
|
|
||||||
**Initialization Command:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
{{full_starter_command_with_options}}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Architectural Decisions Provided by Starter:**
|
|
||||||
|
|
||||||
**Language & Runtime:**
|
|
||||||
{{language_typescript_setup}}
|
|
||||||
|
|
||||||
**Styling Solution:**
|
|
||||||
{{styling_solution_configuration}}
|
|
||||||
|
|
||||||
**Build Tooling:**
|
|
||||||
{{build_tools_and_optimization}}
|
|
||||||
|
|
||||||
**Testing Framework:**
|
|
||||||
{{testing_setup_and_configuration}}
|
|
||||||
|
|
||||||
**Code Organization:**
|
|
||||||
{{project_structure_and_patterns}}
|
|
||||||
|
|
||||||
**Development Experience:**
|
|
||||||
{{development_tools_and_workflow}}
|
|
||||||
|
|
||||||
**Note:** Project initialization using this command should be the first implementation story.
|
|
||||||
|
|
||||||
````
|
|
||||||
|
|
||||||
### 9. Present Content and Menu
|
|
||||||
|
|
||||||
Show the generated content and present choices:
|
|
||||||
|
|
||||||
"I've analyzed starter template options for {{project_type}} projects.
|
|
||||||
|
|
||||||
**Here's what I'll add to the document:**
|
|
||||||
|
|
||||||
[Show the complete markdown content from step 8]
|
|
||||||
|
|
||||||
**What would you like to do?**
|
|
||||||
[A] Advanced Elicitation - Explore custom approaches or unconventional starters
|
|
||||||
[P] Party Mode - Evaluate trade-offs from different perspectives
|
|
||||||
[C] Continue - Save this decision and move to architectural decisions"
|
|
||||||
|
|
||||||
### 10. Handle Menu Selection
|
|
||||||
|
|
||||||
#### If 'A' (Advanced Elicitation):
|
|
||||||
|
|
||||||
- Invoke the `bmad-advanced-elicitation` skill with current starter analysis
|
|
||||||
- Process enhanced insights about starter options or custom approaches
|
|
||||||
- Ask user: "Accept these changes to the starter template evaluation? (y/n)"
|
|
||||||
- If yes: Update content, then return to A/P/C menu
|
|
||||||
- If no: Keep original content, then return to A/P/C menu
|
|
||||||
|
|
||||||
#### If 'P' (Party Mode):
|
|
||||||
|
|
||||||
- Invoke the `bmad-party-mode` skill with starter evaluation context
|
|
||||||
- Process collaborative insights about starter trade-offs
|
|
||||||
- Ask user: "Accept these changes to the starter template evaluation? (y/n)"
|
|
||||||
- If yes: Update content, then return to A/P/C menu
|
|
||||||
- If no: Keep original content, then return to A/P/C menu
|
|
||||||
|
|
||||||
#### If 'C' (Continue):
|
|
||||||
|
|
||||||
- Append the final content to `{planning_artifacts}/architecture.md`
|
|
||||||
- Update frontmatter: `stepsCompleted: [1, 2, 3]`
|
|
||||||
- Load `./step-04-decisions.md`
|
|
||||||
|
|
||||||
## APPEND TO DOCUMENT:
|
|
||||||
|
|
||||||
When user selects 'C', append the content directly to the document using the structure from step 8.
|
|
||||||
|
|
||||||
## SUCCESS METRICS:
|
|
||||||
|
|
||||||
✅ Primary technology domain correctly identified from project context
|
|
||||||
✅ Current, maintained starter templates researched and evaluated
|
|
||||||
✅ All versions verified using web search, not hardcoded
|
|
||||||
✅ Architectural implications of starter choice clearly documented
|
|
||||||
✅ User provided with clear rationale for starter selection
|
|
||||||
✅ A/P/C menu presented and handled correctly
|
|
||||||
✅ Content properly appended to document when C selected
|
|
||||||
|
|
||||||
## FAILURE MODES:
|
|
||||||
|
|
||||||
❌ Not verifying current versions with web search
|
|
||||||
❌ Ignoring UX requirements when evaluating starters
|
|
||||||
❌ Not documenting what architectural decisions the starter makes
|
|
||||||
❌ Failing to consider maintenance status of starter templates
|
|
||||||
❌ Not providing clear rationale for starter selection
|
|
||||||
❌ Not presenting A/P/C menu after content generation
|
|
||||||
❌ **CRITICAL**: Reading only partial step file - leads to incomplete understanding and poor decisions
|
|
||||||
❌ **CRITICAL**: Proceeding with 'C' without fully reading and understanding the next step file
|
|
||||||
❌ **CRITICAL**: Making decisions without complete understanding of step requirements and protocols
|
|
||||||
|
|
||||||
## NEXT STEP:
|
|
||||||
|
|
||||||
After user selects 'C' and content is saved to document, load `./step-04-decisions.md` to begin making specific architectural decisions.
|
|
||||||
|
|
||||||
Remember: Do NOT proceed to step-04 until user explicitly selects 'C' from the A/P/C menu and content is saved!
|
|
||||||
|
|
@ -1,318 +0,0 @@
|
||||||
# Step 4: Core Architectural Decisions
|
|
||||||
|
|
||||||
## MANDATORY EXECUTION RULES (READ FIRST):
|
|
||||||
|
|
||||||
- 🛑 NEVER generate content without user input
|
|
||||||
|
|
||||||
- 📖 CRITICAL: ALWAYS read the complete step file before taking any action - partial understanding leads to incomplete decisions
|
|
||||||
- 🔄 CRITICAL: When loading next step with 'C', ensure the entire file is read and understood before proceeding
|
|
||||||
- ✅ ALWAYS treat this as collaborative discovery between architectural peers
|
|
||||||
- 📋 YOU ARE A FACILITATOR, not a content generator
|
|
||||||
- 💬 FOCUS on making critical architectural decisions collaboratively
|
|
||||||
- 🌐 ALWAYS search the web to verify current technology versions
|
|
||||||
- ⚠️ ABSOLUTELY NO TIME ESTIMATES - AI development speed has fundamentally changed
|
|
||||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
|
||||||
|
|
||||||
## EXECUTION PROTOCOLS:
|
|
||||||
|
|
||||||
- 🎯 Show your analysis before taking any action
|
|
||||||
- 🌐 Search the web to verify technology versions and options
|
|
||||||
- ⚠️ Present A/P/C menu after each major decision category
|
|
||||||
- 💾 ONLY save when user chooses C (Continue)
|
|
||||||
- 📖 Update frontmatter `stepsCompleted: [1, 2, 3, 4]` before loading next step
|
|
||||||
- 🚫 FORBIDDEN to load next step until C is selected
|
|
||||||
|
|
||||||
## COLLABORATION MENUS (A/P/C):
|
|
||||||
|
|
||||||
This step will generate content and present choices for each decision category:
|
|
||||||
|
|
||||||
- **A (Advanced Elicitation)**: Use discovery protocols to explore innovative approaches to specific decisions
|
|
||||||
- **P (Party Mode)**: Bring multiple perspectives to evaluate decision trade-offs
|
|
||||||
- **C (Continue)**: Save the current decisions and proceed to next decision category
|
|
||||||
|
|
||||||
## PROTOCOL INTEGRATION:
|
|
||||||
|
|
||||||
- When 'A' selected: Invoke the `bmad-advanced-elicitation` skill
|
|
||||||
- When 'P' selected: Invoke the `bmad-party-mode` skill
|
|
||||||
- PROTOCOLS always return to display this step's A/P/C menu after the A or P have completed
|
|
||||||
- User accepts/rejects protocol changes before proceeding
|
|
||||||
|
|
||||||
## CONTEXT BOUNDARIES:
|
|
||||||
|
|
||||||
- Project context from step 2 is available
|
|
||||||
- Starter template choice from step 3 is available
|
|
||||||
- Project context file may contain technical preferences and rules
|
|
||||||
- Technical preferences discovered in step 3 are available
|
|
||||||
- Focus on decisions not already made by starter template or existing preferences
|
|
||||||
- Collaborative decision making, not recommendations
|
|
||||||
|
|
||||||
## YOUR TASK:
|
|
||||||
|
|
||||||
Facilitate collaborative architectural decision making, leveraging existing technical preferences and starter template decisions, focusing on remaining choices critical to the project's success.
|
|
||||||
|
|
||||||
## DECISION MAKING SEQUENCE:
|
|
||||||
|
|
||||||
### 1. Load Decision Framework & Check Existing Preferences
|
|
||||||
|
|
||||||
**Review Technical Preferences from Step 3:**
|
|
||||||
"Based on our technical preferences discussion in step 3, let's build on those foundations:
|
|
||||||
|
|
||||||
**Your Technical Preferences:**
|
|
||||||
{{user_technical_preferences_from_step_3}}
|
|
||||||
|
|
||||||
**Starter Template Decisions:**
|
|
||||||
{{starter_template_decisions}}
|
|
||||||
|
|
||||||
**Project Context Technical Rules:**
|
|
||||||
{{project_context_technical_rules}}"
|
|
||||||
|
|
||||||
**Identify Remaining Decisions:**
|
|
||||||
Based on technical preferences, starter template choice, and project context, identify remaining critical decisions:
|
|
||||||
|
|
||||||
**Already Decided (Don't re-decide these):**
|
|
||||||
|
|
||||||
- {{starter_template_decisions}}
|
|
||||||
- {{user_technology_preferences}}
|
|
||||||
- {{project_context_technical_rules}}
|
|
||||||
|
|
||||||
**Critical Decisions:** Must be decided before implementation can proceed
|
|
||||||
**Important Decisions:** Shape the architecture significantly
|
|
||||||
**Nice-to-Have:** Can be deferred if needed
|
|
||||||
|
|
||||||
### 2. Decision Categories by Priority
|
|
||||||
|
|
||||||
#### Category 1: Data Architecture
|
|
||||||
|
|
||||||
- Database choice (if not determined by starter)
|
|
||||||
- Data modeling approach
|
|
||||||
- Data validation strategy
|
|
||||||
- Migration approach
|
|
||||||
- Caching strategy
|
|
||||||
|
|
||||||
#### Category 2: Authentication & Security
|
|
||||||
|
|
||||||
- Authentication method
|
|
||||||
- Authorization patterns
|
|
||||||
- Security middleware
|
|
||||||
- Data encryption approach
|
|
||||||
- API security strategy
|
|
||||||
|
|
||||||
#### Category 3: API & Communication
|
|
||||||
|
|
||||||
- API design patterns (REST, GraphQL, etc.)
|
|
||||||
- API documentation approach
|
|
||||||
- Error handling standards
|
|
||||||
- Rate limiting strategy
|
|
||||||
- Communication between services
|
|
||||||
|
|
||||||
#### Category 4: Frontend Architecture (if applicable)
|
|
||||||
|
|
||||||
- State management approach
|
|
||||||
- Component architecture
|
|
||||||
- Routing strategy
|
|
||||||
- Performance optimization
|
|
||||||
- Bundle optimization
|
|
||||||
|
|
||||||
#### Category 5: Infrastructure & Deployment
|
|
||||||
|
|
||||||
- Hosting strategy
|
|
||||||
- CI/CD pipeline approach
|
|
||||||
- Environment configuration
|
|
||||||
- Monitoring and logging
|
|
||||||
- Scaling strategy
|
|
||||||
|
|
||||||
### 3. Facilitate Each Decision Category
|
|
||||||
|
|
||||||
For each category, facilitate collaborative decision making:
|
|
||||||
|
|
||||||
**Present the Decision:**
|
|
||||||
Based on user skill level and project context:
|
|
||||||
|
|
||||||
**Expert Mode:**
|
|
||||||
"{{Decision_Category}}: {{Specific_Decision}}
|
|
||||||
|
|
||||||
Options: {{concise_option_list_with_tradeoffs}}
|
|
||||||
|
|
||||||
What's your preference for this decision?"
|
|
||||||
|
|
||||||
**Intermediate Mode:**
|
|
||||||
"Next decision: {{Human_Friendly_Category}}
|
|
||||||
|
|
||||||
We need to choose {{Specific_Decision}}.
|
|
||||||
|
|
||||||
Common options:
|
|
||||||
{{option_list_with_brief_explanations}}
|
|
||||||
|
|
||||||
For your project, I'd lean toward {{recommendation}} because {{reason}}. What are your thoughts?"
|
|
||||||
|
|
||||||
**Beginner Mode:**
|
|
||||||
"Let's talk about {{Human_Friendly_Category}}.
|
|
||||||
|
|
||||||
{{Educational_Context_About_Why_This_Matters}}
|
|
||||||
|
|
||||||
Think of it like {{real_world_analogy}}.
|
|
||||||
|
|
||||||
Your main options:
|
|
||||||
{{friendly_options_with_pros_cons}}
|
|
||||||
|
|
||||||
My suggestion: {{recommendation}}
|
|
||||||
This is good for you because {{beginner_friendly_reason}}.
|
|
||||||
|
|
||||||
What feels right to you?"
|
|
||||||
|
|
||||||
**Verify Technology Versions:**
|
|
||||||
If decision involves specific technology:
|
|
||||||
|
|
||||||
```
|
|
||||||
Search the web: "{{technology}} latest stable version"
|
|
||||||
Search the web: "{{technology}} current LTS version"
|
|
||||||
Search the web: "{{technology}} production readiness"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Get User Input:**
|
|
||||||
"What's your preference? (or 'explain more' for details)"
|
|
||||||
|
|
||||||
**Handle User Response:**
|
|
||||||
|
|
||||||
- If user wants more info: Provide deeper explanation
|
|
||||||
- If user has preference: Discuss implications and record decision
|
|
||||||
- If user wants alternatives: Explore other options
|
|
||||||
|
|
||||||
**Record the Decision:**
|
|
||||||
|
|
||||||
- Category: {{category}}
|
|
||||||
- Decision: {{user_choice}}
|
|
||||||
- Version: {{verified_version_if_applicable}}
|
|
||||||
- Rationale: {{user_reasoning_or_default}}
|
|
||||||
- Affects: {{components_or_epics}}
|
|
||||||
- Provided by Starter: {{yes_if_from_starter}}
|
|
||||||
|
|
||||||
### 4. Check for Cascading Implications
|
|
||||||
|
|
||||||
After each major decision, identify related decisions:
|
|
||||||
|
|
||||||
"This choice means we'll also need to decide:
|
|
||||||
|
|
||||||
- {{related_decision_1}}
|
|
||||||
- {{related_decision_2}}"
|
|
||||||
|
|
||||||
### 5. Generate Decisions Content
|
|
||||||
|
|
||||||
After facilitating all decision categories, prepare the content to append:
|
|
||||||
|
|
||||||
#### Content Structure:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Core Architectural Decisions
|
|
||||||
|
|
||||||
### Decision Priority Analysis
|
|
||||||
|
|
||||||
**Critical Decisions (Block Implementation):**
|
|
||||||
{{critical_decisions_made}}
|
|
||||||
|
|
||||||
**Important Decisions (Shape Architecture):**
|
|
||||||
{{important_decisions_made}}
|
|
||||||
|
|
||||||
**Deferred Decisions (Post-MVP):**
|
|
||||||
{{decisions_deferred_with_rationale}}
|
|
||||||
|
|
||||||
### Data Architecture
|
|
||||||
|
|
||||||
{{data_related_decisions_with_versions_and_rationale}}
|
|
||||||
|
|
||||||
### Authentication & Security
|
|
||||||
|
|
||||||
{{security_related_decisions_with_versions_and_rationale}}
|
|
||||||
|
|
||||||
### API & Communication Patterns
|
|
||||||
|
|
||||||
{{api_related_decisions_with_versions_and_rationale}}
|
|
||||||
|
|
||||||
### Frontend Architecture
|
|
||||||
|
|
||||||
{{frontend_related_decisions_with_versions_and_rationale}}
|
|
||||||
|
|
||||||
### Infrastructure & Deployment
|
|
||||||
|
|
||||||
{{infrastructure_related_decisions_with_versions_and_rationale}}
|
|
||||||
|
|
||||||
### Decision Impact Analysis
|
|
||||||
|
|
||||||
**Implementation Sequence:**
|
|
||||||
{{ordered_list_of_decisions_for_implementation}}
|
|
||||||
|
|
||||||
**Cross-Component Dependencies:**
|
|
||||||
{{how_decisions_affect_each_other}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. Present Content and Menu
|
|
||||||
|
|
||||||
Show the generated decisions content and present choices:
|
|
||||||
|
|
||||||
"I've documented all the core architectural decisions we've made together.
|
|
||||||
|
|
||||||
**Here's what I'll add to the document:**
|
|
||||||
|
|
||||||
[Show the complete markdown content from step 5]
|
|
||||||
|
|
||||||
**What would you like to do?**
|
|
||||||
[A] Advanced Elicitation - Explore innovative approaches to any specific decisions
|
|
||||||
[P] Party Mode - Review decisions from multiple perspectives
|
|
||||||
[C] Continue - Save these decisions and move to implementation patterns"
|
|
||||||
|
|
||||||
### 7. Handle Menu Selection
|
|
||||||
|
|
||||||
#### If 'A' (Advanced Elicitation):
|
|
||||||
|
|
||||||
- Invoke the `bmad-advanced-elicitation` skill with specific decision categories
|
|
||||||
- Process enhanced insights about particular decisions
|
|
||||||
- Ask user: "Accept these enhancements to the architectural decisions? (y/n)"
|
|
||||||
- If yes: Update content, then return to A/P/C menu
|
|
||||||
- If no: Keep original content, then return to A/P/C menu
|
|
||||||
|
|
||||||
#### If 'P' (Party Mode):
|
|
||||||
|
|
||||||
- Invoke the `bmad-party-mode` skill with architectural decisions context
|
|
||||||
- Process collaborative insights about decision trade-offs
|
|
||||||
- Ask user: "Accept these changes to the architectural decisions? (y/n)"
|
|
||||||
- If yes: Update content, then return to A/P/C menu
|
|
||||||
- If no: Keep original content, then return to A/P/C menu
|
|
||||||
|
|
||||||
#### If 'C' (Continue):
|
|
||||||
|
|
||||||
- Append the final content to `{planning_artifacts}/architecture.md`
|
|
||||||
- Update frontmatter: `stepsCompleted: [1, 2, 3, 4]`
|
|
||||||
- Load `./step-05-patterns.md`
|
|
||||||
|
|
||||||
## APPEND TO DOCUMENT:
|
|
||||||
|
|
||||||
When user selects 'C', append the content directly to the document using the structure from step 5.
|
|
||||||
|
|
||||||
## SUCCESS METRICS:
|
|
||||||
|
|
||||||
✅ All critical architectural decisions made collaboratively
|
|
||||||
✅ Technology versions verified using web search
|
|
||||||
✅ Decision rationale clearly documented
|
|
||||||
✅ Cascading implications identified and addressed
|
|
||||||
✅ User provided appropriate level of explanation for skill level
|
|
||||||
✅ A/P/C menu presented and handled correctly for each category
|
|
||||||
✅ Content properly appended to document when C selected
|
|
||||||
|
|
||||||
## FAILURE MODES:
|
|
||||||
|
|
||||||
❌ Making recommendations instead of facilitating decisions
|
|
||||||
❌ Not verifying technology versions with web search
|
|
||||||
❌ Missing cascading implications between decisions
|
|
||||||
❌ Not adapting explanations to user skill level
|
|
||||||
❌ Forgetting to document decisions made by starter template
|
|
||||||
❌ Not presenting A/P/C menu after content generation
|
|
||||||
|
|
||||||
❌ **CRITICAL**: Reading only partial step file - leads to incomplete understanding and poor decisions
|
|
||||||
❌ **CRITICAL**: Proceeding with 'C' without fully reading and understanding the next step file
|
|
||||||
❌ **CRITICAL**: Making decisions without complete understanding of step requirements and protocols
|
|
||||||
|
|
||||||
## NEXT STEP:
|
|
||||||
|
|
||||||
After user selects 'C' and content is saved to document, load `./step-05-patterns.md` to define implementation patterns that ensure consistency across AI agents.
|
|
||||||
|
|
||||||
Remember: Do NOT proceed to step-05 until user explicitly selects 'C' from the A/P/C menu and content is saved!
|
|
||||||
|
|
@ -1,359 +0,0 @@
|
||||||
# Step 5: Implementation Patterns & Consistency Rules
|
|
||||||
|
|
||||||
## MANDATORY EXECUTION RULES (READ FIRST):
|
|
||||||
|
|
||||||
- 🛑 NEVER generate content without user input
|
|
||||||
|
|
||||||
- 📖 CRITICAL: ALWAYS read the complete step file before taking any action - partial understanding leads to incomplete decisions
|
|
||||||
- 🔄 CRITICAL: When loading next step with 'C', ensure the entire file is read and understood before proceeding
|
|
||||||
- ✅ ALWAYS treat this as collaborative discovery between architectural peers
|
|
||||||
- 📋 YOU ARE A FACILITATOR, not a content generator
|
|
||||||
- 💬 FOCUS on patterns that prevent AI agent implementation conflicts
|
|
||||||
- 🎯 EMPHASIZE what agents could decide DIFFERENTLY if not specified
|
|
||||||
- ⚠️ ABSOLUTELY NO TIME ESTIMATES - AI development speed has fundamentally changed
|
|
||||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
|
||||||
|
|
||||||
## EXECUTION PROTOCOLS:
|
|
||||||
|
|
||||||
- 🎯 Show your analysis before taking any action
|
|
||||||
- 🎯 Focus on consistency, not implementation details
|
|
||||||
- ⚠️ Present A/P/C menu after generating patterns content
|
|
||||||
- 💾 ONLY save when user chooses C (Continue)
|
|
||||||
- 📖 Update frontmatter `stepsCompleted: [1, 2, 3, 4, 5]` before loading next step
|
|
||||||
- 🚫 FORBIDDEN to load next step until C is selected
|
|
||||||
|
|
||||||
## COLLABORATION MENUS (A/P/C):
|
|
||||||
|
|
||||||
This step will generate content and present choices:
|
|
||||||
|
|
||||||
- **A (Advanced Elicitation)**: Use discovery protocols to develop comprehensive consistency patterns
|
|
||||||
- **P (Party Mode)**: Bring multiple perspectives to identify potential conflict points
|
|
||||||
- **C (Continue)**: Save the patterns and proceed to project structure
|
|
||||||
|
|
||||||
## PROTOCOL INTEGRATION:
|
|
||||||
|
|
||||||
- When 'A' selected: Invoke the `bmad-advanced-elicitation` skill
|
|
||||||
- When 'P' selected: Invoke the `bmad-party-mode` skill
|
|
||||||
- PROTOCOLS always return to display this step's A/P/C menu after the A or P have completed
|
|
||||||
- User accepts/rejects protocol changes before proceeding
|
|
||||||
|
|
||||||
## CONTEXT BOUNDARIES:
|
|
||||||
|
|
||||||
- Core architectural decisions from step 4 are complete
|
|
||||||
- Technology stack is decided and versions are verified
|
|
||||||
- Focus on HOW agents should implement, not WHAT they should implement
|
|
||||||
- Consider what could vary between different AI agents
|
|
||||||
|
|
||||||
## YOUR TASK:
|
|
||||||
|
|
||||||
Define implementation patterns and consistency rules that ensure multiple AI agents write compatible, consistent code that works together seamlessly.
|
|
||||||
|
|
||||||
## PATTERNS DEFINITION SEQUENCE:
|
|
||||||
|
|
||||||
### 1. Identify Potential Conflict Points
|
|
||||||
|
|
||||||
Based on the chosen technology stack and decisions, identify where AI agents could make different choices:
|
|
||||||
|
|
||||||
**Naming Conflicts:**
|
|
||||||
|
|
||||||
- Database table/column naming conventions
|
|
||||||
- API endpoint naming patterns
|
|
||||||
- File and directory naming
|
|
||||||
- Component/function/variable naming
|
|
||||||
- Route parameter formats
|
|
||||||
|
|
||||||
**Structural Conflicts:**
|
|
||||||
|
|
||||||
- Where tests are located
|
|
||||||
- How components are organized
|
|
||||||
- Where utilities and helpers go
|
|
||||||
- Configuration file organization
|
|
||||||
- Static asset organization
|
|
||||||
|
|
||||||
**Format Conflicts:**
|
|
||||||
|
|
||||||
- API response wrapper formats
|
|
||||||
- Error response structures
|
|
||||||
- Date/time formats in APIs and UI
|
|
||||||
- JSON field naming conventions
|
|
||||||
- API status code usage
|
|
||||||
|
|
||||||
**Communication Conflicts:**
|
|
||||||
|
|
||||||
- Event naming conventions
|
|
||||||
- Event payload structures
|
|
||||||
- State update patterns
|
|
||||||
- Action naming conventions
|
|
||||||
- Logging formats and levels
|
|
||||||
|
|
||||||
**Process Conflicts:**
|
|
||||||
|
|
||||||
- Loading state handling
|
|
||||||
- Error recovery patterns
|
|
||||||
- Retry implementation approaches
|
|
||||||
- Authentication flow patterns
|
|
||||||
- Validation timing and methods
|
|
||||||
|
|
||||||
### 2. Facilitate Pattern Decisions
|
|
||||||
|
|
||||||
For each conflict category, facilitate collaborative pattern definition:
|
|
||||||
|
|
||||||
**Present the Conflict Point:**
|
|
||||||
"Given that we're using {{tech_stack}}, different AI agents might handle {{conflict_area}} differently.
|
|
||||||
|
|
||||||
For example, one agent might name database tables 'users' while another uses 'Users' - this would cause conflicts.
|
|
||||||
|
|
||||||
We need to establish consistent patterns that all agents follow."
|
|
||||||
|
|
||||||
**Show Options and Trade-offs:**
|
|
||||||
"Common approaches for {{pattern_category}}:
|
|
||||||
|
|
||||||
1. {{option_1}} - {{pros_and_cons}}
|
|
||||||
2. {{option_2}} - {{pros_and_cons}}
|
|
||||||
3. {{option_3}} - {{pros_and_cons}}
|
|
||||||
|
|
||||||
Which approach makes the most sense for our project?"
|
|
||||||
|
|
||||||
**Get User Decision:**
|
|
||||||
"What's your preference for this pattern? (or discuss the trade-offs more)"
|
|
||||||
|
|
||||||
### 3. Define Pattern Categories
|
|
||||||
|
|
||||||
#### Naming Patterns
|
|
||||||
|
|
||||||
**Database Naming:**
|
|
||||||
|
|
||||||
- Table naming: users, Users, or user?
|
|
||||||
- Column naming: user_id or userId?
|
|
||||||
- Foreign key format: user_id or fk_user?
|
|
||||||
- Index naming: idx_users_email or users_email_index?
|
|
||||||
|
|
||||||
**API Naming:**
|
|
||||||
|
|
||||||
- REST endpoint naming: /users or /user? Plural or singular?
|
|
||||||
- Route parameter format: :id or {id}?
|
|
||||||
- Query parameter naming: user_id or userId?
|
|
||||||
- Header naming conventions: X-Custom-Header or Custom-Header?
|
|
||||||
|
|
||||||
**Code Naming:**
|
|
||||||
|
|
||||||
- Component naming: UserCard or user-card?
|
|
||||||
- File naming: UserCard.tsx or user-card.tsx?
|
|
||||||
- Function naming: getUserData or get_user_data?
|
|
||||||
- Variable naming: userId or user_id?
|
|
||||||
|
|
||||||
#### Structure Patterns
|
|
||||||
|
|
||||||
**Project Organization:**
|
|
||||||
|
|
||||||
- Where do tests live? **tests**/ or \*.test.ts co-located?
|
|
||||||
- How are components organized? By feature or by type?
|
|
||||||
- Where do shared utilities go?
|
|
||||||
- How are services and repositories organized?
|
|
||||||
|
|
||||||
**File Structure:**
|
|
||||||
|
|
||||||
- Config file locations and naming
|
|
||||||
- Static asset organization
|
|
||||||
- Documentation placement
|
|
||||||
- Environment file organization
|
|
||||||
|
|
||||||
#### Format Patterns
|
|
||||||
|
|
||||||
**API Formats:**
|
|
||||||
|
|
||||||
- API response wrapper? {data: ..., error: ...} or direct response?
|
|
||||||
- Error format? {message, code} or {error: {type, detail}}?
|
|
||||||
- Date format in JSON? ISO strings or timestamps?
|
|
||||||
- Success response structure?
|
|
||||||
|
|
||||||
**Data Formats:**
|
|
||||||
|
|
||||||
- JSON field naming: snake_case or camelCase?
|
|
||||||
- Boolean representations: true/false or 1/0?
|
|
||||||
- Null handling patterns
|
|
||||||
- Array vs object for single items
|
|
||||||
|
|
||||||
#### Communication Patterns
|
|
||||||
|
|
||||||
**Event Systems:**
|
|
||||||
|
|
||||||
- Event naming convention: user.created or UserCreated?
|
|
||||||
- Event payload structure standards
|
|
||||||
- Event versioning approach
|
|
||||||
- Async event handling patterns
|
|
||||||
|
|
||||||
**State Management:**
|
|
||||||
|
|
||||||
- State update patterns: immutable updates or direct mutation?
|
|
||||||
- Action naming conventions
|
|
||||||
- Selector patterns
|
|
||||||
- State organization principles
|
|
||||||
|
|
||||||
#### Process Patterns
|
|
||||||
|
|
||||||
**Error Handling:**
|
|
||||||
|
|
||||||
- Global error handling approach
|
|
||||||
- Error boundary patterns
|
|
||||||
- User-facing error message format
|
|
||||||
- Logging vs user error distinction
|
|
||||||
|
|
||||||
**Loading States:**
|
|
||||||
|
|
||||||
- Loading state naming conventions
|
|
||||||
- Global vs local loading states
|
|
||||||
- Loading state persistence
|
|
||||||
- Loading UI patterns
|
|
||||||
|
|
||||||
### 4. Generate Patterns Content
|
|
||||||
|
|
||||||
Prepare the content to append to the document:
|
|
||||||
|
|
||||||
#### Content Structure:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Implementation Patterns & Consistency Rules
|
|
||||||
|
|
||||||
### Pattern Categories Defined
|
|
||||||
|
|
||||||
**Critical Conflict Points Identified:**
|
|
||||||
{{number_of_potential_conflicts}} areas where AI agents could make different choices
|
|
||||||
|
|
||||||
### Naming Patterns
|
|
||||||
|
|
||||||
**Database Naming Conventions:**
|
|
||||||
{{database_naming_rules_with_examples}}
|
|
||||||
|
|
||||||
**API Naming Conventions:**
|
|
||||||
{{api_naming_rules_with_examples}}
|
|
||||||
|
|
||||||
**Code Naming Conventions:**
|
|
||||||
{{code_naming_rules_with_examples}}
|
|
||||||
|
|
||||||
### Structure Patterns
|
|
||||||
|
|
||||||
**Project Organization:**
|
|
||||||
{{project_structure_rules_with_examples}}
|
|
||||||
|
|
||||||
**File Structure Patterns:**
|
|
||||||
{{file_organization_rules_with_examples}}
|
|
||||||
|
|
||||||
### Format Patterns
|
|
||||||
|
|
||||||
**API Response Formats:**
|
|
||||||
{{api_response_structure_rules}}
|
|
||||||
|
|
||||||
**Data Exchange Formats:**
|
|
||||||
{{data_format_rules_with_examples}}
|
|
||||||
|
|
||||||
### Communication Patterns
|
|
||||||
|
|
||||||
**Event System Patterns:**
|
|
||||||
{{event_naming_and_structure_rules}}
|
|
||||||
|
|
||||||
**State Management Patterns:**
|
|
||||||
{{state_update_and_organization_rules}}
|
|
||||||
|
|
||||||
### Process Patterns
|
|
||||||
|
|
||||||
**Error Handling Patterns:**
|
|
||||||
{{consistent_error_handling_approaches}}
|
|
||||||
|
|
||||||
**Loading State Patterns:**
|
|
||||||
{{loading_state_management_rules}}
|
|
||||||
|
|
||||||
### Enforcement Guidelines
|
|
||||||
|
|
||||||
**All AI Agents MUST:**
|
|
||||||
|
|
||||||
- {{mandatory_pattern_1}}
|
|
||||||
- {{mandatory_pattern_2}}
|
|
||||||
- {{mandatory_pattern_3}}
|
|
||||||
|
|
||||||
**Pattern Enforcement:**
|
|
||||||
|
|
||||||
- How to verify patterns are followed
|
|
||||||
- Where to document pattern violations
|
|
||||||
- Process for updating patterns
|
|
||||||
|
|
||||||
### Pattern Examples
|
|
||||||
|
|
||||||
**Good Examples:**
|
|
||||||
{{concrete_examples_of_correct_pattern_usage}}
|
|
||||||
|
|
||||||
**Anti-Patterns:**
|
|
||||||
{{examples_of_what_to_avoid}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Present Content and Menu
|
|
||||||
|
|
||||||
Show the generated patterns content and present choices:
|
|
||||||
|
|
||||||
"I've documented implementation patterns that will prevent conflicts between AI agents working on this project.
|
|
||||||
|
|
||||||
**Here's what I'll add to the document:**
|
|
||||||
|
|
||||||
[Show the complete markdown content from step 4]
|
|
||||||
|
|
||||||
**What would you like to do?**
|
|
||||||
[A] Advanced Elicitation - Explore additional consistency patterns
|
|
||||||
[P] Party Mode - Review patterns from different implementation perspectives
|
|
||||||
[C] Continue - Save these patterns and move to project structure"
|
|
||||||
|
|
||||||
### 6. Handle Menu Selection
|
|
||||||
|
|
||||||
#### If 'A' (Advanced Elicitation):
|
|
||||||
|
|
||||||
- Invoke the `bmad-advanced-elicitation` skill with current patterns
|
|
||||||
- Process enhanced consistency rules that come back
|
|
||||||
- Ask user: "Accept these additional pattern refinements? (y/n)"
|
|
||||||
- If yes: Update content, then return to A/P/C menu
|
|
||||||
- If no: Keep original content, then return to A/P/C menu
|
|
||||||
|
|
||||||
#### If 'P' (Party Mode):
|
|
||||||
|
|
||||||
- Invoke the `bmad-party-mode` skill with implementation patterns context
|
|
||||||
- Process collaborative insights about potential conflicts
|
|
||||||
- Ask user: "Accept these changes to the implementation patterns? (y/n)"
|
|
||||||
- If yes: Update content, then return to A/P/C menu
|
|
||||||
- If no: Keep original content, then return to A/P/C menu
|
|
||||||
|
|
||||||
#### If 'C' (Continue):
|
|
||||||
|
|
||||||
- Append the final content to `{planning_artifacts}/architecture.md`
|
|
||||||
- Update frontmatter: `stepsCompleted: [1, 2, 3, 4, 5]`
|
|
||||||
- Load `./step-06-structure.md`
|
|
||||||
|
|
||||||
## APPEND TO DOCUMENT:
|
|
||||||
|
|
||||||
When user selects 'C', append the content directly to the document using the structure from step 4.
|
|
||||||
|
|
||||||
## SUCCESS METRICS:
|
|
||||||
|
|
||||||
✅ All potential AI agent conflict points identified and addressed
|
|
||||||
✅ Comprehensive patterns defined for naming, structure, and communication
|
|
||||||
✅ Concrete examples provided for each pattern
|
|
||||||
✅ Enforcement guidelines clearly documented
|
|
||||||
✅ User collaborated on pattern decisions rather than receiving recommendations
|
|
||||||
✅ A/P/C menu presented and handled correctly
|
|
||||||
✅ Content properly appended to document when C selected
|
|
||||||
|
|
||||||
## FAILURE MODES:
|
|
||||||
|
|
||||||
❌ Missing potential conflict points that could cause agent conflicts
|
|
||||||
❌ Being too prescriptive about implementation details instead of focusing on consistency
|
|
||||||
❌ Not providing concrete examples for each pattern
|
|
||||||
❌ Failing to address cross-cutting concerns like error handling
|
|
||||||
❌ Not considering the chosen technology stack when defining patterns
|
|
||||||
❌ Not presenting A/P/C menu after content generation
|
|
||||||
|
|
||||||
❌ **CRITICAL**: Reading only partial step file - leads to incomplete understanding and poor decisions
|
|
||||||
❌ **CRITICAL**: Proceeding with 'C' without fully reading and understanding the next step file
|
|
||||||
❌ **CRITICAL**: Making decisions without complete understanding of step requirements and protocols
|
|
||||||
|
|
||||||
## NEXT STEP:
|
|
||||||
|
|
||||||
After user selects 'C' and content is saved to document, load `./step-06-structure.md` to define the complete project structure.
|
|
||||||
|
|
||||||
Remember: Do NOT proceed to step-06 until user explicitly selects 'C' from the A/P/C menu and content is saved!
|
|
||||||
|
|
@ -1,379 +0,0 @@
|
||||||
# Step 6: Project Structure & Boundaries
|
|
||||||
|
|
||||||
## MANDATORY EXECUTION RULES (READ FIRST):
|
|
||||||
|
|
||||||
- 🛑 NEVER generate content without user input
|
|
||||||
|
|
||||||
- 📖 CRITICAL: ALWAYS read the complete step file before taking any action - partial understanding leads to incomplete decisions
|
|
||||||
- 🔄 CRITICAL: When loading next step with 'C', ensure the entire file is read and understood before proceeding
|
|
||||||
- ✅ ALWAYS treat this as collaborative discovery between architectural peers
|
|
||||||
- 📋 YOU ARE A FACILITATOR, not a content generator
|
|
||||||
- 💬 FOCUS on defining complete project structure and clear boundaries
|
|
||||||
- 🗺️ MAP requirements/epics to architectural components
|
|
||||||
- ⚠️ ABSOLUTELY NO TIME ESTIMATES - AI development speed has fundamentally changed
|
|
||||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
|
||||||
|
|
||||||
## EXECUTION PROTOCOLS:
|
|
||||||
|
|
||||||
- 🎯 Show your analysis before taking any action
|
|
||||||
- 🗺️ Create complete project tree, not generic placeholders
|
|
||||||
- ⚠️ Present A/P/C menu after generating project structure
|
|
||||||
- 💾 ONLY save when user chooses C (Continue)
|
|
||||||
- 📖 Update frontmatter `stepsCompleted: [1, 2, 3, 4, 5, 6]` before loading next step
|
|
||||||
- 🚫 FORBIDDEN to load next step until C is selected
|
|
||||||
|
|
||||||
## COLLABORATION MENUS (A/P/C):
|
|
||||||
|
|
||||||
This step will generate content and present choices:
|
|
||||||
|
|
||||||
- **A (Advanced Elicitation)**: Use discovery protocols to explore innovative project organization approaches
|
|
||||||
- **P (Party Mode)**: Bring multiple perspectives to evaluate project structure trade-offs
|
|
||||||
- **C (Continue)**: Save the project structure and proceed to validation
|
|
||||||
|
|
||||||
## PROTOCOL INTEGRATION:
|
|
||||||
|
|
||||||
- When 'A' selected: Invoke the `bmad-advanced-elicitation` skill
|
|
||||||
- When 'P' selected: Invoke the `bmad-party-mode` skill
|
|
||||||
- PROTOCOLS always return to display this step's A/P/C menu after the A or P have completed
|
|
||||||
- User accepts/rejects protocol changes before proceeding
|
|
||||||
|
|
||||||
## CONTEXT BOUNDARIES:
|
|
||||||
|
|
||||||
- All previous architectural decisions are complete
|
|
||||||
- Implementation patterns and consistency rules are defined
|
|
||||||
- Focus on physical project structure and component boundaries
|
|
||||||
- Map requirements to specific files and directories
|
|
||||||
|
|
||||||
## YOUR TASK:
|
|
||||||
|
|
||||||
Define the complete project structure and architectural boundaries based on all decisions made, creating a concrete implementation guide for AI agents.
|
|
||||||
|
|
||||||
## PROJECT STRUCTURE SEQUENCE:
|
|
||||||
|
|
||||||
### 1. Analyze Requirements Mapping
|
|
||||||
|
|
||||||
Map project requirements to architectural components:
|
|
||||||
|
|
||||||
**From Epics (if available):**
|
|
||||||
"Epic: {{epic_name}} → Lives in {{module/directory/service}}"
|
|
||||||
|
|
||||||
- User stories within the epic
|
|
||||||
- Cross-epic dependencies
|
|
||||||
- Shared components needed
|
|
||||||
|
|
||||||
**From FR Categories (if no epics):**
|
|
||||||
"FR Category: {{fr_category_name}} → Lives in {{module/directory/service}}"
|
|
||||||
|
|
||||||
- Related functional requirements
|
|
||||||
- Shared functionality across categories
|
|
||||||
- Integration points between categories
|
|
||||||
|
|
||||||
### 2. Define Project Directory Structure
|
|
||||||
|
|
||||||
Based on technology stack and patterns, create the complete project structure:
|
|
||||||
|
|
||||||
**Root Configuration Files:**
|
|
||||||
|
|
||||||
- Package management files (package.json, requirements.txt, etc.)
|
|
||||||
- Build and development configuration
|
|
||||||
- Environment configuration files
|
|
||||||
- CI/CD pipeline files
|
|
||||||
- Documentation files
|
|
||||||
|
|
||||||
**Source Code Organization:**
|
|
||||||
|
|
||||||
- Application entry points
|
|
||||||
- Core application structure
|
|
||||||
- Feature/module organization
|
|
||||||
- Shared utilities and libraries
|
|
||||||
- Configuration and environment files
|
|
||||||
|
|
||||||
**Test Organization:**
|
|
||||||
|
|
||||||
- Unit test locations and structure
|
|
||||||
- Integration test organization
|
|
||||||
- End-to-end test structure
|
|
||||||
- Test utilities and fixtures
|
|
||||||
|
|
||||||
**Build and Distribution:**
|
|
||||||
|
|
||||||
- Build output directories
|
|
||||||
- Distribution files
|
|
||||||
- Static assets
|
|
||||||
- Documentation build
|
|
||||||
|
|
||||||
### 3. Define Integration Boundaries
|
|
||||||
|
|
||||||
Map how components communicate and where boundaries exist:
|
|
||||||
|
|
||||||
**API Boundaries:**
|
|
||||||
|
|
||||||
- External API endpoints
|
|
||||||
- Internal service boundaries
|
|
||||||
- Authentication and authorization boundaries
|
|
||||||
- Data access layer boundaries
|
|
||||||
|
|
||||||
**Component Boundaries:**
|
|
||||||
|
|
||||||
- Frontend component communication patterns
|
|
||||||
- State management boundaries
|
|
||||||
- Service communication patterns
|
|
||||||
- Event-driven integration points
|
|
||||||
|
|
||||||
**Data Boundaries:**
|
|
||||||
|
|
||||||
- Database schema boundaries
|
|
||||||
- Data access patterns
|
|
||||||
- Caching boundaries
|
|
||||||
- External data integration points
|
|
||||||
|
|
||||||
### 4. Create Complete Project Tree
|
|
||||||
|
|
||||||
Generate a comprehensive directory structure showing all files and directories:
|
|
||||||
|
|
||||||
**Technology-Specific Structure Examples:**
|
|
||||||
|
|
||||||
**Next.js Full-Stack:**
|
|
||||||
|
|
||||||
```
|
|
||||||
project-name/
|
|
||||||
├── README.md
|
|
||||||
├── package.json
|
|
||||||
├── next.config.js
|
|
||||||
├── tailwind.config.js
|
|
||||||
├── tsconfig.json
|
|
||||||
├── .env.local
|
|
||||||
├── .env.example
|
|
||||||
├── .gitignore
|
|
||||||
├── .github/
|
|
||||||
│ └── workflows/
|
|
||||||
│ └── ci.yml
|
|
||||||
├── src/
|
|
||||||
│ ├── app/
|
|
||||||
│ │ ├── globals.css
|
|
||||||
│ │ ├── layout.tsx
|
|
||||||
│ │ └── page.tsx
|
|
||||||
│ ├── components/
|
|
||||||
│ │ ├── ui/
|
|
||||||
│ │ ├── forms/
|
|
||||||
│ │ └── features/
|
|
||||||
│ ├── lib/
|
|
||||||
│ │ ├── db.ts
|
|
||||||
│ │ ├── auth.ts
|
|
||||||
│ │ └── utils.ts
|
|
||||||
│ ├── types/
|
|
||||||
│ └── middleware.ts
|
|
||||||
├── prisma/
|
|
||||||
│ ├── schema.prisma
|
|
||||||
│ └── migrations/
|
|
||||||
├── tests/
|
|
||||||
│ ├── __mocks__/
|
|
||||||
│ ├── components/
|
|
||||||
│ └── e2e/
|
|
||||||
└── public/
|
|
||||||
└── assets/
|
|
||||||
```
|
|
||||||
|
|
||||||
**API Backend (NestJS):**
|
|
||||||
|
|
||||||
```
|
|
||||||
project-name/
|
|
||||||
├── package.json
|
|
||||||
├── nest-cli.json
|
|
||||||
├── tsconfig.json
|
|
||||||
├── .env
|
|
||||||
├── .env.example
|
|
||||||
├── .gitignore
|
|
||||||
├── README.md
|
|
||||||
├── src/
|
|
||||||
│ ├── main.ts
|
|
||||||
│ ├── app.module.ts
|
|
||||||
│ ├── config/
|
|
||||||
│ ├── modules/
|
|
||||||
│ │ ├── auth/
|
|
||||||
│ │ ├── users/
|
|
||||||
│ │ └── common/
|
|
||||||
│ ├── services/
|
|
||||||
│ ├── repositories/
|
|
||||||
│ ├── decorators/
|
|
||||||
│ ├── pipes/
|
|
||||||
│ ├── guards/
|
|
||||||
│ └── interceptors/
|
|
||||||
├── test/
|
|
||||||
│ ├── unit/
|
|
||||||
│ ├── integration/
|
|
||||||
│ └── e2e/
|
|
||||||
├── prisma/
|
|
||||||
│ ├── schema.prisma
|
|
||||||
│ └── migrations/
|
|
||||||
└── docker-compose.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Map Requirements to Structure
|
|
||||||
|
|
||||||
Create explicit mapping from project requirements to specific files/directories:
|
|
||||||
|
|
||||||
**Epic/Feature Mapping:**
|
|
||||||
"Epic: User Management
|
|
||||||
|
|
||||||
- Components: src/components/features/users/
|
|
||||||
- Services: src/services/users/
|
|
||||||
- API Routes: src/app/api/users/
|
|
||||||
- Database: prisma/migrations/_*users*_
|
|
||||||
- Tests: tests/features/users/"
|
|
||||||
|
|
||||||
**Cross-Cutting Concerns:**
|
|
||||||
"Authentication System
|
|
||||||
|
|
||||||
- Components: src/components/auth/
|
|
||||||
- Services: src/services/auth/
|
|
||||||
- Middleware: src/middleware/auth.ts
|
|
||||||
- Guards: src/guards/auth.guard.ts
|
|
||||||
- Tests: tests/auth/"
|
|
||||||
|
|
||||||
### 6. Generate Structure Content
|
|
||||||
|
|
||||||
Prepare the content to append to the document:
|
|
||||||
|
|
||||||
#### Content Structure:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Project Structure & Boundaries
|
|
||||||
|
|
||||||
### Complete Project Directory Structure
|
|
||||||
```
|
|
||||||
|
|
||||||
{{complete_project_tree_with_all_files_and_directories}}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### Architectural Boundaries
|
|
||||||
|
|
||||||
**API Boundaries:**
|
|
||||||
{{api_boundary_definitions_and_endpoints}}
|
|
||||||
|
|
||||||
**Component Boundaries:**
|
|
||||||
{{component_communication_patterns_and_boundaries}}
|
|
||||||
|
|
||||||
**Service Boundaries:**
|
|
||||||
{{service_integration_patterns_and_boundaries}}
|
|
||||||
|
|
||||||
**Data Boundaries:**
|
|
||||||
{{data_access_patterns_and_boundaries}}
|
|
||||||
|
|
||||||
### Requirements to Structure Mapping
|
|
||||||
|
|
||||||
**Feature/Epic Mapping:**
|
|
||||||
{{mapping_of_epics_or_features_to_specific_directories}}
|
|
||||||
|
|
||||||
**Cross-Cutting Concerns:**
|
|
||||||
{{mapping_of_shared_functionality_to_locations}}
|
|
||||||
|
|
||||||
### Integration Points
|
|
||||||
|
|
||||||
**Internal Communication:**
|
|
||||||
{{how_components_within_the_project_communicate}}
|
|
||||||
|
|
||||||
**External Integrations:**
|
|
||||||
{{third_party_service_integration_points}}
|
|
||||||
|
|
||||||
**Data Flow:**
|
|
||||||
{{how_data_flows_through_the_architecture}}
|
|
||||||
|
|
||||||
### File Organization Patterns
|
|
||||||
|
|
||||||
**Configuration Files:**
|
|
||||||
{{where_and_how_config_files_are_organized}}
|
|
||||||
|
|
||||||
**Source Organization:**
|
|
||||||
{{how_source_code_is_structured_and_organized}}
|
|
||||||
|
|
||||||
**Test Organization:**
|
|
||||||
{{how_tests_are_structured_and_organized}}
|
|
||||||
|
|
||||||
**Asset Organization:**
|
|
||||||
{{how_static_and_dynamic_assets_are_organized}}
|
|
||||||
|
|
||||||
### Development Workflow Integration
|
|
||||||
|
|
||||||
**Development Server Structure:**
|
|
||||||
{{how_the_project_is organized_for_development}}
|
|
||||||
|
|
||||||
**Build Process Structure:**
|
|
||||||
{{how_the_build_process_uses_the_project_structure}}
|
|
||||||
|
|
||||||
**Deployment Structure:**
|
|
||||||
{{how_the_project_structure_supports_deployment}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7. Present Content and Menu
|
|
||||||
|
|
||||||
Show the generated project structure content and present choices:
|
|
||||||
|
|
||||||
"I've created a complete project structure based on all our architectural decisions.
|
|
||||||
|
|
||||||
**Here's what I'll add to the document:**
|
|
||||||
|
|
||||||
[Show the complete markdown content from step 6]
|
|
||||||
|
|
||||||
**What would you like to do?**
|
|
||||||
[A] Advanced Elicitation - Explore innovative project organization approaches
|
|
||||||
[P] Party Mode - Review structure from different development perspectives
|
|
||||||
[C] Continue - Save this structure and move to architecture validation"
|
|
||||||
|
|
||||||
### 8. Handle Menu Selection
|
|
||||||
|
|
||||||
#### If 'A' (Advanced Elicitation):
|
|
||||||
|
|
||||||
- Invoke the `bmad-advanced-elicitation` skill with current project structure
|
|
||||||
- Process enhanced organizational insights that come back
|
|
||||||
- Ask user: "Accept these changes to the project structure? (y/n)"
|
|
||||||
- If yes: Update content, then return to A/P/C menu
|
|
||||||
- If no: Keep original content, then return to A/P/C menu
|
|
||||||
|
|
||||||
#### If 'P' (Party Mode):
|
|
||||||
|
|
||||||
- Invoke the `bmad-party-mode` skill with project structure context
|
|
||||||
- Process collaborative insights about organization trade-offs
|
|
||||||
- Ask user: "Accept these changes to the project structure? (y/n)"
|
|
||||||
- If yes: Update content, then return to A/P/C menu
|
|
||||||
- If no: Keep original content, then return to A/P/C menu
|
|
||||||
|
|
||||||
#### If 'C' (Continue):
|
|
||||||
|
|
||||||
- Append the final content to `{planning_artifacts}/architecture.md`
|
|
||||||
- Update frontmatter: `stepsCompleted: [1, 2, 3, 4, 5, 6]`
|
|
||||||
- Load `./step-07-validation.md`
|
|
||||||
|
|
||||||
## APPEND TO DOCUMENT:
|
|
||||||
|
|
||||||
When user selects 'C', append the content directly to the document using the structure from step 6.
|
|
||||||
|
|
||||||
## SUCCESS METRICS:
|
|
||||||
|
|
||||||
✅ Complete project tree defined with all files and directories
|
|
||||||
✅ All architectural boundaries clearly documented
|
|
||||||
✅ Requirements/epics mapped to specific locations
|
|
||||||
✅ Integration points and communication patterns defined
|
|
||||||
✅ Project structure aligned with chosen technology stack
|
|
||||||
✅ A/P/C menu presented and handled correctly
|
|
||||||
✅ Content properly appended to document when C selected
|
|
||||||
|
|
||||||
## FAILURE MODES:
|
|
||||||
|
|
||||||
❌ Creating generic placeholder structure instead of specific, complete tree
|
|
||||||
❌ Not mapping requirements to specific files and directories
|
|
||||||
❌ Missing important integration boundaries
|
|
||||||
❌ Not considering the chosen technology stack in structure design
|
|
||||||
❌ Not defining how components communicate across boundaries
|
|
||||||
❌ Not presenting A/P/C menu after content generation
|
|
||||||
|
|
||||||
❌ **CRITICAL**: Reading only partial step file - leads to incomplete understanding and poor decisions
|
|
||||||
❌ **CRITICAL**: Proceeding with 'C' without fully reading and understanding the next step file
|
|
||||||
❌ **CRITICAL**: Making decisions without complete understanding of step requirements and protocols
|
|
||||||
|
|
||||||
## NEXT STEP:
|
|
||||||
|
|
||||||
After user selects 'C' and content is saved to document, load `./step-07-validation.md` to validate architectural coherence and completeness.
|
|
||||||
|
|
||||||
Remember: Do NOT proceed to step-07 until user explicitly selects 'C' from the A/P/C menu and content is saved!
|
|
||||||
|
|
@ -1,361 +0,0 @@
|
||||||
# Step 7: Architecture Validation & Completion
|
|
||||||
|
|
||||||
## MANDATORY EXECUTION RULES (READ FIRST):
|
|
||||||
|
|
||||||
- 🛑 NEVER generate content without user input
|
|
||||||
|
|
||||||
- 📖 CRITICAL: ALWAYS read the complete step file before taking any action - partial understanding leads to incomplete decisions
|
|
||||||
- 🔄 CRITICAL: When loading next step with 'C', ensure the entire file is read and understood before proceeding
|
|
||||||
- ✅ ALWAYS treat this as collaborative discovery between architectural peers
|
|
||||||
- 📋 YOU ARE A FACILITATOR, not a content generator
|
|
||||||
- 💬 FOCUS on validating architectural coherence and completeness
|
|
||||||
- ✅ VALIDATE all requirements are covered by architectural decisions
|
|
||||||
- ⚠️ ABSOLUTELY NO TIME ESTIMATES - AI development speed has fundamentally changed
|
|
||||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
|
||||||
|
|
||||||
## EXECUTION PROTOCOLS:
|
|
||||||
|
|
||||||
- 🎯 Show your analysis before taking any action
|
|
||||||
- ✅ Run comprehensive validation checks on the complete architecture
|
|
||||||
- ⚠️ Present A/P/C menu after generating validation results
|
|
||||||
- 💾 ONLY save when user chooses C (Continue)
|
|
||||||
- 📖 Update frontmatter `stepsCompleted: [1, 2, 3, 4, 5, 6, 7]` before loading next step
|
|
||||||
- 🚫 FORBIDDEN to load next step until C is selected
|
|
||||||
|
|
||||||
## COLLABORATION MENUS (A/P/C):
|
|
||||||
|
|
||||||
This step will generate content and present choices:
|
|
||||||
|
|
||||||
- **A (Advanced Elicitation)**: Use discovery protocols to address complex architectural issues found during validation
|
|
||||||
- **P (Party Mode)**: Bring multiple perspectives to resolve validation concerns
|
|
||||||
- **C (Continue)**: Save the validation results and complete the architecture
|
|
||||||
|
|
||||||
## PROTOCOL INTEGRATION:
|
|
||||||
|
|
||||||
- When 'A' selected: Invoke the `bmad-advanced-elicitation` skill
|
|
||||||
- When 'P' selected: Invoke the `bmad-party-mode` skill
|
|
||||||
- PROTOCOLS always return to display this step's A/P/C menu after the A or P have completed
|
|
||||||
- User accepts/rejects protocol changes before proceeding
|
|
||||||
|
|
||||||
## CONTEXT BOUNDARIES:
|
|
||||||
|
|
||||||
- Complete architecture document with all sections is available
|
|
||||||
- All architectural decisions, patterns, and structure are defined
|
|
||||||
- Focus on validation, gap analysis, and coherence checking
|
|
||||||
- Prepare for handoff to implementation phase
|
|
||||||
|
|
||||||
## YOUR TASK:
|
|
||||||
|
|
||||||
Validate the complete architecture for coherence, completeness, and readiness to guide AI agents through consistent implementation.
|
|
||||||
|
|
||||||
## VALIDATION SEQUENCE:
|
|
||||||
|
|
||||||
### 1. Coherence Validation
|
|
||||||
|
|
||||||
Check that all architectural decisions work together:
|
|
||||||
|
|
||||||
**Decision Compatibility:**
|
|
||||||
|
|
||||||
- Do all technology choices work together without conflicts?
|
|
||||||
- Are all versions compatible with each other?
|
|
||||||
- Do patterns align with technology choices?
|
|
||||||
- Are there any contradictory decisions?
|
|
||||||
|
|
||||||
**Pattern Consistency:**
|
|
||||||
|
|
||||||
- Do implementation patterns support the architectural decisions?
|
|
||||||
- Are naming conventions consistent across all areas?
|
|
||||||
- Do structure patterns align with technology stack?
|
|
||||||
- Are communication patterns coherent?
|
|
||||||
|
|
||||||
**Structure Alignment:**
|
|
||||||
|
|
||||||
- Does the project structure support all architectural decisions?
|
|
||||||
- Are boundaries properly defined and respected?
|
|
||||||
- Does the structure enable the chosen patterns?
|
|
||||||
- Are integration points properly structured?
|
|
||||||
|
|
||||||
### 2. Requirements Coverage Validation
|
|
||||||
|
|
||||||
Verify all project requirements are architecturally supported:
|
|
||||||
|
|
||||||
**From Epics (if available):**
|
|
||||||
|
|
||||||
- Does every epic have architectural support?
|
|
||||||
- Are all user stories implementable with these decisions?
|
|
||||||
- Are cross-epic dependencies handled architecturally?
|
|
||||||
- Are there any gaps in epic coverage?
|
|
||||||
|
|
||||||
**From FR Categories (if no epics):**
|
|
||||||
|
|
||||||
- Does every functional requirement have architectural support?
|
|
||||||
- Are all FR categories fully covered by architectural decisions?
|
|
||||||
- Are cross-cutting FRs properly addressed?
|
|
||||||
- Are there any missing architectural capabilities?
|
|
||||||
|
|
||||||
**Non-Functional Requirements:**
|
|
||||||
|
|
||||||
- Are performance requirements addressed architecturally?
|
|
||||||
- Are security requirements fully covered?
|
|
||||||
- Are scalability considerations properly handled?
|
|
||||||
- Are compliance requirements architecturally supported?
|
|
||||||
|
|
||||||
### 3. Implementation Readiness Validation
|
|
||||||
|
|
||||||
Assess if AI agents can implement consistently:
|
|
||||||
|
|
||||||
**Decision Completeness:**
|
|
||||||
|
|
||||||
- Are all critical decisions documented with versions?
|
|
||||||
- Are implementation patterns comprehensive enough?
|
|
||||||
- Are consistency rules clear and enforceable?
|
|
||||||
- Are examples provided for all major patterns?
|
|
||||||
|
|
||||||
**Structure Completeness:**
|
|
||||||
|
|
||||||
- Is the project structure complete and specific?
|
|
||||||
- Are all files and directories defined?
|
|
||||||
- Are integration points clearly specified?
|
|
||||||
- Are component boundaries well-defined?
|
|
||||||
|
|
||||||
**Pattern Completeness:**
|
|
||||||
|
|
||||||
- Are all potential conflict points addressed?
|
|
||||||
- Are naming conventions comprehensive?
|
|
||||||
- Are communication patterns fully specified?
|
|
||||||
- Are process patterns (error handling, etc.) complete?
|
|
||||||
|
|
||||||
### 4. Gap Analysis
|
|
||||||
|
|
||||||
Identify and document any missing elements:
|
|
||||||
|
|
||||||
**Critical Gaps:**
|
|
||||||
|
|
||||||
- Missing architectural decisions that block implementation
|
|
||||||
- Incomplete patterns that could cause conflicts
|
|
||||||
- Missing structural elements needed for development
|
|
||||||
- Undefined integration points
|
|
||||||
|
|
||||||
**Important Gaps:**
|
|
||||||
|
|
||||||
- Areas that need more detailed specification
|
|
||||||
- Patterns that could be more comprehensive
|
|
||||||
- Documentation that would help implementation
|
|
||||||
- Examples that would clarify complex decisions
|
|
||||||
|
|
||||||
**Nice-to-Have Gaps:**
|
|
||||||
|
|
||||||
- Additional patterns that would be helpful
|
|
||||||
- Supplementary documentation
|
|
||||||
- Tooling recommendations
|
|
||||||
- Development workflow optimizations
|
|
||||||
|
|
||||||
### 5. Address Validation Issues
|
|
||||||
|
|
||||||
For any issues found, facilitate resolution:
|
|
||||||
|
|
||||||
**Critical Issues:**
|
|
||||||
"I found some issues that need to be addressed before implementation:
|
|
||||||
|
|
||||||
{{critical_issue_description}}
|
|
||||||
|
|
||||||
These could cause implementation problems. How would you like to resolve this?"
|
|
||||||
|
|
||||||
**Important Issues:**
|
|
||||||
"I noticed a few areas that could be improved:
|
|
||||||
|
|
||||||
{{important_issue_description}}
|
|
||||||
|
|
||||||
These aren't blocking, but addressing them would make implementation smoother. Should we work on these?"
|
|
||||||
|
|
||||||
**Minor Issues:**
|
|
||||||
"Here are some minor suggestions for improvement:
|
|
||||||
|
|
||||||
{{minor_issue_description}}
|
|
||||||
|
|
||||||
These are optional refinements. Would you like to address any of these?"
|
|
||||||
|
|
||||||
### 6. Generate Validation Content
|
|
||||||
|
|
||||||
Prepare the content to append to the document:
|
|
||||||
|
|
||||||
#### Content Structure:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Architecture Validation Results
|
|
||||||
|
|
||||||
### Coherence Validation ✅
|
|
||||||
|
|
||||||
**Decision Compatibility:**
|
|
||||||
{{assessment_of_how_all_decisions_work_together}}
|
|
||||||
|
|
||||||
**Pattern Consistency:**
|
|
||||||
{{verification_that_patterns_support_decisions}}
|
|
||||||
|
|
||||||
**Structure Alignment:**
|
|
||||||
{{confirmation_that_structure_supports_architecture}}
|
|
||||||
|
|
||||||
### Requirements Coverage Validation ✅
|
|
||||||
|
|
||||||
**Epic/Feature Coverage:**
|
|
||||||
{{verification_that_all_epics_or_features_are_supported}}
|
|
||||||
|
|
||||||
**Functional Requirements Coverage:**
|
|
||||||
{{confirmation_that_all_FRs_are_architecturally_supported}}
|
|
||||||
|
|
||||||
**Non-Functional Requirements Coverage:**
|
|
||||||
{{verification_that_NFRs_are_addressed}}
|
|
||||||
|
|
||||||
### Implementation Readiness Validation ✅
|
|
||||||
|
|
||||||
**Decision Completeness:**
|
|
||||||
{{assessment_of_decision_documentation_completeness}}
|
|
||||||
|
|
||||||
**Structure Completeness:**
|
|
||||||
{{evaluation_of_project_structure_completeness}}
|
|
||||||
|
|
||||||
**Pattern Completeness:**
|
|
||||||
{{verification_of_implementation_patterns_completeness}}
|
|
||||||
|
|
||||||
### Gap Analysis Results
|
|
||||||
|
|
||||||
{{gap_analysis_findings_with_priority_levels}}
|
|
||||||
|
|
||||||
### Validation Issues Addressed
|
|
||||||
|
|
||||||
{{description_of_any_issues_found_and_resolutions}}
|
|
||||||
|
|
||||||
### Architecture Completeness Checklist
|
|
||||||
|
|
||||||
Mark each item `[x]` only if validation confirms it; leave `[ ]` if it is missing, partial, or unverified. Any unchecked item must be reflected in the Gap Analysis above and in the Overall Status below.
|
|
||||||
|
|
||||||
**Requirements Analysis**
|
|
||||||
|
|
||||||
- [ ] Project context thoroughly analyzed
|
|
||||||
- [ ] Scale and complexity assessed
|
|
||||||
- [ ] Technical constraints identified
|
|
||||||
- [ ] Cross-cutting concerns mapped
|
|
||||||
|
|
||||||
**Architectural Decisions**
|
|
||||||
|
|
||||||
- [ ] Critical decisions documented with versions
|
|
||||||
- [ ] Technology stack fully specified
|
|
||||||
- [ ] Integration patterns defined
|
|
||||||
- [ ] Performance considerations addressed
|
|
||||||
|
|
||||||
**Implementation Patterns**
|
|
||||||
|
|
||||||
- [ ] Naming conventions established
|
|
||||||
- [ ] Structure patterns defined
|
|
||||||
- [ ] Communication patterns specified
|
|
||||||
- [ ] Process patterns documented
|
|
||||||
|
|
||||||
**Project Structure**
|
|
||||||
|
|
||||||
- [ ] Complete directory structure defined
|
|
||||||
- [ ] Component boundaries established
|
|
||||||
- [ ] Integration points mapped
|
|
||||||
- [ ] Requirements to structure mapping complete
|
|
||||||
|
|
||||||
### Architecture Readiness Assessment
|
|
||||||
|
|
||||||
**Overall Status:** {{READY FOR IMPLEMENTATION | READY WITH MINOR GAPS | NOT READY}} (choose READY FOR IMPLEMENTATION only when all 16 checklist items are `[x]` and no Critical Gaps remain; choose NOT READY when any Critical Gap is open or any Requirements Analysis or Architectural Decisions item is unchecked; otherwise READY WITH MINOR GAPS)
|
|
||||||
|
|
||||||
**Confidence Level:** {{high/medium/low}} based on validation results
|
|
||||||
|
|
||||||
**Key Strengths:**
|
|
||||||
{{list_of_architecture_strengths}}
|
|
||||||
|
|
||||||
**Areas for Future Enhancement:**
|
|
||||||
{{areas_that_could_be_improved_later}}
|
|
||||||
|
|
||||||
### Implementation Handoff
|
|
||||||
|
|
||||||
**AI Agent Guidelines:**
|
|
||||||
|
|
||||||
- Follow all architectural decisions exactly as documented
|
|
||||||
- Use implementation patterns consistently across all components
|
|
||||||
- Respect project structure and boundaries
|
|
||||||
- Refer to this document for all architectural questions
|
|
||||||
|
|
||||||
**First Implementation Priority:**
|
|
||||||
{{starter_template_command_or_first_architectural_step}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7. Present Content and Menu
|
|
||||||
|
|
||||||
Show the validation results and present choices:
|
|
||||||
|
|
||||||
"I've completed a comprehensive validation of your architecture.
|
|
||||||
|
|
||||||
**Validation Summary:**
|
|
||||||
|
|
||||||
- ✅ Coherence: All decisions work together
|
|
||||||
- ✅ Coverage: All requirements are supported
|
|
||||||
- ✅ Readiness: AI agents can implement consistently
|
|
||||||
|
|
||||||
**Here's what I'll add to complete the architecture document:**
|
|
||||||
|
|
||||||
[Show the complete markdown content from step 6]
|
|
||||||
|
|
||||||
**What would you like to do?**
|
|
||||||
[A] Advanced Elicitation - Address any complex architectural concerns
|
|
||||||
[P] Party Mode - Review validation from different implementation perspectives
|
|
||||||
[C] Continue - Complete the architecture and finish workflow
|
|
||||||
|
|
||||||
### 8. Handle Menu Selection
|
|
||||||
|
|
||||||
#### If 'A' (Advanced Elicitation):
|
|
||||||
|
|
||||||
- Invoke the `bmad-advanced-elicitation` skill with validation issues
|
|
||||||
- Process enhanced solutions for complex concerns
|
|
||||||
- Ask user: "Accept these architectural improvements? (y/n)"
|
|
||||||
- If yes: Update content, then return to A/P/C menu
|
|
||||||
- If no: Keep original content, then return to A/P/C menu
|
|
||||||
|
|
||||||
#### If 'P' (Party Mode):
|
|
||||||
|
|
||||||
- Invoke the `bmad-party-mode` skill with validation context
|
|
||||||
- Process collaborative insights on implementation readiness
|
|
||||||
- Ask user: "Accept these changes to the validation results? (y/n)"
|
|
||||||
- If yes: Update content, then return to A/P/C menu
|
|
||||||
- If no: Keep original content, then return to A/P/C menu
|
|
||||||
|
|
||||||
#### If 'C' (Continue):
|
|
||||||
|
|
||||||
- Append the final content to `{planning_artifacts}/architecture.md`
|
|
||||||
- Update frontmatter: `stepsCompleted: [1, 2, 3, 4, 5, 6, 7]`
|
|
||||||
- Load `./step-08-complete.md`
|
|
||||||
|
|
||||||
## APPEND TO DOCUMENT:
|
|
||||||
|
|
||||||
When user selects 'C', append the content directly to the document using the structure from step 6.
|
|
||||||
|
|
||||||
## SUCCESS METRICS:
|
|
||||||
|
|
||||||
✅ All architectural decisions validated for coherence
|
|
||||||
✅ Complete requirements coverage verified
|
|
||||||
✅ Implementation readiness confirmed
|
|
||||||
✅ All gaps identified and addressed
|
|
||||||
✅ Comprehensive validation checklist completed
|
|
||||||
✅ A/P/C menu presented and handled correctly
|
|
||||||
✅ Content properly appended to document when C selected
|
|
||||||
|
|
||||||
## FAILURE MODES:
|
|
||||||
|
|
||||||
❌ Skipping validation of decision compatibility
|
|
||||||
❌ Not verifying all requirements are architecturally supported
|
|
||||||
❌ Missing potential implementation conflicts
|
|
||||||
❌ Not addressing gaps found during validation
|
|
||||||
❌ Providing incomplete validation checklist
|
|
||||||
❌ Not presenting A/P/C menu after content generation
|
|
||||||
|
|
||||||
❌ **CRITICAL**: Reading only partial step file - leads to incomplete understanding and poor decisions
|
|
||||||
❌ **CRITICAL**: Proceeding with 'C' without fully reading and understanding the next step file
|
|
||||||
❌ **CRITICAL**: Making decisions without complete understanding of step requirements and protocols
|
|
||||||
|
|
||||||
## NEXT STEP:
|
|
||||||
|
|
||||||
After user selects 'C' and content is saved to document, load `./step-08-complete.md` to complete the workflow and provide implementation guidance.
|
|
||||||
|
|
||||||
Remember: Do NOT proceed to step-08 until user explicitly selects 'C' from the A/P/C menu and content is saved!
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
# Step 8: Architecture Completion & Handoff
|
|
||||||
|
|
||||||
## MANDATORY EXECUTION RULES (READ FIRST):
|
|
||||||
|
|
||||||
- 🛑 NEVER generate content without user input
|
|
||||||
|
|
||||||
- 📖 CRITICAL: ALWAYS read the complete step file before taking any action - partial understanding leads to incomplete decisions
|
|
||||||
- ✅ ALWAYS treat this as collaborative completion between architectural peers
|
|
||||||
- 📋 YOU ARE A FACILITATOR, not a content generator
|
|
||||||
- 💬 FOCUS on successful workflow completion and implementation handoff
|
|
||||||
- 🎯 PROVIDE clear next steps for implementation phase
|
|
||||||
- ⚠️ ABSOLUTELY NO TIME ESTIMATES - AI development speed has fundamentally changed
|
|
||||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
|
||||||
|
|
||||||
## EXECUTION PROTOCOLS:
|
|
||||||
|
|
||||||
- 🎯 Show your analysis before taking any action
|
|
||||||
- 🎯 Present completion summary and implementation guidance
|
|
||||||
- 📖 Update frontmatter with final workflow state
|
|
||||||
- 🚫 THIS IS THE FINAL STEP IN THIS WORKFLOW
|
|
||||||
|
|
||||||
## YOUR TASK:
|
|
||||||
|
|
||||||
Complete the architecture workflow, provide a comprehensive completion summary, and guide the user to the next phase of their project development.
|
|
||||||
|
|
||||||
## COMPLETION SEQUENCE:
|
|
||||||
|
|
||||||
### 1. Congratulate the User on Completion
|
|
||||||
|
|
||||||
Both you and the User completed something amazing here - give a summary of what you achieved together and really congratulate the user on a job well done.
|
|
||||||
|
|
||||||
### 2. Update the created document's frontmatter
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
stepsCompleted: [1, 2, 3, 4, 5, 6, 7, 8]
|
|
||||||
workflowType: 'architecture'
|
|
||||||
lastStep: 8
|
|
||||||
status: 'complete'
|
|
||||||
completedAt: '{{current_date}}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Next Steps Guidance
|
|
||||||
|
|
||||||
Architecture complete. Invoke the `bmad-help` skill.
|
|
||||||
|
|
||||||
Upon Completion of task output: offer to answer any questions about the Architecture Document.
|
|
||||||
|
|
||||||
|
|
||||||
## SUCCESS METRICS:
|
|
||||||
|
|
||||||
✅ Complete architecture document delivered with all sections
|
|
||||||
✅ All architectural decisions documented and validated
|
|
||||||
✅ Implementation patterns and consistency rules finalized
|
|
||||||
✅ Project structure complete with all files and directories
|
|
||||||
✅ User provided with clear next steps and implementation guidance
|
|
||||||
✅ Workflow status properly updated
|
|
||||||
✅ User collaboration maintained throughout completion process
|
|
||||||
|
|
||||||
## FAILURE MODES:
|
|
||||||
|
|
||||||
❌ Not providing clear implementation guidance
|
|
||||||
❌ Missing final validation of document completeness
|
|
||||||
❌ Not updating workflow status appropriately
|
|
||||||
❌ Failing to celebrate the successful completion
|
|
||||||
❌ Not providing specific next steps for the user
|
|
||||||
❌ Rushing completion without proper summary
|
|
||||||
|
|
||||||
❌ **CRITICAL**: Reading only partial step file - leads to incomplete understanding and poor decisions
|
|
||||||
❌ **CRITICAL**: Proceeding with 'C' without fully reading and understanding the next step file
|
|
||||||
❌ **CRITICAL**: Making decisions without complete understanding of step requirements and protocols
|
|
||||||
|
|
||||||
## WORKFLOW COMPLETE:
|
|
||||||
|
|
||||||
This is the final step of the Architecture workflow. The user now has a complete, validated architecture document ready for AI agent implementation.
|
|
||||||
|
|
||||||
The architecture will serve as the single source of truth for all technical decisions, ensuring consistent implementation across the entire project development lifecycle.
|
|
||||||
|
|
||||||
## On Complete
|
|
||||||
|
|
||||||
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete`
|
|
||||||
|
|
||||||
If the resolved `workflow.on_complete` is non-empty, follow it as the final terminal instruction before exiting.
|
|
||||||
|
|
@ -17,8 +17,8 @@ BMad Method,bmad-product-brief,Create Brief,CB,An expert guided experience to na
|
||||||
BMad Method,bmad-prfaq,PRFAQ Challenge,WB,Working Backwards guided experience to forge and stress-test your product concept to ensure you have a great product that users will love and need through the PRFAQ gauntlet to determine feasibility and alignment with user needs. alternative to product brief.,,-H,1-analysis,,,false,planning_artifacts,prfaq document
|
BMad Method,bmad-prfaq,PRFAQ Challenge,WB,Working Backwards guided experience to forge and stress-test your product concept to ensure you have a great product that users will love and need through the PRFAQ gauntlet to determine feasibility and alignment with user needs. alternative to product brief.,,-H,1-analysis,,,false,planning_artifacts,prfaq document
|
||||||
BMad Method,bmad-prd,Create Edit and Review PRD,PRD,"Facilitated PRD workflow — create a new PRD via coached discovery, update an existing one against a change signal, or validate a finished PRD against a checklist with an HTML findings report.",,,2-planning,bmad-product-brief,,true,planning_artifacts,prd
|
BMad Method,bmad-prd,Create Edit and Review PRD,PRD,"Facilitated PRD workflow — create a new PRD via coached discovery, update an existing one against a change signal, or validate a finished PRD against a checklist with an HTML findings report.",,,2-planning,bmad-product-brief,,true,planning_artifacts,prd
|
||||||
BMad Method,bmad-ux,Create UX,CU,"Guidance through realizing the plan for your UX, strongly recommended if a UI is a primary piece of the proposed project.",,,2-planning,bmad-prd,,false,planning_artifacts,ux design
|
BMad Method,bmad-ux,Create UX,CU,"Guidance through realizing the plan for your UX, strongly recommended if a UI is a primary piece of the proposed project.",,,2-planning,bmad-prd,,false,planning_artifacts,ux design
|
||||||
BMad Method,bmad-create-architecture,Create Architecture,CA,Guided workflow to document technical decisions.,,,3-solutioning,,,true,planning_artifacts,architecture
|
BMad Method,bmad-architecture,Architecture,CA,Offer once requirements exist (a PRD or spec; plus UX if present) and the user is ready to move from what to how. Also offer any time independently-built parts risk diverging. Produces the architecture spine: the invariants that keep features epics and stories consistent. Comes before epics and stories and scales from a quick spine to a full architecture (brownfield: ratifies the existing codebase).,,,3-solutioning,,,true,planning_artifacts,architecture
|
||||||
BMad Method,bmad-create-epics-and-stories,Create Epics and Stories,CE,,,,3-solutioning,bmad-create-architecture,,true,planning_artifacts,epics and stories
|
BMad Method,bmad-create-epics-and-stories,Create Epics and Stories,CE,,,,3-solutioning,bmad-architecture,,true,planning_artifacts,epics and stories
|
||||||
BMad Method,bmad-check-implementation-readiness,Check Implementation Readiness,IR,Ensure PRD UX Architecture and Epics Stories are aligned.,,,3-solutioning,bmad-create-epics-and-stories,,true,planning_artifacts,readiness report
|
BMad Method,bmad-check-implementation-readiness,Check Implementation Readiness,IR,Ensure PRD UX Architecture and Epics Stories are aligned.,,,3-solutioning,bmad-create-epics-and-stories,,true,planning_artifacts,readiness report
|
||||||
BMad Method,bmad-sprint-planning,Sprint Planning,SP,Kicks off implementation by producing a plan the implementation agents will follow in sequence for every story.,,,4-implementation,,,true,implementation_artifacts,sprint status
|
BMad Method,bmad-sprint-planning,Sprint Planning,SP,Kicks off implementation by producing a plan the implementation agents will follow in sequence for every story.,,,4-implementation,,,true,implementation_artifacts,sprint status
|
||||||
BMad Method,bmad-sprint-status,Sprint Status,SS,Anytime: Summarize sprint status and route to next workflow.,,,4-implementation,bmad-sprint-planning,,false,,
|
BMad Method,bmad-sprint-status,Sprint Status,SS,Anytime: Summarize sprint status and route to next workflow.,,,4-implementation,bmad-sprint-planning,,false,,
|
||||||
|
|
|
||||||
|
|
|
@ -43,22 +43,38 @@ Inside the spec folder:
|
||||||
|
|
||||||
```
|
```
|
||||||
<spec-folder>/
|
<spec-folder>/
|
||||||
SPEC.md ← uppercase, the kernel
|
SPEC.md ← uppercase, the kernel — DERIVED from .memlog.md, never hand-edited
|
||||||
<companion-1>.md ← optional, content-typed (e.g. glossary.md)
|
<companion-1>.md ← optional, content-typed (e.g. glossary.md); spec-authored ones are derived too
|
||||||
<companion-2>.md
|
<companion-2>.md
|
||||||
.decision-log.md ← canonical memory for this spec
|
.memlog.md ← canonical, append-only memory; what SPEC.md is distilled from
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Memory and derivation
|
||||||
|
|
||||||
|
`.memlog.md` is canonical — an append-only, chronological record of every decision, constraint, capability (with its stable `CAP-N`), assumption, open question, and bit of user direction, one line each in the order it happened, never edited or reordered. `SPEC.md` and every spec-authored companion are **derived on each run** from the memlog (the decision-of-record) plus the sources it cites for raw content — never hand-patched.
|
||||||
|
|
||||||
|
Deriving the contract from a living log instead of editing the contract in place is what lets the steps around the spec (PRD, UX, architecture, epics) run in any order and feed the same spec without merge drift: the log only accumulates, the artifact is re-rendered. So the spec is updated *only* by re-deriving it here — bmad-spec is its single writer; a hand-edit to `SPEC.md` from outside is unsupported and is overwritten on the next derive.
|
||||||
|
|
||||||
|
Writes go through the shared script — `{project-root}/_bmad/scripts/memlog.py`, the same location as `resolve_customization.py` (atomic; never read it back except to resume):
|
||||||
|
|
||||||
|
- `python3 {project-root}/_bmad/scripts/memlog.py init --workspace {spec-folder} --field topic="<what is being specced>"` — once, at create.
|
||||||
|
- `python3 {project-root}/_bmad/scripts/memlog.py append --workspace {spec-folder} --type <decision|constraint|capability|assumption|question|direction|note|event> --text "<one-line gist, reason included>"` — as each lands.
|
||||||
|
- Terminal moments (a validation verdict, "spec finalized") are `--type event` entries; the memlog carries no status field.
|
||||||
|
|
||||||
## The Operation
|
## The Operation
|
||||||
|
|
||||||
Read the input and its ancillary linked materials. If there is no input, follow the no-input branch in **Workspace** (ask or block). If a prior `SPEC.md` exists at the target folder, read it too — the operation becomes an update. Preserve capability IDs; new capabilities get the next unused `CAP-N`; never reuse retired IDs. Otherwise this is a create.
|
Read the input and its ancillary linked materials. If there is no input, follow the no-input branch in **Workspace** (ask or block). If a prior `.memlog.md` exists at the target folder, read it — the operation becomes an update, and the memlog (not the rendered `SPEC.md`) is the authority on what was decided and on capability IDs. Preserve those IDs; new capabilities get the next unused `CAP-N`; never reuse retired IDs. Otherwise this is a create, and the first move is `memlog.py init`.
|
||||||
|
|
||||||
When the input is structured and pre-sorted (a PRD with an addendum, a GDD, a brief produced by an upstream BMad skill), trust the authored separation: lift kernel-fitting content into SPEC.md, lift overflow into appropriately-named companions. When the input is mixed (a brain dump, a transcript, an RFC, a customer email), do the sorting yourself: walk each claim, apply the three-lens load-bearing test (Spec Law rule 7), and route to the kernel field or a companion.
|
When the input is structured and pre-sorted (a PRD with an addendum, a GDD, a brief produced by an upstream BMad skill), trust the authored separation: lift kernel-fitting content into SPEC.md, lift overflow into appropriately-named companions. When the input is mixed (a brain dump, a transcript, an RFC, a customer email), do the sorting yourself: walk each claim, apply the three-lens load-bearing test (Spec Law rule 7), and route to the kernel field or a companion.
|
||||||
|
|
||||||
Distill the input into the five-field kernel using `{workflow.spec_template}` as the skeleton. When input is rich, extract directly — no elicitation. When input is sparse, choose: **express** (best-effort distill, every gap becomes an `open_questions[]` entry) or **guided** (walk the five fields with the user one at a time). Headless defaults to express and logs the choice. Interactive asks.
|
Distill the input into the five-field kernel using `{workflow.spec_template}` as the skeleton. When input is rich, extract directly — no elicitation. When input is sparse, choose: **express** (best-effort distill, every gap becomes an `open_questions[]` entry) or **guided** (walk the five fields with the user one at a time). Headless defaults to express and logs the choice. Interactive asks.
|
||||||
|
|
||||||
|
A recognized domain implication the input leaves unaddressed *is* such a gap — name it as an `open_questions[]` entry (healthcare input silent on PHI/HIPAA, payments silent on PCI, control systems silent on fail-safe) and move on. Flag it; never invent the answer or coach toward it. If these dominate, the input is too thin — suggest `bmad-prd`.
|
||||||
|
|
||||||
Write lean from the first pass: every sentence must earn its place. Decoration costs tokens and dilutes downstream readers.
|
Write lean from the first pass: every sentence must earn its place. Decoration costs tokens and dilutes downstream readers.
|
||||||
|
|
||||||
|
Log each decision, capability, constraint, and accepted change to `.memlog.md` as it is made — that running record is what the render reads. Because the log is append-only, a later entry supersedes an earlier one on the same point while the history stays intact. When two currently-live sources or companions disagree on the same field, or an either/or never got resolved, surface it to the user rather than silently choosing — the resolution is itself a new memlog entry.
|
||||||
|
|
||||||
If the input is genuinely too thin to distill (e.g. "an app for hikers" with no surrounding context), stop and suggest `bmad-prd` (or sibling ceremony skill). This skill distills; it does not coach.
|
If the input is genuinely too thin to distill (e.g. "an app for hikers" with no surrounding context), stop and suggest `bmad-prd` (or sibling ceremony skill). This skill distills; it does not coach.
|
||||||
|
|
||||||
## Load-bearing
|
## Load-bearing
|
||||||
|
|
@ -94,7 +110,7 @@ Every spec must satisfy these eight rules. The operation aims for them; the self
|
||||||
5. **Success signal is concrete enough to test or demonstrate against.** "Users love it" doesn't qualify.
|
5. **Success signal is concrete enough to test or demonstrate against.** "Users love it" doesn't qualify.
|
||||||
6. **Capability IDs are stable and unique.** Never reused, never renumbered.
|
6. **Capability IDs are stable and unique.** Never reused, never renumbered.
|
||||||
7. **Preservation.** Every load-bearing source claim lands in SPEC.md or a companion. Wrapper ceremony does not.
|
7. **Preservation.** Every load-bearing source claim lands in SPEC.md or a companion. Wrapper ceremony does not.
|
||||||
8. **Lean prose.** Every sentence carries load-bearing content. Cut decoration, hedges, backstory, throat-clearing. Applies to SPEC.md, companions, and `.decision-log.md`.
|
8. **Lean prose.** Every sentence carries load-bearing content. Cut decoration, hedges, backstory, throat-clearing. Applies to SPEC.md, companions, and `.memlog.md`.
|
||||||
|
|
||||||
## Self-Validate
|
## Self-Validate
|
||||||
|
|
||||||
|
|
@ -104,7 +120,7 @@ After every create or update, sweep the resulting artifact in **two passes** bef
|
||||||
|
|
||||||
**Pass 2 — Preservation.** Walk the source claim by claim. Confirm each load-bearing claim landed in SPEC.md or a companion. Wrapper-ceremony drops are logged under "Wrapper-only content" so the drop is on the record, not silent.
|
**Pass 2 — Preservation.** Walk the source claim by claim. Confirm each load-bearing claim landed in SPEC.md or a companion. Wrapper-ceremony drops are logged under "Wrapper-only content" so the drop is on the record, not silent.
|
||||||
|
|
||||||
Append a one-paragraph verdict to `.decision-log.md` covering both passes. In interactive mode, review the verdict with the user. In headless mode, `.decision-log.md` is one of the files returned, so the caller (or its downstream LLM) reads the verdict there.
|
Record the verdict for each pass to `.memlog.md` (`append --type event`). In interactive mode, review it with the user. In headless mode, `.memlog.md` is one of the files returned, so the caller (or its downstream LLM) reads the verdict there.
|
||||||
|
|
||||||
## Spec with no change signal
|
## Spec with no change signal
|
||||||
|
|
||||||
|
|
@ -120,10 +136,10 @@ Run `{workflow.on_complete}` if set.
|
||||||
|
|
||||||
## After Spec is Output
|
## After Spec is Output
|
||||||
|
|
||||||
Any update to spec regarding assumptions, open questions, or other changes should be appended to that source's decision log also and offer to update the source.
|
Any update to the spec — resolved assumptions, answered open questions, other changes — is appended to `.memlog.md` as it happens. When a change overrides something that came from a source input, offer to update that source too, so upstream and the spec don't silently diverge.
|
||||||
|
|
||||||
## Frontmatter conventions
|
## Frontmatter conventions
|
||||||
|
|
||||||
- `companions:` array of `.md` files downstream MUST read alongside SPEC.md to have the full contract. Paths may point inside the spec folder (spec-authored companions like `glossary.md`) or outside it (adopted companions like `../planning-artifacts/ux-designs/ux-foo-bar-2026-05-23/DESIGN.md`). The split between spec-authored and adopted is implicit by path; downstream treats both the same.
|
- `companions:` array of `.md` files downstream MUST read alongside SPEC.md to have the full contract. Paths may point inside the spec folder (spec-authored companions like `glossary.md`) or outside it (adopted companions like `../planning-artifacts/ux-designs/ux-foo-bar-2026-05-23/DESIGN.md`). The split between spec-authored and adopted is implicit by path; downstream treats both the same.
|
||||||
- `sources:` array of paths to files that were **fully absorbed** into the SPEC, with no remaining downstream value (e.g., a PRD whose every load-bearing claim is now in the kernel). Listed for audit and for bmad-spec to re-read on update. Downstream does NOT read these. Files that downstream still needs to read belong in `companions:`, not here.
|
- `sources:` array of paths to files that were **fully absorbed** into the SPEC, with no remaining downstream value (e.g., a PRD whose every load-bearing claim is now in the kernel). Listed for audit and for bmad-spec to re-read on update. Downstream does NOT read these. Files that downstream still needs to read belong in `companions:`, not here.
|
||||||
- **Do not list** decision logs, README files, organizational artifacts, or any operational record of how upstream skills produced their artifacts. Those are not source content; they are process metadata that downstream consumers don't need.
|
- **Do not list** the memlog, README files, organizational artifacts, or any operational record of how upstream skills produced their artifacts. Those are not source content; they are process metadata that downstream consumers don't need.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Headless JSON Response
|
# Headless JSON Response
|
||||||
|
|
||||||
The default invocation is headless: input goes in, JSON comes out. The contract is intentionally tiny — return the outcome and the files touched. Anything else a caller needs is inside those files (SPEC.md, companions, `.decision-log.md`).
|
The default invocation is headless: input goes in, JSON comes out. The contract is intentionally tiny — return the outcome and the files touched. Anything else a caller needs is inside those files (SPEC.md, companions, `.memlog.md`).
|
||||||
|
|
||||||
## Success
|
## Success
|
||||||
|
|
||||||
|
|
@ -10,12 +10,12 @@ The default invocation is headless: input goes in, JSON comes out. The contract
|
||||||
"files": [
|
"files": [
|
||||||
"_bmad-output/specs/spec-quarter-drop/SPEC.md",
|
"_bmad-output/specs/spec-quarter-drop/SPEC.md",
|
||||||
"_bmad-output/specs/spec-quarter-drop/glossary.md",
|
"_bmad-output/specs/spec-quarter-drop/glossary.md",
|
||||||
"_bmad-output/specs/spec-quarter-drop/.decision-log.md"
|
"_bmad-output/specs/spec-quarter-drop/.memlog.md"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`files` lists every file written or modified in this run, in any order. The spec folder, kernel filename, decision log location, capabilities, companions, and verdict are all readable from those files; no need to re-encode them in the response.
|
`files` lists every file written or modified in this run, in any order. The spec folder, kernel filename, memlog location, capabilities, companions, and verdict are all readable from those files; no need to re-encode them in the response.
|
||||||
|
|
||||||
## Blocked
|
## Blocked
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
id: SPEC-{slug}
|
id: SPEC-{slug}
|
||||||
companions: [] # files downstream MUST read alongside SPEC.md. Paths may point inside the spec folder (spec-authored) or outside it (adopted from an upstream skill).
|
companions: [] # files downstream MUST read alongside SPEC.md. Paths may point inside the spec folder (spec-authored) or outside it (adopted from an upstream skill).
|
||||||
sources: [] # files fully absorbed into the SPEC (audit only; downstream does NOT read these). Never decision logs.
|
sources: [] # files fully absorbed into the SPEC (audit only; downstream does NOT read these). Never the memlog.
|
||||||
---
|
---
|
||||||
|
|
||||||
> **Canonical contract.** This SPEC and the files in `companions:` are the complete, preservation-validated contract for what to build, test, and validate. Source documents listed in frontmatter are for traceability only — consult them only if you need narrative rationale or prose color this contract intentionally omits.
|
> **Canonical contract.** This SPEC and the files in `companions:` are the complete, preservation-validated contract for what to build, test, and validate. Source documents listed in frontmatter are for traceability only — consult them only if you need narrative rationale or prose color this contract intentionally omits.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,224 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# /// script
|
||||||
|
# requires-python = ">=3.8"
|
||||||
|
# ///
|
||||||
|
"""memlog — an append-only memory log: LLM-optimal working memory for a skill.
|
||||||
|
|
||||||
|
A memlog is the dense, chronological record of everything that mattered in a piece of
|
||||||
|
work — every item the user generated or accepted — kept minimal like human memory: only
|
||||||
|
what's important, never bloated. It persists ACROSS sessions, so a fresh session can
|
||||||
|
load it and continue. It is NOT a deliverable; downstream artifacts (a brief, a PRD, a
|
||||||
|
deck, a report) are *derived* from it on demand. The host skill supplies the vocabulary
|
||||||
|
by how it calls `append` — the tool stays neutral.
|
||||||
|
|
||||||
|
It is a FLAT log: there are no sections or grouping. Every entry is one line, recorded
|
||||||
|
at the END in the order it happened. The chronology itself is the structure — an event
|
||||||
|
like "started technique X" is just another entry, same as an idea or an insight.
|
||||||
|
|
||||||
|
Three invariants make it trustworthy:
|
||||||
|
|
||||||
|
1. Append-only, chronological. Entries land at the end, in the order they happen.
|
||||||
|
Nothing is ever inserted backward, reordered, edited, or removed. There is no
|
||||||
|
edit or delete subcommand by design; history is never rewritten.
|
||||||
|
2. Write-only / blind. Every command is an atomic, context-free write and echoes the
|
||||||
|
new state as one line of JSON, so the caller never re-reads the file mid-session.
|
||||||
|
The one time the file is read is on resume — and the caller reads it itself, not
|
||||||
|
via this script.
|
||||||
|
3. No lifecycle status. A memory log has no "complete" flag. Whether the work is done,
|
||||||
|
blocked, or paused is itself a fact that happened, so it is recorded as an entry
|
||||||
|
(e.g. `append --type event --text "session complete"`), never as frontmatter the
|
||||||
|
log would have to mutate. The chronology stays the single source of truth, and a
|
||||||
|
resume learns the state by reading the last entries — the same way it learns
|
||||||
|
everything else.
|
||||||
|
|
||||||
|
Atomicity: every write goes to a temp file, is flushed and fsync'd, then atomically
|
||||||
|
renamed over the target, so a crash never leaves a half-written entry.
|
||||||
|
|
||||||
|
The file shape (.memlog.md):
|
||||||
|
|
||||||
|
---
|
||||||
|
topic: Onboarding flow for a budgeting app
|
||||||
|
goal: lift week-1 retention
|
||||||
|
updated: 2026-06-07T14:22
|
||||||
|
---
|
||||||
|
|
||||||
|
- (note) user picked techniques: SCAMPER, then Six Thinking Hats
|
||||||
|
- (technique) started SCAMPER
|
||||||
|
- (idea) skip the signup wall: let people try with sample data first
|
||||||
|
- (idea) auto-import one bank account so the first screen shows real numbers
|
||||||
|
- (question) is open-banking consent too heavy for step one?
|
||||||
|
- (insight) the "scary numbers" risk and the "real numbers" idea are one lever: show real data, pre-categorized
|
||||||
|
- (direction) optimize for the anxious first-timer, not the power user
|
||||||
|
- (decision) lead with one pre-categorized account; defer multi-account import
|
||||||
|
- (event) session complete
|
||||||
|
|
||||||
|
Each entry may carry an optional `--type` — what KIND it is (idea, insight, question,
|
||||||
|
decision, direction, assumption, gap, note, event, …) — and an optional `--by` naming
|
||||||
|
who it came from (e.g. `user`, `coach`), for sessions where authorship matters. Both
|
||||||
|
render into one short inline tag: `(idea)`, `(idea by user)`, `(by coach)`. Omit them
|
||||||
|
for a plain note. The host skill names the vocabulary; the script does not enforce one.
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
init (--workspace DIR | --path FILE) [--field k=v ...] create the memlog (errors if it exists)
|
||||||
|
append (--workspace DIR | --path FILE) --text STR [--type T] [--by W] append one entry at the end
|
||||||
|
set (--workspace DIR | --path FILE) --key K --value V set/replace a descriptive frontmatter field
|
||||||
|
|
||||||
|
Addressing: `--workspace` is the run folder, and the memlog is always {workspace}/.memlog.md.
|
||||||
|
`--path` points straight at the memlog file instead, for callers that already hold the path.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations # keep type-hint syntax lazy so the script runs on 3.8+
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
MEMLOG = ".memlog.md"
|
||||||
|
|
||||||
|
|
||||||
|
def now() -> str:
|
||||||
|
return datetime.now().strftime("%Y-%m-%dT%H:%M")
|
||||||
|
|
||||||
|
|
||||||
|
def resolve(args) -> Path:
|
||||||
|
"""The memlog file, from either addressing mode: {workspace}/.memlog.md or an explicit --path."""
|
||||||
|
return Path(args.path) if args.path else Path(args.workspace) / MEMLOG
|
||||||
|
|
||||||
|
|
||||||
|
def split(text: str) -> tuple[dict, str]:
|
||||||
|
"""Return (frontmatter dict in source order, body str). Frontmatter is plain key: value.
|
||||||
|
|
||||||
|
The closing fence is the first line that is *exactly* `---`, so a `---` inside a
|
||||||
|
field value (topic/goal are free user text) never truncates the frontmatter.
|
||||||
|
"""
|
||||||
|
lines = text.splitlines()
|
||||||
|
if not lines or lines[0] != "---":
|
||||||
|
raise ValueError(".memlog.md has no frontmatter")
|
||||||
|
end = next((i for i in range(1, len(lines)) if lines[i] == "---"), None)
|
||||||
|
if end is None:
|
||||||
|
raise ValueError(".memlog.md frontmatter is not terminated")
|
||||||
|
meta: dict[str, str] = {}
|
||||||
|
for line in lines[1:end]:
|
||||||
|
if ":" in line:
|
||||||
|
k, v = line.split(":", 1)
|
||||||
|
meta[k.strip()] = v.strip()
|
||||||
|
return meta, "\n".join(lines[end + 1:]).lstrip("\n")
|
||||||
|
|
||||||
|
|
||||||
|
def render(meta: dict, body: str) -> str:
|
||||||
|
# Neutralize newlines in values so a multi-line field can't break the fence on re-read.
|
||||||
|
fm = "\n".join(f"{k}: {' '.join(str(v).splitlines())}" for k, v in meta.items())
|
||||||
|
return "---\n" + fm + "\n---\n\n" + body.rstrip("\n") + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def touch(meta: dict) -> None:
|
||||||
|
"""Stamp `updated` and keep it last so the field order stays predictable."""
|
||||||
|
meta.pop("updated", None)
|
||||||
|
meta["updated"] = now()
|
||||||
|
|
||||||
|
|
||||||
|
def write_atomic(path: Path, text: str) -> None:
|
||||||
|
"""Temp + flush + fsync + atomic rename, so a crash never half-writes an entry."""
|
||||||
|
tmp = path.with_suffix(path.suffix + ".tmp")
|
||||||
|
with open(tmp, "w", encoding="utf-8") as f:
|
||||||
|
f.write(text)
|
||||||
|
f.flush()
|
||||||
|
os.fsync(f.fileno())
|
||||||
|
os.replace(tmp, path)
|
||||||
|
|
||||||
|
|
||||||
|
def entry_count(body: str) -> int:
|
||||||
|
return sum(1 for ln in body.splitlines() if ln.startswith("- "))
|
||||||
|
|
||||||
|
|
||||||
|
def ack(path: Path, body: str) -> None:
|
||||||
|
"""Echo new state so the caller never re-reads the file to know where it stands."""
|
||||||
|
print(json.dumps({
|
||||||
|
"ok": True,
|
||||||
|
"memlog": str(path),
|
||||||
|
"entries": entry_count(body),
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_init(args) -> int:
|
||||||
|
path = resolve(args)
|
||||||
|
if path.exists():
|
||||||
|
print(f"error: {path} already exists; use append/set to update it", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
meta: dict[str, str] = {}
|
||||||
|
for pair in args.field or []:
|
||||||
|
if "=" not in pair:
|
||||||
|
print(f"error: --field expects key=value, got {pair!r}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
k, v = pair.split("=", 1)
|
||||||
|
meta[k.strip()] = v.strip()
|
||||||
|
touch(meta)
|
||||||
|
write_atomic(path, render(meta, ""))
|
||||||
|
ack(path, "")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_append(args) -> int:
|
||||||
|
path = resolve(args)
|
||||||
|
meta, body = split(path.read_text(encoding="utf-8"))
|
||||||
|
text = " ".join(args.text.split()) # collapse newlines/runs → one-line entry, no prose bloat
|
||||||
|
label = args.type or ""
|
||||||
|
if args.by:
|
||||||
|
label = f"{label} by {args.by}".strip() # attribution: "(idea by user)" / "(by coach)"
|
||||||
|
tag = f"({label}) " if label else ""
|
||||||
|
entry = f"- {tag}{text}"
|
||||||
|
body = (body.rstrip("\n") + "\n" + entry) if body.strip() else entry # always at the end
|
||||||
|
touch(meta)
|
||||||
|
write_atomic(path, render(meta, body))
|
||||||
|
ack(path, body)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_set(args) -> int:
|
||||||
|
path = resolve(args)
|
||||||
|
meta, body = split(path.read_text(encoding="utf-8"))
|
||||||
|
meta[args.key] = args.value
|
||||||
|
touch(meta)
|
||||||
|
write_atomic(path, render(meta, body))
|
||||||
|
ack(path, body)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def add_target(sp) -> None:
|
||||||
|
"""Every command addresses the memlog the same way: a run folder or an explicit path."""
|
||||||
|
g = sp.add_mutually_exclusive_group(required=True)
|
||||||
|
g.add_argument("--workspace", help="run folder; the memlog is {workspace}/.memlog.md")
|
||||||
|
g.add_argument("--path", help="explicit memlog file path (alternative to --workspace)")
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: list[str] | None = None) -> int:
|
||||||
|
p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
sub = p.add_subparsers(dest="cmd", required=True)
|
||||||
|
|
||||||
|
pi = sub.add_parser("init", help="create the memlog")
|
||||||
|
add_target(pi)
|
||||||
|
pi.add_argument("--field", action="append", metavar="KEY=VALUE", help="frontmatter field (repeatable)")
|
||||||
|
pi.set_defaults(func=cmd_init)
|
||||||
|
|
||||||
|
pa = sub.add_parser("append", help="append one entry at the end")
|
||||||
|
add_target(pa)
|
||||||
|
pa.add_argument("--text", required=True)
|
||||||
|
pa.add_argument("--type", help="entry kind, rendered as an inline tag")
|
||||||
|
pa.add_argument("--by", help="who the entry came from (e.g. user, coach); rendered into the tag")
|
||||||
|
pa.set_defaults(func=cmd_append)
|
||||||
|
|
||||||
|
pset = sub.add_parser("set", help="set a descriptive frontmatter field")
|
||||||
|
add_target(pset)
|
||||||
|
pset.add_argument("--key", required=True)
|
||||||
|
pset.add_argument("--value", required=True)
|
||||||
|
pset.set_defaults(func=cmd_set)
|
||||||
|
|
||||||
|
args = p.parse_args(argv)
|
||||||
|
return args.func(args)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
|
|
@ -0,0 +1,306 @@
|
||||||
|
# /// script
|
||||||
|
# requires-python = ">=3.10"
|
||||||
|
# dependencies = ["pytest>=8.0"]
|
||||||
|
# ///
|
||||||
|
"""Tests for memlog.py. Run: uv run --with pytest pytest scripts/tests/test_memlog.py
|
||||||
|
|
||||||
|
The spine under test is the flat, append-only, chronological invariant: every entry is
|
||||||
|
one line recorded at the end in the order it happened — no sections, no grouping, and no
|
||||||
|
lifecycle status the log would have to mutate.
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||||
|
import memlog # noqa: E402
|
||||||
|
|
||||||
|
MEMLOG = ".memlog.md"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def ws(tmp_path):
|
||||||
|
return str(tmp_path)
|
||||||
|
|
||||||
|
|
||||||
|
def read(ws):
|
||||||
|
return (Path(ws) / MEMLOG).read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def body_of(ws):
|
||||||
|
return memlog.split(read(ws))[1]
|
||||||
|
|
||||||
|
|
||||||
|
def entries(ws):
|
||||||
|
return [ln for ln in body_of(ws).splitlines() if ln.startswith("- ")]
|
||||||
|
|
||||||
|
|
||||||
|
def init(ws, **fields):
|
||||||
|
fields = fields or {"topic": "Reinvent the lunchbox", "goal": "ideas for a pitch"}
|
||||||
|
argv = ["init", "--workspace", ws]
|
||||||
|
for k, v in fields.items():
|
||||||
|
argv += ["--field", f"{k}={v}"]
|
||||||
|
assert memlog.main(argv) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def append(ws, text, entry_type=None, by=None):
|
||||||
|
argv = ["append", "--workspace", ws, "--text", text]
|
||||||
|
if entry_type:
|
||||||
|
argv += ["--type", entry_type]
|
||||||
|
if by:
|
||||||
|
argv += ["--by", by]
|
||||||
|
assert memlog.main(argv) == 0
|
||||||
|
|
||||||
|
|
||||||
|
# --- init ---------------------------------------------------------------
|
||||||
|
|
||||||
|
def test_init_writes_frontmatter_fields(ws):
|
||||||
|
init(ws)
|
||||||
|
meta, body = memlog.split(read(ws))
|
||||||
|
assert meta["topic"] == "Reinvent the lunchbox"
|
||||||
|
assert meta["goal"] == "ideas for a pitch"
|
||||||
|
assert "updated" in meta
|
||||||
|
assert body.strip() == ""
|
||||||
|
|
||||||
|
|
||||||
|
def test_init_has_no_lifecycle_status(ws):
|
||||||
|
# A memory log carries no "status" flag; completion is an appended entry, not frontmatter.
|
||||||
|
init(ws)
|
||||||
|
meta, _ = memlog.split(read(ws))
|
||||||
|
assert "status" not in meta
|
||||||
|
|
||||||
|
|
||||||
|
def test_init_arbitrary_fields(ws):
|
||||||
|
init(ws, topic="T", audience="board")
|
||||||
|
meta, _ = memlog.split(read(ws))
|
||||||
|
assert meta["audience"] == "board"
|
||||||
|
|
||||||
|
|
||||||
|
def test_init_refuses_overwrite(ws):
|
||||||
|
init(ws)
|
||||||
|
assert memlog.main(["init", "--workspace", ws, "--field", "topic=other"]) == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_init_creates_missing_workspace(tmp_path):
|
||||||
|
nested = str(tmp_path / "a" / "b")
|
||||||
|
assert memlog.main(["init", "--workspace", nested, "--field", "topic=T"]) == 0
|
||||||
|
assert (Path(nested) / MEMLOG).is_file()
|
||||||
|
|
||||||
|
|
||||||
|
def test_init_rejects_malformed_field(ws):
|
||||||
|
assert memlog.main(["init", "--workspace", ws, "--field", "noequals"]) == 2
|
||||||
|
|
||||||
|
|
||||||
|
# --- addressing: --workspace and --path are interchangeable --------------
|
||||||
|
|
||||||
|
def test_path_addressing_targets_the_file_directly(tmp_path):
|
||||||
|
target = tmp_path / "run" / ".memlog.md"
|
||||||
|
assert memlog.main(["init", "--path", str(target), "--field", "topic=T"]) == 0
|
||||||
|
assert target.is_file()
|
||||||
|
assert memlog.main(["append", "--path", str(target), "--text", "an idea", "--type", "idea"]) == 0
|
||||||
|
body = memlog.split(target.read_text(encoding="utf-8"))[1]
|
||||||
|
assert "- (idea) an idea" in body
|
||||||
|
|
||||||
|
|
||||||
|
def test_workspace_and_path_resolve_to_same_file(ws):
|
||||||
|
init(ws)
|
||||||
|
via_path = str(Path(ws) / MEMLOG)
|
||||||
|
assert memlog.main(["append", "--path", via_path, "--text", "from path"]) == 0
|
||||||
|
assert memlog.main(["append", "--workspace", ws, "--text", "from workspace"]) == 0
|
||||||
|
assert entries(ws) == ["- from path", "- from workspace"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_target_is_required(ws):
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
memlog.main(["append", "--text", "orphan"]) # neither --workspace nor --path
|
||||||
|
|
||||||
|
|
||||||
|
# --- append: flat chronological order is the whole point -----------------
|
||||||
|
|
||||||
|
def test_append_lands_at_end_in_order(ws):
|
||||||
|
init(ws)
|
||||||
|
append(ws, "first")
|
||||||
|
append(ws, "second")
|
||||||
|
append(ws, "third")
|
||||||
|
assert entries(ws) == ["- first", "- second", "- third"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_sections_or_headings_ever(ws):
|
||||||
|
init(ws)
|
||||||
|
append(ws, "started foo", entry_type="technique")
|
||||||
|
append(ws, "an idea", entry_type="idea")
|
||||||
|
append(ws, "started bar", entry_type="technique")
|
||||||
|
assert "## " not in body_of(ws) # the flat log never grows headings
|
||||||
|
|
||||||
|
|
||||||
|
def test_type_renders_as_inline_tag(ws):
|
||||||
|
init(ws)
|
||||||
|
append(ws, "the earth revolves around the sun", entry_type="idea")
|
||||||
|
append(ws, "how do we handle stampede?", entry_type="question")
|
||||||
|
body = body_of(ws)
|
||||||
|
assert "- (idea) the earth revolves around the sun" in body
|
||||||
|
assert "- (question) how do we handle stampede?" in body
|
||||||
|
|
||||||
|
|
||||||
|
def test_append_without_type_is_plain_note(ws):
|
||||||
|
init(ws)
|
||||||
|
append(ws, "bare entry")
|
||||||
|
assert entries(ws) == ["- bare entry"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_completion_is_an_entry_not_a_status(ws):
|
||||||
|
# The documented way to mark a session done: append it. Frontmatter never gains a status.
|
||||||
|
init(ws)
|
||||||
|
append(ws, "session complete", entry_type="event")
|
||||||
|
meta, _ = memlog.split(read(ws))
|
||||||
|
assert "status" not in meta
|
||||||
|
assert entries(ws)[-1] == "- (event) session complete"
|
||||||
|
|
||||||
|
|
||||||
|
def test_append_collapses_newlines_into_one_line(ws):
|
||||||
|
init(ws)
|
||||||
|
append(ws, "line one\nline two\n spaced out")
|
||||||
|
assert entries(ws) == ["- line one line two spaced out"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_revisited_technique_is_just_a_later_entry(ws):
|
||||||
|
# the user's model: switching techniques is an entry, not a section to return to
|
||||||
|
init(ws)
|
||||||
|
append(ws, "started SCAMPER", entry_type="technique")
|
||||||
|
append(ws, "magnetic latch", entry_type="idea")
|
||||||
|
append(ws, "started Six Hats", entry_type="technique")
|
||||||
|
append(ws, "stale data risk", entry_type="idea")
|
||||||
|
append(ws, "started SCAMPER", entry_type="technique") # back to SCAMPER — just appended again
|
||||||
|
append(ws, "stackable tiers", entry_type="idea")
|
||||||
|
assert entries(ws) == [
|
||||||
|
"- (technique) started SCAMPER",
|
||||||
|
"- (idea) magnetic latch",
|
||||||
|
"- (technique) started Six Hats",
|
||||||
|
"- (idea) stale data risk",
|
||||||
|
"- (technique) started SCAMPER",
|
||||||
|
"- (idea) stackable tiers",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_by_renders_attribution_in_tag(ws):
|
||||||
|
# Creative Partner mode must record whose idea each one was
|
||||||
|
init(ws)
|
||||||
|
append(ws, "magnetic latch lid", entry_type="idea", by="user")
|
||||||
|
append(ws, "lid doubles as a plate", entry_type="idea", by="coach")
|
||||||
|
body = body_of(ws)
|
||||||
|
assert "- (idea by user) magnetic latch lid" in body
|
||||||
|
assert "- (idea by coach) lid doubles as a plate" in body
|
||||||
|
|
||||||
|
|
||||||
|
def test_by_without_type_renders_alone(ws):
|
||||||
|
init(ws)
|
||||||
|
append(ws, "off-the-cuff thought", by="coach")
|
||||||
|
assert entries(ws) == ["- (by coach) off-the-cuff thought"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_heterogeneous_entry_types_coexist(ws):
|
||||||
|
init(ws)
|
||||||
|
append(ws, "an idea", entry_type="idea")
|
||||||
|
append(ws, "an open question", entry_type="question")
|
||||||
|
append(ws, "a decision we made", entry_type="decision")
|
||||||
|
append(ws, "user wants mobile-first", entry_type="direction")
|
||||||
|
body = body_of(ws)
|
||||||
|
for tag in ("(idea)", "(question)", "(decision)", "(direction)"):
|
||||||
|
assert tag in body
|
||||||
|
|
||||||
|
|
||||||
|
def test_free_vocabulary_is_not_enforced(ws):
|
||||||
|
# The tool is neutral: any --type the host skill names renders verbatim.
|
||||||
|
init(ws)
|
||||||
|
append(ws, "a custom kind", entry_type="crack")
|
||||||
|
append(ws, "another", entry_type="lock")
|
||||||
|
body = body_of(ws)
|
||||||
|
assert "- (crack) a custom kind" in body
|
||||||
|
assert "- (lock) another" in body
|
||||||
|
|
||||||
|
|
||||||
|
# --- set: generic descriptive frontmatter, no lifecycle semantics --------
|
||||||
|
|
||||||
|
def test_set_adds_field(ws):
|
||||||
|
init(ws)
|
||||||
|
memlog.main(["set", "--workspace", ws, "--key", "mode", "--value", "partner"])
|
||||||
|
assert memlog.split(read(ws))[0]["mode"] == "partner"
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_replaces_field(ws):
|
||||||
|
init(ws, topic="T", mode="facilitator")
|
||||||
|
memlog.main(["set", "--workspace", ws, "--key", "mode", "--value", "partner"])
|
||||||
|
assert memlog.split(read(ws))[0]["mode"] == "partner"
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_preserves_body(ws):
|
||||||
|
init(ws)
|
||||||
|
append(ws, "keep me", entry_type="idea")
|
||||||
|
memlog.main(["set", "--workspace", ws, "--key", "mode", "--value", "partner"])
|
||||||
|
meta, body = memlog.split(read(ws))
|
||||||
|
assert meta["mode"] == "partner"
|
||||||
|
assert "- (idea) keep me" in body
|
||||||
|
|
||||||
|
|
||||||
|
def test_updated_stays_last(ws):
|
||||||
|
init(ws)
|
||||||
|
memlog.main(["set", "--workspace", ws, "--key", "owner", "--value", "BMad"])
|
||||||
|
meta = memlog.split(read(ws))[0]
|
||||||
|
assert list(meta)[-1] == "updated"
|
||||||
|
|
||||||
|
|
||||||
|
# --- robustness ---------------------------------------------------------
|
||||||
|
|
||||||
|
def test_roundtrip_render_is_stable(ws):
|
||||||
|
init(ws)
|
||||||
|
append(ws, "one", entry_type="idea")
|
||||||
|
first = read(ws)
|
||||||
|
meta, body = memlog.split(first)
|
||||||
|
assert memlog.render(meta, body) == first
|
||||||
|
|
||||||
|
|
||||||
|
def test_commas_in_field_survive(ws):
|
||||||
|
init(ws, topic="cars, trains, and planes")
|
||||||
|
append(ws, "z", entry_type="idea")
|
||||||
|
meta, _ = memlog.split(read(ws))
|
||||||
|
assert meta["topic"] == "cars, trains, and planes"
|
||||||
|
|
||||||
|
|
||||||
|
def test_triple_dash_in_field_does_not_corrupt_frontmatter(ws):
|
||||||
|
# A `---` inside a value must NOT be read as the closing fence: topic stays intact
|
||||||
|
# and the body never leaks frontmatter text.
|
||||||
|
init(ws, topic="Pricing --- tiers --- and add-ons")
|
||||||
|
append(ws, "an idea", entry_type="idea")
|
||||||
|
meta, body = memlog.split(read(ws))
|
||||||
|
assert meta["topic"] == "Pricing --- tiers --- and add-ons"
|
||||||
|
assert entries(ws) == ["- (idea) an idea"]
|
||||||
|
assert "topic:" not in body # frontmatter never bled into the body
|
||||||
|
|
||||||
|
|
||||||
|
def test_newline_in_field_is_neutralized(ws):
|
||||||
|
# A value carrying a newline can't break the fence on the next round-trip.
|
||||||
|
memlog.main(["init", "--workspace", ws, "--field", "topic=line one\nline two"])
|
||||||
|
append(ws, "x", entry_type="idea")
|
||||||
|
meta, _ = memlog.split(read(ws))
|
||||||
|
assert "\n" not in meta["topic"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_append_emits_json_ack(ws, capsys):
|
||||||
|
init(ws)
|
||||||
|
append(ws, "x", entry_type="idea")
|
||||||
|
out = json.loads(capsys.readouterr().out.strip().splitlines()[-1])
|
||||||
|
assert out["ok"] is True
|
||||||
|
assert out["entries"] == 1
|
||||||
|
assert out["memlog"].endswith(MEMLOG)
|
||||||
|
assert "status" not in out # no lifecycle status
|
||||||
|
assert "section" not in out # sections are gone
|
||||||
|
|
||||||
|
|
||||||
|
def test_ack_entry_count_climbs(ws, capsys):
|
||||||
|
init(ws)
|
||||||
|
append(ws, "a")
|
||||||
|
append(ws, "b")
|
||||||
|
out = json.loads(capsys.readouterr().out.strip().splitlines()[-1])
|
||||||
|
assert out["entries"] == 2
|
||||||
|
|
@ -3273,6 +3273,189 @@ async function runTests() {
|
||||||
|
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Test Suite 45: _cleanupSkillDirs prunes empty parent dirs (#empty-bmm-folders)
|
||||||
|
// ============================================================
|
||||||
|
console.log(`${colors.yellow}Test Suite 45: cleanup prunes empty skill-group dirs${colors.reset}\n`);
|
||||||
|
|
||||||
|
let root45;
|
||||||
|
try {
|
||||||
|
root45 = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-cleanup-test-'));
|
||||||
|
const bmadDir45 = path.join(root45, '_bmad');
|
||||||
|
await fs.ensureDir(path.join(bmadDir45, '_config'));
|
||||||
|
|
||||||
|
// Two skills nested under the same grouping dir (1-analysis), plus a
|
||||||
|
// module-level file that must survive the cleanup.
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(bmadDir45, '_config', 'skill-manifest.csv'),
|
||||||
|
[
|
||||||
|
'canonicalId,name,description,module,path',
|
||||||
|
'"bmad-agent-analyst","bmad-agent-analyst","fixture","bmm","_bmad/bmm/1-analysis/bmad-agent-analyst/SKILL.md"',
|
||||||
|
'"bmad-research","bmad-research","fixture","bmm","_bmad/bmm/1-analysis/research/bmad-research/SKILL.md"',
|
||||||
|
'',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
await fs.ensureDir(path.join(bmadDir45, 'bmm', '1-analysis', 'bmad-agent-analyst'));
|
||||||
|
await fs.writeFile(path.join(bmadDir45, 'bmm', '1-analysis', 'bmad-agent-analyst', 'SKILL.md'), 'x');
|
||||||
|
await fs.ensureDir(path.join(bmadDir45, 'bmm', '1-analysis', 'research', 'bmad-research'));
|
||||||
|
await fs.writeFile(path.join(bmadDir45, 'bmm', '1-analysis', 'research', 'bmad-research', 'SKILL.md'), 'x');
|
||||||
|
await fs.writeFile(path.join(bmadDir45, 'bmm', 'config.yaml'), 'module: bmm\n');
|
||||||
|
|
||||||
|
const installer45 = new Installer();
|
||||||
|
await installer45._cleanupSkillDirs(bmadDir45);
|
||||||
|
|
||||||
|
assert(!(await fs.pathExists(path.join(bmadDir45, 'bmm', '1-analysis'))), 'empty skill-group dir is pruned after cleanup');
|
||||||
|
assert(!(await fs.pathExists(path.join(bmadDir45, 'bmm', '1-analysis', 'research'))), 'empty nested skill-group dir is pruned');
|
||||||
|
assert(await fs.pathExists(path.join(bmadDir45, 'bmm', 'config.yaml')), 'module-level files are preserved');
|
||||||
|
assert(await fs.pathExists(bmadDir45), 'bmad root is never removed');
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`${colors.red}Test Suite 45 setup failed: ${error.message}${colors.reset}`);
|
||||||
|
console.log(error.stack);
|
||||||
|
failed++;
|
||||||
|
} finally {
|
||||||
|
if (root45) await fs.remove(root45).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Test Suite 46: Python environment check (version parsing + classification)
|
||||||
|
// ============================================================
|
||||||
|
console.log(`${colors.yellow}Test Suite 46: python-check version parsing and classification${colors.reset}\n`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { parsePythonVersion, classifyPython, detectPython } = require('../tools/installer/core/python-check');
|
||||||
|
|
||||||
|
// Version parsing
|
||||||
|
const v312 = parsePythonVersion('Python 3.12.1');
|
||||||
|
assert(v312 && v312.major === 3 && v312.minor === 12 && v312.patch === 1, 'parses "Python 3.12.1"');
|
||||||
|
const v311 = parsePythonVersion('Python 3.11.0\n');
|
||||||
|
assert(v311 && v311.raw === '3.11.0', 'parses with trailing newline');
|
||||||
|
const v2 = parsePythonVersion('\nPython 2.7.18');
|
||||||
|
assert(v2 && v2.major === 2, 'parses Python 2 output (stderr-style)');
|
||||||
|
const noPatch = parsePythonVersion('Python 3.13');
|
||||||
|
assert(noPatch && noPatch.patch === 0, 'missing patch defaults to 0');
|
||||||
|
assert(parsePythonVersion('') === null, 'empty output returns null');
|
||||||
|
assert(parsePythonVersion('command not found: python3') === null, 'non-version output returns null');
|
||||||
|
assert(parsePythonVersion(null) === null, 'null output returns null');
|
||||||
|
|
||||||
|
// Classification against feature requirements
|
||||||
|
assert(classifyPython({ major: 3, minor: 11 }) === 'full', '3.11 is full support (tomllib floor)');
|
||||||
|
assert(classifyPython({ major: 3, minor: 13 }) === 'full', '3.13 is full support');
|
||||||
|
assert(classifyPython({ major: 4, minor: 0 }) === 'full', 'hypothetical 4.0 is full support');
|
||||||
|
assert(classifyPython({ major: 3, minor: 10 }) === 'partial', '3.10 is partial (memlog yes, tomllib no)');
|
||||||
|
assert(classifyPython({ major: 3, minor: 8 }) === 'partial', '3.8 is partial (memlog floor)');
|
||||||
|
assert(classifyPython({ major: 3, minor: 7 }) === 'unsupported', '3.7 is unsupported');
|
||||||
|
assert(classifyPython({ major: 2, minor: 7 }) === 'unsupported', '2.7 is unsupported');
|
||||||
|
assert(classifyPython(null) === 'none', 'no python is none');
|
||||||
|
|
||||||
|
// Detection smoke test — must not throw, and if it finds a Python the
|
||||||
|
// result must be well-formed. (CI machines may or may not have Python.)
|
||||||
|
const detected = detectPython();
|
||||||
|
assert(
|
||||||
|
detected === null ||
|
||||||
|
(typeof detected.command === 'string' &&
|
||||||
|
typeof detected.version.raw === 'string' &&
|
||||||
|
typeof detected.isRuntimeCommand === 'boolean'),
|
||||||
|
'detectPython returns null or a well-formed result',
|
||||||
|
);
|
||||||
|
|
||||||
|
// checkPythonEnvironment branch coverage — stub detection, prompts, and
|
||||||
|
// process.exit so the assertions are deterministic regardless of the
|
||||||
|
// machine's Python. python-check resolves detectPython via module.exports
|
||||||
|
// and prompts via the shared module object, so swapping properties works.
|
||||||
|
const pythonCheck = require('../tools/installer/core/python-check');
|
||||||
|
const promptsModule = require('../tools/installer/prompts');
|
||||||
|
const real = {
|
||||||
|
detectPython: pythonCheck.detectPython,
|
||||||
|
log: promptsModule.log,
|
||||||
|
note: promptsModule.note,
|
||||||
|
select: promptsModule.select,
|
||||||
|
cancel: promptsModule.cancel,
|
||||||
|
exit: process.exit,
|
||||||
|
};
|
||||||
|
const stub = (detectResult, selectAnswer) => {
|
||||||
|
const seen = { success: [], warn: [], info: [], note: [], select: [], cancel: [], exit: [] };
|
||||||
|
pythonCheck.detectPython = () => detectResult;
|
||||||
|
promptsModule.log = {
|
||||||
|
success: async (m) => void seen.success.push(m),
|
||||||
|
warn: async (m) => void seen.warn.push(m),
|
||||||
|
info: async (m) => void seen.info.push(m),
|
||||||
|
error: async () => {},
|
||||||
|
};
|
||||||
|
promptsModule.note = async (m, t) => void seen.note.push(t || m);
|
||||||
|
promptsModule.select = async (opts) => {
|
||||||
|
seen.select.push(opts.message);
|
||||||
|
return selectAnswer;
|
||||||
|
};
|
||||||
|
promptsModule.cancel = async (m) => void seen.cancel.push(m);
|
||||||
|
process.exit = (code) => {
|
||||||
|
seen.exit.push(code);
|
||||||
|
throw new Error('__stub_exit__');
|
||||||
|
};
|
||||||
|
return seen;
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const v = (major, minor, patch) => ({ major, minor, patch, raw: `${major}.${minor}.${patch}` });
|
||||||
|
|
||||||
|
// Branch: full support via the runtime command — success, no prompt.
|
||||||
|
let seen = stub({ command: 'python3', version: v(3, 12, 1), isRuntimeCommand: true }, 'continue');
|
||||||
|
let result = await pythonCheck.checkPythonEnvironment();
|
||||||
|
assert(result.status === 'full' && seen.success.length === 1, 'full support via python3 logs success');
|
||||||
|
assert(seen.select.length === 0 && seen.warn.length === 0, 'full support via python3 skips warning and ack prompt');
|
||||||
|
|
||||||
|
// Branch: modern Python found, but not as `python3` — runtime mismatch.
|
||||||
|
seen = stub({ command: 'py -3', version: v(3, 12, 0), isRuntimeCommand: false }, 'continue');
|
||||||
|
result = await pythonCheck.checkPythonEnvironment();
|
||||||
|
assert(seen.success.length === 0, 'python3-mismatch never reports full support');
|
||||||
|
assert(
|
||||||
|
seen.warn.length === 1 && seen.warn[0].includes('python3') && seen.warn[0].includes('py -3'),
|
||||||
|
'python3-mismatch warns that scripts invoke python3',
|
||||||
|
);
|
||||||
|
assert(seen.select.length === 1 && result.status === 'full', 'python3-mismatch still requires the ack prompt');
|
||||||
|
|
||||||
|
// Branch: partial support (3.8–3.10) — warn + ack, continue returns.
|
||||||
|
seen = stub({ command: 'python3', version: v(3, 9, 5), isRuntimeCommand: true }, 'continue');
|
||||||
|
result = await pythonCheck.checkPythonEnvironment();
|
||||||
|
assert(
|
||||||
|
result.status === 'partial' && seen.warn.length === 1 && seen.warn[0].includes('3.11+'),
|
||||||
|
'partial support warns about tomllib floor',
|
||||||
|
);
|
||||||
|
assert(seen.select.length === 1 && seen.exit.length === 0, 'partial support prompts and continue proceeds');
|
||||||
|
|
||||||
|
// Branch: no Python, non-interactive — warn + info, never prompts.
|
||||||
|
seen = stub(null, 'continue');
|
||||||
|
result = await pythonCheck.checkPythonEnvironment({ nonInteractive: true });
|
||||||
|
assert(result.status === 'none' && seen.warn[0].includes('No Python found'), 'non-interactive with no Python warns');
|
||||||
|
assert(seen.select.length === 0 && seen.info.length === 1, 'non-interactive skips the ack prompt and logs continuation');
|
||||||
|
|
||||||
|
// Branch: no Python, interactive, user quits — cancel message + exit 0.
|
||||||
|
seen = stub(null, 'quit');
|
||||||
|
let threw = false;
|
||||||
|
try {
|
||||||
|
await pythonCheck.checkPythonEnvironment();
|
||||||
|
} catch (error) {
|
||||||
|
threw = error.message === '__stub_exit__';
|
||||||
|
}
|
||||||
|
assert(threw && seen.exit.length === 1 && seen.exit[0] === 0, 'quit choice exits 0 (user-cancel convention)');
|
||||||
|
assert(seen.cancel.length === 1, 'quit choice shows the cancel guidance');
|
||||||
|
} finally {
|
||||||
|
pythonCheck.detectPython = real.detectPython;
|
||||||
|
promptsModule.log = real.log;
|
||||||
|
promptsModule.note = real.note;
|
||||||
|
promptsModule.select = real.select;
|
||||||
|
promptsModule.cancel = real.cancel;
|
||||||
|
process.exit = real.exit;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`${colors.red}Test Suite 46 setup failed: ${error.message}${colors.reset}`);
|
||||||
|
console.log(error.stack);
|
||||||
|
failed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('');
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Summary
|
// Summary
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
|
||||||
|
|
@ -419,10 +419,35 @@ class Installer {
|
||||||
const sourceDir = path.dirname(path.join(bmadDir, relativePath));
|
const sourceDir = path.dirname(path.join(bmadDir, relativePath));
|
||||||
if (await fs.pathExists(sourceDir)) {
|
if (await fs.pathExists(sourceDir)) {
|
||||||
await fs.remove(sourceDir);
|
await fs.remove(sourceDir);
|
||||||
|
await this._removeEmptyParents(path.dirname(sourceDir), bmadDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove now-empty parent directories left behind after skill dir cleanup.
|
||||||
|
* Walks up from dir, stopping at (and never removing) bmadDir. Best-effort:
|
||||||
|
* a directory that vanishes or fills in mid-walk just ends the walk.
|
||||||
|
* @param {string} dir - Directory to start walking up from
|
||||||
|
* @param {string} bmadDir - BMAD installation directory (boundary)
|
||||||
|
*/
|
||||||
|
async _removeEmptyParents(dir, bmadDir) {
|
||||||
|
let current = dir;
|
||||||
|
while (true) {
|
||||||
|
// Path-boundary check (not a string prefix, so siblings like _bmad2 don't match).
|
||||||
|
const rel = path.relative(bmadDir, current);
|
||||||
|
if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel)) break;
|
||||||
|
try {
|
||||||
|
const entries = await fs.readdir(current);
|
||||||
|
if (entries.length > 0) break;
|
||||||
|
await fs.rmdir(current);
|
||||||
|
} catch {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current = path.dirname(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async _readSkillManifestRows(bmadDir) {
|
async _readSkillManifestRows(bmadDir) {
|
||||||
const csvPath = path.join(bmadDir, '_config', 'skill-manifest.csv');
|
const csvPath = path.join(bmadDir, '_config', 'skill-manifest.csv');
|
||||||
if (!(await fs.pathExists(csvPath))) return [];
|
if (!(await fs.pathExists(csvPath))) return [];
|
||||||
|
|
@ -630,6 +655,7 @@ class Installer {
|
||||||
/**
|
/**
|
||||||
* Sync src/scripts/* → _bmad/scripts/ so shared Python scripts
|
* Sync src/scripts/* → _bmad/scripts/ so shared Python scripts
|
||||||
* (e.g. resolve_customization.py) are available at install time.
|
* (e.g. resolve_customization.py) are available at install time.
|
||||||
|
* Excludes dev-only tests and Python caches so they don't ship to users.
|
||||||
* Wipes the destination first so files removed or renamed in source
|
* Wipes the destination first so files removed or renamed in source
|
||||||
* don't linger and get recorded as installed. Also seeds
|
* don't linger and get recorded as installed. Also seeds
|
||||||
* _bmad/custom/.gitignore on fresh installs so *.user.toml overrides
|
* _bmad/custom/.gitignore on fresh installs so *.user.toml overrides
|
||||||
|
|
@ -643,7 +669,12 @@ class Installer {
|
||||||
|
|
||||||
await fs.remove(paths.scriptsDir);
|
await fs.remove(paths.scriptsDir);
|
||||||
await fs.ensureDir(paths.scriptsDir);
|
await fs.ensureDir(paths.scriptsDir);
|
||||||
await fs.copy(srcScriptsDir, paths.scriptsDir, { overwrite: true });
|
// Ship only the runtime scripts — dev-only tests and Python caches must not land in user projects.
|
||||||
|
const isInstallable = (srcPath) => {
|
||||||
|
const base = path.basename(srcPath);
|
||||||
|
return base !== 'tests' && base !== '__pycache__' && base !== '.pytest_cache' && !base.endsWith('.pyc');
|
||||||
|
};
|
||||||
|
await fs.copy(srcScriptsDir, paths.scriptsDir, { overwrite: true, filter: isInstallable });
|
||||||
await this._trackFilesRecursive(paths.scriptsDir);
|
await this._trackFilesRecursive(paths.scriptsDir);
|
||||||
|
|
||||||
const customGitignore = path.join(paths.customDir, '.gitignore');
|
const customGitignore = path.join(paths.customDir, '.gitignore');
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
const { spawnSync } = require('node:child_process');
|
||||||
|
const prompts = require('../prompts');
|
||||||
|
|
||||||
|
// Python 3.11 added stdlib `tomllib` (PEP 680), which the shared scripts in
|
||||||
|
// src/scripts/ (resolve_config.py, resolve_customization.py) require to read
|
||||||
|
// BMAD's TOML config files. memlog.py is more lenient and runs on 3.8+.
|
||||||
|
const PYTHON_FULL_SUPPORT = { major: 3, minor: 11 };
|
||||||
|
const PYTHON_PARTIAL_SUPPORT = { major: 3, minor: 8 };
|
||||||
|
|
||||||
|
// Every runtime call site (skill steps, on_complete hooks) invokes a literal
|
||||||
|
// `python3`, so only that command's version vouches for BMAD features. The
|
||||||
|
// fallback probes exist to tell the user "Python is installed, but not under
|
||||||
|
// the name BMAD uses" instead of a misleading "No Python found".
|
||||||
|
const RUNTIME_COMMAND = 'python3';
|
||||||
|
const PROBE_CANDIDATES =
|
||||||
|
process.platform === 'win32'
|
||||||
|
? [
|
||||||
|
{ command: 'python3', args: ['--version'] },
|
||||||
|
{ command: 'py', args: ['-3', '--version'] },
|
||||||
|
{ command: 'python', args: ['--version'] },
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{ command: 'python3', args: ['--version'] },
|
||||||
|
{ command: 'python', args: ['--version'] },
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a `python --version` output line into version parts.
|
||||||
|
* Python 3 prints to stdout; Python 2 printed to stderr — callers pass both.
|
||||||
|
* @param {string} output - Combined stdout/stderr from `python --version`
|
||||||
|
* @returns {{major: number, minor: number, patch: number, raw: string}|null}
|
||||||
|
*/
|
||||||
|
function parsePythonVersion(output) {
|
||||||
|
if (!output) return null;
|
||||||
|
const match = output.match(/Python\s+(\d+)\.(\d+)(?:\.(\d+))?/);
|
||||||
|
if (!match) return null;
|
||||||
|
return {
|
||||||
|
major: Number(match[1]),
|
||||||
|
minor: Number(match[2]),
|
||||||
|
patch: Number(match[3] || 0),
|
||||||
|
raw: `${match[1]}.${match[2]}.${match[3] || 0}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classify a detected Python version against BMAD's feature requirements.
|
||||||
|
* @param {{major: number, minor: number}|null} version
|
||||||
|
* @returns {'full'|'partial'|'unsupported'|'none'}
|
||||||
|
*/
|
||||||
|
function classifyPython(version) {
|
||||||
|
if (!version) return 'none';
|
||||||
|
const { major, minor } = version;
|
||||||
|
if (major > PYTHON_FULL_SUPPORT.major || (major === PYTHON_FULL_SUPPORT.major && minor >= PYTHON_FULL_SUPPORT.minor)) {
|
||||||
|
return 'full';
|
||||||
|
}
|
||||||
|
if (major === PYTHON_PARTIAL_SUPPORT.major && minor >= PYTHON_PARTIAL_SUPPORT.minor) {
|
||||||
|
return 'partial';
|
||||||
|
}
|
||||||
|
return 'unsupported';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run one probe candidate and return its parsed version, or null.
|
||||||
|
* @param {{command: string, args: string[]}} candidate
|
||||||
|
* @returns {{major: number, minor: number, patch: number, raw: string}|null}
|
||||||
|
*/
|
||||||
|
function probeVersion(candidate) {
|
||||||
|
const run = (extra = {}) =>
|
||||||
|
spawnSync(candidate.command, candidate.args, {
|
||||||
|
encoding: 'utf8',
|
||||||
|
timeout: 5000,
|
||||||
|
windowsHide: true,
|
||||||
|
...extra,
|
||||||
|
});
|
||||||
|
let result = run();
|
||||||
|
// Node >=18.20/20.12 refuses to spawn .bat/.cmd without a shell
|
||||||
|
// (CVE-2024-27980 hardening) and reports EINVAL — pyenv-win ships its
|
||||||
|
// python shims as .bat. Args here are static literals, so a shell retry
|
||||||
|
// is injection-safe.
|
||||||
|
if (result.error && result.error.code === 'EINVAL' && process.platform === 'win32') {
|
||||||
|
result = run({ shell: true });
|
||||||
|
}
|
||||||
|
if (result.error) return null;
|
||||||
|
return parsePythonVersion(`${result.stdout || ''}\n${result.stderr || ''}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Probe the local environment for a Python interpreter.
|
||||||
|
* Tries each candidate command and returns the first that reports a version.
|
||||||
|
* `isRuntimeCommand` is true only when the match is `python3` — the command
|
||||||
|
* BMAD scripts actually invoke.
|
||||||
|
* @returns {{command: string, version: {major: number, minor: number, patch: number, raw: string}, isRuntimeCommand: boolean}|null}
|
||||||
|
*/
|
||||||
|
function detectPython() {
|
||||||
|
for (const candidate of PROBE_CANDIDATES) {
|
||||||
|
try {
|
||||||
|
const version = probeVersion(candidate);
|
||||||
|
if (version) {
|
||||||
|
const display = candidate.args.length > 1 ? `${candidate.command} ${candidate.args.slice(0, -1).join(' ')}` : candidate.command;
|
||||||
|
return { command: display, version, isRuntimeCommand: candidate.command === RUNTIME_COMMAND };
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Candidate not runnable — try the next one.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgradeHints() {
|
||||||
|
return [
|
||||||
|
'How to get Python 3.11+ (as `python3`):',
|
||||||
|
' macOS: brew install python3',
|
||||||
|
' Windows: winget install Python.Python.3.12 (then ensure `python3` resolves, e.g. enable the python3 alias)',
|
||||||
|
' Linux/WSL: sudo apt install python3 (Ubuntu 24.04+ ships 3.12; older distros: use pyenv or deadsnakes)',
|
||||||
|
' Docker: add python3 to your image (e.g. apk add python3 / apt-get install -y python3)',
|
||||||
|
].join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the local Python environment and warn about degraded BMAD features.
|
||||||
|
*
|
||||||
|
* Warn-don't-block: most of BMAD works without Python, so the install always
|
||||||
|
* may proceed — but the user must explicitly acknowledge the warning so it
|
||||||
|
* can't scroll past unseen. In non-interactive runs (--yes, or stdin is not
|
||||||
|
* a TTY) the warning is logged and the install continues without a prompt.
|
||||||
|
*
|
||||||
|
* @param {Object} [options]
|
||||||
|
* @param {boolean} [options.nonInteractive=false] - Skip the ack prompt (--yes, or no TTY)
|
||||||
|
* @returns {Promise<{status: string, detected: Object|null}>}
|
||||||
|
*/
|
||||||
|
async function checkPythonEnvironment({ nonInteractive = false } = {}) {
|
||||||
|
// Called via module.exports so tests can stub detection.
|
||||||
|
const detected = module.exports.detectPython();
|
||||||
|
const status = classifyPython(detected ? detected.version : null);
|
||||||
|
|
||||||
|
if (status === 'full' && detected.isRuntimeCommand) {
|
||||||
|
await prompts.log.success(`Python ${detected.version.raw} detected (${detected.command}) — all BMAD features supported.`);
|
||||||
|
return { status, detected };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detected && !detected.isRuntimeCommand) {
|
||||||
|
await prompts.log.warn(
|
||||||
|
`Python ${detected.version.raw} found via \`${detected.command}\`, but BMAD scripts invoke \`python3\`, which is not on PATH.\n` +
|
||||||
|
`Python-powered features (memlog session memory, TOML config resolution) won't run until \`python3\` resolves —\n` +
|
||||||
|
`add a python3 alias/shim, or reinstall Python with the python3 launcher enabled.`,
|
||||||
|
);
|
||||||
|
} else if (status === 'partial') {
|
||||||
|
await prompts.log.warn(
|
||||||
|
`Python ${detected.version.raw} detected (${detected.command}) — BMAD's TOML config tools need Python 3.11+ (stdlib tomllib).\n` +
|
||||||
|
`Works: memlog session memory. Won't work: config/customization resolution scripts.`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const found =
|
||||||
|
status === 'unsupported' ? `Python ${detected.version.raw} detected (${detected.command}) — too old.` : 'No Python found on PATH.';
|
||||||
|
await prompts.log.warn(
|
||||||
|
`${found} BMAD installs fine without it, but Python-powered features\n` +
|
||||||
|
`(memlog session memory, TOML config resolution) won't run until Python 3.11+ is available.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await prompts.note(upgradeHints(), 'Python 3.11+ recommended');
|
||||||
|
|
||||||
|
if (nonInteractive) {
|
||||||
|
await prompts.log.info('Continuing anyway (non-interactive run). You can fix Python later — no reinstall needed.');
|
||||||
|
return { status, detected };
|
||||||
|
}
|
||||||
|
|
||||||
|
const choice = await prompts.select({
|
||||||
|
message: "BMAD's Python-powered features won't work yet. How do you want to proceed?",
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
name: 'Continue install',
|
||||||
|
value: 'continue',
|
||||||
|
hint: 'BMAD works without Python — you can fix Python later, no reinstall needed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Quit and fix Python first',
|
||||||
|
value: 'quit',
|
||||||
|
hint: 'make Python 3.11+ available as python3, then re-run the installer',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'continue',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (choice === 'quit') {
|
||||||
|
await prompts.cancel('Make Python 3.11+ available as `python3` (see hints above), then re-run the installer.');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { status, detected };
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
checkPythonEnvironment,
|
||||||
|
detectPython,
|
||||||
|
parsePythonVersion,
|
||||||
|
classifyPython,
|
||||||
|
PYTHON_FULL_SUPPORT,
|
||||||
|
PYTHON_PARTIAL_SUPPORT,
|
||||||
|
};
|
||||||
|
|
@ -161,6 +161,16 @@ class UI {
|
||||||
const messageLoader = new MessageLoader();
|
const messageLoader = new MessageLoader();
|
||||||
await messageLoader.displayStartMessage();
|
await messageLoader.displayStartMessage();
|
||||||
|
|
||||||
|
// Probe the local Python before any other prompts: several BMAD features
|
||||||
|
// (memlog session memory, TOML config resolution) need Python 3.11+ at
|
||||||
|
// runtime. Warn-don't-block, but require an explicit ack so the warning
|
||||||
|
// can't scroll past unseen. The installer runs in the destination
|
||||||
|
// environment, so probing PATH here tests the right machine.
|
||||||
|
// Skip the ack when stdin isn't a TTY (CI/Docker/piped): clack's select
|
||||||
|
// on closed stdin resolves to cancel, which would silently exit 0.
|
||||||
|
const { checkPythonEnvironment } = require('./core/python-check');
|
||||||
|
await checkPythonEnvironment({ nonInteractive: !!options.yes || !process.stdin.isTTY });
|
||||||
|
|
||||||
// Parse channel flags (--channel/--all-*/--next=/--pin) once. Warnings
|
// Parse channel flags (--channel/--all-*/--next=/--pin) once. Warnings
|
||||||
// are surfaced immediately so the user sees them before any git ops run.
|
// are surfaced immediately so the user sees them before any git ops run.
|
||||||
const channelOptions = parseChannelOptions(options);
|
const channelOptions = parseChannelOptions(options);
|
||||||
|
|
|
||||||
|
|
@ -419,7 +419,7 @@
|
||||||
<div class="workflow-meta">
|
<div class="workflow-meta">
|
||||||
<div class="agent">
|
<div class="agent">
|
||||||
<div class="agent-icon john">J</div>
|
<div class="agent-icon john">J</div>
|
||||||
<span class="agent-name">Any</span>
|
<span class="agent-name">John</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="output">prd.md →</span>
|
<span class="output">prd.md →</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -427,7 +427,7 @@
|
||||||
<div class="decision">UI가 있나요?</div>
|
<div class="decision">UI가 있나요?</div>
|
||||||
<div class="workflow">
|
<div class="workflow">
|
||||||
<div class="workflow-header">
|
<div class="workflow-header">
|
||||||
<span class="workflow-name">create-ux-design</span>
|
<span class="workflow-name">ux</span>
|
||||||
<span class="badge iffy">예</span>
|
<span class="badge iffy">예</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="workflow-meta">
|
<div class="workflow-meta">
|
||||||
|
|
@ -435,7 +435,7 @@
|
||||||
<div class="agent-icon sally">S</div>
|
<div class="agent-icon sally">S</div>
|
||||||
<span class="agent-name">Sally</span>
|
<span class="agent-name">Sally</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="output">ux-spec.md →</span>
|
<span class="output">DESIGN.md + EXPERIENCE.md →</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -591,7 +591,7 @@
|
||||||
<div class="quickflow-header">
|
<div class="quickflow-header">
|
||||||
<span>⚡</span>
|
<span>⚡</span>
|
||||||
<div>
|
<div>
|
||||||
<h2>Quick Flow (병렬 트랙)</h2>
|
<h2>빠른 흐름 (병렬 트랙)</h2>
|
||||||
<span>범위가 작고 명확한 변경에 사용됩니다 — 1~3단계를 건너뜁니다</span>
|
<span>범위가 작고 명확한 변경에 사용됩니다 — 1~3단계를 건너뜁니다</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue