scaffold-ca-python 0.4.0__tar.gz → 0.5.0__tar.gz

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.
Files changed (413) hide show
  1. scaffold_ca_python-0.5.0/.release-please-manifest.json +3 -0
  2. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/CHANGELOG.md +7 -0
  3. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/PKG-INFO +1 -1
  4. scaffold_ca_python-0.5.0/specs/027-mcp-health-check/checklists/requirements.md +36 -0
  5. scaffold_ca_python-0.5.0/specs/027-mcp-health-check/contracts/generated-routes.md +83 -0
  6. scaffold_ca_python-0.5.0/specs/027-mcp-health-check/data-model.md +31 -0
  7. scaffold_ca_python-0.5.0/specs/027-mcp-health-check/plan.md +106 -0
  8. scaffold_ca_python-0.5.0/specs/027-mcp-health-check/quickstart.md +65 -0
  9. scaffold_ca_python-0.5.0/specs/027-mcp-health-check/research.md +63 -0
  10. scaffold_ca_python-0.5.0/specs/027-mcp-health-check/spec.md +147 -0
  11. scaffold_ca_python-0.5.0/specs/027-mcp-health-check/tasks.md +220 -0
  12. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/entry_points/ep_mcp.py +13 -0
  13. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/mcp/app.py.jinja2 +2 -1
  14. scaffold_ca_python-0.5.0/src/scaffold_ca_python/templates/entry_point/mcp/routes.py.jinja2 +25 -0
  15. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/mcp/test_app.py.jinja2 +17 -0
  16. scaffold_ca_python-0.5.0/src/scaffold_ca_python/templates/entry_point/mcp/test_routes.py.jinja2 +25 -0
  17. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_generate_entry_point.py +35 -0
  18. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/entry_points/test_ep_mcp.py +30 -0
  19. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/fixtures/dry_run_baseline.json +2 -0
  20. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/templates/test_entry_point_templates.py +79 -0
  21. scaffold_ca_python-0.4.0/.release-please-manifest.json +0 -3
  22. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.claude/skills/speckit-analyze/SKILL.md +0 -0
  23. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.claude/skills/speckit-checklist/SKILL.md +0 -0
  24. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.claude/skills/speckit-clarify/SKILL.md +0 -0
  25. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.claude/skills/speckit-constitution/SKILL.md +0 -0
  26. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.claude/skills/speckit-converge/SKILL.md +0 -0
  27. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.claude/skills/speckit-implement/SKILL.md +0 -0
  28. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.claude/skills/speckit-plan/SKILL.md +0 -0
  29. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.claude/skills/speckit-specify/SKILL.md +0 -0
  30. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.claude/skills/speckit-tasks/SKILL.md +0 -0
  31. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.claude/skills/speckit-taskstoissues/SKILL.md +0 -0
  32. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.cursor/skills/speckit-analyze/SKILL.md +0 -0
  33. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.cursor/skills/speckit-checklist/SKILL.md +0 -0
  34. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.cursor/skills/speckit-clarify/SKILL.md +0 -0
  35. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.cursor/skills/speckit-constitution/SKILL.md +0 -0
  36. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.cursor/skills/speckit-converge/SKILL.md +0 -0
  37. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.cursor/skills/speckit-implement/SKILL.md +0 -0
  38. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.cursor/skills/speckit-plan/SKILL.md +0 -0
  39. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.cursor/skills/speckit-specify/SKILL.md +0 -0
  40. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.cursor/skills/speckit-tasks/SKILL.md +0 -0
  41. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.cursor/skills/speckit-taskstoissues/SKILL.md +0 -0
  42. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/copilot-instructions.md +0 -0
  43. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/issue_template.md +0 -0
  44. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/pull_request_template.md +0 -0
  45. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/skills/speckit-analyze/SKILL.md +0 -0
  46. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/skills/speckit-checklist/SKILL.md +0 -0
  47. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/skills/speckit-clarify/SKILL.md +0 -0
  48. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/skills/speckit-constitution/SKILL.md +0 -0
  49. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/skills/speckit-converge/SKILL.md +0 -0
  50. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/skills/speckit-implement/SKILL.md +0 -0
  51. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/skills/speckit-plan/SKILL.md +0 -0
  52. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/skills/speckit-specify/SKILL.md +0 -0
  53. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/skills/speckit-tasks/SKILL.md +0 -0
  54. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/skills/speckit-taskstoissues/SKILL.md +0 -0
  55. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/workflows/build.yml +0 -0
  56. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/workflows/dependency-review.yml +0 -0
  57. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/workflows/publish.yml +0 -0
  58. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/workflows/release-please.yml +0 -0
  59. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/workflows/scorecards-analysis.yml +0 -0
  60. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.github/workflows/secret-scanner.yml +0 -0
  61. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.gitignore +0 -0
  62. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.pre-commit-config.yaml +0 -0
  63. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.python-version +0 -0
  64. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/.gitignore +0 -0
  65. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/init-options.json +0 -0
  66. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/integration.json +0 -0
  67. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/integrations/claude.manifest.json +0 -0
  68. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/integrations/copilot.manifest.json +0 -0
  69. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/integrations/cursor-agent.manifest.json +0 -0
  70. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/integrations/speckit.manifest.json +0 -0
  71. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/memory/constitution.md +0 -0
  72. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/scripts/bash/check-prerequisites.sh +0 -0
  73. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/scripts/bash/common.sh +0 -0
  74. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/scripts/bash/create-new-feature.sh +0 -0
  75. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/scripts/bash/resolve-template.sh +0 -0
  76. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/scripts/bash/setup-plan.sh +0 -0
  77. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/scripts/bash/setup-tasks.sh +0 -0
  78. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/scripts/bash/update-agent-context.sh +0 -0
  79. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/templates/agent-file-template.md +0 -0
  80. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/templates/checklist-template.md +0 -0
  81. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/templates/constitution-template.md +0 -0
  82. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/templates/plan-template.md +0 -0
  83. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/templates/spec-template.md +0 -0
  84. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/.specify/templates/tasks-template.md +0 -0
  85. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/LICENSE +0 -0
  86. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/README.md +0 -0
  87. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/SECURITY.md +0 -0
  88. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/pyproject.toml +0 -0
  89. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/release-please-config.json +0 -0
  90. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/checklists/requirements.md +0 -0
  91. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/contracts/ca.md +0 -0
  92. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/contracts/dm.md +0 -0
  93. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/contracts/gda.md +0 -0
  94. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/contracts/gep.md +0 -0
  95. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/contracts/gh.md +0 -0
  96. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/contracts/gm.md +0 -0
  97. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/contracts/gpipe.md +0 -0
  98. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/contracts/guc.md +0 -0
  99. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/contracts/up.md +0 -0
  100. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/contracts/vs.md +0 -0
  101. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/data-model.md +0 -0
  102. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/plan.md +0 -0
  103. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/quickstart.md +0 -0
  104. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/research.md +0 -0
  105. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/spec.md +0 -0
  106. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/004-scaffold-ca-python-cli/tasks.md +0 -0
  107. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/006-ca-scaffold-enhancements/checklists/requirements.md +0 -0
  108. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/006-ca-scaffold-enhancements/plan.md +0 -0
  109. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/006-ca-scaffold-enhancements/spec.md +0 -0
  110. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/006-ca-scaffold-enhancements/tasks.md +0 -0
  111. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/007-cli-usability-enhancements/checklists/requirements.md +0 -0
  112. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/007-cli-usability-enhancements/contracts/clean-architecture.md +0 -0
  113. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/007-cli-usability-enhancements/contracts/gda.md +0 -0
  114. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/007-cli-usability-enhancements/contracts/gep.md +0 -0
  115. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/007-cli-usability-enhancements/contracts/gpipe.md +0 -0
  116. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/007-cli-usability-enhancements/data-model.md +0 -0
  117. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/007-cli-usability-enhancements/plan.md +0 -0
  118. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/007-cli-usability-enhancements/quickstart.md +0 -0
  119. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/007-cli-usability-enhancements/research.md +0 -0
  120. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/007-cli-usability-enhancements/spec.md +0 -0
  121. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/007-cli-usability-enhancements/tasks.md +0 -0
  122. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/008-fastapi-entrypoint-baseline/checklists/requirements.md +0 -0
  123. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/008-fastapi-entrypoint-baseline/contracts/gep.md +0 -0
  124. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/008-fastapi-entrypoint-baseline/data-model.md +0 -0
  125. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/008-fastapi-entrypoint-baseline/plan.md +0 -0
  126. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/008-fastapi-entrypoint-baseline/quickstart.md +0 -0
  127. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/008-fastapi-entrypoint-baseline/research.md +0 -0
  128. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/008-fastapi-entrypoint-baseline/spec.md +0 -0
  129. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/008-fastapi-entrypoint-baseline/tasks.md +0 -0
  130. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/009-app-factory-split/checklists/requirements.md +0 -0
  131. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/009-app-factory-split/contracts/gep-restapi.md +0 -0
  132. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/009-app-factory-split/data-model.md +0 -0
  133. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/009-app-factory-split/plan.md +0 -0
  134. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/009-app-factory-split/quickstart.md +0 -0
  135. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/009-app-factory-split/research.md +0 -0
  136. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/009-app-factory-split/spec.md +0 -0
  137. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/009-app-factory-split/tasks.md +0 -0
  138. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/011-fix-restapi-cleanup/data-model.md +0 -0
  139. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/011-fix-restapi-cleanup/plan.md +0 -0
  140. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/011-fix-restapi-cleanup/quickstart.md +0 -0
  141. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/011-fix-restapi-cleanup/research.md +0 -0
  142. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/011-fix-restapi-cleanup/spec.md +0 -0
  143. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/011-fix-restapi-cleanup/tasks.md +0 -0
  144. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/012-fix-restapi-test-templates/checklists/requirements.md +0 -0
  145. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/012-fix-restapi-test-templates/data-model.md +0 -0
  146. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/012-fix-restapi-test-templates/plan.md +0 -0
  147. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/012-fix-restapi-test-templates/quickstart.md +0 -0
  148. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/012-fix-restapi-test-templates/research.md +0 -0
  149. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/012-fix-restapi-test-templates/spec.md +0 -0
  150. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/012-fix-restapi-test-templates/tasks.md +0 -0
  151. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/014-tests-in-src/checklists/requirements.md +0 -0
  152. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/014-tests-in-src/data-model.md +0 -0
  153. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/014-tests-in-src/plan.md +0 -0
  154. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/014-tests-in-src/quickstart.md +0 -0
  155. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/014-tests-in-src/research.md +0 -0
  156. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/014-tests-in-src/spec.md +0 -0
  157. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/014-tests-in-src/tasks.md +0 -0
  158. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/015-factory-builder-refactor/checklists/requirements.md +0 -0
  159. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/015-factory-builder-refactor/data-model.md +0 -0
  160. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/015-factory-builder-refactor/plan.md +0 -0
  161. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/015-factory-builder-refactor/quickstart.md +0 -0
  162. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/015-factory-builder-refactor/research.md +0 -0
  163. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/015-factory-builder-refactor/spec.md +0 -0
  164. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/015-factory-builder-refactor/tasks.md +0 -0
  165. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/016-dedup-command-aliases/checklists/requirements.md +0 -0
  166. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/016-dedup-command-aliases/data-model.md +0 -0
  167. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/016-dedup-command-aliases/plan.md +0 -0
  168. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/016-dedup-command-aliases/research.md +0 -0
  169. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/016-dedup-command-aliases/spec.md +0 -0
  170. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/016-dedup-command-aliases/tasks.md +0 -0
  171. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/017-pep8-naming-validation/checklists/requirements.md +0 -0
  172. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/017-pep8-naming-validation/contracts/name-validation.md +0 -0
  173. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/017-pep8-naming-validation/data-model.md +0 -0
  174. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/017-pep8-naming-validation/plan.md +0 -0
  175. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/017-pep8-naming-validation/research.md +0 -0
  176. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/017-pep8-naming-validation/spec.md +0 -0
  177. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/017-pep8-naming-validation/tasks.md +0 -0
  178. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/019-mcp-entry-point-restructure/contracts/gep-mcp.md +0 -0
  179. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/019-mcp-entry-point-restructure/data-model.md +0 -0
  180. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/019-mcp-entry-point-restructure/plan.md +0 -0
  181. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/019-mcp-entry-point-restructure/research.md +0 -0
  182. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/019-mcp-entry-point-restructure/spec.md +0 -0
  183. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/019-mcp-entry-point-restructure/tasks.md +0 -0
  184. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/020-pypi-publish-readme/checklists/requirements.md +0 -0
  185. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/020-pypi-publish-readme/contracts/readme-outline.md +0 -0
  186. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/020-pypi-publish-readme/data-model.md +0 -0
  187. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/020-pypi-publish-readme/plan.md +0 -0
  188. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/020-pypi-publish-readme/quickstart.md +0 -0
  189. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/020-pypi-publish-readme/research.md +0 -0
  190. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/020-pypi-publish-readme/spec.md +0 -0
  191. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/020-pypi-publish-readme/tasks.md +0 -0
  192. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/021-mcp-add-tool/checklists/requirements.md +0 -0
  193. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/021-mcp-add-tool/contracts/gep-add-tool.md +0 -0
  194. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/021-mcp-add-tool/data-model.md +0 -0
  195. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/021-mcp-add-tool/plan.md +0 -0
  196. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/021-mcp-add-tool/quickstart.md +0 -0
  197. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/021-mcp-add-tool/research.md +0 -0
  198. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/021-mcp-add-tool/spec.md +0 -0
  199. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/021-mcp-add-tool/tasks.md +0 -0
  200. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/022-solid-code-cleanup/checklists/requirements.md +0 -0
  201. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/022-solid-code-cleanup/contracts/cli-behavior.md +0 -0
  202. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/022-solid-code-cleanup/contracts/factory-extension.md +0 -0
  203. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/022-solid-code-cleanup/data-model.md +0 -0
  204. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/022-solid-code-cleanup/plan.md +0 -0
  205. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/022-solid-code-cleanup/quickstart.md +0 -0
  206. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/022-solid-code-cleanup/research.md +0 -0
  207. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/022-solid-code-cleanup/spec.md +0 -0
  208. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/022-solid-code-cleanup/tasks.md +0 -0
  209. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/023-error-hints/spec.md +0 -0
  210. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/024-typed-template-contexts/spec.md +0 -0
  211. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/025-model-gateway-generation/checklists/requirements.md +0 -0
  212. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/025-model-gateway-generation/contracts/dm.md +0 -0
  213. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/025-model-gateway-generation/contracts/gm.md +0 -0
  214. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/025-model-gateway-generation/data-model.md +0 -0
  215. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/025-model-gateway-generation/plan.md +0 -0
  216. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/025-model-gateway-generation/quickstart.md +0 -0
  217. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/025-model-gateway-generation/research.md +0 -0
  218. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/025-model-gateway-generation/spec.md +0 -0
  219. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/025-model-gateway-generation/tasks.md +0 -0
  220. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/026-usecase-naming-standardization/checklists/requirements.md +0 -0
  221. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/026-usecase-naming-standardization/contracts/dm.md +0 -0
  222. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/026-usecase-naming-standardization/contracts/guc.md +0 -0
  223. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/026-usecase-naming-standardization/data-model.md +0 -0
  224. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/026-usecase-naming-standardization/plan.md +0 -0
  225. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/026-usecase-naming-standardization/quickstart.md +0 -0
  226. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/026-usecase-naming-standardization/research.md +0 -0
  227. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/026-usecase-naming-standardization/spec.md +0 -0
  228. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/specs/026-usecase-naming-standardization/tasks.md +0 -0
  229. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/__init__.py +0 -0
  230. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/cli.py +0 -0
  231. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/__init__.py +0 -0
  232. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/_entry_point_rules.py +0 -0
  233. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/_shared.py +0 -0
  234. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/add_mcp_tool.py +0 -0
  235. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/delete_module.py +0 -0
  236. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/generate_driven_adapter.py +0 -0
  237. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/generate_entry_point.py +0 -0
  238. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/generate_helper.py +0 -0
  239. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/generate_model.py +0 -0
  240. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/generate_pipeline.py +0 -0
  241. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/generate_project.py +0 -0
  242. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/generate_use_case.py +0 -0
  243. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/update_project.py +0 -0
  244. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/commands/validate_structure.py +0 -0
  245. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/core/__init__.py +0 -0
  246. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/core/file_writer.py +0 -0
  247. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/core/mcp_tool_spec.py +0 -0
  248. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/core/module_builder.py +0 -0
  249. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/core/module_locator.py +0 -0
  250. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/core/name_utils.py +0 -0
  251. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/core/openapi_routes.py +0 -0
  252. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/core/project_detector.py +0 -0
  253. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/core/pyproject_writer.py +0 -0
  254. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/core/structure_validator.py +0 -0
  255. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/core/template_renderer.py +0 -0
  256. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/__init__.py +0 -0
  257. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/driven_adapters/__init__.py +0 -0
  258. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/driven_adapters/base.py +0 -0
  259. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/driven_adapters/da_generic.py +0 -0
  260. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/driven_adapters/da_rest_consumer.py +0 -0
  261. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/driven_adapters/da_secrets.py +0 -0
  262. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/entry_points/__init__.py +0 -0
  263. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/entry_points/base.py +0 -0
  264. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/entry_points/ep_agent.py +0 -0
  265. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/entry_points/ep_generic.py +0 -0
  266. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/entry_points/ep_restapi.py +0 -0
  267. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/pipelines/__init__.py +0 -0
  268. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/pipelines/pipeline_factory.py +0 -0
  269. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/simple/__init__.py +0 -0
  270. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/simple/delete_module_factory.py +0 -0
  271. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/simple/helper_factory.py +0 -0
  272. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/simple/model_factory.py +0 -0
  273. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/factory/simple/use_case_factory.py +0 -0
  274. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/models/__init__.py +0 -0
  275. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/models/context.py +0 -0
  276. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/models/file_operation.py +0 -0
  277. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/models/layer.py +0 -0
  278. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/models/options.py +0 -0
  279. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/models/violation.py +0 -0
  280. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/__init__.py +0 -0
  281. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/driven_adapter/generic/__init__.py.jinja2 +0 -0
  282. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/driven_adapter/generic/adapter.py.jinja2 +0 -0
  283. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/driven_adapter/generic/test_adapter.py.jinja2 +0 -0
  284. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/driven_adapter/rest_consumer/__init__.py.jinja2 +0 -0
  285. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/driven_adapter/rest_consumer/rest_consumer.py.jinja2 +0 -0
  286. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/driven_adapter/rest_consumer/test_rest_consumer.py.jinja2 +0 -0
  287. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/driven_adapter/secrets/__init__.py.jinja2 +0 -0
  288. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/driven_adapter/secrets/secrets_adapter.py.jinja2 +0 -0
  289. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/driven_adapter/secrets/test_secrets_adapter.py.jinja2 +0 -0
  290. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/agent/__init__.py.jinja2 +0 -0
  291. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/agent/agent.py.jinja2 +0 -0
  292. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/agent/card.py.jinja2 +0 -0
  293. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/agent/entrypoint_main.py.jinja2 +0 -0
  294. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/agent/test_agent.py.jinja2 +0 -0
  295. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/generic/__init__.py.jinja2 +0 -0
  296. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/generic/entrypoint_main.py.jinja2 +0 -0
  297. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/generic/handler.py.jinja2 +0 -0
  298. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/generic/test_handler.py.jinja2 +0 -0
  299. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/mcp/__init__.py.jinja2 +0 -0
  300. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/mcp/prompts.py.jinja2 +0 -0
  301. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/mcp/resources.py.jinja2 +0 -0
  302. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/mcp/server.py.jinja2 +0 -0
  303. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/mcp/test_prompts.py.jinja2 +0 -0
  304. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/mcp/test_resources.py.jinja2 +0 -0
  305. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/mcp/test_tool_stub.py.jinja2 +0 -0
  306. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/mcp/test_tools.py.jinja2 +0 -0
  307. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/mcp/tool_stub.py.jinja2 +0 -0
  308. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/mcp/tools.py.jinja2 +0 -0
  309. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/restapi/__init__.py.jinja2 +0 -0
  310. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/restapi/app.py.jinja2 +0 -0
  311. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/restapi/exception_handler.py.jinja2 +0 -0
  312. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/restapi/health.py.jinja2 +0 -0
  313. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/restapi/rest_controller.py.jinja2 +0 -0
  314. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/restapi/server.py.jinja2 +0 -0
  315. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/restapi/test_app.py.jinja2 +0 -0
  316. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/restapi/test_exception_handler.py.jinja2 +0 -0
  317. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/restapi/test_rest_controller.py.jinja2 +0 -0
  318. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/entry_point/restapi/test_server.py.jinja2 +0 -0
  319. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/helper/__init__.py.jinja2 +0 -0
  320. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/helper/helper.py.jinja2 +0 -0
  321. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/helper/test_helper.py.jinja2 +0 -0
  322. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/model/__init__.py.jinja2 +0 -0
  323. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/model/gateway.py.jinja2 +0 -0
  324. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/model/gateways_init.py.jinja2 +0 -0
  325. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/model/model.py.jinja2 +0 -0
  326. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/model/test_gateway.py.jinja2 +0 -0
  327. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/model/test_model.py.jinja2 +0 -0
  328. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/pipeline/azure/azure_pipelines.yml.jinja2 +0 -0
  329. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/pipeline/github/ci.yml.jinja2 +0 -0
  330. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/README.jinja2 +0 -0
  331. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/application/config/__init__.py.jinja2 +0 -0
  332. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/application/config/config.py.jinja2 +0 -0
  333. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/application/config/container.py.jinja2 +0 -0
  334. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/application/config/driven_adapters_container.py.jinja2 +0 -0
  335. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/application/config/resource_container.py.jinja2 +0 -0
  336. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/application/config/usecases_container.py.jinja2 +0 -0
  337. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/dockerfile.jinja2 +0 -0
  338. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/dockerignore.jinja2 +0 -0
  339. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/empty.jinja2 +0 -0
  340. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/gitignore.jinja2 +0 -0
  341. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/layer_init.jinja2 +0 -0
  342. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/main.py.jinja2 +0 -0
  343. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/mypy_ini.jinja2 +0 -0
  344. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/package_init.py.jinja2 +0 -0
  345. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/pyproject_toml.jinja2 +0 -0
  346. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/project/python_version.jinja2 +0 -0
  347. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/use_case/test_use_case.py.jinja2 +0 -0
  348. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/src/scaffold_ca_python/templates/use_case/use_case.py.jinja2 +0 -0
  349. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/__init__.py +0 -0
  350. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/__init__.py +0 -0
  351. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_behavior_contract.py +0 -0
  352. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_cli.py +0 -0
  353. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_delete_module.py +0 -0
  354. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_dry_run_checksum.py +0 -0
  355. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_generate_driven_adapter.py +0 -0
  356. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_generate_helper.py +0 -0
  357. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_generate_model.py +0 -0
  358. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_generate_pipeline.py +0 -0
  359. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_generate_project.py +0 -0
  360. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_generate_use_case.py +0 -0
  361. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_performance.py +0 -0
  362. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_shared.py +0 -0
  363. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_update_project.py +0 -0
  364. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_validate_structure.py +0 -0
  365. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/commands/test_workflow.py +0 -0
  366. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/conftest.py +0 -0
  367. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/core/__init__.py +0 -0
  368. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/core/test_file_writer.py +0 -0
  369. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/core/test_mcp_tool_spec.py +0 -0
  370. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/core/test_module_locator.py +0 -0
  371. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/core/test_name_utils.py +0 -0
  372. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/core/test_openapi_routes.py +0 -0
  373. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/core/test_project_context.py +0 -0
  374. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/core/test_project_detector.py +0 -0
  375. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/core/test_pyproject_writer.py +0 -0
  376. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/core/test_structure_validator.py +0 -0
  377. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/core/test_template_renderer.py +0 -0
  378. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/__init__.py +0 -0
  379. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/driven_adapters/__init__.py +0 -0
  380. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/driven_adapters/test_da_generic.py +0 -0
  381. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/driven_adapters/test_da_rest_consumer.py +0 -0
  382. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/driven_adapters/test_da_secrets.py +0 -0
  383. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/entry_points/__init__.py +0 -0
  384. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/entry_points/test_ep_agent.py +0 -0
  385. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/entry_points/test_ep_generic.py +0 -0
  386. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/entry_points/test_ep_restapi.py +0 -0
  387. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/simple/__init__.py +0 -0
  388. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/simple/test_delete_module_factory.py +0 -0
  389. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/simple/test_helper_factory.py +0 -0
  390. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/simple/test_model_factory.py +0 -0
  391. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/simple/test_use_case_factory.py +0 -0
  392. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/test_dry_run_parity.py +0 -0
  393. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/test_extensibility.py +0 -0
  394. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/test_module_builder.py +0 -0
  395. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/factory/test_registry.py +0 -0
  396. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/models/__init__.py +0 -0
  397. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/models/test_context.py +0 -0
  398. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/models/test_file_operation.py +0 -0
  399. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/models/test_layer.py +0 -0
  400. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/models/test_options.py +0 -0
  401. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/models/test_violation.py +0 -0
  402. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/templates/__init__.py +0 -0
  403. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/templates/test_di_config_templates.py +0 -0
  404. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/templates/test_docker_templates.py +0 -0
  405. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/templates/test_driven_adapter_templates.py +0 -0
  406. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/templates/test_entrypoint_main_templates.py +0 -0
  407. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/templates/test_helper_templates.py +0 -0
  408. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/templates/test_model_templates.py +0 -0
  409. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/templates/test_pipeline_templates.py +0 -0
  410. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/templates/test_project_templates.py +0 -0
  411. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/templates/test_use_case_templates.py +0 -0
  412. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/tests/test_source_hygiene.py +0 -0
  413. {scaffold_ca_python-0.4.0 → scaffold_ca_python-0.5.0}/uv.lock +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.5.0"
3
+ }
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.0](https://github.com/bancolombia/scaffold-clean-architecture-py/compare/v0.4.0...v0.5.0) (2026-10-27)
4
+
5
+
6
+ ### Features
7
+
8
+ * **mcp:** generate health check route for MCP entry points ([70a2645](https://github.com/bancolombia/scaffold-clean-architecture-py/commit/70a2645e63957d211761e7535edc675685031d57))
9
+
3
10
  ## [0.4.0](https://github.com/bancolombia/scaffold-clean-architecture-py/compare/v0.3.0...v0.4.0) (2026-10-26)
4
11
 
5
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: scaffold-ca-python
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Scaffolder to generate Clean Architecture apps
5
5
  Project-URL: Homepage, https://github.com/bancolombia/scaffold-clean-architecture-py
6
6
  Project-URL: Repository, https://github.com/bancolombia/scaffold-clean-architecture-py
@@ -0,0 +1,36 @@
1
+ # Specification Quality Checklist: MCP Entry Point Health Check Route
2
+
3
+ **Purpose**: Validate specification completeness and quality before proceeding to planning
4
+ **Created**: 2026-10-26
5
+ **Feature**: [spec.md](../spec.md)
6
+
7
+ ## Content Quality
8
+
9
+ - [x] No implementation details (languages, frameworks, APIs) — see Notes
10
+ - [x] Focused on user value and business needs
11
+ - [x] Written for non-technical stakeholders — see Notes
12
+ - [x] All mandatory sections completed
13
+
14
+ ## Requirement Completeness
15
+
16
+ - [x] No [NEEDS CLARIFICATION] markers remain
17
+ - [x] Requirements are testable and unambiguous
18
+ - [x] Success criteria are measurable
19
+ - [x] Success criteria are technology-agnostic (no implementation details)
20
+ - [x] All acceptance scenarios are defined
21
+ - [x] Edge cases are identified
22
+ - [x] Scope is clearly bounded
23
+ - [x] Dependencies and assumptions identified
24
+
25
+ ## Feature Readiness
26
+
27
+ - [x] All functional requirements have clear acceptance criteria
28
+ - [x] User scenarios cover primary flows
29
+ - [x] Feature meets measurable outcomes defined in Success Criteria
30
+ - [x] No implementation details leak into specification — see Notes
31
+
32
+ ## Notes
33
+
34
+ - This CLI is a code generator, so the generated artifact (file path, function name, route path, response body) **is** the user-facing contract. The reference `routes.py` in FR-013 was supplied by the requester and is kept intentionally; framework names appear only where they define the generated output.
35
+ - Route binding must happen before the MCP HTTP app is built (FR-006): `start_server()` materializes routes when it builds the MCP HTTP app, while tools/resources/prompts are bound inside the lifespan. Binding the health route in the lifespan would leave it unregistered.
36
+ - Items marked incomplete require spec updates before `/speckit-clarify` or `/speckit-plan`.
@@ -0,0 +1,83 @@
1
+ # Contract: Generated MCP Health Route
2
+
3
+ **Feature**: `027-mcp-health-check`
4
+
5
+ The CLI's public interface (`gep --type mcp` and its flags) does not change. The contract below describes the **generated output**, which is what consumers depend on.
6
+
7
+ ## 1. HTTP contract (generated server)
8
+
9
+ | Request | Status | Body |
10
+ |---|---|---|
11
+ | `GET /api/v1/health` | `200` | `{"status": "ok"}` (`application/json`) |
12
+ | `HEAD /api/v1/health` | `200` | empty |
13
+ | `POST`/`PUT`/`DELETE`/`PATCH /api/v1/health` | `405` | Starlette default |
14
+
15
+ - No authentication.
16
+ - Served on the same `HOST`/`PORT` as the MCP endpoint (`/mcp`).
17
+
18
+ ## 2. Generated `routes.py`
19
+
20
+ Path: `src/<pkg>/infrastructure/entry_points/mcp_server/routes.py`
21
+
22
+ ```python
23
+ """MCP custom routes binding — register non-MCP HTTP routes such as the health check."""
24
+
25
+ from __future__ import annotations
26
+
27
+ from mcp.server.fastmcp import FastMCP
28
+ from starlette.requests import Request
29
+ from starlette.responses import JSONResponse, Response
30
+
31
+
32
+ def bind_routes(mcp: FastMCP) -> None:
33
+ """
34
+ Bind routes to the FastMCP instance.
35
+ """
36
+
37
+ @mcp.custom_route(name="health_check", path="/api/v1/health", methods=["GET"])
38
+ async def health_check(_request: Request) -> Response:
39
+ """
40
+ Health check endpoint to verify the server is running.
41
+
42
+ Returns:
43
+ JSON response indicating the server is healthy.
44
+ """
45
+
46
+ response_data = {"status": "ok"}
47
+ return JSONResponse(response_data)
48
+ ```
49
+
50
+ The file must pass the generated project's `ruff check` (`E`, `F`, `I`, `UP`, `ANN`).
51
+
52
+ ## 3. Generated `app.py` delta
53
+
54
+ ```python
55
+ from {{ project.python_package }}.infrastructure.entry_points.mcp_server import routes, tools
56
+ # ... optional resources / prompts imports unchanged ...
57
+
58
+ mcp: FastMCP = FastMCP("{{ project.name }}", stateless_http=True)
59
+ routes.bind_routes(mcp)
60
+ ```
61
+
62
+ - `lifespan` is unchanged. `routes` is **not** added to `container.wire(...)`.
63
+ - `start_server()` is unchanged and MUST NOT call `bind_routes`.
64
+
65
+ ## 4. Generated tests
66
+
67
+ - **`test_routes.py`** (new):
68
+ - `bind_routes(FastMCP("test"))` registers `/api/v1/health`.
69
+ - `GET` returns 200 with `{"status": "ok"}`.
70
+ - `POST` returns 405.
71
+ - Uses `starlette.testclient.TestClient` without starting the lifespan.
72
+ - **`test_app.py`** (modified):
73
+ - After calling `start_server()` twice, `/api/v1/health` appears exactly once in the mounted app's routes.
74
+ - `TestClient(start_server()).get("/api/v1/health")` returns 200 with `{"status": "ok"}`, without starting the lifespan.
75
+
76
+ ## 5. CLI dry-run contract
77
+
78
+ `gep --type mcp --dry-run` lists, in addition to the current files:
79
+
80
+ ```text
81
+ src/<pkg>/infrastructure/entry_points/mcp_server/routes.py
82
+ <tests_root>/infrastructure/entry_points/mcp_server/test_routes.py
83
+ ```
@@ -0,0 +1,31 @@
1
+ # Data Model: MCP Entry Point Health Check Route
2
+
3
+ **Feature**: `027-mcp-health-check`
4
+
5
+ This feature adds no domain models, Pydantic context models, or persisted data. The only "data" is the generated HTTP contract and the files queued by the factory.
6
+
7
+ ## Health Response (generated project)
8
+
9
+ | Field | Type | Value | Rule |
10
+ |---|---|---|---|
11
+ | `status` | string | `"ok"` | Always `"ok"` when the process serves HTTP; no other fields. |
12
+
13
+ - Served at `GET /api/v1/health` (also `HEAD`, added automatically by Starlette).
14
+ - Content type `application/json`, HTTP 200.
15
+ - Any other method returns HTTP 405.
16
+ - It is a stateless liveness signal: it does not depend on the DI container, the domain, or driven adapters.
17
+
18
+ ## Template Context (CLI)
19
+
20
+ `routes.py.jinja2` and `test_routes.py.jinja2` reuse the existing module context (`builder.module_ctx.model_dump()`, i.e. `project.python_package`, `project.name`) already passed to the other `entry_point/mcp/` templates. No new context fields or Pydantic models are introduced (Principle II is unaffected).
21
+
22
+ ## Files Queued by `EntryPointMcp.build()`
23
+
24
+ | Path | Template | Condition | Change |
25
+ |---|---|---|---|
26
+ | `src/<pkg>/infrastructure/entry_points/mcp_server/routes.py` | `entry_point/mcp/routes.py.jinja2` | always | **NEW** |
27
+ | `<tests_root>/infrastructure/entry_points/mcp_server/test_routes.py` | `entry_point/mcp/test_routes.py.jinja2` (`is_test=True`) | always | **NEW** |
28
+ | `src/<pkg>/application/app.py` | `entry_point/mcp/app.py.jinja2` | always | MODIFIED: import `routes`; `routes.bind_routes(mcp)` after `mcp` creation |
29
+ | `<tests_root>/infrastructure/entry_points/mcp_server/test_app.py` | `entry_point/mcp/test_app.py.jinja2` | always | MODIFIED: asserts health route registered exactly once and reachable through `start_server()` |
30
+
31
+ All other queued files, dependencies, and overwrite flags are unchanged. The new files use the default `overwrite=False`, the same as `tools.py`.
@@ -0,0 +1,106 @@
1
+ # Implementation Plan: MCP Entry Point Health Check Route
2
+
3
+ **Branch**: `feature/mcp-health-check` | **Date**: 2026-10-26 | **Spec**: [spec.md](./spec.md)
4
+
5
+ **Input**: Feature specification from `/specs/027-mcp-health-check/spec.md`
6
+
7
+ ## Summary
8
+
9
+ Make `gep --type mcp` always generate `infrastructure/entry_points/mcp_server/routes.py`.
10
+
11
+ - **Route**: `routes.py` exposes a synchronous `bind_routes(mcp)` that registers an async `health_check` custom route (`GET /api/v1/health` returns `{"status": "ok"}`) via `FastMCP.custom_route`.
12
+ - **Wiring**: The generated `app.py` calls `routes.bind_routes(mcp)` once at module level, right after creating `mcp`, so the route is in place before `start_server()` builds the MCP HTTP app and is never duplicated.
13
+ - **Tests**: The feature ships a generated `test_routes.py`, extends the generated `test_app.py`, and adds CLI-side template, factory, and dry-run-baseline tests.
14
+ - **Scope**: Two new Jinja2 templates and a small edit to `EntryPointMcp.build()`. No new dependencies, flags, or CLI surface.
15
+
16
+ ## Technical Context
17
+
18
+ **Language/Version**: Python 3.13+ (no change)
19
+
20
+ **Primary Dependencies**:
21
+ - CLI: Typer, Rich, Jinja2, Pydantic v2 (unchanged).
22
+ - Generated project: the existing `mcp~=1.30.0` (`FastMCP.custom_route`) and `starlette~=1.6.0` (`Request`, `JSONResponse`, `TestClient`).
23
+ - `httpx` for `TestClient` is already a transitive dependency of `mcp`.
24
+ - **No new dependency.**
25
+
26
+ **Storage**: N/A
27
+
28
+ **Testing**:
29
+ - CLI: pytest + pytest-cov (≥ 80% gate), in `tests/templates/`, `tests/factory/entry_points/`, and `tests/factory/` (dry-run parity).
30
+ - Generated project: pytest with Starlette `TestClient`.
31
+
32
+ **Target Platform**: Cross-platform CLI; generated server runs under uvicorn (unchanged)
33
+
34
+ **Project Type**: Single project — CLI code generator (template + factory change)
35
+
36
+ **Performance Goals**: N/A (constant-time health response; CLI generation time unchanged)
37
+
38
+ **Constraints**:
39
+ - `bind_routes` MUST run before `mcp.streamable_http_app()` is called and exactly once per process. It is called at module level, not inside `start_server()` or `lifespan` ([research R2](./research.md#r2--when-to-call-bind_routesmcp)).
40
+ - Generated `routes.py`/`test_routes.py` MUST pass the generated project's `ruff` (`E`, `F`, `I`, `UP`, `ANN`; tests ignore `ANN`).
41
+ - MUST NOT change `tools.py.jinja2`, the `--add-tool` path, flags, dependencies, or overwrite policy.
42
+
43
+ **Scale/Scope**:
44
+ - 2 new templates and 3 modified files (`ep_mcp.py`, `app.py.jinja2`, `test_app.py.jinja2`).
45
+ - 1 fixture update and test additions in 2 CLI test files.
46
+
47
+ ## Constitution Check
48
+
49
+ *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
50
+
51
+ | Principle | Check | Result |
52
+ |---|---|---|
53
+ | I. Clean Architecture in Generated Projects | `routes.py` lives in `infrastructure/entry_points/mcp_server/` and imports only the MCP SDK and Starlette. `app.py` (application layer) imports it, the same way it imports `tools`. No inward-crossing imports. | ✅ PASS |
54
+ | II. Template-Driven Code Generation | New `routes.py.jinja2` and `test_routes.py.jinja2` live under `templates/entry_point/mcp/`, with rendering tests in `tests/templates/test_entry_point_templates.py`. They reuse the existing validated module context. | ✅ PASS |
55
+ | III. Full Command Parity | No command, alias, or `--type` added or changed. | ✅ PASS |
56
+ | IV. Python-First Idioms | The generated handler is `async`. `bind_routes` is fully typed (`-> None`). CLI changes are typed and keep ruff/mypy strict compliance. | ✅ PASS |
57
+ | V. Test-First Development | Failing template, factory, and baseline tests are written before the templates and the factory edit. The generated project gets the `test_routes.py` scaffold. | ✅ PASS (enforced in `/speckit-tasks` → `/speckit-implement`) |
58
+ | VI. Developer Experience | `--dry-run` previews both new files. No new error paths, so no new hints are needed. | ✅ PASS |
59
+ | VII. Git Workflow and Branch Naming | Branch `feature/mcp-health-check` follows `feature/<kebab-name>`. | ✅ PASS |
60
+
61
+ **Post-design re-check (after Phase 1)**: unchanged — all ✅. No violations; Complexity Tracking is empty.
62
+
63
+ ## Project Structure
64
+
65
+ ### Documentation (this feature)
66
+
67
+ ```text
68
+ specs/027-mcp-health-check/
69
+ ├── plan.md # This file
70
+ ├── research.md # Phase 0
71
+ ├── data-model.md # Phase 1
72
+ ├── quickstart.md # Phase 1
73
+ ├── contracts/
74
+ │ └── generated-routes.md # Phase 1 — generated HTTP + file contract
75
+ ├── checklists/
76
+ │ └── requirements.md # From /speckit-specify + /speckit-clarify
77
+ └── tasks.md # Phase 2 (/speckit-tasks — not created here)
78
+ ```
79
+
80
+ ### Source Code (repository root)
81
+
82
+ ```text
83
+ src/scaffold_ca_python/
84
+ ├── factory/entry_points/
85
+ │ └── ep_mcp.py # MODIFIED: always queue routes.py + test_routes.py; docstring updated
86
+ └── templates/entry_point/mcp/
87
+ ├── routes.py.jinja2 # NEW: bind_routes(mcp) + async health_check
88
+ ├── test_routes.py.jinja2 # NEW: GET 200 {"status":"ok"}, POST 405
89
+ ├── app.py.jinja2 # MODIFIED: import routes; routes.bind_routes(mcp) after mcp creation
90
+ └── test_app.py.jinja2 # MODIFIED: health route present once after repeated start_server(); GET through start_server() → 200
91
+
92
+ tests/
93
+ ├── factory/
94
+ │ ├── entry_points/test_ep_mcp.py # MODIFIED: routes.py/test_routes.py queued (with and without optional flags)
95
+ │ └── fixtures/dry_run_baseline.json # MODIFIED: gep:mcp gains the two new paths
96
+ └── templates/
97
+ └── test_entry_point_templates.py # MODIFIED: render tests for routes/test_routes; app/test_app assertions
98
+ ```
99
+
100
+ `CHANGELOG.md` is generated by release-please from the commit message (e.g. `feat(mcp): ...`), so it is not edited by hand.
101
+
102
+ **Structure Decision**: Single-project CLI layout, the same as every prior feature. Changes stay inside `factory/entry_points/` and `templates/entry_point/mcp/` and their matching tests. `book_smcp/` is out of scope.
103
+
104
+ ## Complexity Tracking
105
+
106
+ *No entries — Constitution Check reported no violations.*
@@ -0,0 +1,65 @@
1
+ # Quickstart: Validating the MCP Health Check Route
2
+
3
+ **Feature**: `027-mcp-health-check`
4
+ **Audience**: Developer implementing or reviewing this feature
5
+
6
+ ## Prerequisites
7
+
8
+ - Python ≥ 3.13 and [uv](https://docs.astral.sh/uv/)
9
+ - This repository on branch `feature/mcp-health-check`, with `uv sync` run once
10
+
11
+ ## 1. CLI test suite
12
+
13
+ ```bash
14
+ uv run pytest tests/templates/test_entry_point_templates.py tests/factory/entry_points/test_ep_mcp.py tests/factory/test_dry_run_parity.py
15
+ uv run pytest # full suite, coverage gate ≥ 80%
16
+ uv run ruff check . && uv run mypy src
17
+ ```
18
+
19
+ Expected: everything passes. The dry-run baseline includes `routes.py` and `test_routes.py` under `gep:mcp`.
20
+
21
+ ## 2. Dry run in a throwaway project
22
+
23
+ ```bash
24
+ cd /tmp
25
+ uv run --project /path/to/scaffold-clean-architecture-py scaffold ca --name demo-mcp
26
+ cd demo-mcp
27
+ uv run --project /path/to/scaffold-clean-architecture-py scaffold gep --type mcp --dry-run
28
+ ```
29
+
30
+ Expected: the preview lists `mcp_server/routes.py` and `mcp_server/test_routes.py`, and nothing is written (see [contract §5](./contracts/generated-routes.md#5-cli-dry-run-contract)).
31
+
32
+ ## 3. Generate and verify the generated project
33
+
34
+ ```bash
35
+ uv run --project /path/to/scaffold-clean-architecture-py scaffold gep --type mcp
36
+ uv sync
37
+ uv run ruff check src
38
+ uv run pytest
39
+ ```
40
+
41
+ Expected:
42
+
43
+ - `ruff` reports no issues for `routes.py` and `test_routes.py`.
44
+ - `test_routes.py` and `test_app.py` pass without edits.
45
+
46
+ ## 4. Hit the endpoint
47
+
48
+ ```bash
49
+ uv run demo-mcp & # project script → server.main()
50
+ curl -i http://localhost:8000/api/v1/health
51
+ curl -i -X POST http://localhost:8000/api/v1/health
52
+ kill %1
53
+ ```
54
+
55
+ Expected:
56
+
57
+ - `GET` returns `HTTP/1.1 200` with `{"status":"ok"}`.
58
+ - `POST` returns `HTTP/1.1 405`.
59
+
60
+ See [contract §1](./contracts/generated-routes.md#1-http-contract-generated-server).
61
+
62
+ ## 5. Regression checks
63
+
64
+ - `scaffold gep --type mcp --with-resources --with-prompts` still generates `routes.py`, and the health check still answers.
65
+ - `scaffold gep --type mcp --add-tool --name foo --returns str --description "x"` leaves `routes.py` and the `bind_routes` line in `app.py` untouched.
@@ -0,0 +1,63 @@
1
+ # Research: MCP Entry Point Health Check Route
2
+
3
+ **Feature**: `027-mcp-health-check` | **Date**: 2026-10-26
4
+
5
+ No `NEEDS CLARIFICATION` items remained after `/speckit-clarify`. The research below records the technical decisions that the plan depends on.
6
+
7
+ ## R1 — How `FastMCP.custom_route` registers routes
8
+
9
+ - **Decision**: Use `@mcp.custom_route(name="health_check", path="/api/v1/health", methods=["GET"])` inside `bind_routes(mcp)`.
10
+ - **Rationale**: Verified in the installed SDK (`mcp/server/fastmcp/server.py`): `custom_route(path, methods, name=None, include_in_schema=True)` appends a Starlette `Route` to `self._custom_starlette_routes`, and `streamable_http_app()` copies that list into the Starlette app it builds (`routes.extend(self._custom_starlette_routes)`), after the `/mcp` route (lowest matching precedence). No new dependency is needed.
11
+ - **Alternatives considered**: Adding a separate Starlette `Route` next to the `Mount("/")` in `start_server()` — rejected because it moves route wiring into the composition root and bypasses the `bind_*` pattern already used by `tools`, `resources`, and `prompts`.
12
+
13
+ ## R2 — When to call `bind_routes(mcp)`
14
+
15
+ - **Decision**: Call `routes.bind_routes(mcp)` once at module level in `app.py`, immediately after `mcp: FastMCP = FastMCP(...)` (clarification Q2).
16
+ - **Rationale**:
17
+ - `streamable_http_app()` takes a snapshot of the custom routes when `start_server()` runs. Tools, resources, and prompts are bound later, inside `lifespan`, so binding the health route there would leave it out of the route table.
18
+ - `custom_route` does not deduplicate. A module-level call happens once per process, so repeated `start_server()` calls in `test_app.py` do not accumulate duplicate routes.
19
+ - **Alternatives considered**: Inside `start_server()` (works in production, duplicates routes in tests); inside `lifespan` (route never registered).
20
+
21
+ ## R3 — `bind_routes` is synchronous
22
+
23
+ - **Decision**: `def bind_routes(mcp: FastMCP) -> None` (not `async`), without `@inject`.
24
+ - **Rationale**: It runs at import time, outside an event loop, and has no dependencies to inject. Only the handler `health_check` is `async`, which satisfies Principle IV (async I/O in generated code).
25
+ - **Alternatives considered**: `async def bind_routes` awaited from `lifespan` for symmetry with `bind_tools` — rejected by R2.
26
+
27
+ ## R4 — Lint compliance of the generated `routes.py`
28
+
29
+ - **Decision**: Render the reference code with minimal fixes: module docstring, `from __future__ import annotations`, sorted imports (`JSONResponse, Response`), two blank lines before `def`, and `-> None` on `bind_routes` (clarification Q1).
30
+ - **Rationale**: Generated projects run `ruff` with `select = ["E", "F", "I", "UP", "ANN"]`. The raw reference fails `I001` (unsorted imports) and `ANN201` (missing return type). `from __future__ import annotations` is safe here because neither `custom_route` nor Starlette's `Route` inspects handler annotations.
31
+ - **Alternatives considered**: `noqa` comments or per-file ignores — rejected; they add noise to generated code.
32
+
33
+ ## R5 — How the generated tests exercise the route
34
+
35
+ - **Decision**: `test_routes.py` builds a fresh `FastMCP("test")`, calls `bind_routes(mcp)`, wraps `mcp.streamable_http_app()` in `starlette.testclient.TestClient` (used **without** a `with` block, so the MCP session-manager lifespan is not started), and asserts:
36
+ - `GET /api/v1/health` returns 200 with body `{"status": "ok"}`.
37
+ - `POST /api/v1/health` returns 405.
38
+ - **Rationale**:
39
+ - `TestClient` needs `httpx`, which `mcp` already declares (`Requires-Dist: httpx>=0.27.1`). The generated pyproject already filters httpx deprecation warnings, so no new test dependency is needed.
40
+ - A fresh `FastMCP` per test avoids touching the module-level instance in `app.py`.
41
+ - Starlette answers 405 when the path matches but the method does not. It also adds `HEAD` automatically for `GET` routes.
42
+ - **Alternatives considered**: Building a bare `Starlette(routes=mcp._custom_starlette_routes)` — rejected because it relies on a private attribute.
43
+
44
+ ## R6 — How `test_app.py` asserts single registration
45
+
46
+ - **Decision**: Call `start_server()` twice, then assert that `/api/v1/health` appears exactly once among the routes of the mounted app (`server.routes[0].routes`, i.e. `Mount.routes`, which proxies to the inner Starlette app).
47
+ - **Rationale**: Locks in FR-008 and the clarification Q2 guarantee using only public Starlette APIs.
48
+
49
+ ## R7 — CLI-side test and fixture impact
50
+
51
+ - **Decision**:
52
+ - Add `routes.py` and `test_routes.py` to the `gep:mcp` entry in `tests/factory/fixtures/dry_run_baseline.json`.
53
+ - Add a factory test in `tests/factory/entry_points/test_ep_mcp.py`.
54
+ - Add template rendering tests in `tests/templates/test_entry_point_templates.py`, covering the new templates plus the `app.py`/`test_app.py` changes.
55
+ - **Rationale**:
56
+ - The dry-run parity test compares sorted queued paths against the baseline.
57
+ - Principle II requires rendering tests per template group, and `entry_point/mcp/` is already covered in that file.
58
+ - **Alternatives considered**: None.
59
+
60
+ ## R8 — SDK version drift
61
+
62
+ - **Decision**: Keep the `mcp~=1.30.0` pin; no change.
63
+ - **Rationale**: `custom_route` and `streamable_http_app` exist with the same signatures in the 1.x line (verified against an installed 1.27.0; the 1.30 pin targets the same FastMCP API, as noted in `ep_mcp.py`).
@@ -0,0 +1,147 @@
1
+ # Feature Specification: MCP Entry Point Health Check Route
2
+
3
+ **Feature Branch**: `feature/mcp-health-check`
4
+
5
+ **Created**: 2026-10-26
6
+
7
+ **Status**: Draft
8
+
9
+ **Input**: User description: "When the `mcp` entry point is generated, also generate a health endpoint in a module named `routes.py` inside `infrastructure/entry_points/mcp_server/`, exposing a `GET /api/v1/health` health check that returns `{\"status\": \"ok\"}` via a `bind_routes(mcp)` function."
10
+
11
+ ## Clarifications
12
+
13
+ ### Session 2026-10-26
14
+
15
+ - Q: Should the generated `routes.py` follow the reference code exactly, or be adjusted so it passes the generated project's lint rules? → A: Keep the reference behavior and structure, with minimal lint fixes (`-> None` on `bind_routes`, sorted imports, module docstring, `from __future__ import annotations`, matching `tools.py`).
16
+ - Q: Where in the generated `app.py` should `routes.bind_routes(mcp)` be called: once at module level right after `mcp` is created, or inside `start_server()`? → A: At module level, immediately after `mcp` is created; registered exactly once per process.
17
+
18
+ ## User Scenarios & Testing *(mandatory)*
19
+
20
+ ### User Story 1 - Generated MCP server exposes a health check out of the box (Priority: P1)
21
+
22
+ A developer generates an MCP entry point (`scaffold-ca-python gep --type mcp`) in a Clean Architecture project. Without writing any extra code, the resulting server answers a health check request so it can be deployed behind load balancers, container orchestrators (liveness/readiness probes), and uptime monitors.
23
+
24
+ **Why this priority**: A health endpoint is a baseline operational requirement for any deployable service. Without it, every team must hand-write the same route before the server can run in a managed environment.
25
+
26
+ **Independent Test**: Run `gep --type mcp --dry-run` and confirm `routes.py` is listed; render `routes.py` and confirm `bind_routes` registers `GET /api/v1/health` returning `{"status": "ok"}` on a standalone `FastMCP` instance. (Reaching the endpoint on the running server additionally requires User Story 2.)
27
+
28
+ **Acceptance Scenarios**:
29
+
30
+ 1. **Given** a freshly scaffolded project, **When** the developer runs `gep --type mcp`, **Then** a `routes.py` module is created at `src/<pkg>/infrastructure/entry_points/mcp_server/routes.py` alongside `tools.py`.
31
+ 2. **Given** the generated `routes.py`, **When** the developer inspects it, **Then** it exposes a single public function `bind_routes(mcp)` that registers a route named `health_check` at path `/api/v1/health` registered for `GET`.
32
+ 3. **Given** the generated MCP server is running, **When** a client sends `GET /api/v1/health`, **Then** the server responds with HTTP 200, a JSON content type, and the body `{"status": "ok"}`.
33
+ 4. **Given** the generated MCP server is running, **When** a client sends any method other than `GET` or `HEAD` (e.g. `POST`) to `/api/v1/health`, **Then** the server rejects it with HTTP 405.
34
+
35
+ ---
36
+
37
+ ### User Story 2 - Health route is wired into the composition root automatically (Priority: P1)
38
+
39
+ The developer does not have to edit the application composition root to activate the health route; the generated `app.py` already binds it so the endpoint is live as soon as the server starts.
40
+
41
+ **Why this priority**: A generated route that is not wired is dead code. Wiring is part of the same deliverable as Story 1 and is required for its acceptance scenario 3 to pass.
42
+
43
+ **Independent Test**: Render the generated `app.py`, build the ASGI application with `start_server()`, and confirm the `/api/v1/health` route is present in the application's route table before any request or lifespan event runs.
44
+
45
+ **Acceptance Scenarios**:
46
+
47
+ 1. **Given** the generated `application/app.py`, **When** the developer inspects it, **Then** it imports `routes` from the `mcp_server` package and calls `routes.bind_routes(mcp)`.
48
+ 2. **Given** the generated application, **When** `start_server()` builds the ASGI app, **Then** the health route is already registered (it is bound at module import time, not inside `start_server()` or the lifespan).
49
+ 3. **Given** the generated application, **When** `start_server()` is called multiple times in the same process (e.g. across tests), **Then** `/api/v1/health` appears exactly once in the route table.
50
+ 4. **Given** the generated application with resources and/or prompts enabled, **When** the server starts, **Then** the health route is still registered and the existing tools/resources/prompts behaviour is unchanged.
51
+
52
+ ---
53
+
54
+ ### User Story 3 - Generated project ships a test for the health route (Priority: P2)
55
+
56
+ The generated project includes a test file for `routes.py` so the health contract is covered from day one and TDD remains the default workflow.
57
+
58
+ **Why this priority**: Required by the constitution (Principle V: every `generate-*` command MUST produce a corresponding test scaffold), but the server is still operable without it.
59
+
60
+ **Independent Test**: Generate a project with the `mcp` entry point and run its test suite; the routes test passes without modification.
61
+
62
+ **Acceptance Scenarios**:
63
+
64
+ 1. **Given** `gep --type mcp` was run, **When** the developer lists the tests, **Then** `tests/infrastructure/entry_points/mcp_server/test_routes.py` exists (resolved through the project's tests root).
65
+ 2. **Given** the generated test, **When** it runs, **Then** it asserts that `GET /api/v1/health` returns 200 with body `{"status": "ok"}`.
66
+
67
+ ---
68
+
69
+ ### Edge Cases
70
+
71
+ - **Dry run**: `gep --type mcp --dry-run` MUST list `routes.py` and `test_routes.py` in the preview and write nothing to disk.
72
+ - **Existing MCP entry point**: If `mcp_server/` already exists, `gep --type mcp` aborts with the existing "Directory already exists" error before writing `routes.py` (no new policy is introduced).
73
+ - **Conflicting entry point**: When the `restapi` entry point is already present, the existing MCP/restapi conflict check still aborts generation before `routes.py` is written.
74
+ - **Optional primitives**: The health route is generated regardless of `--with-resources` / `--with-prompts`; it is not gated by any flag.
75
+ - **`gep --type mcp --add-tool`**: Adding tools afterwards MUST NOT modify or remove `routes.py` or its binding in `app.py`.
76
+ - **Route ordering**: The health route MUST NOT be shadowed by the MCP HTTP app mounted at `/`.
77
+
78
+ ## Requirements *(mandatory)*
79
+
80
+ ### Functional Requirements
81
+
82
+ - **FR-001**: The `mcp` entry-point generator MUST always emit `src/<pkg>/infrastructure/entry_points/mcp_server/routes.py`, independent of optional flags.
83
+ - **FR-002**: `routes.py` MUST be rendered from a new Jinja2 template under the existing `entry_point/mcp/` template group (no string assembly), per Principle II.
84
+ - **FR-003**: `routes.py` MUST expose a synchronous public function `bind_routes(mcp)` that receives the server's `FastMCP` instance and registers the health route on it.
85
+ - **FR-004**: The health route MUST be named `health_check`, served at `/api/v1/health`, accept `GET` (Starlette implicitly also answers `HEAD` for `GET` routes), and be implemented as an `async` handler (Principle IV: async-first in generated code).
86
+ - **FR-005**: The health route MUST respond with HTTP 200 and the JSON body `{"status": "ok"}`, with no dependency on the DI container, domain, or driven adapters.
87
+ - **FR-006**: The generated `application/app.py` MUST import `routes` and call `routes.bind_routes(mcp)` once at module level, immediately after the `mcp` instance is created, so the route is registered exactly once per process and before `start_server()` builds the ASGI application. `start_server()` MUST NOT register routes, and `routes` is not added to `container.wire(...)`.
88
+ - **FR-007**: The generator MUST emit `tests/infrastructure/entry_points/mcp_server/test_routes.py` (via the resolved tests root) covering the 200/`{"status": "ok"}` contract and the 405 response for `POST`.
89
+ - **FR-008**: The generated `test_app.py` MUST assert that the `/api/v1/health` route is present exactly once in the application returned by `start_server()`, and that `GET /api/v1/health` against that application returns 200 with `{"status": "ok"}`.
90
+ - **FR-009**: The generated `routes.py` and `test_routes.py` MUST pass the generated project's `ruff` lint configuration.
91
+ - **FR-010**: The generated `routes.py` MUST only import from the MCP SDK and Starlette (already declared dependencies); no new runtime dependency is added.
92
+ - **FR-011**: `--dry-run` output for `gep --type mcp` MUST include both new files, and the dry-run parity baseline MUST be updated accordingly.
93
+ - **FR-012**: The CLI test suite MUST include template rendering tests for `routes.py.jinja2` and `test_routes.py.jinja2` under `tests/templates/`, plus factory tests asserting the files are queued by the `mcp` entry-point factory.
94
+ - **FR-013**: The generated `routes.py` MUST keep the behavior and structure of the requester's reference code, adjusted only as needed to satisfy FR-009 (`ruff` rules `E`, `F`, `I`, `UP`, `ANN`) and to match the conventions of `tools.py`. Expected output:
95
+
96
+ ```python
97
+ """MCP custom routes binding — register non-MCP HTTP routes such as the health check."""
98
+
99
+ from __future__ import annotations
100
+
101
+ from mcp.server.fastmcp import FastMCP
102
+ from starlette.requests import Request
103
+ from starlette.responses import JSONResponse, Response
104
+
105
+
106
+ def bind_routes(mcp: FastMCP) -> None:
107
+ """
108
+ Bind routes to the FastMCP instance.
109
+ """
110
+
111
+ @mcp.custom_route(name="health_check", path="/api/v1/health", methods=["GET"])
112
+ async def health_check(_request: Request) -> Response:
113
+ """
114
+ Health check endpoint to verify the server is running.
115
+
116
+ Returns:
117
+ JSON response indicating the server is healthy.
118
+ """
119
+
120
+ response_data = {"status": "ok"}
121
+ return JSONResponse(response_data)
122
+ ```
123
+
124
+ ### Key Entities
125
+
126
+ - **Health response**: A minimal payload with a single field `status` whose value is `"ok"` when the server process is up and able to serve HTTP requests.
127
+ - **Route binder (`bind_routes`)**: The single extension point for non-MCP HTTP routes of the generated server; future custom routes are added inside it.
128
+
129
+ ## Success Criteria *(mandatory)*
130
+
131
+ ### Measurable Outcomes
132
+
133
+ - **SC-001**: 100% of projects generated with `gep --type mcp` contain `routes.py` and `test_routes.py`, verified by the CLI factory tests.
134
+ - **SC-002**: A freshly generated MCP project answers `GET /api/v1/health` with `{"status": "ok"}` with zero manual edits by the developer.
135
+ - **SC-003**: The generated project's test suite passes on first run, including the new routes test.
136
+ - **SC-004**: The CLI test suite keeps its ≥ 80% coverage gate and all existing MCP entry-point tests still pass unchanged (other than the intended dry-run baseline update).
137
+
138
+ ## Assumptions
139
+
140
+ - The health check is a **liveness** signal only: it reports that the process is serving HTTP and does not probe downstream dependencies (databases, external APIs). Readiness checks are out of scope.
141
+ - The health route is public (no authentication), consistent with standard probe usage.
142
+ - The path `/api/v1/health` is fixed; making it configurable via settings is out of scope.
143
+ - The health route is served by the same host/port as the MCP server (existing `HOST`/`PORT` settings); no separate listener is introduced.
144
+ - Only the `mcp` entry point is affected; `restapi`, `agent`, and `generic` entry points are unchanged.
145
+ - Existing projects that already generated the MCP entry point are not migrated. Re-running `gep --type mcp` is blocked by the existing `mcp_server/` directory guard, so those projects must add `routes.py` and the `routes.bind_routes(mcp)` line in `app.py` manually.
146
+ - Only `ruff` compliance is required for generated files; `mypy --strict` compliance of the generated project is out of scope (`FastMCP.custom_route` is an untyped decorator).
147
+ - The reference `book_smcp/` sample project is not part of this feature's scope.