bmad-method-quarkus 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +53 -0
- package/AGENTS.md +12 -0
- package/LICENSE +30 -0
- package/README.md +94 -0
- package/README_CN.md +108 -0
- package/README_VN.md +109 -0
- package/bmad-modules.yaml +133 -0
- package/package.json +123 -0
- package/removals.txt +87 -0
- package/src/bmm-skills/agents/bmad-agent-analyst/SKILL.md +76 -0
- package/src/bmm-skills/agents/bmad-agent-analyst/customize.toml +105 -0
- package/src/bmm-skills/agents/bmad-agent-architect/SKILL.md +76 -0
- package/src/bmm-skills/agents/bmad-agent-architect/customize.toml +65 -0
- package/src/bmm-skills/agents/bmad-agent-dev/SKILL.md +76 -0
- package/src/bmm-skills/agents/bmad-agent-dev/customize.toml +83 -0
- package/src/bmm-skills/agents/bmad-agent-pm/SKILL.md +76 -0
- package/src/bmm-skills/agents/bmad-agent-pm/customize.toml +75 -0
- package/src/bmm-skills/agents/bmad-agent-ux-designer/SKILL.md +76 -0
- package/src/bmm-skills/agents/bmad-agent-ux-designer/customize.toml +60 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/.memlog.md +12 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/.memlog.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/SKILL.md +86 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/customize.toml +37 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/customize.toml:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/references/enrich-stories.md +19 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/references/enrich-stories.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/references/prompt-quality-canon.md +79 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/references/prompt-quality-canon.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/SKILL.md +80 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module-help.csv +9 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module-help.csv:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module.yaml +16 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module.yaml:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/cleanup-legacy.py +287 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/cleanup-legacy.py:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-config.py +441 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-config.py:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-help-csv.py +246 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-help-csv.py:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-error-handling-i18n/SKILL.md +181 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-error-handling-i18n/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-grpc-services/SKILL.md +141 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-grpc-services/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-hexagonal-core/SKILL.md +392 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-hexagonal-core/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-kafka-messaging/SKILL.md +148 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-kafka-messaging/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-observability-otel/SKILL.md +180 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-observability-otel/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-openapi-tmforum/SKILL.md +128 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-openapi-tmforum/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-sql-jdbc-agroal/SKILL.md +245 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-sql-jdbc-agroal/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/module-help.csv +19 -0
- package/src/bmm-skills/module.yaml +92 -0
- package/src/bmm-skills/plan/bmad-architecture/SKILL.md +85 -0
- package/src/bmm-skills/plan/bmad-architecture/assets/spine-template.md +79 -0
- package/src/bmm-skills/plan/bmad-architecture/customize.toml +102 -0
- package/src/bmm-skills/plan/bmad-architecture/references/headless.md +26 -0
- package/src/bmm-skills/plan/bmad-architecture/references/reviewer-gate.md +13 -0
- package/src/bmm-skills/plan/bmad-architecture/scripts/lint_spine.py +257 -0
- package/src/bmm-skills/plan/bmad-architecture/scripts/tests/test_lint_spine.py +270 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/SKILL.md +93 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/customize.toml +41 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-01-validate-prerequisites.md +263 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-02-design-epics.md +242 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-03-create-stories.md +255 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-04-final-validation.md +143 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/templates/epics-template.md +61 -0
- package/src/bmm-skills/plan/bmad-generate-project-context/SKILL.md +10 -0
- package/src/bmm-skills/plan/bmad-prd/SKILL.md +94 -0
- package/src/bmm-skills/plan/bmad-prd/assets/headless-schemas.md +76 -0
- package/src/bmm-skills/plan/bmad-prd/assets/prd-template.md +165 -0
- package/src/bmm-skills/plan/bmad-prd/assets/prd-validation-checklist.md +135 -0
- package/src/bmm-skills/plan/bmad-prd/assets/validation-report-template.html +325 -0
- package/src/bmm-skills/plan/bmad-prd/customize.toml +149 -0
- package/src/bmm-skills/plan/bmad-prd/references/headless.md +39 -0
- package/src/bmm-skills/plan/bmad-prd/references/validate.md +97 -0
- package/src/bmm-skills/plan/bmad-prfaq/SKILL.md +135 -0
- package/src/bmm-skills/plan/bmad-prfaq/agents/artifact-analyzer.md +60 -0
- package/src/bmm-skills/plan/bmad-prfaq/agents/web-researcher.md +49 -0
- package/src/bmm-skills/plan/bmad-prfaq/assets/prfaq-template.md +62 -0
- package/src/bmm-skills/plan/bmad-prfaq/bmad-manifest.json +16 -0
- package/src/bmm-skills/plan/bmad-prfaq/customize.toml +41 -0
- package/src/bmm-skills/plan/bmad-prfaq/references/customer-faq.md +55 -0
- package/src/bmm-skills/plan/bmad-prfaq/references/internal-faq.md +51 -0
- package/src/bmm-skills/plan/bmad-prfaq/references/press-release.md +60 -0
- package/src/bmm-skills/plan/bmad-prfaq/references/verdict.md +83 -0
- package/src/bmm-skills/plan/bmad-product-brief/SKILL.md +91 -0
- package/src/bmm-skills/plan/bmad-product-brief/assets/brief-template.md +41 -0
- package/src/bmm-skills/plan/bmad-product-brief/customize.toml +101 -0
- package/src/bmm-skills/plan/bmad-project-context/SKILL.md +110 -0
- package/src/bmm-skills/plan/bmad-project-context/customize.toml +24 -0
- package/src/bmm-skills/plan/bmad-project-context/references/best-practices.md +65 -0
- package/src/bmm-skills/plan/bmad-project-context/references/template.md +55 -0
- package/src/bmm-skills/plan/bmad-spec/SKILL.md +160 -0
- package/src/bmm-skills/plan/bmad-spec/assets/headless-schemas.md +33 -0
- package/src/bmm-skills/plan/bmad-spec/assets/spec-template.md +49 -0
- package/src/bmm-skills/plan/bmad-spec/assets/stories-schema.md +44 -0
- package/src/bmm-skills/plan/bmad-spec/customize.toml +52 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/SKILL.md +62 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/customize.toml +41 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/references/fix-sprint-status.md +30 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/references/generate-tracking.md +25 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/references/readiness-gate.md +20 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/references/status-view.md +14 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/references/validate.md +10 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc +0 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/sprint_plan.py +697 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/__pycache__/test_sprint_plan.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/test_sprint_plan.py +524 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/sprint-status-template.yaml +71 -0
- package/src/bmm-skills/plan/bmad-ux/SKILL.md +90 -0
- package/src/bmm-skills/plan/bmad-ux/assets/color-themes.md +9 -0
- package/src/bmm-skills/plan/bmad-ux/assets/design-directions.md +9 -0
- package/src/bmm-skills/plan/bmad-ux/assets/design-example-editorial.md +158 -0
- package/src/bmm-skills/plan/bmad-ux/assets/design-example-mobile.md +93 -0
- package/src/bmm-skills/plan/bmad-ux/assets/design-example-shadcn.md +109 -0
- package/src/bmm-skills/plan/bmad-ux/assets/excalidraw-wireframe.md +19 -0
- package/src/bmm-skills/plan/bmad-ux/assets/experience-example-mobile.md +112 -0
- package/src/bmm-skills/plan/bmad-ux/assets/experience-example-shadcn.md +133 -0
- package/src/bmm-skills/plan/bmad-ux/assets/headless-schemas.md +84 -0
- package/src/bmm-skills/plan/bmad-ux/assets/key-screens.md +29 -0
- package/src/bmm-skills/plan/bmad-ux/assets/validation-report-template.html +319 -0
- package/src/bmm-skills/plan/bmad-ux/customize.toml +102 -0
- package/src/bmm-skills/plan/bmad-ux/references/creative-tools.md +19 -0
- package/src/bmm-skills/plan/bmad-ux/references/design-md-spec.md +50 -0
- package/src/bmm-skills/plan/bmad-ux/references/headless.md +37 -0
- package/src/bmm-skills/plan/bmad-ux/references/validate.md +115 -0
- package/src/bmm-skills/ship/bmad-build/SKILL.md +13 -0
- package/src/bmm-skills/ship/bmad-build/compile-epic-context.md +62 -0
- package/src/bmm-skills/ship/bmad-build/customize.toml +164 -0
- package/src/bmm-skills/ship/bmad-build/references/deletion-check.md +14 -0
- package/src/bmm-skills/ship/bmad-build/review-prompts/edge-case-hunter.md +88 -0
- package/src/bmm-skills/ship/bmad-build/review-prompts/verification-gap.md +113 -0
- package/src/bmm-skills/ship/bmad-build/spec-template.md +89 -0
- package/src/bmm-skills/ship/bmad-build/step-01-clarify-and-route.md +105 -0
- package/src/bmm-skills/ship/bmad-build/step-02-plan.md +47 -0
- package/src/bmm-skills/ship/bmad-build/step-03-implement.md +49 -0
- package/src/bmm-skills/ship/bmad-build/step-04-review.md +55 -0
- package/src/bmm-skills/ship/bmad-build/step-05-present.md +75 -0
- package/src/bmm-skills/ship/bmad-build/step-oneshot.md +77 -0
- package/src/bmm-skills/ship/bmad-build/sync-sprint-status.md +19 -0
- package/src/bmm-skills/ship/bmad-build/workflow.md +84 -0
- package/src/bmm-skills/ship/bmad-build-auto/SKILL.md +13 -0
- package/src/bmm-skills/ship/bmad-build-auto/compile-epic-context.md +62 -0
- package/src/bmm-skills/ship/bmad-build-auto/customize.toml +121 -0
- package/src/bmm-skills/ship/bmad-build-auto/references/deletion-check.md +14 -0
- package/src/bmm-skills/ship/bmad-build-auto/review-prompts/edge-case-hunter.md +88 -0
- package/src/bmm-skills/ship/bmad-build-auto/review-prompts/verification-gap.md +113 -0
- package/src/bmm-skills/ship/bmad-build-auto/spec-template.md +99 -0
- package/src/bmm-skills/ship/bmad-build-auto/step-01-clarify-and-route.md +83 -0
- package/src/bmm-skills/ship/bmad-build-auto/step-02-plan.md +27 -0
- package/src/bmm-skills/ship/bmad-build-auto/step-03-implement.md +44 -0
- package/src/bmm-skills/ship/bmad-build-auto/step-04-review.md +96 -0
- package/src/bmm-skills/ship/bmad-build-auto/workflow.md +104 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/SKILL.md +68 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/customize.toml +41 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/generate-trail.md +38 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/step-01-orientation.md +105 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/step-02-walkthrough.md +89 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/step-03-detail-pass.md +106 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/step-04-testing.md +74 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/step-05-wrapup.md +30 -0
- package/src/bmm-skills/ship/bmad-code-review/SKILL.md +90 -0
- package/src/bmm-skills/ship/bmad-code-review/customize.toml +113 -0
- package/src/bmm-skills/ship/bmad-code-review/references/deletion-check.md +14 -0
- package/src/bmm-skills/ship/bmad-code-review/review-prompts/edge-case-hunter.md +88 -0
- package/src/bmm-skills/ship/bmad-code-review/review-prompts/verification-gap.md +113 -0
- package/src/bmm-skills/ship/bmad-code-review/steps/step-01-gather-context.md +87 -0
- package/src/bmm-skills/ship/bmad-code-review/steps/step-02-review.md +32 -0
- package/src/bmm-skills/ship/bmad-code-review/steps/step-03-triage.md +50 -0
- package/src/bmm-skills/ship/bmad-code-review/steps/step-04-present.md +132 -0
- package/src/bmm-skills/ship/bmad-correct-course/SKILL.md +300 -0
- package/src/bmm-skills/ship/bmad-correct-course/checklist.md +288 -0
- package/src/bmm-skills/ship/bmad-correct-course/customize.toml +41 -0
- package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/SKILL.md +176 -0
- package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/checklist.md +33 -0
- package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/customize.toml +41 -0
- package/src/bmm-skills/ship/bmad-retrospective/SKILL.md +94 -0
- package/src/bmm-skills/ship/bmad-retrospective/customize.toml +41 -0
- package/src/bmm-skills/ship/bmad-retrospective/references/acceptance-verdict.md +55 -0
- package/src/bmm-skills/ship/bmad-retrospective/references/aggregate-views.md +17 -0
- package/src/bmm-skills/ship/bmad-retrospective/references/evidence-gathering.md +30 -0
- package/src/bmm-skills/ship/bmad-retrospective/references/retro-document.md +84 -0
- package/src/bmm-skills/ship/bmad-retrospective/references/team-discussion.md +22 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/git_evidence.py +304 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/sprint_status.py +746 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_git_evidence.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_sprint_status.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/fixtures/sprint-status-template.yaml +71 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/test_git_evidence.py +750 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/test_sprint_status.py +1579 -0
- package/src/bmm-skills/v6-shims/README.md +28 -0
- package/src/bmm-skills/v6-shims/bmad-create-architecture/SKILL.md +30 -0
- package/src/bmm-skills/v6-shims/bmad-create-architecture/customize.toml +41 -0
- package/src/bmm-skills/v6-shims/bmad-create-prd/SKILL.md +30 -0
- package/src/bmm-skills/v6-shims/bmad-create-prd/customize.toml +41 -0
- package/src/bmm-skills/v6-shims/bmad-create-story/SKILL.md +434 -0
- package/src/bmm-skills/v6-shims/bmad-create-story/checklist.md +357 -0
- package/src/bmm-skills/v6-shims/bmad-create-story/customize.toml +41 -0
- package/src/bmm-skills/v6-shims/bmad-create-story/discover-inputs.md +88 -0
- package/src/bmm-skills/v6-shims/bmad-create-story/template.md +49 -0
- package/src/bmm-skills/v6-shims/bmad-dev-auto/SKILL.md +19 -0
- package/src/bmm-skills/v6-shims/bmad-dev-story/SKILL.md +502 -0
- package/src/bmm-skills/v6-shims/bmad-dev-story/checklist.md +80 -0
- package/src/bmm-skills/v6-shims/bmad-dev-story/customize.toml +44 -0
- package/src/bmm-skills/v6-shims/bmad-document-project/SKILL.md +14 -0
- package/src/bmm-skills/v6-shims/bmad-domain-research/SKILL.md +14 -0
- package/src/bmm-skills/v6-shims/bmad-edit-prd/SKILL.md +30 -0
- package/src/bmm-skills/v6-shims/bmad-edit-prd/customize.toml +42 -0
- package/src/bmm-skills/v6-shims/bmad-market-research/SKILL.md +14 -0
- package/src/bmm-skills/v6-shims/bmad-quick-dev/SKILL.md +19 -0
- package/src/bmm-skills/v6-shims/bmad-sprint-status/SKILL.md +26 -0
- package/src/bmm-skills/v6-shims/bmad-sprint-status/customize.toml +41 -0
- package/src/bmm-skills/v6-shims/bmad-technical-research/SKILL.md +14 -0
- package/src/bmm-skills/v6-shims/bmad-validate-prd/SKILL.md +30 -0
- package/src/bmm-skills/v6-shims/bmad-validate-prd/customize.toml +42 -0
- package/src/core-skills/bmad-advanced-elicitation/SKILL.md +65 -0
- package/src/core-skills/bmad-advanced-elicitation/assets/methods.csv +72 -0
- package/src/core-skills/bmad-advanced-elicitation/customize.toml +54 -0
- package/src/core-skills/bmad-advanced-elicitation/scripts/pick_methods.py +233 -0
- package/src/core-skills/bmad-advanced-elicitation/scripts/tests/test_pick_methods.py +228 -0
- package/src/core-skills/bmad-brainstorming/SKILL.md +80 -0
- package/src/core-skills/bmad-brainstorming/assets/brain-icons.json +166 -0
- package/src/core-skills/bmad-brainstorming/assets/brain-methods.csv +109 -0
- package/src/core-skills/bmad-brainstorming/assets/brain-selector.html +328 -0
- package/src/core-skills/bmad-brainstorming/customize.toml +84 -0
- package/src/core-skills/bmad-brainstorming/references/converge.md +24 -0
- package/src/core-skills/bmad-brainstorming/references/finalize.md +26 -0
- package/src/core-skills/bmad-brainstorming/references/headless.md +54 -0
- package/src/core-skills/bmad-brainstorming/references/in-chat-techniques.md +18 -0
- package/src/core-skills/bmad-brainstorming/references/mode-autonomous.md +10 -0
- package/src/core-skills/bmad-brainstorming/references/mode-facilitator.md +11 -0
- package/src/core-skills/bmad-brainstorming/references/mode-partner.md +16 -0
- package/src/core-skills/bmad-brainstorming/references/resume.md +5 -0
- package/src/core-skills/bmad-brainstorming/scripts/brain.py +770 -0
- package/src/core-skills/bmad-brainstorming/scripts/tests/test_brain.py +239 -0
- package/src/core-skills/bmad-customize/SKILL.md +111 -0
- package/src/core-skills/bmad-customize/scripts/list_customizable_skills.py +231 -0
- package/src/core-skills/bmad-customize/scripts/tests/test_list_customizable_skills.py +249 -0
- package/src/core-skills/bmad-deep-recon/SKILL.md +82 -0
- package/src/core-skills/bmad-deep-recon/assets/research.template.md +18 -0
- package/src/core-skills/bmad-deep-recon/customize.toml +212 -0
- package/src/core-skills/bmad-deep-recon/references/draft.md +8 -0
- package/src/core-skills/bmad-deep-recon/references/finalize.md +11 -0
- package/src/core-skills/bmad-deep-recon/references/html-briefing.md +16 -0
- package/src/core-skills/bmad-deep-recon/references/lifecycle.md +11 -0
- package/src/core-skills/bmad-deep-recon/references/process.md +10 -0
- package/src/core-skills/bmad-deep-recon/references/run.md +73 -0
- package/src/core-skills/bmad-deep-recon/references/selection.md +13 -0
- package/src/core-skills/bmad-deep-recon/references/synthesis.md +16 -0
- package/src/core-skills/bmad-deep-recon/references/verification.md +29 -0
- package/src/core-skills/bmad-deep-recon/scripts/recon_kit.py +322 -0
- package/src/core-skills/bmad-deep-recon/scripts/tests/test_recon_kit.py +144 -0
- package/src/core-skills/bmad-deep-recon/types/academic-lit.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/competitive.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/domain.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/market.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/technical.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/user-voice.md +19 -0
- package/src/core-skills/bmad-forge-idea/SKILL.md +107 -0
- package/src/core-skills/bmad-forge-idea/customize.toml +42 -0
- package/src/core-skills/bmad-forge-idea/scripts/resolve_personas.py +275 -0
- package/src/core-skills/bmad-forge-idea/scripts/tests/test_resolve_personas.py +138 -0
- package/src/core-skills/bmad-help/SKILL.md +75 -0
- package/src/core-skills/bmad-party-mode/SKILL.md +60 -0
- package/src/core-skills/bmad-party-mode/customize.toml +211 -0
- package/src/core-skills/bmad-party-mode/references/create-party.md +70 -0
- package/src/core-skills/bmad-party-mode/references/mode-agent-team.md +13 -0
- package/src/core-skills/bmad-party-mode/references/mode-auto.md +13 -0
- package/src/core-skills/bmad-party-mode/references/mode-subagent.md +31 -0
- package/src/core-skills/bmad-party-mode/references/party-memory.md +51 -0
- package/src/core-skills/bmad-party-mode/scripts/resolve_party.py +282 -0
- package/src/core-skills/bmad-party-mode/scripts/tests/test_resolve_party.py +146 -0
- package/src/core-skills/bmad-review/SKILL.md +49 -0
- package/src/core-skills/bmad-review/customize.toml +141 -0
- package/src/core-skills/bmad-review/references/editorial-common.md +56 -0
- package/src/core-skills/bmad-review/references/lens-adversarial.md +19 -0
- package/src/core-skills/bmad-review/references/lens-edge-case-hunter.md +54 -0
- package/src/core-skills/bmad-review/references/lens-prose.md +7 -0
- package/src/core-skills/bmad-review/references/lens-structure.md +9 -0
- package/src/core-skills/bmad-review/references/lens-verification-gap.md +92 -0
- package/src/core-skills/bmad-review/references/structure-models.md +44 -0
- package/src/core-skills/bmad-review/scripts/tests/test_word_metrics.py +62 -0
- package/src/core-skills/bmad-review/scripts/word_metrics.py +102 -0
- package/src/core-skills/module-help.csv +10 -0
- package/src/core-skills/module.yaml +38 -0
- package/src/core-skills/v6-shims/README.md +25 -0
- package/src/core-skills/v6-shims/bmad-editorial-review/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-editorial-review/customize.toml +31 -0
- package/src/core-skills/v6-shims/bmad-editorial-review-prose/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-editorial-review-structure/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-review-adversarial-general/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-review-edge-case-hunter/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-review-verification-gap/SKILL.md +6 -0
- package/src/scripts/__pycache__/config_utils.cpython-311.pyc +0 -0
- package/src/scripts/config_utils.py +119 -0
- package/src/scripts/memlog.py +224 -0
- package/src/scripts/render_skill.py +401 -0
- package/src/scripts/resolve_config.py +74 -0
- package/src/scripts/resolve_customization.py +99 -0
- package/src/scripts/tests/__pycache__/test_config_utils.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_resolve_config.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-311.pyc +0 -0
- package/src/scripts/tests/test_config_utils.py +85 -0
- package/src/scripts/tests/test_memlog.py +306 -0
- package/src/scripts/tests/test_resolve_config.py +89 -0
- package/src/scripts/tests/test_resolve_customization.py +77 -0
- package/tools/bundle-web-bundles.js +117 -0
- package/tools/format-workflow-md.js +263 -0
- package/tools/installer/README.md +60 -0
- package/tools/installer/bmad-cli.js +105 -0
- package/tools/installer/cli-utils.js +57 -0
- package/tools/installer/commands/install.js +149 -0
- package/tools/installer/commands/status.js +65 -0
- package/tools/installer/commands/uninstall.js +167 -0
- package/tools/installer/core/config.js +73 -0
- package/tools/installer/core/existing-install.js +121 -0
- package/tools/installer/core/install-paths.js +132 -0
- package/tools/installer/core/installer.js +1767 -0
- package/tools/installer/core/legacy-warnings.js +151 -0
- package/tools/installer/core/manifest-generator.js +859 -0
- package/tools/installer/core/manifest.js +433 -0
- package/tools/installer/core/uv-check.js +195 -0
- package/tools/installer/core/wsl-node-check.js +109 -0
- package/tools/installer/file-ops.js +204 -0
- package/tools/installer/fs-native.js +116 -0
- package/tools/installer/ide/_config-driven.js +972 -0
- package/tools/installer/ide/manager.js +324 -0
- package/tools/installer/ide/platform-codes.js +80 -0
- package/tools/installer/ide/platform-codes.yaml +343 -0
- package/tools/installer/ide/shared/installed-skills.js +50 -0
- package/tools/installer/ide/shared/path-utils.js +219 -0
- package/tools/installer/ide/shared/skill-manifest.js +57 -0
- package/tools/installer/install-messages.yaml +37 -0
- package/tools/installer/list-options.js +210 -0
- package/tools/installer/message-loader.js +83 -0
- package/tools/installer/modules/channel-plan.js +203 -0
- package/tools/installer/modules/channel-resolver.js +241 -0
- package/tools/installer/modules/custom-module-manager.js +924 -0
- package/tools/installer/modules/external-manager.js +671 -0
- package/tools/installer/modules/git-env.js +47 -0
- package/tools/installer/modules/module-help-schema.js +13 -0
- package/tools/installer/modules/official-modules.js +2257 -0
- package/tools/installer/modules/plugin-resolver.js +398 -0
- package/tools/installer/modules/version-resolver.js +336 -0
- package/tools/installer/project-root.js +224 -0
- package/tools/installer/prompts.js +791 -0
- package/tools/installer/set-overrides.js +330 -0
- package/tools/installer/ui.js +2167 -0
- package/tools/installer/yaml-format.js +245 -0
- package/tools/javascript-conventions.md +5 -0
- package/tools/migrate-custom-module-paths.js +124 -0
- package/tools/skill-validator.md +378 -0
- package/tools/validate-published-implementation-model.mjs +68 -0
- package/tools/validate-sidebar-order.js +388 -0
- package/tools/validate-skills.js +735 -0
- package/tools/validate-svg-changes.sh +356 -0
- package/web-bundles/README.md +46 -0
- package/web-bundles/brainstorming-coach/INSTRUCTIONS.md +86 -0
- package/web-bundles/brainstorming-coach/SKILL.md +83 -0
- package/web-bundles/brainstorming-coach/brain-methods.csv +62 -0
- package/web-bundles/bundles.json +139 -0
- package/web-bundles/market-and-industry-research/INSTRUCTIONS.md +88 -0
- package/web-bundles/market-and-industry-research/SKILL.md +59 -0
- package/web-bundles/prd-coach/INSTRUCTIONS.md +86 -0
- package/web-bundles/prd-coach/SKILL.md +101 -0
- package/web-bundles/prd-coach/prd-template.md +165 -0
- package/web-bundles/prd-coach/prd-validation-checklist.md +135 -0
- package/web-bundles/prfaq-coach/INSTRUCTIONS.md +86 -0
- package/web-bundles/prfaq-coach/SKILL.md +139 -0
- package/web-bundles/product-brief-coach/INSTRUCTIONS.md +86 -0
- package/web-bundles/product-brief-coach/SKILL.md +113 -0
- package/web-bundles/ux-coach/INSTRUCTIONS.md +92 -0
- package/web-bundles/ux-coach/SKILL.md +187 -0
- package/web-bundles/ux-coach/ux-validation.md +100 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# /// script
|
|
3
|
+
# requires-python = ">=3.11"
|
|
4
|
+
# ///
|
|
5
|
+
"""Resolve the party-mode roster, lazily.
|
|
6
|
+
|
|
7
|
+
Merges the installed BMAD agents with the user's custom `party_members`
|
|
8
|
+
into one collective, then projects only what the moment needs:
|
|
9
|
+
|
|
10
|
+
* default (no flag) — the active roster to load on entry: the
|
|
11
|
+
`default_party` group if one is configured, else the whole collective.
|
|
12
|
+
Other groups come back as names only, so nothing you aren't using is
|
|
13
|
+
loaded into the party.
|
|
14
|
+
* --list-groups — just id + name + size for every configured group. The
|
|
15
|
+
cheap menu for "which room?", with no member detail.
|
|
16
|
+
* --party <id> — full member detail for one chosen group, on demand
|
|
17
|
+
(e.g. when the user switches rooms). Unknown id returns the available
|
|
18
|
+
names instead of an error wall.
|
|
19
|
+
|
|
20
|
+
The merge is deterministic (a keyed union; a custom member whose code
|
|
21
|
+
matches an installed agent overrides it), so the orchestrator consumes a
|
|
22
|
+
resolved roster instead of re-deriving it every session.
|
|
23
|
+
|
|
24
|
+
Stdlib only (Python 3.11+ for tomllib). Shells out to the project's
|
|
25
|
+
resolve_config.py and resolve_customization.py; falls back to reading
|
|
26
|
+
customize.toml directly if the customization resolver is unavailable.
|
|
27
|
+
|
|
28
|
+
resolve_party.py --project-root P --skill S
|
|
29
|
+
resolve_party.py --project-root P --skill S --list-groups
|
|
30
|
+
resolve_party.py --project-root P --skill S --party writers-room
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
import argparse
|
|
34
|
+
import json
|
|
35
|
+
import subprocess
|
|
36
|
+
import sys
|
|
37
|
+
from pathlib import Path
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
import tomllib
|
|
41
|
+
except ImportError: # pragma: no cover - guarded for <3.11
|
|
42
|
+
sys.stderr.write("error: Python 3.11+ is required (stdlib `tomllib`).\n")
|
|
43
|
+
sys.exit(3)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _run_json(cmd):
|
|
47
|
+
"""Run a resolver script and parse its JSON stdout. None on any failure."""
|
|
48
|
+
try:
|
|
49
|
+
out = subprocess.run(
|
|
50
|
+
cmd, capture_output=True, text=True, encoding="utf-8", timeout=60
|
|
51
|
+
)
|
|
52
|
+
except (OSError, subprocess.SubprocessError):
|
|
53
|
+
return None
|
|
54
|
+
if out.returncode != 0 or not out.stdout.strip():
|
|
55
|
+
return None
|
|
56
|
+
try:
|
|
57
|
+
return json.loads(out.stdout)
|
|
58
|
+
except json.JSONDecodeError:
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def load_agents(project_root: Path):
|
|
63
|
+
"""Installed agents as {code: entry}. Empty dict (with a flag) on failure."""
|
|
64
|
+
script = project_root / "_bmad" / "scripts" / "resolve_config.py"
|
|
65
|
+
data = _run_json([sys.executable, str(script), "--project-root", str(project_root), "--key", "agents"])
|
|
66
|
+
if data is None:
|
|
67
|
+
return {}, False
|
|
68
|
+
return data.get("agents", {}) or {}, True
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def load_workflow(project_root: Path, skill_root: Path):
|
|
72
|
+
"""Merged [workflow] table. Falls back to the skill's base customize.toml."""
|
|
73
|
+
script = project_root / "_bmad" / "scripts" / "resolve_customization.py"
|
|
74
|
+
data = _run_json([sys.executable, str(script), "--skill", str(skill_root), "--key", "workflow"])
|
|
75
|
+
if data is not None and "workflow" in data:
|
|
76
|
+
return data["workflow"]
|
|
77
|
+
# Fallback: read the skill's base customize.toml directly (no override merge).
|
|
78
|
+
toml_path = skill_root / "customize.toml"
|
|
79
|
+
if toml_path.exists():
|
|
80
|
+
try:
|
|
81
|
+
with toml_path.open("rb") as f:
|
|
82
|
+
return tomllib.load(f).get("workflow", {})
|
|
83
|
+
except (OSError, tomllib.TOMLDecodeError):
|
|
84
|
+
pass
|
|
85
|
+
return {}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _alias(code: str) -> str:
|
|
89
|
+
"""Short alias for an installed agent code: bmad-agent-analyst -> analyst."""
|
|
90
|
+
for prefix in ("bmad-agent-", "bmad-"):
|
|
91
|
+
if code.startswith(prefix):
|
|
92
|
+
return code[len(prefix):]
|
|
93
|
+
return code
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def build_collective(agents: dict, party_members: list):
|
|
97
|
+
"""One pool keyed by code. Custom members override matching installed agents.
|
|
98
|
+
|
|
99
|
+
Returns (collective, index, installed_codes):
|
|
100
|
+
* collective — every member (installed + custom), the pool groups draw
|
|
101
|
+
from and the orchestrator can summon by name.
|
|
102
|
+
* index — maps every resolvable token (code, prefix-stripped alias,
|
|
103
|
+
lower-cased name) to a canonical code.
|
|
104
|
+
* installed_codes — the codes occupying an installed-agent slot, in
|
|
105
|
+
order. This is the DEFAULT room: installed agents (with any custom
|
|
106
|
+
override applied in place), and NOT the pure-custom additions. So
|
|
107
|
+
shipping or defining custom members grows the pool without crowding
|
|
108
|
+
the default party.
|
|
109
|
+
"""
|
|
110
|
+
collective = {}
|
|
111
|
+
index = {}
|
|
112
|
+
installed_codes = []
|
|
113
|
+
|
|
114
|
+
def register(code, entry):
|
|
115
|
+
collective[code] = entry
|
|
116
|
+
index[code] = code
|
|
117
|
+
index[code.lower()] = code
|
|
118
|
+
index[_alias(code).lower()] = code
|
|
119
|
+
name = entry.get("name")
|
|
120
|
+
if name:
|
|
121
|
+
index[name.lower()] = code
|
|
122
|
+
|
|
123
|
+
for code, info in agents.items():
|
|
124
|
+
register(code, {
|
|
125
|
+
"code": code,
|
|
126
|
+
"name": info.get("name", code),
|
|
127
|
+
"icon": info.get("icon", ""),
|
|
128
|
+
"title": info.get("title", ""),
|
|
129
|
+
"description": info.get("description", ""),
|
|
130
|
+
"module": info.get("module", ""),
|
|
131
|
+
"team": info.get("team", ""),
|
|
132
|
+
"source": "installed",
|
|
133
|
+
})
|
|
134
|
+
installed_codes.append(code)
|
|
135
|
+
|
|
136
|
+
for m in (party_members if isinstance(party_members, list) else []):
|
|
137
|
+
if not isinstance(m, dict):
|
|
138
|
+
continue
|
|
139
|
+
code = m.get("code")
|
|
140
|
+
if not code:
|
|
141
|
+
continue
|
|
142
|
+
# A custom member overrides an installed agent it matches by code/alias/name.
|
|
143
|
+
canonical = index.get(code) or index.get(code.lower()) or code
|
|
144
|
+
# Start from the installed entry so fields the override omits
|
|
145
|
+
# (icon, title, description, module, team) survive.
|
|
146
|
+
entry = dict(collective.get(canonical, {}))
|
|
147
|
+
entry.update({"code": canonical, "source": "custom"})
|
|
148
|
+
for field in ("name", "icon", "title", "persona", "capabilities", "model"):
|
|
149
|
+
if m.get(field) is not None:
|
|
150
|
+
entry[field] = m[field]
|
|
151
|
+
entry.setdefault("name", canonical)
|
|
152
|
+
register(canonical, entry)
|
|
153
|
+
# An override keeps the installed slot; a brand-new custom does not join it.
|
|
154
|
+
|
|
155
|
+
return collective, index, installed_codes
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def resolve_members(member_tokens, collective, index):
|
|
159
|
+
"""(resolved entries in listed order, unresolved tokens)."""
|
|
160
|
+
resolved, unresolved = [], []
|
|
161
|
+
for token in member_tokens or []:
|
|
162
|
+
if not isinstance(token, str):
|
|
163
|
+
unresolved.append(token) # malformed config value — never a key lookup
|
|
164
|
+
continue
|
|
165
|
+
code = index.get(token) or index.get(token.lower())
|
|
166
|
+
if code and code in collective:
|
|
167
|
+
resolved.append(collective[code])
|
|
168
|
+
else:
|
|
169
|
+
unresolved.append(token)
|
|
170
|
+
return resolved, unresolved
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def group_menu(groups):
|
|
174
|
+
"""Names only — the cheap menu. Open-cast groups (no roster) are flagged."""
|
|
175
|
+
out = []
|
|
176
|
+
for g in groups or []:
|
|
177
|
+
if not isinstance(g, dict) or not g.get("id"):
|
|
178
|
+
continue
|
|
179
|
+
members = g.get("members", []) or []
|
|
180
|
+
entry = {"id": g["id"], "name": g.get("name", g["id"]),
|
|
181
|
+
"member_count": len(members)}
|
|
182
|
+
if not members:
|
|
183
|
+
entry["open_cast"] = True
|
|
184
|
+
out.append(entry)
|
|
185
|
+
return out
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def find_group(groups, group_id):
|
|
189
|
+
for g in groups or []:
|
|
190
|
+
if isinstance(g, dict) and g.get("id") == group_id:
|
|
191
|
+
return g
|
|
192
|
+
return None
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def group_detail(g, collective, index):
|
|
196
|
+
"""Full detail for one group: resolved members + the optional scene.
|
|
197
|
+
|
|
198
|
+
`scene` is a freeform line the orchestrator plays — setting, what's
|
|
199
|
+
happening, room dynamics, in-the-moment character notes. Surfaced only
|
|
200
|
+
here (when a group is the active/chosen roster), never in the menu.
|
|
201
|
+
|
|
202
|
+
`members` is optional. With none, the group is open-cast: `open_cast`
|
|
203
|
+
is flagged and the scene describes the pool the orchestrator casts from
|
|
204
|
+
on the fly (e.g. "figures from the Star Wars Rebels universe"). A few
|
|
205
|
+
listed members anchor the room; the scene can still invite more.
|
|
206
|
+
"""
|
|
207
|
+
raw_members = g.get("members", []) or []
|
|
208
|
+
members, unresolved = resolve_members(raw_members, collective, index)
|
|
209
|
+
detail = {"active": g["id"], "name": g.get("name", g["id"]),
|
|
210
|
+
"members": members, "unresolved": unresolved,
|
|
211
|
+
"memory_enabled": bool(g.get("memory", False))}
|
|
212
|
+
if g.get("scene"):
|
|
213
|
+
detail["scene"] = g["scene"]
|
|
214
|
+
if not raw_members:
|
|
215
|
+
detail["open_cast"] = True
|
|
216
|
+
return detail
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def main():
|
|
220
|
+
ap = argparse.ArgumentParser(description="Resolve the party-mode roster, lazily.")
|
|
221
|
+
ap.add_argument("--project-root", required=True)
|
|
222
|
+
ap.add_argument("--skill", required=True, help="Path to the bmad-party-mode skill dir")
|
|
223
|
+
ap.add_argument("--party", help="Resolve full detail for this group id")
|
|
224
|
+
ap.add_argument("--list-groups", action="store_true", help="Group names only")
|
|
225
|
+
args = ap.parse_args()
|
|
226
|
+
|
|
227
|
+
project_root = Path(args.project_root).resolve()
|
|
228
|
+
skill_root = Path(args.skill).resolve()
|
|
229
|
+
|
|
230
|
+
workflow = load_workflow(project_root, skill_root)
|
|
231
|
+
groups = workflow.get("party_groups", []) or []
|
|
232
|
+
default_party = workflow.get("default_party", "") or ""
|
|
233
|
+
party_mode = workflow.get("party_mode", "session") or "session"
|
|
234
|
+
# The global party_memory flag governs only the DEFAULT installed-agent room;
|
|
235
|
+
# a named group carries its own `memory` flag (resolved in group_detail).
|
|
236
|
+
party_memory = bool(workflow.get("party_memory", True))
|
|
237
|
+
|
|
238
|
+
# Group menu never needs the (more expensive) installed-agent resolve.
|
|
239
|
+
if args.list_groups:
|
|
240
|
+
_emit({
|
|
241
|
+
"party_mode": party_mode,
|
|
242
|
+
"default_party": default_party,
|
|
243
|
+
"groups": group_menu(groups),
|
|
244
|
+
})
|
|
245
|
+
return
|
|
246
|
+
|
|
247
|
+
agents, agents_ok = load_agents(project_root)
|
|
248
|
+
collective, index, installed_codes = build_collective(agents, workflow.get("party_members", []))
|
|
249
|
+
|
|
250
|
+
if args.party:
|
|
251
|
+
g = find_group(groups, args.party)
|
|
252
|
+
if g is None:
|
|
253
|
+
_emit({"error": "unknown_group", "requested": args.party,
|
|
254
|
+
"available": group_menu(groups)})
|
|
255
|
+
return
|
|
256
|
+
_emit({**group_detail(g, collective, index), "party_mode": party_mode})
|
|
257
|
+
return
|
|
258
|
+
|
|
259
|
+
# Default: the active roster to load on entry.
|
|
260
|
+
result = {"party_mode": party_mode, "groups": group_menu(groups),
|
|
261
|
+
"installed_agents_resolved": agents_ok}
|
|
262
|
+
g = find_group(groups, default_party) if default_party else None
|
|
263
|
+
if g is not None:
|
|
264
|
+
result.update(group_detail(g, collective, index))
|
|
265
|
+
else:
|
|
266
|
+
# No default group: the installed agents (custom additions stay in the
|
|
267
|
+
# pool but don't crowd the default room), exactly like a plain install.
|
|
268
|
+
result.update({"active": "installed",
|
|
269
|
+
"members": [collective[c] for c in installed_codes],
|
|
270
|
+
"memory_enabled": party_memory})
|
|
271
|
+
_emit(result)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def _emit(obj):
|
|
275
|
+
reconfigure = getattr(sys.stdout, "reconfigure", None)
|
|
276
|
+
if reconfigure is not None:
|
|
277
|
+
reconfigure(encoding="utf-8")
|
|
278
|
+
sys.stdout.write(json.dumps(obj, indent=2, ensure_ascii=False) + "\n")
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
if __name__ == "__main__":
|
|
282
|
+
main()
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# /// script
|
|
3
|
+
# requires-python = ">=3.11"
|
|
4
|
+
# ///
|
|
5
|
+
"""Unit tests for resolve_party.py — merge, alias, override, group resolution."""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
import unittest
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
12
|
+
import resolve_party as rp # noqa: E402
|
|
13
|
+
|
|
14
|
+
AGENTS = {
|
|
15
|
+
"bmad-agent-analyst": {"name": "Mary", "icon": "📊", "title": "Analyst"},
|
|
16
|
+
"bmad-agent-pm": {"name": "John", "icon": "📋", "title": "PM"},
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TestAlias(unittest.TestCase):
|
|
21
|
+
def test_strips_known_prefixes(self):
|
|
22
|
+
self.assertEqual(rp._alias("bmad-agent-analyst"), "analyst")
|
|
23
|
+
self.assertEqual(rp._alias("bmad-foo"), "foo")
|
|
24
|
+
|
|
25
|
+
def test_passes_through_unprefixed(self):
|
|
26
|
+
self.assertEqual(rp._alias("morpheus"), "morpheus")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TestBuildCollective(unittest.TestCase):
|
|
30
|
+
def test_installed_agents_indexed_by_code_alias_and_name(self):
|
|
31
|
+
col, idx, _ = rp.build_collective(AGENTS, [])
|
|
32
|
+
self.assertEqual(set(col), {"bmad-agent-analyst", "bmad-agent-pm"})
|
|
33
|
+
self.assertEqual(idx["analyst"], "bmad-agent-analyst") # alias
|
|
34
|
+
self.assertEqual(idx["mary"], "bmad-agent-analyst") # name (ci)
|
|
35
|
+
self.assertEqual(idx["bmad-agent-pm"], "bmad-agent-pm") # full code
|
|
36
|
+
self.assertEqual(col["bmad-agent-analyst"]["source"], "installed")
|
|
37
|
+
|
|
38
|
+
def test_custom_member_appends(self):
|
|
39
|
+
col, _, _ = rp.build_collective(AGENTS, [{"code": "morpheus", "name": "Morpheus", "persona": "riddles"}])
|
|
40
|
+
self.assertIn("morpheus", col)
|
|
41
|
+
self.assertEqual(col["morpheus"]["source"], "custom")
|
|
42
|
+
self.assertEqual(col["morpheus"]["persona"], "riddles")
|
|
43
|
+
|
|
44
|
+
def test_custom_overrides_installed_by_alias(self):
|
|
45
|
+
col, _, _ = rp.build_collective(AGENTS, [{"code": "analyst", "name": "Mary-Custom", "persona": "p"}])
|
|
46
|
+
# Override lands on the canonical installed code, not a new "analyst" entry.
|
|
47
|
+
self.assertNotIn("analyst", col)
|
|
48
|
+
self.assertEqual(col["bmad-agent-analyst"]["source"], "custom")
|
|
49
|
+
self.assertEqual(col["bmad-agent-analyst"]["name"], "Mary-Custom")
|
|
50
|
+
|
|
51
|
+
def test_member_without_code_skipped(self):
|
|
52
|
+
col, _, _ = rp.build_collective(AGENTS, [{"name": "Nameless"}])
|
|
53
|
+
self.assertEqual(set(col), {"bmad-agent-analyst", "bmad-agent-pm"})
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class TestResolveMembers(unittest.TestCase):
|
|
57
|
+
def setUp(self):
|
|
58
|
+
self.col, self.idx, _ = rp.build_collective(AGENTS, [{"code": "morpheus", "name": "Morpheus"}])
|
|
59
|
+
|
|
60
|
+
def test_resolves_in_listed_order_and_flags_unknowns(self):
|
|
61
|
+
resolved, unresolved = rp.resolve_members(["morpheus", "analyst", "ghost"], self.col, self.idx)
|
|
62
|
+
self.assertEqual([m["code"] for m in resolved], ["morpheus", "bmad-agent-analyst"])
|
|
63
|
+
self.assertEqual(unresolved, ["ghost"])
|
|
64
|
+
|
|
65
|
+
def test_empty(self):
|
|
66
|
+
self.assertEqual(rp.resolve_members([], self.col, self.idx), ([], []))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class TestGroups(unittest.TestCase):
|
|
70
|
+
GROUPS = [
|
|
71
|
+
{"id": "wr", "name": "Writers", "members": ["analyst", "morpheus"]},
|
|
72
|
+
{"id": "bad"}, # no name -> falls back to id; no members -> count 0
|
|
73
|
+
{"name": "no-id"}, # dropped from menu
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
def test_menu_is_names_only_with_counts_and_open_cast_flag(self):
|
|
77
|
+
menu = rp.group_menu(self.GROUPS)
|
|
78
|
+
self.assertEqual(menu, [
|
|
79
|
+
{"id": "wr", "name": "Writers", "member_count": 2},
|
|
80
|
+
{"id": "bad", "name": "bad", "member_count": 0, "open_cast": True},
|
|
81
|
+
])
|
|
82
|
+
|
|
83
|
+
def test_find_group(self):
|
|
84
|
+
self.assertEqual(rp.find_group(self.GROUPS, "wr")["name"], "Writers")
|
|
85
|
+
self.assertIsNone(rp.find_group(self.GROUPS, "missing"))
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class TestGroupDetail(unittest.TestCase):
|
|
89
|
+
def setUp(self):
|
|
90
|
+
self.col, self.idx, _ = rp.build_collective(AGENTS, [{"code": "morpheus", "name": "Morpheus"}])
|
|
91
|
+
|
|
92
|
+
def test_scene_passes_through_when_present(self):
|
|
93
|
+
g = {"id": "tos-10-forward", "name": "Ten Forward", "members": ["morpheus"],
|
|
94
|
+
"scene": "Late evening, a few rounds in."}
|
|
95
|
+
d = rp.group_detail(g, self.col, self.idx)
|
|
96
|
+
self.assertEqual(d["scene"], "Late evening, a few rounds in.")
|
|
97
|
+
self.assertEqual([m["code"] for m in d["members"]], ["morpheus"])
|
|
98
|
+
|
|
99
|
+
def test_scene_omitted_when_absent_or_empty(self):
|
|
100
|
+
for g in ({"id": "g", "members": ["morpheus"]},
|
|
101
|
+
{"id": "g", "members": ["morpheus"], "scene": ""}):
|
|
102
|
+
self.assertNotIn("scene", rp.group_detail(g, self.col, self.idx))
|
|
103
|
+
|
|
104
|
+
def test_anchored_group_is_not_open_cast(self):
|
|
105
|
+
g = {"id": "g", "members": ["morpheus"]}
|
|
106
|
+
self.assertNotIn("open_cast", rp.group_detail(g, self.col, self.idx))
|
|
107
|
+
|
|
108
|
+
def test_open_cast_group_flagged_with_empty_members(self):
|
|
109
|
+
g = {"id": "rebels", "name": "Star Wars Rebels",
|
|
110
|
+
"scene": "Figures from the Rebels universe drop in as the topic calls for them."}
|
|
111
|
+
d = rp.group_detail(g, self.col, self.idx)
|
|
112
|
+
self.assertTrue(d["open_cast"])
|
|
113
|
+
self.assertEqual(d["members"], [])
|
|
114
|
+
self.assertEqual(d["scene"][:7], "Figures")
|
|
115
|
+
|
|
116
|
+
def test_memory_enabled_follows_group_flag_and_defaults_off(self):
|
|
117
|
+
on = rp.group_detail({"id": "g", "members": ["morpheus"], "memory": True}, self.col, self.idx)
|
|
118
|
+
self.assertTrue(on["memory_enabled"])
|
|
119
|
+
off = rp.group_detail({"id": "g", "members": ["morpheus"], "memory": False}, self.col, self.idx)
|
|
120
|
+
self.assertFalse(off["memory_enabled"])
|
|
121
|
+
absent = rp.group_detail({"id": "g", "members": ["morpheus"]}, self.col, self.idx)
|
|
122
|
+
self.assertFalse(absent["memory_enabled"]) # opt-in per named group
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class TestInstalledCodesIsDefaultRoom(unittest.TestCase):
|
|
126
|
+
"""The default room is installed agents only; pure customs stay in the pool."""
|
|
127
|
+
|
|
128
|
+
def test_pure_custom_excluded_override_kept_in_default_room(self):
|
|
129
|
+
col, _, installed = rp.build_collective(AGENTS, [
|
|
130
|
+
{"code": "morpheus", "name": "Morpheus"}, # pure custom
|
|
131
|
+
{"code": "analyst", "name": "Mary-Custom", "persona": "p"}, # override
|
|
132
|
+
{"code": "sec-hawk", "name": "Vex"}, # shipped crew member
|
|
133
|
+
])
|
|
134
|
+
# Pure customs are in the pool...
|
|
135
|
+
self.assertIn("morpheus", col)
|
|
136
|
+
self.assertIn("sec-hawk", col)
|
|
137
|
+
# ...but NOT in the default room.
|
|
138
|
+
self.assertEqual(installed, ["bmad-agent-analyst", "bmad-agent-pm"])
|
|
139
|
+
default_room = [col[c]["code"] for c in installed]
|
|
140
|
+
self.assertEqual(default_room, ["bmad-agent-analyst", "bmad-agent-pm"])
|
|
141
|
+
# An override keeps its installed slot (and its custom content).
|
|
142
|
+
self.assertEqual(col["bmad-agent-analyst"]["name"], "Mary-Custom")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
if __name__ == "__main__":
|
|
146
|
+
unittest.main()
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bmad-review
|
|
3
|
+
description: 'Multi-lens review over any diff, doc, spec, or artifact — whichever installed lenses fit the content, run singly or together. Shipped lenses include adversarial, edge-case, verification-gap, structure, and prose. Use when the user says "review this", "critical review", "editorial review", "hunt edge cases", "review the structure", or "review the prose".'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# BMad Review
|
|
7
|
+
|
|
8
|
+
Review content through lenses — each a distinct method and stance — and report findings in one canonical shape. Report what is real — never pad to look thorough. Each lens sets its own stance toward the content and toward zero findings: for most an empty result is valid; the adversarial lens requires at least ten concrete findings and treats an empty list as a signal to re-check; the editorial lenses hold content sacrosanct and critique only how it is organized and expressed.
|
|
9
|
+
|
|
10
|
+
The lens set is whatever `{workflow.lenses}` resolves to, not a fixed list — overrides add lenses and replace shipped ones. Never claim a capability from this file; read the resolved lenses and work from those.
|
|
11
|
+
|
|
12
|
+
## Inputs
|
|
13
|
+
|
|
14
|
+
- **content** — what to review: a diff, branch, uncommitted changes, file, spec, story, or any document. Args: `[path]`.
|
|
15
|
+
- **lenses** (optional) — one or more lens codes or names, however the caller expresses them: a spoken request, or a directive of the form `skill:bmad-review lenses=<code>[,<code>...]` (the form bmm's `doc_standards` uses). Default: every applicable lens (a full review).
|
|
16
|
+
- **also_consider** (optional) — areas to keep in mind alongside each lens's normal analysis.
|
|
17
|
+
- **pre-resolved customization** (optional) — `[workflow]` field values supplied by a forwarding caller. See Execution step 1.
|
|
18
|
+
|
|
19
|
+
## Conventions
|
|
20
|
+
|
|
21
|
+
- Bare paths (e.g. `references/lens-edge-case-hunter.md`) resolve from `{skill-root}` — this skill's installed directory, where `customize.toml` lives. `{project-root}` resolves to the project working directory.
|
|
22
|
+
- `{workflow.<name>}` resolves to fields in `customize.toml`'s `[workflow]` table (overrides win per BMad merge rules).
|
|
23
|
+
- In `style_guide`, `review_guidance`, and `persistent_facts`, a value prefixed `file:` is a path or glob — load that file's contents. If a `file:` value cannot be read, name the failed file in the output header and continue: the shipped baseline for `style_guide`, the remaining entries otherwise.
|
|
24
|
+
|
|
25
|
+
## Execution
|
|
26
|
+
|
|
27
|
+
1. **Resolve customization:** `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults. **Forwarded activation:** if a caller invoked you with pre-resolved customization fields (e.g. the `bmad-editorial-review` shim), honor them verbatim for those named fields — they already carry the user's overrides — and resolve only the remaining fields from your own `customize.toml`. Then execute each `{workflow.activation_steps_prepend}` entry in order, hold `{workflow.persistent_facts}` as standing context for the session, and treat `{workflow.review_guidance}` entries as standing review directives for every lens.
|
|
28
|
+
2. **Load the content.** If it is empty or cannot be decoded as text: when the caller expects the raw findings JSON array (e.g. the legacy edge-case forwarder), return `[{"location":"N/A","trigger_condition":"Input empty or undecodable","guard_snippet":"Provide valid content to review","potential_consequence":"Review skipped — no analysis performed"}]` (no `lens` field) and stop; otherwise say what's wrong and ask for reviewable content. Classify the content — diff, source file, function, or document — and whether it is **code** or **docs**; scope rules and lens applicability both depend on it. A document that defines behavior (spec, requirements, plan, story) is `docs` that a behavioral lens may still apply to; judge by `when`.
|
|
29
|
+
3. **Select lenses** from `{workflow.lenses}`. A lens with an empty `instruction` is disabled. If the user or caller named lenses, run exactly those only — `applies_to` and `when` do not filter an explicit request. Otherwise run every enabled lens whose `applies_to` covers the content class (`any` always covers) and whose `when` applies.
|
|
30
|
+
4. **Announce the plan** in one line before running anything: the content class, the lenses about to run, and — when any lens has `after` set — that it runs on top of the named lens's findings. Skip the announcement entirely when the caller pinned an exact output contract (the legacy forwarders that demand raw JSON or one exact line) — their contract covers everything you emit, not just the findings block. Then execute each `{workflow.activation_steps_append}` entry in order.
|
|
31
|
+
5. **Run the independent lenses** — every selected lens without `after`. Each sees the content and `also_consider`, never another lens's findings. Follow each lens's `instruction`; the shipped lenses load their reference file just-in-time, so load only what runs. When subagents are available, spawn one per lens in parallel: give it the lens `instruction` with `{skill-root}` and paths resolved absolute, the content or where to read it, any `also_consider` areas, the standing review directives, and the constraint "Return ONLY your findings — no other output." Otherwise run the lenses sequentially yourself, completing one before starting the next.
|
|
32
|
+
6. **Run the dependent lenses** — every selected lens with `after`, once the lens it names has completed, passing that lens's findings in. A lens whose `after` target was not selected or produced nothing still runs, with no prior findings. Dependent lenses that name different targets are independent of each other and may run in parallel.
|
|
33
|
+
7. **Assemble and present** per Output below. Keep every lens's findings — overlap between lenses is signal, not duplication; note it in the markdown report rather than deduping. Execute `{workflow.on_complete}` if set.
|
|
34
|
+
|
|
35
|
+
## Output
|
|
36
|
+
|
|
37
|
+
One JSON array holding every finding from every lens. Each finding carries:
|
|
38
|
+
|
|
39
|
+
- `lens` — the code of the lens that produced it
|
|
40
|
+
- `location` — where in the content (file:line-range for code, section for documents)
|
|
41
|
+
- `trigger_condition` — the problem, or the condition that exposes it, in one line
|
|
42
|
+
- `guard_snippet` — the concrete fix, guard, or missing check
|
|
43
|
+
- `potential_consequence` — what goes wrong if it ships as-is
|
|
44
|
+
|
|
45
|
+
Each lens file refines these semantics for its findings and may add lens-specific fields (e.g. `kind`/`confidence` on deletion findings, `gap_shape`/`consumer`/`evidence` on verification-gap findings). A lens file may instead declare its own findings shape and rendering — the editorial lenses render a findings table — and that shape wins for that lens's findings. `[]` is valid when nothing is found. No severity, priority, or ranking anywhere.
|
|
46
|
+
|
|
47
|
+
Present per `{workflow.output_format}` — `"json"` (the raw array in a fenced json block), `"markdown"`, or `"both"` — unless the caller requested a specific shape; a legacy forwarder's output contract always wins, and governs everything you emit rather than the findings block alone. The markdown report groups findings by lens, each rendered in its declared shape: a short block per finding rendering the fields plus any extras worth surfacing, one line for a lens that found nothing, and a plain clean statement when the whole review is clean. Shape the report per `{workflow.output_preferences}`.
|
|
48
|
+
|
|
49
|
+
When `{workflow.report_path}` is set, write the report there; otherwise present it in chat.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# DO NOT EDIT -- overwritten on every update.
|
|
2
|
+
#
|
|
3
|
+
# Workflow customization surface for bmad-review.
|
|
4
|
+
#
|
|
5
|
+
# Override files (not edited here):
|
|
6
|
+
# {project-root}/_bmad/custom/bmad-review.toml (team)
|
|
7
|
+
# {project-root}/_bmad/custom/bmad-review.user.toml (personal)
|
|
8
|
+
|
|
9
|
+
[workflow]
|
|
10
|
+
|
|
11
|
+
# --- Configurable below. Overrides merge per BMad structural rules: ---
|
|
12
|
+
# scalars: override wins
|
|
13
|
+
# arrays (persistent_facts, activation_steps_*, review_guidance): append
|
|
14
|
+
# arrays of tables keyed by `code`: matching key replaces, new keys append
|
|
15
|
+
|
|
16
|
+
# Steps executed on activation: prepend runs before the skill's own
|
|
17
|
+
# activation flow, append runs after the lens plan is settled and before the
|
|
18
|
+
# lenses run. Each entry is a literal instruction.
|
|
19
|
+
activation_steps_prepend = []
|
|
20
|
+
activation_steps_append = []
|
|
21
|
+
|
|
22
|
+
# Standing context held for every review, code and document alike. Entries
|
|
23
|
+
# prefixed `file:` are paths or globs whose contents load as facts; all others
|
|
24
|
+
# are literal facts. The shipped entry is a project-wide glob — set it to []
|
|
25
|
+
# if you don't want every review scanning for it.
|
|
26
|
+
persistent_facts = ["file:{project-root}/**/project-context.md"]
|
|
27
|
+
|
|
28
|
+
# Standing review directives applied on every run alongside each lens's own
|
|
29
|
+
# method. Each entry is a literal sentence or a `file:`-prefixed path/glob
|
|
30
|
+
# whose contents load as directives.
|
|
31
|
+
#
|
|
32
|
+
# Examples:
|
|
33
|
+
# "Flag passive voice in headings."
|
|
34
|
+
# "Second-person imperative is the house voice; never suggest changing it."
|
|
35
|
+
# "file:{project-root}/docs/terminology.md"
|
|
36
|
+
review_guidance = []
|
|
37
|
+
|
|
38
|
+
# Executed after the findings are delivered. Freeform directive; empty = the
|
|
39
|
+
# review ends with the findings.
|
|
40
|
+
#
|
|
41
|
+
# Example:
|
|
42
|
+
# on_complete = "Append a one-line review summary to {project-root}/docs/review-log.md"
|
|
43
|
+
on_complete = ""
|
|
44
|
+
|
|
45
|
+
# How findings are presented when the caller doesn't say: "json" (the raw
|
|
46
|
+
# findings array only), "markdown" (the human report only), or "both". A lens
|
|
47
|
+
# that declares its own rendering keeps it for its own findings.
|
|
48
|
+
output_format = "both"
|
|
49
|
+
|
|
50
|
+
# Where to write the review report. Empty = present in chat only. Accepts
|
|
51
|
+
# {project-root}-prefixed paths.
|
|
52
|
+
report_path = ""
|
|
53
|
+
|
|
54
|
+
# How findings are presented — shaping, not destination. Freeform directive;
|
|
55
|
+
# empty = each lens's default ordering and rollup.
|
|
56
|
+
#
|
|
57
|
+
# Example:
|
|
58
|
+
# output_preferences = "Cap output at the 20 highest-impact findings."
|
|
59
|
+
output_preferences = ""
|
|
60
|
+
|
|
61
|
+
# --- Editorial lens settings (used by the structure and prose lenses) ---
|
|
62
|
+
|
|
63
|
+
# Default reader the editorial lenses calibrate for when the request doesn't
|
|
64
|
+
# say:
|
|
65
|
+
# "humans" clarity, flow, comprehension aids preserved
|
|
66
|
+
# "llm" precision, consistent terminology, no hedging
|
|
67
|
+
# A reader type stated in the request wins for that run.
|
|
68
|
+
reader_type = "humans"
|
|
69
|
+
|
|
70
|
+
# The baseline style guide for every editorial review: the name of a guide the
|
|
71
|
+
# model knows well, a `file:`-prefixed path to a style guide document, or the
|
|
72
|
+
# rules inline as text. A style guide stated in the request wins for that run.
|
|
73
|
+
# Where the guide in effect conflicts with the lens's generic principles, the
|
|
74
|
+
# guide wins — except content is sacrosanct.
|
|
75
|
+
#
|
|
76
|
+
# Examples (set in team/user override TOML):
|
|
77
|
+
# style_guide = "file:{project-root}/_bmad/style-guides/company-voice.md"
|
|
78
|
+
# style_guide = "Sentence-case headings. No Oxford comma. Address the reader as 'you'."
|
|
79
|
+
style_guide = "Microsoft Writing Style Guide"
|
|
80
|
+
|
|
81
|
+
# ---------------------------------------------------------------------------
|
|
82
|
+
# Review lenses. Each lens is a pass over the content with its own method and
|
|
83
|
+
# stance. `instruction` is the lens's whole execution recipe — the shipped
|
|
84
|
+
# lenses load a reference file from the skill root, but an override may inline
|
|
85
|
+
# any prompt.
|
|
86
|
+
#
|
|
87
|
+
# `applies_to` is the content this lens can review: "code", "docs", or "any".
|
|
88
|
+
# It is the first filter — a lens never joins a default review for content it
|
|
89
|
+
# does not apply to. `when` (optional) refines that judgement in prose. An
|
|
90
|
+
# explicitly requested lens always runs, whatever both say.
|
|
91
|
+
#
|
|
92
|
+
# `after` (optional) names a lens this one builds on: it runs once that lens
|
|
93
|
+
# has completed and receives its findings, instead of running independently.
|
|
94
|
+
#
|
|
95
|
+
# Empty `instruction` disables a lens. Keyed by `code`: an override with a
|
|
96
|
+
# matching code replaces the shipped lens, a new code appends.
|
|
97
|
+
#
|
|
98
|
+
# Example (add an org-specific lens in team/user override TOML):
|
|
99
|
+
# [[workflow.lenses]]
|
|
100
|
+
# code = "accessibility"
|
|
101
|
+
# name = "Accessibility"
|
|
102
|
+
# applies_to = "any"
|
|
103
|
+
# when = "UI code or user-facing documents."
|
|
104
|
+
# instruction = "Review against WCAG 2.2 AA. Emit findings in the canonical fields."
|
|
105
|
+
# ---------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
[[workflow.lenses]]
|
|
108
|
+
code = "adversarial"
|
|
109
|
+
name = "Adversarial"
|
|
110
|
+
applies_to = "any"
|
|
111
|
+
when = "always"
|
|
112
|
+
instruction = "Load `references/lens-adversarial.md` from the skill root and follow it."
|
|
113
|
+
|
|
114
|
+
[[workflow.lenses]]
|
|
115
|
+
code = "edge-case-hunter"
|
|
116
|
+
name = "Edge-Case Hunter"
|
|
117
|
+
applies_to = "any"
|
|
118
|
+
when = "Content with behavior to trace: code, diffs, and the specs, requirements, plans, and stories that define behavior. Skip for prose documents with no behavioral surface."
|
|
119
|
+
instruction = "Load `references/lens-edge-case-hunter.md` from the skill root and follow it."
|
|
120
|
+
|
|
121
|
+
[[workflow.lenses]]
|
|
122
|
+
code = "verification-gap"
|
|
123
|
+
name = "Verification Gap"
|
|
124
|
+
applies_to = "code"
|
|
125
|
+
when = "Reviewed inside a repo where tests can be searched and read."
|
|
126
|
+
instruction = "Load `references/lens-verification-gap.md` from the skill root and follow it."
|
|
127
|
+
|
|
128
|
+
[[workflow.lenses]]
|
|
129
|
+
code = "structure"
|
|
130
|
+
name = "Editorial Structure"
|
|
131
|
+
applies_to = "docs"
|
|
132
|
+
when = "Documents whose shape is the author's to change."
|
|
133
|
+
instruction = "Load `references/lens-structure.md` from the skill root and follow it."
|
|
134
|
+
|
|
135
|
+
[[workflow.lenses]]
|
|
136
|
+
code = "prose"
|
|
137
|
+
name = "Editorial Prose"
|
|
138
|
+
applies_to = "docs"
|
|
139
|
+
after = "structure"
|
|
140
|
+
when = "Documents being copy-edited."
|
|
141
|
+
instruction = "Load `references/lens-prose.md` from the skill root and follow it."
|