specfact-cli 0.20.0__tar.gz → 0.20.5__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 (181) hide show
  1. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/PKG-INFO +1 -1
  2. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/pyproject.toml +1 -1
  3. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/prompts/shared/cli-enforcement.md +6 -0
  4. specfact_cli-0.20.5/resources/prompts/specfact.01-import.md +263 -0
  5. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/prompts/specfact.02-plan.md +3 -1
  6. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/prompts/specfact.03-review.md +104 -0
  7. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/prompts/specfact.04-sdd.md +1 -0
  8. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/prompts/specfact.05-enforce.md +1 -0
  9. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/prompts/specfact.06-sync.md +1 -0
  10. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/prompts/specfact.compare.md +1 -0
  11. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/prompts/specfact.validate.md +1 -0
  12. specfact_cli-0.20.5/resources/templates/sidecar/README.md +187 -0
  13. specfact_cli-0.20.5/resources/templates/sidecar/__init__.py +0 -0
  14. specfact_cli-0.20.5/resources/templates/sidecar/adapters.py +632 -0
  15. specfact_cli-0.20.5/resources/templates/sidecar/bindings.yaml +26 -0
  16. specfact_cli-0.20.5/resources/templates/sidecar/bindings.yaml.example +42 -0
  17. specfact_cli-0.20.5/resources/templates/sidecar/crosshair_django_wrapper.py +140 -0
  18. specfact_cli-0.20.5/resources/templates/sidecar/crosshair_plugin.py +34 -0
  19. specfact_cli-0.20.5/resources/templates/sidecar/django_form_extractor.py +440 -0
  20. specfact_cli-0.20.5/resources/templates/sidecar/django_url_extractor.py +304 -0
  21. specfact_cli-0.20.5/resources/templates/sidecar/generate_harness.py +561 -0
  22. specfact_cli-0.20.5/resources/templates/sidecar/harness_contracts.py +26 -0
  23. specfact_cli-0.20.5/resources/templates/sidecar/populate_contracts.py +278 -0
  24. specfact_cli-0.20.5/resources/templates/sidecar/run_sidecar.sh +410 -0
  25. specfact_cli-0.20.5/resources/templates/sidecar/sidecar-init.sh +107 -0
  26. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/__init__.py +1 -1
  27. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/__init__.py +1 -1
  28. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/generate.py +63 -68
  29. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/init.py +95 -9
  30. specfact_cli-0.20.5/src/specfact_cli/commands/repro.py +468 -0
  31. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/enrichment_parser.py +97 -24
  32. specfact_cli-0.20.5/src/specfact_cli/utils/env_manager.py +443 -0
  33. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/validators/repro_checker.py +233 -73
  34. specfact_cli-0.20.0/resources/prompts/specfact.01-import.md +0 -121
  35. specfact_cli-0.20.0/src/specfact_cli/commands/repro.py +0 -226
  36. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/.gitignore +0 -0
  37. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/LICENSE.md +0 -0
  38. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/README.md +0 -0
  39. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/mappings/node-async.yaml +0 -0
  40. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/mappings/python-async.yaml +0 -0
  41. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/mappings/speckit-default.yaml +0 -0
  42. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/prompts/specfact.07-contracts.md +0 -0
  43. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/schemas/deviation.schema.json +0 -0
  44. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/schemas/plan.schema.json +0 -0
  45. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/schemas/protocol.schema.json +0 -0
  46. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/templates/github-action.yml.j2 +0 -0
  47. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/templates/persona/architect.md.j2 +0 -0
  48. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/templates/persona/developer.md.j2 +0 -0
  49. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/templates/persona/product-owner.md.j2 +0 -0
  50. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/templates/plan.bundle.yaml.j2 +0 -0
  51. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/templates/pr-template.md.j2 +0 -0
  52. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/templates/protocol.yaml.j2 +0 -0
  53. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/resources/templates/telemetry.yaml.example +0 -0
  54. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/agents/__init__.py +0 -0
  55. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/agents/analyze_agent.py +0 -0
  56. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/agents/base.py +0 -0
  57. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/agents/plan_agent.py +0 -0
  58. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/agents/registry.py +0 -0
  59. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/agents/sync_agent.py +0 -0
  60. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/analyzers/__init__.py +0 -0
  61. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
  62. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/analyzers/code_analyzer.py +0 -0
  63. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
  64. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
  65. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
  66. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/analyzers/graph_analyzer.py +0 -0
  67. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
  68. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
  69. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
  70. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/cli.py +0 -0
  71. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/__init__.py +0 -0
  72. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/analyze.py +0 -0
  73. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/bridge.py +0 -0
  74. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/contract_cmd.py +0 -0
  75. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/drift.py +0 -0
  76. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/enforce.py +0 -0
  77. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/implement.py +0 -0
  78. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/import_cmd.py +0 -0
  79. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/migrate.py +0 -0
  80. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/plan.py +0 -0
  81. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/project_cmd.py +0 -0
  82. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/sdd.py +0 -0
  83. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/spec.py +0 -0
  84. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/commands/sync.py +0 -0
  85. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/common/__init__.py +0 -0
  86. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/common/logger_setup.py +0 -0
  87. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/common/logging_utils.py +0 -0
  88. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/common/text_utils.py +0 -0
  89. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/common/utils.py +0 -0
  90. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/comparators/__init__.py +0 -0
  91. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/comparators/plan_comparator.py +0 -0
  92. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
  93. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
  94. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/generators/__init__.py +0 -0
  95. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/generators/contract_generator.py +0 -0
  96. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/generators/openapi_extractor.py +0 -0
  97. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/generators/persona_exporter.py +0 -0
  98. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/generators/plan_generator.py +0 -0
  99. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/generators/protocol_generator.py +0 -0
  100. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/generators/report_generator.py +0 -0
  101. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/generators/task_generator.py +0 -0
  102. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/generators/test_to_openapi.py +0 -0
  103. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/generators/workflow_generator.py +0 -0
  104. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/importers/__init__.py +0 -0
  105. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/importers/speckit_converter.py +0 -0
  106. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/importers/speckit_scanner.py +0 -0
  107. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/integrations/__init__.py +0 -0
  108. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/integrations/specmatic.py +0 -0
  109. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/merge/__init__.py +0 -0
  110. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/merge/resolver.py +0 -0
  111. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/migrations/__init__.py +0 -0
  112. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/migrations/plan_migrator.py +0 -0
  113. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/models/__init__.py +0 -0
  114. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/models/bridge.py +0 -0
  115. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/models/contract.py +0 -0
  116. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/models/deviation.py +0 -0
  117. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/models/enforcement.py +0 -0
  118. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/models/persona_template.py +0 -0
  119. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/models/plan.py +0 -0
  120. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/models/project.py +0 -0
  121. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/models/protocol.py +0 -0
  122. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/models/quality.py +0 -0
  123. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/models/sdd.py +0 -0
  124. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/models/source_tracking.py +0 -0
  125. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/models/task.py +0 -0
  126. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/modes/__init__.py +0 -0
  127. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/modes/detector.py +0 -0
  128. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/modes/router.py +0 -0
  129. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/parsers/__init__.py +0 -0
  130. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/parsers/persona_importer.py +0 -0
  131. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/resources/semgrep/async.yml +0 -0
  132. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
  133. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
  134. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/runtime.py +0 -0
  135. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/sync/__init__.py +0 -0
  136. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/sync/bridge_probe.py +0 -0
  137. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/sync/bridge_sync.py +0 -0
  138. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/sync/bridge_watch.py +0 -0
  139. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/sync/change_detector.py +0 -0
  140. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/sync/code_to_spec.py +0 -0
  141. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/sync/drift_detector.py +0 -0
  142. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/sync/repository_sync.py +0 -0
  143. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/sync/spec_to_code.py +0 -0
  144. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/sync/spec_to_tests.py +0 -0
  145. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/sync/speckit_sync.py +0 -0
  146. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/sync/watcher.py +0 -0
  147. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
  148. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/telemetry.py +0 -0
  149. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/templates/__init__.py +0 -0
  150. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/templates/bridge_templates.py +0 -0
  151. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/templates/specification_templates.py +0 -0
  152. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/__init__.py +0 -0
  153. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
  154. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/bundle_loader.py +0 -0
  155. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/console.py +0 -0
  156. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/context_detection.py +0 -0
  157. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/enrichment_context.py +0 -0
  158. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/feature_keys.py +0 -0
  159. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/git.py +0 -0
  160. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/github_annotations.py +0 -0
  161. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/ide_setup.py +0 -0
  162. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/incremental_check.py +0 -0
  163. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/optional_deps.py +0 -0
  164. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/performance.py +0 -0
  165. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/progress.py +0 -0
  166. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
  167. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/prompts.py +0 -0
  168. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/sdd_discovery.py +0 -0
  169. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/source_scanner.py +0 -0
  170. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/structure.py +0 -0
  171. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/structured_io.py +0 -0
  172. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/suggestions.py +0 -0
  173. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/utils/yaml_utils.py +0 -0
  174. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/validators/__init__.py +0 -0
  175. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/validators/agile_validation.py +0 -0
  176. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/validators/cli_first_validator.py +0 -0
  177. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/validators/contract_validator.py +0 -0
  178. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/validators/fsm.py +0 -0
  179. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/validators/schema.py +0 -0
  180. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/versioning/__init__.py +0 -0
  181. {specfact_cli-0.20.0 → specfact_cli-0.20.5}/src/specfact_cli/versioning/analyzer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specfact-cli
3
- Version: 0.20.0
3
+ Version: 0.20.5
4
4
  Summary: Brownfield-first CLI: Reverse engineer legacy Python → specs → enforced contracts. Automate legacy code documentation and prevent modernization regressions.
5
5
  Project-URL: Homepage, https://github.com/nold-ai/specfact-cli
6
6
  Project-URL: Repository, https://github.com/nold-ai/specfact-cli.git
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "specfact-cli"
7
- version = "0.20.0"
7
+ version = "0.20.5"
8
8
  description = "Brownfield-first CLI: Reverse engineer legacy Python → specs → enforced contracts. Automate legacy code documentation and prevent modernization regressions."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -37,6 +37,12 @@ These operations **require LLM** and are only available via AI IDE slash prompts
37
37
  **Access**: Only available via AI IDE slash prompts (Cursor, CoPilot, etc.)
38
38
  **Pattern**: Slash prompt → LLM generates → CLI validates → Apply if valid
39
39
 
40
+ ## LLM Grounding Rules
41
+
42
+ - Treat CLI artifacts as the source of truth for keys, structure, and metadata.
43
+ - Scan the codebase only when asked to infer missing behavior/context or explain deviations; respect `--entry-point` scope when provided.
44
+ - Use codebase findings to propose updates via CLI (enrichment report, plan update commands), never to rewrite artifacts directly.
45
+
40
46
  ## Rules
41
47
 
42
48
  1. **Execute CLI First**: Always run CLI commands before any analysis
@@ -0,0 +1,263 @@
1
+ ---
2
+ description: Import codebase → plan bundle. CLI extracts routes/schemas/relationships. LLM enriches with context.
3
+ ---
4
+
5
+ # SpecFact Import Command
6
+
7
+ ## User Input
8
+
9
+ ```text
10
+ $ARGUMENTS
11
+ ```
12
+
13
+ You **MUST** consider the user input before proceeding (if not empty).
14
+
15
+ ## Purpose
16
+
17
+ Import codebase → plan bundle. CLI extracts routes/schemas/relationships/contracts. LLM enriches context/"why"/completeness.
18
+
19
+ ## Parameters
20
+
21
+ **Target/Input**: `--bundle NAME` (optional, defaults to active plan), `--repo PATH`, `--entry-point PATH`, `--enrichment PATH`
22
+ **Output/Results**: `--report PATH`
23
+ **Behavior/Options**: `--shadow-only`, `--enrich-for-speckit/--no-enrich-for-speckit` (default: enabled, uses PlanEnricher for consistent enrichment)
24
+ **Advanced/Configuration**: `--confidence FLOAT` (0.0-1.0), `--key-format FORMAT` (classname|sequential)
25
+
26
+ ## Workflow
27
+
28
+ 1. **Execute CLI**: `specfact [GLOBAL OPTIONS] import from-code [<bundle>] --repo <path> [options]`
29
+ - CLI extracts: routes (FastAPI/Flask/Django), schemas (Pydantic), relationships, contracts (OpenAPI scaffolds), source tracking
30
+ - Uses active plan if bundle not specified
31
+ - Note: `--no-interactive` is a global option and must appear before the subcommand (e.g., `specfact --no-interactive import from-code ...`).
32
+ - **Auto-enrichment enabled by default**: Automatically enhances vague acceptance criteria, incomplete requirements, and generic tasks using PlanEnricher (same logic as `plan review --auto-enrich`)
33
+ - Use `--no-enrich-for-speckit` to disable auto-enrichment
34
+ - **Contract extraction**: OpenAPI contracts are extracted automatically **only** for features with `source_tracking.implementation_files` and detectable API endpoints (FastAPI/Flask patterns). For enrichment-added features or Django apps, use `specfact contract init` after enrichment (see Phase 4)
35
+
36
+ 2. **LLM Enrichment** (Copilot-only, before applying `--enrichment`):
37
+ - Read CLI artifacts: `.specfact/projects/<bundle>/enrichment_context.md`, feature YAMLs, contract scaffolds, and brownfield reports
38
+ - Scan the codebase within `--entry-point` (and adjacent modules) to identify missing features, dependencies, and behavior; do **not** rely solely on AST-derived YAML
39
+ - Compare code findings vs CLI artifacts, then add missing features/stories, reasoning, and acceptance criteria (each added feature must include at least one story)
40
+ - Save the enrichment report to `.specfact/projects/<bundle-name>/reports/enrichment/<bundle-name>-<timestamp>.enrichment.md` (bundle-specific, Phase 8.5)
41
+ - **CRITICAL**: Follow the exact enrichment report format (see "Enrichment Report Format" section below) to ensure successful parsing
42
+
43
+ 3. **Present**: Bundle location, report path, summary (features/stories/contracts/relationships)
44
+
45
+ ## CLI Enforcement
46
+
47
+ **CRITICAL**: Always use SpecFact CLI commands. See [CLI Enforcement Rules](./shared/cli-enforcement.md) for details.
48
+
49
+ **Rules:**
50
+
51
+ - Execute CLI first - never create artifacts directly
52
+ - Use the global `--no-interactive` flag in CI/CD environments (must appear before the subcommand)
53
+ - Never modify `.specfact/` directly
54
+ - Use CLI output as grounding for validation
55
+ - Code generation requires LLM (only via AI IDE slash prompts, not CLI-only)
56
+
57
+ ## Dual-Stack Workflow (Copilot Mode)
58
+
59
+ When in copilot mode, follow this three-phase workflow:
60
+
61
+ ### Phase 1: CLI Grounding (REQUIRED)
62
+
63
+ ```bash
64
+ # Execute CLI to get structured output
65
+ specfact --no-interactive import from-code [<bundle>] --repo <path>
66
+ ```
67
+
68
+ **Capture**:
69
+
70
+ - CLI-generated artifacts (plan bundles, reports)
71
+ - Metadata (timestamps, confidence scores)
72
+ - Telemetry (execution time, file counts)
73
+
74
+ ### Phase 2: LLM Enrichment (OPTIONAL, Copilot Only)
75
+
76
+ **Purpose**: Add semantic understanding to CLI output
77
+
78
+ **What to do**:
79
+
80
+ - Read CLI-generated artifacts (use file reading tools for display only)
81
+ - Scan the codebase within `--entry-point` for missing features/behavior and compare against CLI artifacts
82
+ - Identify missing features/stories and add reasoning/acceptance criteria (no direct edits to `.specfact/`)
83
+ - Suggest confidence adjustments and extract business context
84
+ - **CRITICAL**: Generate enrichment report in the exact format specified below (see "Enrichment Report Format" section)
85
+
86
+ **What NOT to do**:
87
+
88
+ - ❌ Create YAML/JSON artifacts directly
89
+ - ❌ Modify CLI artifacts directly (use CLI commands to update)
90
+ - ❌ Bypass CLI validation
91
+ - ❌ Write to `.specfact/` folder directly (always use CLI)
92
+ - ❌ Use direct file manipulation tools for writing (use CLI commands)
93
+ - ❌ Deviate from the enrichment report format (will cause parsing failures)
94
+
95
+ **Output**: Generate enrichment report (Markdown) saved to `.specfact/projects/<bundle-name>/reports/enrichment/` (bundle-specific, Phase 8.5)
96
+
97
+ **Enrichment Report Format** (REQUIRED for successful parsing):
98
+
99
+ The enrichment parser expects a specific Markdown format. Follow this structure exactly:
100
+
101
+ ```markdown
102
+ # [Bundle Name] Enrichment Report
103
+
104
+ **Date**: YYYY-MM-DDTHH:MM:SS
105
+ **Bundle**: <bundle-name>
106
+
107
+ ---
108
+
109
+ ## Missing Features
110
+
111
+ 1. **Feature Title** (Key: FEATURE-XXX)
112
+ - Confidence: 0.85
113
+ - Outcomes: outcome1, outcome2, outcome3
114
+ - Stories:
115
+ 1. Story title here
116
+ - Acceptance: criterion1, criterion2, criterion3
117
+ 2. Another story title
118
+ - Acceptance: criterion1, criterion2
119
+
120
+ 2. **Another Feature** (Key: FEATURE-YYY)
121
+ - Confidence: 0.80
122
+ - Outcomes: outcome1, outcome2
123
+ - Stories:
124
+ 1. Story title
125
+ - Acceptance: criterion1, criterion2, criterion3
126
+
127
+ ## Confidence Adjustments
128
+
129
+ - FEATURE-EXISTING-KEY: 0.90 (reason: improved understanding after code review)
130
+
131
+ ## Business Context
132
+
133
+ - Priority: High priority feature for core functionality
134
+ - Constraint: Must support both REST and GraphQL APIs
135
+ - Risk: Potential performance issues with large datasets
136
+ ```
137
+
138
+ **Format Requirements**:
139
+
140
+ 1. **Section Header**: Must use `## Missing Features` (case-insensitive, but prefer this exact format)
141
+ 2. **Feature Format**:
142
+ - Numbered list: `1. **Feature Title** (Key: FEATURE-XXX)`
143
+ - **Bold title** is required (use `**Title**`)
144
+ - **Key in parentheses**: `(Key: FEATURE-XXX)` - must be uppercase, alphanumeric with hyphens/underscores
145
+ - Fields on separate lines with `-` prefix:
146
+ - `- Confidence: 0.85` (float between 0.0-1.0)
147
+ - `- Outcomes: comma-separated or line-separated list`
148
+ - `- Stories:` (required - each feature must have at least one story)
149
+ 3. **Stories Format**:
150
+ - Numbered list under `Stories:` section: `1. Story title`
151
+ - **Indentation**: Stories must be indented (2-4 spaces) under the feature
152
+ - **Acceptance Criteria**: `- Acceptance: criterion1, criterion2, criterion3`
153
+ - Can be comma-separated on one line
154
+ - Or multi-line (each criterion on new line)
155
+ - Must start with `- Acceptance:`
156
+ 4. **Optional Sections**:
157
+ - `## Confidence Adjustments`: List existing features with confidence updates
158
+ - `## Business Context`: Priorities, constraints, risks (bullet points)
159
+ 5. **File Naming**: `<bundle-name>-<timestamp>.enrichment.md` (e.g., `djangogoat-2025-12-23T23-50-00.enrichment.md`)
160
+
161
+ **Example** (working format):
162
+
163
+ ```markdown
164
+ ## Missing Features
165
+
166
+ 1. **User Authentication** (Key: FEATURE-USER-AUTHENTICATION)
167
+ - Confidence: 0.85
168
+ - Outcomes: User registration, login, profile management
169
+ - Stories:
170
+ 1. User can sign up for new account
171
+ - Acceptance: sign_up view processes POST requests, creates User automatically, user is logged in after signup, redirects to profile page
172
+ 2. User can log in with credentials
173
+ - Acceptance: log_in view authenticates username/password, on success user is logged in and redirected, on failure error message is displayed
174
+ ```
175
+
176
+ **Common Mistakes to Avoid**:
177
+
178
+ - ❌ Missing `(Key: FEATURE-XXX)` - parser needs this to identify features
179
+ - ❌ Missing `Stories:` section - every feature must have at least one story
180
+ - ❌ Stories not indented - parser expects indented numbered lists
181
+ - ❌ Missing `- Acceptance:` prefix - acceptance criteria won't be parsed
182
+ - ❌ Using bullet points (`-`) instead of numbers (`1.`) for stories
183
+ - ❌ Feature title not in bold (`**Title**`) - parser may not extract title correctly
184
+
185
+ ### Phase 3: CLI Artifact Creation (REQUIRED)
186
+
187
+ ```bash
188
+ # Use enrichment to update plan via CLI
189
+ specfact --no-interactive import from-code [<bundle>] --repo <path> --enrichment <enrichment-report>
190
+ ```
191
+
192
+ **Result**: Final artifacts are CLI-generated with validated enrichments
193
+
194
+ **Note**: If code generation is needed, use the validation loop pattern (see [CLI Enforcement Rules](./shared/cli-enforcement.md#standard-validation-loop-pattern-for-llm-generated-code))
195
+
196
+ ### Phase 4: OpenAPI Contract Generation (REQUIRED for Sidecar Validation)
197
+
198
+ **When contracts are generated automatically:**
199
+
200
+ The `import from-code` command attempts to extract OpenAPI contracts automatically, but **only if**:
201
+
202
+ 1. Features have `source_tracking.implementation_files` (AST-detected features)
203
+ 2. The OpenAPI extractor finds API endpoints (FastAPI/Flask patterns like `@app.get`, `@router.post`, `@app.route`)
204
+
205
+ **When contracts are NOT generated:**
206
+
207
+ Contracts are **NOT** generated automatically when:
208
+
209
+ - Features were added via enrichment (no `source_tracking.implementation_files`)
210
+ - Django applications (Django `path()` patterns are not detected by the extractor)
211
+ - Features without API endpoints (models, utilities, middleware, etc.)
212
+ - Framework SDKs or libraries without web endpoints
213
+
214
+ **How to generate contracts manually:**
215
+
216
+ For features that need OpenAPI contracts (e.g., for sidecar validation with CrossHair), use:
217
+
218
+ ```bash
219
+ # Generate contract for a single feature
220
+ specfact --no-interactive contract init --bundle <bundle-name> --feature <FEATURE_KEY> --repo <path>
221
+
222
+ # Example: Generate contracts for all enrichment-added features
223
+ specfact --no-interactive contract init --bundle djangogoat-validation --feature FEATURE-USER-AUTHENTICATION --repo .
224
+ specfact --no-interactive contract init --bundle djangogoat-validation --feature FEATURE-NOTES-MANAGEMENT --repo .
225
+ # ... repeat for each feature that needs a contract
226
+ ```
227
+
228
+ **When to apply contract generation:**
229
+
230
+ - **After Phase 3** (enrichment applied): Check which features have contracts in `.specfact/projects/<bundle>/contracts/`
231
+ - **Before sidecar validation**: All features that will be analyzed by CrossHair/Specmatic need OpenAPI contracts
232
+ - **For Django apps**: Always generate contracts manually after enrichment, as Django URL patterns are not auto-detected
233
+
234
+ **Verification:**
235
+
236
+ ```bash
237
+ # Check which features have contracts
238
+ ls .specfact/projects/<bundle>/contracts/*.yaml
239
+
240
+ # Compare with total features
241
+ ls .specfact/projects/<bundle>/features/*.yaml
242
+ ```
243
+
244
+ If the contract count is less than the feature count, generate missing contracts using `contract init`.
245
+
246
+ ## Expected Output
247
+
248
+ **Success**: Bundle location, report path, summary (features/stories/contracts/relationships)
249
+ **Error**: Missing bundle name or bundle already exists
250
+
251
+ ## Common Patterns
252
+
253
+ ```bash
254
+ /specfact.01-import --repo . # Uses active plan, auto-enrichment enabled by default
255
+ /specfact.01-import --bundle legacy-api --repo . # Auto-enrichment enabled
256
+ /specfact.01-import --repo . --no-enrich-for-speckit # Disable auto-enrichment
257
+ /specfact.01-import --repo . --entry-point src/auth/
258
+ /specfact.01-import --repo . --enrichment report.md
259
+ ```
260
+
261
+ ## Context
262
+
263
+ {ARGS}
@@ -107,7 +107,9 @@ specfact plan <operation> [--bundle <name>] [options] --no-interactive
107
107
  **What to do**:
108
108
 
109
109
  - Read CLI-generated artifacts (use file reading tools for display only)
110
- - Research codebase for additional context
110
+ - Use CLI artifacts as the source of truth for keys/structure/metadata
111
+ - Scan codebase only if asked to align the plan with implementation or to add missing features
112
+ - When scanning, compare findings against CLI artifacts and propose updates via CLI commands
111
113
  - Identify missing features/stories
112
114
  - Suggest confidence adjustments
113
115
  - Extract business context
@@ -135,6 +135,9 @@ For these cases, use the **export-to-file → LLM reasoning → import-from-file
135
135
 
136
136
  **CRITICAL**: Always use `/tmp/` for temporary artifacts to avoid polluting the codebase. Never create temporary files in the project root.
137
137
 
138
+ **CRITICAL**: Question IDs are generated per run and can change if you re-run review.
139
+ **Do not** re-run `plan review` between exporting questions and applying answers. Always answer using the exact exported questions file for that session.
140
+
138
141
  **Note**: The `--max-questions` parameter (default: 5) limits the number of questions per session, not the total number of available questions. If there are more questions available, you may need to run the review multiple times to answer all questions. Each session will ask different questions (avoiding duplicates from previous sessions).
139
142
 
140
143
  **Export questions to file for LLM reasoning:**
@@ -397,6 +400,11 @@ specfact plan review [<bundle-name>] --list-questions --output-questions /tmp/qu
397
400
 
398
401
  **What to do**:
399
402
 
403
+ 0. **Grounding rule**:
404
+ - Treat CLI-exported questions as the source of truth; consult codebase/docs only to answer them (do not invent new artifacts)
405
+ - **Feature/Story Completeness note**: Answers here are clarifications only. They do **NOT** create stories.
406
+ For missing stories, use `specfact plan add-story` (or `plan update-story --batch-updates` if stories already exist).
407
+
400
408
  1. **Read exported questions file** (`/tmp/questions.json`):
401
409
  - Review all questions and their categories
402
410
  - Identify questions requiring code/feature analysis
@@ -605,6 +613,102 @@ Create one with: specfact plan init legacy-api
605
613
  - Use `plan update-idea` to update idea fields directly
606
614
  - If bundle needs regeneration, use `import from-code --enrichment`
607
615
 
616
+ **Note on OpenAPI Contracts:**
617
+
618
+ After applying enrichment or review updates, check if features need OpenAPI contracts for sidecar validation:
619
+
620
+ - Features added via enrichment typically don't have contracts (no `source_tracking`)
621
+ - Django applications require manual contract generation (Django URL patterns not auto-detected)
622
+ - Use `specfact contract init --bundle <bundle> --feature <FEATURE_KEY>` to generate contracts for features that need them
623
+
624
+ **Enrichment Report Format** (for `import from-code --enrichment`):
625
+
626
+ When generating enrichment reports for use with `import from-code --enrichment`, follow this exact format:
627
+
628
+ ```markdown
629
+ # [Bundle Name] Enrichment Report
630
+
631
+ **Date**: YYYY-MM-DDTHH:MM:SS
632
+ **Bundle**: <bundle-name>
633
+
634
+ ---
635
+
636
+ ## Missing Features
637
+
638
+ 1. **Feature Title** (Key: FEATURE-XXX)
639
+ - Confidence: 0.85
640
+ - Outcomes: outcome1, outcome2, outcome3
641
+ - Stories:
642
+ 1. Story title here
643
+ - Acceptance: criterion1, criterion2, criterion3
644
+ 2. Another story title
645
+ - Acceptance: criterion1, criterion2
646
+
647
+ 2. **Another Feature** (Key: FEATURE-YYY)
648
+ - Confidence: 0.80
649
+ - Outcomes: outcome1, outcome2
650
+ - Stories:
651
+ 1. Story title
652
+ - Acceptance: criterion1, criterion2, criterion3
653
+
654
+ ## Confidence Adjustments
655
+
656
+ - FEATURE-EXISTING-KEY: 0.90 (reason: improved understanding after code review)
657
+
658
+ ## Business Context
659
+
660
+ - Priority: High priority feature for core functionality
661
+ - Constraint: Must support both REST and GraphQL APIs
662
+ - Risk: Potential performance issues with large datasets
663
+ ```
664
+
665
+ **Format Requirements**:
666
+
667
+ 1. **Section Header**: Must use `## Missing Features` (case-insensitive, but prefer this exact format)
668
+ 2. **Feature Format**:
669
+ - Numbered list: `1. **Feature Title** (Key: FEATURE-XXX)`
670
+ - **Bold title** is required (use `**Title**`)
671
+ - **Key in parentheses**: `(Key: FEATURE-XXX)` - must be uppercase, alphanumeric with hyphens/underscores
672
+ - Fields on separate lines with `-` prefix:
673
+ - `- Confidence: 0.85` (float between 0.0-1.0)
674
+ - `- Outcomes: comma-separated or line-separated list`
675
+ - `- Stories:` (required - each feature must have at least one story)
676
+ 3. **Stories Format**:
677
+ - Numbered list under `Stories:` section: `1. Story title`
678
+ - **Indentation**: Stories must be indented (2-4 spaces) under the feature
679
+ - **Acceptance Criteria**: `- Acceptance: criterion1, criterion2, criterion3`
680
+ - Can be comma-separated on one line
681
+ - Or multi-line (each criterion on new line)
682
+ - Must start with `- Acceptance:`
683
+ 4. **Optional Sections**:
684
+ - `## Confidence Adjustments`: List existing features with confidence updates
685
+ - `## Business Context`: Priorities, constraints, risks (bullet points)
686
+ 5. **File Naming**: `<bundle-name>-<timestamp>.enrichment.md` (e.g., `djangogoat-2025-12-23T23-50-00.enrichment.md`)
687
+
688
+ **Example** (working format):
689
+
690
+ ```markdown
691
+ ## Missing Features
692
+
693
+ 1. **User Authentication** (Key: FEATURE-USER-AUTHENTICATION)
694
+ - Confidence: 0.85
695
+ - Outcomes: User registration, login, profile management
696
+ - Stories:
697
+ 1. User can sign up for new account
698
+ - Acceptance: sign_up view processes POST requests, creates User automatically, user is logged in after signup, redirects to profile page
699
+ 2. User can log in with credentials
700
+ - Acceptance: log_in view authenticates username/password, on success user is logged in and redirected, on failure error message is displayed
701
+ ```
702
+
703
+ **Common Mistakes to Avoid**:
704
+
705
+ - ❌ Missing `(Key: FEATURE-XXX)` - parser needs this to identify features
706
+ - ❌ Missing `Stories:` section - every feature must have at least one story
707
+ - ❌ Stories not indented - parser expects indented numbered lists
708
+ - ❌ Missing `- Acceptance:` prefix - acceptance criteria won't be parsed
709
+ - ❌ Using bullet points (`-`) instead of numbers (`1.`) for stories
710
+ - ❌ Feature title not in bold (`**Title**`) - parser may not extract title correctly
711
+
608
712
  ## Context
609
713
 
610
714
  {ARGS}
@@ -90,6 +90,7 @@ specfact plan harden [<bundle-name>] [--sdd <path>] --no-interactive
90
90
  **What to do**:
91
91
 
92
92
  - Read CLI-generated SDD (use file reading tools for display only)
93
+ - Treat CLI SDD as the source of truth; scan codebase only to enrich WHY/WHAT/HOW context
93
94
  - Research codebase for additional context
94
95
  - Suggest improvements to WHY/WHAT/HOW sections
95
96
 
@@ -94,6 +94,7 @@ specfact enforce sdd [<bundle-name>] [--sdd <path>] --no-interactive
94
94
  **What to do**:
95
95
 
96
96
  - Read CLI-generated validation report (use file reading tools for display only)
97
+ - Treat the CLI report as the source of truth; scan codebase only to explain deviations or propose fixes
97
98
  - Research codebase for context on deviations
98
99
  - Suggest fixes for validation failures
99
100
 
@@ -97,6 +97,7 @@ specfact sync bridge --adapter <adapter> --repo <path> [options] --no-interactiv
97
97
  **What to do**:
98
98
 
99
99
  - Read CLI-generated sync results (use file reading tools for display only)
100
+ - Treat CLI sync output as the source of truth; scan codebase only to explain conflicts
100
101
  - Research codebase for context on conflicts
101
102
  - Suggest resolution strategies
102
103
 
@@ -94,6 +94,7 @@ specfact plan compare [--bundle <name>] [options] --no-interactive
94
94
  **What to do**:
95
95
 
96
96
  - Read CLI-generated comparison report (use file reading tools for display only)
97
+ - Treat the comparison report as the source of truth; scan codebase only to explain or confirm deviations
97
98
  - Research codebase for context on deviations
98
99
  - Suggest fixes for missing features or mismatches
99
100
 
@@ -96,6 +96,7 @@ specfact repro --repo <path> [options] --no-interactive
96
96
  **What to do**:
97
97
 
98
98
  - Read CLI-generated validation report (use file reading tools for display only)
99
+ - Treat the validation report as the source of truth; scan codebase only to explain failures
99
100
  - Research codebase for context on failures
100
101
  - Suggest fixes for validation failures
101
102
 
@@ -0,0 +1,187 @@
1
+ # Sidecar Validation Templates
2
+
3
+ Purpose: Run validation tools against a target repository without modifying its source.
4
+
5
+ This template set is intended for Phase B validation and can be copied into a
6
+ separate sidecar workspace. Use `.specfact/projects/<bundle>/contracts/` as the
7
+ source of truth for API contracts (specmatic/OpenAPI).
8
+
9
+ ## Quick Start
10
+
11
+ 1. Copy this folder into a sidecar workspace, or run:
12
+
13
+ ```bash
14
+ ./sidecar-init.sh /path/to/sidecar /path/to/target/repo bundle-name
15
+ ```
16
+
17
+ 1. Export environment variables (or use the `.env` file created by `sidecar-init.sh`):
18
+
19
+ ```bash
20
+ export REPO_PATH=/path/to/target/repo
21
+ export BUNDLE_NAME=bundle-name
22
+ export SEMGREP_CONFIG=/path/to/semgrep.yml # optional
23
+ export REPO_PYTHONPATH="/path/to/target/repo/src:/path/to/target/repo"
24
+ export SIDECAR_SOURCE_DIRS="/path/to/target/repo/src" # optional (defaults to src/)
25
+ export PYTHON_CMD=python3 # optional (auto-detects venv if .venv/ or venv/ exists)
26
+ export DJANGO_SETTINGS_MODULE=project.settings # optional (auto-detected for Django projects)
27
+ export SPECMATIC_CMD=/path/to/specmatic # optional (CLI binary, or: "npx --yes specmatic")
28
+ export SPECMATIC_JAR=/path/to/specmatic.jar # optional (java -jar fallback)
29
+ export SPECMATIC_CONFIG=/path/to/specmatic.yaml # optional config file
30
+ export SPECMATIC_TEST_BASE_URL=http://localhost:5000 # optional target
31
+ export SPECMATIC_HOST=localhost # optional target host
32
+ export SPECMATIC_PORT=5000 # optional target port
33
+ export SPECMATIC_TIMEOUT=30 # optional request timeout (seconds)
34
+ export SPECMATIC_AUTO_STUB=1 # optional (default: 1) run stub when no target configured
35
+ export SPECMATIC_STUB_HOST=127.0.0.1 # optional stub host
36
+ export SPECMATIC_STUB_PORT=19000 # optional stub port
37
+ export SPECMATIC_STUB_WAIT=15 # optional stub startup wait (seconds)
38
+ export SIDECAR_APP_CMD="python -m your_app" # optional app command to run
39
+ export SIDECAR_APP_HOST=127.0.0.1 # optional app host
40
+ export SIDECAR_APP_PORT=5000 # optional app port
41
+ export SIDECAR_APP_WAIT=15 # optional app startup wait (seconds)
42
+ export BINDINGS_PATH=/path/to/bindings.yaml # optional bindings map
43
+ export FEATURES_DIR=/path/to/features # optional features dir (FEATURE-*.yaml)
44
+ export CROSSHAIR_VERBOSE=1 # optional CrossHair debug output
45
+ export CROSSHAIR_REPORT_ALL=1 # optional report all postconditions
46
+ export CROSSHAIR_REPORT_VERBOSE=1 # optional report stack traces
47
+ export CROSSHAIR_MAX_UNINTERESTING_ITERATIONS=50 # optional iteration budget
48
+ export CROSSHAIR_PER_PATH_TIMEOUT=2 # optional per-path timeout
49
+ export CROSSHAIR_PER_CONDITION_TIMEOUT=10 # optional per-condition timeout
50
+ export CROSSHAIR_ANALYSIS_KIND=icontract # optional kinds (comma-separated)
51
+ export CROSSHAIR_EXTRA_PLUGIN=/path/to/plugin.py # optional extra plugins
52
+ export RUN_BASEDPYRIGHT=0 # optional toggle per tool (default: 0)
53
+ export TIMEOUT_BASEDPYRIGHT=30 # optional per-tool timeout
54
+ export GENERATE_HARNESS=1 # optional (default: 1)
55
+ export HARNESS_PATH=harness_contracts.py # optional
56
+ export INPUTS_PATH=inputs.json # optional
57
+ export SIDECAR_REPORTS_DIR=/path/to/repo/.specfact/projects/bundle/reports/sidecar # optional
58
+ ```
59
+
60
+ 1. Run the sidecar script:
61
+
62
+ ```bash
63
+ ./run_sidecar.sh
64
+ ```
65
+
66
+ ## Refreshing the Sidecar Workspace
67
+
68
+ If you update templates (for example `adapters.py`, `run_sidecar.sh`, or the
69
+ harness generator), re-initialize the sidecar workspace so the new templates
70
+ are copied over:
71
+
72
+ ```bash
73
+ ./sidecar-init.sh /path/to/sidecar /path/to/target/repo bundle-name
74
+ ```
75
+
76
+ Notes:
77
+
78
+ - This overwrites existing template files in the sidecar workspace.
79
+ - Preserve local changes (for example `bindings.yaml` or `.env`) before
80
+ re-running if you have custom edits.
81
+ - Re-run `./run_sidecar.sh` with `GENERATE_HARNESS=1` if you want a fresh
82
+ `harness_contracts.py` and `inputs.json` after template updates.
83
+
84
+ ## Notes
85
+
86
+ - CrossHair requires contracts (icontract/PEP316/deal) or registered contracts.
87
+ Use `harness_contracts.py` or `crosshair_plugin.py` to attach contracts
88
+ externally without touching production code.
89
+
90
+ - **Dual CrossHair Analysis**: The sidecar runs CrossHair in two modes:
91
+ 1. **Source code analysis**: Analyzes source directories directly to catch existing decorators
92
+ (beartype, icontract, PEP316, deal) already present in the codebase (e.g., SpecFact CLI dogfooding).
93
+ 2. **Harness analysis**: Analyzes generated harness files to catch contracts added externally
94
+ for code without decorators (e.g., DjangoGoat, Flask, Requests).
95
+
96
+ Both analyses are necessary for complete coverage:
97
+ - **Case A**: Code with existing decorators → CrossHair analyzes source directly
98
+ - **Case B**: Code without decorators → CrossHair analyzes harness with externally-added contracts
99
+ - Specmatic contracts are expected in:
100
+ `<REPO_PATH>/.specfact/projects/<BUNDLE_NAME>/contracts/`
101
+ - If you only have the Python `specmatic` package installed, note it does not
102
+ expose a CLI or module runner. Provide a CLI path (`SPECMATIC_CMD`), use `npx`,
103
+ or supply a jar (`SPECMATIC_JAR`) to execute Specmatic in the sidecar.
104
+ - For contract tests that hit a running service, set `SPECMATIC_TEST_BASE_URL`
105
+ (or `SPECMATIC_HOST`/`SPECMATIC_PORT`) so Specmatic knows where to send requests.
106
+ - If you don't have a target service, the sidecar can auto-start a Specmatic
107
+ stub (`SPECMATIC_AUTO_STUB=1`) or launch a real service with `SIDECAR_APP_CMD`.
108
+ - All reports/logs should be written to SpecFact bundle reports, not into the
109
+ target repo.
110
+
111
+ ## CrossHair Defaults (Suggested)
112
+
113
+ These defaults provide stable results for most repositories; tune them if your
114
+ codebase is large or has heavy initialization.
115
+
116
+ ```bash
117
+ export CROSSHAIR_ANALYSIS_KIND=icontract
118
+ export CROSSHAIR_PER_PATH_TIMEOUT=2
119
+ export CROSSHAIR_PER_CONDITION_TIMEOUT=10
120
+ export CROSSHAIR_MAX_UNINTERESTING_ITERATIONS=50
121
+ export CROSSHAIR_REPORT_ALL=1
122
+ export CROSSHAIR_REPORT_VERBOSE=0
123
+ ```
124
+
125
+ ## Tool Toggles & Timeouts
126
+
127
+ The sidecar runner supports basic toggles (set to `0` to skip):
128
+
129
+ - `RUN_SEMGREP`, `RUN_BASEDPYRIGHT`, `RUN_SPECMATIC`, `RUN_CROSSHAIR`
130
+ - `GENERATE_HARNESS` (generate `harness_contracts.py` and `inputs.json` from OpenAPI)
131
+
132
+ And per-tool timeouts in seconds:
133
+
134
+ - `TIMEOUT_SEMGREP`, `TIMEOUT_BASEDPYRIGHT`, `TIMEOUT_SPECMATIC`, `TIMEOUT_CROSSHAIR`
135
+
136
+ ## Harness Generation
137
+
138
+ The harness is auto-generated from OpenAPI contracts in:
139
+ `<REPO_PATH>/.specfact/projects/<BUNDLE_NAME>/contracts/`
140
+
141
+ Generated outputs (in the sidecar workspace):
142
+
143
+ - `harness_contracts.py` (CrossHair harness)
144
+ - `inputs.json` (deterministic example requests/responses)
145
+ - `bindings.yaml` (optional mapping to real code)
146
+
147
+ Bindings let you attach harness functions to real code without editing the repo.
148
+ If `bindings.yaml` is present, the harness will call the bound function instead
149
+ of returning a fixed example.
150
+
151
+ Binding schema (minimal):
152
+
153
+ ```yaml
154
+ bindings:
155
+ - operation_id: create_item
156
+ target: your_package.factory:ItemFactory
157
+ method: create
158
+ factory:
159
+ args: ["$request.item_type"]
160
+ call_style: kwargs
161
+ ```
162
+
163
+ Optional keys:
164
+
165
+ - `adapter`: name of a function in `adapters.py` to handle complex setup.
166
+ - `factory.target`: alternate factory callable (module:func) to create instance.
167
+ - `factory.args` / `factory.kwargs`: supports `$request.<key>` or `$env.<VAR>` values.
168
+
169
+ Available adapters (see `adapters.py` for config fields):
170
+
171
+ - `call_method_with_factory`: construct instance then call method.
172
+ - `call_constructor_then_method`: construct instance via `init` and call method.
173
+ - `call_classmethod`: call a classmethod/staticmethod on a class target.
174
+ - `call_with_context_manager`: create resource in `with` block then call method.
175
+ - `call_async`: call async function and run the coroutine.
176
+ - `call_with_setup_teardown`: run setup/teardown around a target call.
177
+ - `call_with_request_transform`: rename/drop/set/coerce request fields before call.
178
+ - `call_generator`: consume a generator/iterator and return list/last/count.
179
+ - `call_from_registry`: resolve a callable from a registry/entrypoint map.
180
+ - `call_with_overrides`: temporarily override module attributes during a call.
181
+ - `call_with_contextvars`: set context variables for the call duration.
182
+ - `call_with_session`: create a session/transaction around the call.
183
+ - `call_with_callbacks`: inject callbacks into the request payload.
184
+
185
+ Logs are written to:
186
+
187
+ - `<REPO_PATH>/.specfact/projects/<BUNDLE_NAME>/reports/sidecar/`