devflow-engine 1.0.0__py3-none-any.whl

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 (393) hide show
  1. devflow_engine/__init__.py +3 -0
  2. devflow_engine/agentic_prompts.py +100 -0
  3. devflow_engine/agentic_runtime.py +398 -0
  4. devflow_engine/api_key_flow_harness.py +539 -0
  5. devflow_engine/api_keys.py +357 -0
  6. devflow_engine/bootstrap/__init__.py +2 -0
  7. devflow_engine/bootstrap/provision_from_template.py +84 -0
  8. devflow_engine/cli/__init__.py +0 -0
  9. devflow_engine/cli/app.py +7270 -0
  10. devflow_engine/core/__init__.py +0 -0
  11. devflow_engine/core/config.py +86 -0
  12. devflow_engine/core/logging.py +29 -0
  13. devflow_engine/core/paths.py +45 -0
  14. devflow_engine/core/toml_kv.py +33 -0
  15. devflow_engine/devflow_event_worker.py +1292 -0
  16. devflow_engine/devflow_state.py +201 -0
  17. devflow_engine/devin2/__init__.py +9 -0
  18. devflow_engine/devin2/agent_definition.py +120 -0
  19. devflow_engine/devin2/pi_runner.py +204 -0
  20. devflow_engine/devin_orchestration.py +69 -0
  21. devflow_engine/docs/prompts/anti-patterns.md +42 -0
  22. devflow_engine/docs/prompts/devin-agent-prompt.md +55 -0
  23. devflow_engine/docs/prompts/devin2-agent-prompt.md +81 -0
  24. devflow_engine/docs/prompts/examples/devin-vapi-clone-reference-exchange.json +85 -0
  25. devflow_engine/doctor/__init__.py +2 -0
  26. devflow_engine/doctor/triage.py +140 -0
  27. devflow_engine/error/__init__.py +0 -0
  28. devflow_engine/error/remediation.py +21 -0
  29. devflow_engine/errors/error_solver_dag.py +522 -0
  30. devflow_engine/errors/runtime_observability.py +67 -0
  31. devflow_engine/idea/__init__.py +4 -0
  32. devflow_engine/idea/actors.py +481 -0
  33. devflow_engine/idea/agentic.py +465 -0
  34. devflow_engine/idea/analyze.py +93 -0
  35. devflow_engine/idea/devin_chat_dag.py +1 -0
  36. devflow_engine/idea/diff.py +99 -0
  37. devflow_engine/idea/drafts.py +446 -0
  38. devflow_engine/idea/idea_creation_dag.py +643 -0
  39. devflow_engine/idea/ideation_enrichment.py +355 -0
  40. devflow_engine/idea/ideation_enrichment_worker.py +19 -0
  41. devflow_engine/idea/paths.py +28 -0
  42. devflow_engine/idea/promote.py +53 -0
  43. devflow_engine/idea/redaction.py +27 -0
  44. devflow_engine/idea/repo_tools.py +1277 -0
  45. devflow_engine/idea/response_mode.py +30 -0
  46. devflow_engine/idea/story_pipeline.py +1585 -0
  47. devflow_engine/idea/sufficiency.py +376 -0
  48. devflow_engine/idea/traditional_stories.py +1257 -0
  49. devflow_engine/implementation/__init__.py +0 -0
  50. devflow_engine/implementation/alembic_preflight.py +700 -0
  51. devflow_engine/implementation/dag.py +8450 -0
  52. devflow_engine/implementation/green_gate.py +93 -0
  53. devflow_engine/implementation/prompts.py +108 -0
  54. devflow_engine/implementation/test_runtime.py +623 -0
  55. devflow_engine/integration/__init__.py +19 -0
  56. devflow_engine/integration/agentic.py +66 -0
  57. devflow_engine/integration/dag.py +3539 -0
  58. devflow_engine/integration/prompts.py +114 -0
  59. devflow_engine/integration/supabase_schema.sql +31 -0
  60. devflow_engine/integration/supabase_sync.py +177 -0
  61. devflow_engine/llm/__init__.py +1 -0
  62. devflow_engine/llm/cli_one_shot.py +84 -0
  63. devflow_engine/llm/cli_stream.py +371 -0
  64. devflow_engine/llm/execution_context.py +26 -0
  65. devflow_engine/llm/invoke.py +1322 -0
  66. devflow_engine/llm/provider_api.py +304 -0
  67. devflow_engine/llm/repo_knowledge.py +588 -0
  68. devflow_engine/llm_primitives.py +315 -0
  69. devflow_engine/orchestration.py +62 -0
  70. devflow_engine/planning/__init__.py +0 -0
  71. devflow_engine/planning/analyze_repo.py +92 -0
  72. devflow_engine/planning/render_drafts.py +133 -0
  73. devflow_engine/playground/__init__.py +0 -0
  74. devflow_engine/playground/hooks.py +26 -0
  75. devflow_engine/playwright_workflow/__init__.py +5 -0
  76. devflow_engine/playwright_workflow/dag.py +1317 -0
  77. devflow_engine/process/__init__.py +5 -0
  78. devflow_engine/process/dag.py +59 -0
  79. devflow_engine/project_registration/__init__.py +3 -0
  80. devflow_engine/project_registration/dag.py +1581 -0
  81. devflow_engine/project_registry.py +109 -0
  82. devflow_engine/prompts/devin/generic/prompt.md +6 -0
  83. devflow_engine/prompts/devin/ideation/prompt.md +263 -0
  84. devflow_engine/prompts/devin/ideation/scenarios.md +5 -0
  85. devflow_engine/prompts/devin/ideation_loop/prompt.md +6 -0
  86. devflow_engine/prompts/devin/insight/prompt.md +11 -0
  87. devflow_engine/prompts/devin/insight/scenarios.md +5 -0
  88. devflow_engine/prompts/devin/intake/prompt.md +15 -0
  89. devflow_engine/prompts/devin/iterate/prompt.md +12 -0
  90. devflow_engine/prompts/devin/shared/eval_doctrine.md +9 -0
  91. devflow_engine/prompts/devin/shared/principles.md +246 -0
  92. devflow_engine/prompts/devin_eval/assessment/prompt.md +18 -0
  93. devflow_engine/prompts/idea/api_ideation_agent/prompt.md +8 -0
  94. devflow_engine/prompts/idea/api_insight_agent/prompt.md +8 -0
  95. devflow_engine/prompts/idea/response_doctrine/prompt.md +18 -0
  96. devflow_engine/prompts/implementation/dependency_assessment/prompt.md +12 -0
  97. devflow_engine/prompts/implementation/green/green/prompt.md +11 -0
  98. devflow_engine/prompts/implementation/green/node_config/prompt.md +3 -0
  99. devflow_engine/prompts/implementation/green_review/outcome_review/prompt.md +5 -0
  100. devflow_engine/prompts/implementation/green_review/prior_run_review/prompt.md +5 -0
  101. devflow_engine/prompts/implementation/red/prompt.md +27 -0
  102. devflow_engine/prompts/implementation/redreview/prompt.md +23 -0
  103. devflow_engine/prompts/implementation/redreview_repair/prompt.md +16 -0
  104. devflow_engine/prompts/implementation/setupdoc/prompt.md +10 -0
  105. devflow_engine/prompts/implementation/story_planning/prompt.md +13 -0
  106. devflow_engine/prompts/implementation/test_design/prompt.md +27 -0
  107. devflow_engine/prompts/integration/README.md +185 -0
  108. devflow_engine/prompts/integration/green/example.md +67 -0
  109. devflow_engine/prompts/integration/green/green/prompt.md +10 -0
  110. devflow_engine/prompts/integration/green/node_config/prompt.md +42 -0
  111. devflow_engine/prompts/integration/green/past_prompts/20260417T212300/green/prompt.md +15 -0
  112. devflow_engine/prompts/integration/green/past_prompts/20260417T212300/node_config/prompt.md +42 -0
  113. devflow_engine/prompts/integration/green_enrich/example.md +79 -0
  114. devflow_engine/prompts/integration/green_enrich/green_enrich/prompt.md +9 -0
  115. devflow_engine/prompts/integration/green_enrich/node_config/prompt.md +41 -0
  116. devflow_engine/prompts/integration/green_enrich/past_prompts/20260417T212300/green_enrich/prompt.md +14 -0
  117. devflow_engine/prompts/integration/green_enrich/past_prompts/20260417T212300/node_config/prompt.md +41 -0
  118. devflow_engine/prompts/integration/red/code_repair/prompt.md +12 -0
  119. devflow_engine/prompts/integration/red/example.md +152 -0
  120. devflow_engine/prompts/integration/red/node_config/prompt.md +86 -0
  121. devflow_engine/prompts/integration/red/past_prompts/20260417T212300/code_repair/prompt.md +19 -0
  122. devflow_engine/prompts/integration/red/past_prompts/20260417T212300/node_config/prompt.md +84 -0
  123. devflow_engine/prompts/integration/red/past_prompts/20260417T212300/red/prompt.md +16 -0
  124. devflow_engine/prompts/integration/red/past_prompts/20260417T212300/red_repair/prompt.md +15 -0
  125. devflow_engine/prompts/integration/red/past_prompts/20260417T215032/code_repair/prompt.md +10 -0
  126. devflow_engine/prompts/integration/red/past_prompts/20260417T215032/node_config/prompt.md +84 -0
  127. devflow_engine/prompts/integration/red/past_prompts/20260417T215032/red_repair/prompt.md +11 -0
  128. devflow_engine/prompts/integration/red/red/prompt.md +11 -0
  129. devflow_engine/prompts/integration/red/red_repair/prompt.md +12 -0
  130. devflow_engine/prompts/integration/red_review/example.md +71 -0
  131. devflow_engine/prompts/integration/red_review/node_config/prompt.md +41 -0
  132. devflow_engine/prompts/integration/red_review/past_prompts/20260417T212300/node_config/prompt.md +41 -0
  133. devflow_engine/prompts/integration/red_review/past_prompts/20260417T212300/red_review/prompt.md +15 -0
  134. devflow_engine/prompts/integration/red_review/red_review/prompt.md +9 -0
  135. devflow_engine/prompts/integration/resolve/example.md +111 -0
  136. devflow_engine/prompts/integration/resolve/node_config/prompt.md +64 -0
  137. devflow_engine/prompts/integration/resolve/past_prompts/20260417T212300/node_config/prompt.md +64 -0
  138. devflow_engine/prompts/integration/resolve/past_prompts/20260417T212300/resolve_implicated_users/prompt.md +15 -0
  139. devflow_engine/prompts/integration/resolve/past_prompts/20260417T212300/resolve_side_effects/prompt.md +15 -0
  140. devflow_engine/prompts/integration/resolve/resolve_implicated_users/prompt.md +10 -0
  141. devflow_engine/prompts/integration/resolve/resolve_side_effects/prompt.md +10 -0
  142. devflow_engine/prompts/integration/validate/build_idea_acceptance_coverage/prompt.md +12 -0
  143. devflow_engine/prompts/integration/validate/code_repair/prompt.md +13 -0
  144. devflow_engine/prompts/integration/validate/example.md +143 -0
  145. devflow_engine/prompts/integration/validate/node_config/prompt.md +87 -0
  146. devflow_engine/prompts/integration/validate/past_prompts/20260417T212300/code_repair/prompt.md +19 -0
  147. devflow_engine/prompts/integration/validate/past_prompts/20260417T212300/node_config/prompt.md +67 -0
  148. devflow_engine/prompts/integration/validate/past_prompts/20260417T212300/validate_enrich_gate/prompt.md +17 -0
  149. devflow_engine/prompts/integration/validate/past_prompts/20260417T212300/validate_repair/prompt.md +16 -0
  150. devflow_engine/prompts/integration/validate/past_prompts/20260417T215032/code_repair/prompt.md +10 -0
  151. devflow_engine/prompts/integration/validate/past_prompts/20260417T215032/node_config/prompt.md +67 -0
  152. devflow_engine/prompts/integration/validate/past_prompts/20260417T215032/validate_repair/prompt.md +9 -0
  153. devflow_engine/prompts/integration/validate/validate_enrich_gate/prompt.md +10 -0
  154. devflow_engine/prompts/integration/validate/validate_repair/prompt.md +20 -0
  155. devflow_engine/prompts/integration/write_workflows/example.md +100 -0
  156. devflow_engine/prompts/integration/write_workflows/node_config/prompt.md +44 -0
  157. devflow_engine/prompts/integration/write_workflows/past_prompts/20260417T212300/node_config/prompt.md +44 -0
  158. devflow_engine/prompts/integration/write_workflows/past_prompts/20260417T212300/write_workflows/prompt.md +17 -0
  159. devflow_engine/prompts/integration/write_workflows/write_workflows/prompt.md +11 -0
  160. devflow_engine/prompts/iterate/README.md +7 -0
  161. devflow_engine/prompts/iterate/coder/prompt.md +11 -0
  162. devflow_engine/prompts/iterate/framer/prompt.md +11 -0
  163. devflow_engine/prompts/iterate/iterator/prompt.md +13 -0
  164. devflow_engine/prompts/iterate/observer/prompt.md +11 -0
  165. devflow_engine/prompts/recovery/diagnosis/prompt.md +7 -0
  166. devflow_engine/prompts/recovery/execution/prompt.md +8 -0
  167. devflow_engine/prompts/recovery/execution_verification/prompt.md +7 -0
  168. devflow_engine/prompts/recovery/failure_investigation/prompt.md +10 -0
  169. devflow_engine/prompts/recovery/preflight_health_repo_repair/prompt.md +8 -0
  170. devflow_engine/prompts/recovery/remediation_execution/prompt.md +11 -0
  171. devflow_engine/prompts/recovery/root_cause_investigation/prompt.md +12 -0
  172. devflow_engine/prompts/scope_idea/doctrine/prompt.md +7 -0
  173. devflow_engine/prompts/source_doc_eval/document/prompt.md +6 -0
  174. devflow_engine/prompts/source_doc_eval/targeted_mutation/prompt.md +9 -0
  175. devflow_engine/prompts/source_doc_mutation/domain_entities/prompt.md +6 -0
  176. devflow_engine/prompts/source_doc_mutation/product_brief/prompt.md +6 -0
  177. devflow_engine/prompts/source_doc_mutation/project_doc_coherence/prompt.md +7 -0
  178. devflow_engine/prompts/source_doc_mutation/project_doc_render/prompt.md +9 -0
  179. devflow_engine/prompts/source_doc_mutation/source_doc_coherence/prompt.md +5 -0
  180. devflow_engine/prompts/source_doc_mutation/source_doc_enrichment_coherence/prompt.md +6 -0
  181. devflow_engine/prompts/source_doc_mutation/user_workflows/prompt.md +6 -0
  182. devflow_engine/prompts/source_scope/doctrine/prompt.md +10 -0
  183. devflow_engine/prompts/ui_grounding/doctrine/prompt.md +7 -0
  184. devflow_engine/recovery/__init__.py +3 -0
  185. devflow_engine/recovery/dag.py +2609 -0
  186. devflow_engine/recovery/models.py +220 -0
  187. devflow_engine/refactor.py +93 -0
  188. devflow_engine/registry/__init__.py +1 -0
  189. devflow_engine/registry/cards.py +238 -0
  190. devflow_engine/registry/domain_normalize.py +60 -0
  191. devflow_engine/registry/effects.py +65 -0
  192. devflow_engine/registry/enforce_report.py +150 -0
  193. devflow_engine/registry/module_cards_classify.py +164 -0
  194. devflow_engine/registry/module_cards_draft.py +184 -0
  195. devflow_engine/registry/module_cards_gate.py +59 -0
  196. devflow_engine/registry/packages.py +347 -0
  197. devflow_engine/registry/pathways.py +323 -0
  198. devflow_engine/review/__init__.py +11 -0
  199. devflow_engine/review/dag.py +588 -0
  200. devflow_engine/review/review_story.py +67 -0
  201. devflow_engine/scope_idea/__init__.py +3 -0
  202. devflow_engine/scope_idea/agentic.py +39 -0
  203. devflow_engine/scope_idea/dag.py +1069 -0
  204. devflow_engine/scope_idea/models.py +175 -0
  205. devflow_engine/skills/builtins/devflow/queue_failure_investigation/SKILL.md +112 -0
  206. devflow_engine/skills/builtins/devflow/queue_idea_to_story/SKILL.md +120 -0
  207. devflow_engine/skills/builtins/devflow/queue_integration/SKILL.md +105 -0
  208. devflow_engine/skills/builtins/devflow/queue_recovery/SKILL.md +108 -0
  209. devflow_engine/skills/builtins/devflow/queue_runtime_core/SKILL.md +155 -0
  210. devflow_engine/skills/builtins/devflow/queue_story_implementation/SKILL.md +122 -0
  211. devflow_engine/skills/builtins/devin/idea_to_story_handoff/SKILL.md +120 -0
  212. devflow_engine/skills/builtins/devin/ideation/SKILL.md +168 -0
  213. devflow_engine/skills/builtins/devin/ideation/state-and-phrasing-reference.md +18 -0
  214. devflow_engine/skills/builtins/devin/insight/SKILL.md +22 -0
  215. devflow_engine/skills/registry.example.yaml +42 -0
  216. devflow_engine/source_doc_assumptions.py +291 -0
  217. devflow_engine/source_doc_mutation_dag.py +1606 -0
  218. devflow_engine/source_doc_mutation_eval.py +417 -0
  219. devflow_engine/source_doc_mutation_worker.py +25 -0
  220. devflow_engine/source_docs_schema.py +207 -0
  221. devflow_engine/source_docs_updater.py +309 -0
  222. devflow_engine/source_scope/__init__.py +15 -0
  223. devflow_engine/source_scope/agentic.py +45 -0
  224. devflow_engine/source_scope/dag.py +1626 -0
  225. devflow_engine/source_scope/models.py +177 -0
  226. devflow_engine/stores/__init__.py +0 -0
  227. devflow_engine/stores/execution_store.py +3534 -0
  228. devflow_engine/story/__init__.py +0 -0
  229. devflow_engine/story/contracts.py +160 -0
  230. devflow_engine/story/discovery.py +47 -0
  231. devflow_engine/story/evidence.py +118 -0
  232. devflow_engine/story/hashing.py +27 -0
  233. devflow_engine/story/implemented_queue_purge.py +148 -0
  234. devflow_engine/story/indexer.py +105 -0
  235. devflow_engine/story/io.py +20 -0
  236. devflow_engine/story/markdown_contracts.py +298 -0
  237. devflow_engine/story/reconciliation.py +408 -0
  238. devflow_engine/story/validate_stories.py +149 -0
  239. devflow_engine/story/validate_tests_story.py +512 -0
  240. devflow_engine/story/validation.py +133 -0
  241. devflow_engine/ui_grounding/__init__.py +11 -0
  242. devflow_engine/ui_grounding/agentic.py +31 -0
  243. devflow_engine/ui_grounding/dag.py +874 -0
  244. devflow_engine/ui_grounding/models.py +224 -0
  245. devflow_engine/ui_grounding/pencil_bridge.py +247 -0
  246. devflow_engine/vendor/__init__.py +0 -0
  247. devflow_engine/vendor/datalumina_genai/__init__.py +11 -0
  248. devflow_engine/vendor/datalumina_genai/core/__init__.py +0 -0
  249. devflow_engine/vendor/datalumina_genai/core/exceptions.py +9 -0
  250. devflow_engine/vendor/datalumina_genai/core/nodes/__init__.py +0 -0
  251. devflow_engine/vendor/datalumina_genai/core/nodes/agent.py +48 -0
  252. devflow_engine/vendor/datalumina_genai/core/nodes/agent_streaming_node.py +26 -0
  253. devflow_engine/vendor/datalumina_genai/core/nodes/base.py +89 -0
  254. devflow_engine/vendor/datalumina_genai/core/nodes/concurrent.py +30 -0
  255. devflow_engine/vendor/datalumina_genai/core/nodes/router.py +69 -0
  256. devflow_engine/vendor/datalumina_genai/core/schema.py +72 -0
  257. devflow_engine/vendor/datalumina_genai/core/task.py +52 -0
  258. devflow_engine/vendor/datalumina_genai/core/validate.py +139 -0
  259. devflow_engine/vendor/datalumina_genai/core/workflow.py +200 -0
  260. devflow_engine/worker.py +1086 -0
  261. devflow_engine/worker_guard.py +233 -0
  262. devflow_engine-1.0.0.dist-info/METADATA +235 -0
  263. devflow_engine-1.0.0.dist-info/RECORD +393 -0
  264. devflow_engine-1.0.0.dist-info/WHEEL +4 -0
  265. devflow_engine-1.0.0.dist-info/entry_points.txt +3 -0
  266. devin/__init__.py +6 -0
  267. devin/dag.py +58 -0
  268. devin/dag_two_arm.py +138 -0
  269. devin/devin_chat_scenario_catalog.json +588 -0
  270. devin/devin_eval.py +677 -0
  271. devin/nodes/__init__.py +0 -0
  272. devin/nodes/ideation/__init__.py +0 -0
  273. devin/nodes/ideation/node.py +195 -0
  274. devin/nodes/ideation/playground.py +267 -0
  275. devin/nodes/ideation/prompt.md +65 -0
  276. devin/nodes/ideation/scenarios/continue_refinement.py +13 -0
  277. devin/nodes/ideation/scenarios/continue_refinement_evals.py +18 -0
  278. devin/nodes/ideation/scenarios/idea_fits_existing_patterns.py +17 -0
  279. devin/nodes/ideation/scenarios/idea_fits_existing_patterns_evals.py +16 -0
  280. devin/nodes/ideation/scenarios/large_idea_split.py +4 -0
  281. devin/nodes/ideation/scenarios/large_idea_split_evals.py +17 -0
  282. devin/nodes/ideation/scenarios/source_documentation_added.py +4 -0
  283. devin/nodes/ideation/scenarios/source_documentation_added_evals.py +16 -0
  284. devin/nodes/ideation/scenarios/user_says_create_it.py +30 -0
  285. devin/nodes/ideation/scenarios/user_says_create_it_evals.py +23 -0
  286. devin/nodes/ideation/scenarios/vague_idea.py +16 -0
  287. devin/nodes/ideation/scenarios/vague_idea_evals.py +47 -0
  288. devin/nodes/ideation/tools.json +312 -0
  289. devin/nodes/insight/__init__.py +0 -0
  290. devin/nodes/insight/node.py +49 -0
  291. devin/nodes/insight/playground.py +154 -0
  292. devin/nodes/insight/prompt.md +61 -0
  293. devin/nodes/insight/scenarios/architecture_pattern_query.py +15 -0
  294. devin/nodes/insight/scenarios/architecture_pattern_query_evals.py +25 -0
  295. devin/nodes/insight/scenarios/codebase_exploration.py +15 -0
  296. devin/nodes/insight/scenarios/codebase_exploration_evals.py +23 -0
  297. devin/nodes/insight/scenarios/devin_ideation_routing.py +19 -0
  298. devin/nodes/insight/scenarios/devin_ideation_routing_evals.py +39 -0
  299. devin/nodes/insight/scenarios/devin_insight_routing.py +20 -0
  300. devin/nodes/insight/scenarios/devin_insight_routing_evals.py +40 -0
  301. devin/nodes/insight/scenarios/operational_debugging.py +15 -0
  302. devin/nodes/insight/scenarios/operational_debugging_evals.py +23 -0
  303. devin/nodes/insight/scenarios/operational_question.py +9 -0
  304. devin/nodes/insight/scenarios/operational_question_evals.py +8 -0
  305. devin/nodes/insight/scenarios/queue_status.py +15 -0
  306. devin/nodes/insight/scenarios/queue_status_evals.py +23 -0
  307. devin/nodes/insight/scenarios/source_doc_explanation.py +14 -0
  308. devin/nodes/insight/scenarios/source_doc_explanation_evals.py +21 -0
  309. devin/nodes/insight/scenarios/worker_state_check.py +15 -0
  310. devin/nodes/insight/scenarios/worker_state_check_evals.py +22 -0
  311. devin/nodes/insight/tools.json +126 -0
  312. devin/nodes/intake/__init__.py +0 -0
  313. devin/nodes/intake/node.py +27 -0
  314. devin/nodes/intake/playground.py +47 -0
  315. devin/nodes/intake/prompt.md +12 -0
  316. devin/nodes/intake/scenarios/ideation_routing.py +4 -0
  317. devin/nodes/intake/scenarios/ideation_routing_evals.py +5 -0
  318. devin/nodes/intake/scenarios/insight_routing.py +4 -0
  319. devin/nodes/intake/scenarios/insight_routing_evals.py +5 -0
  320. devin/nodes/iterate/README.md +44 -0
  321. devin/nodes/iterate/__init__.py +1 -0
  322. devin/nodes/iterate/_archived_design_stages/01-objectives-requirements.md +112 -0
  323. devin/nodes/iterate/_archived_design_stages/02-evals.md +131 -0
  324. devin/nodes/iterate/_archived_design_stages/03-tools-and-boundaries.md +110 -0
  325. devin/nodes/iterate/_archived_design_stages/04-harness-and-playground.md +32 -0
  326. devin/nodes/iterate/_archived_design_stages/05-prompt-deferred.md +11 -0
  327. devin/nodes/iterate/_archived_design_stages/coder_agent_design/01-objectives-requirements.md +20 -0
  328. devin/nodes/iterate/_archived_design_stages/coder_agent_design/02-evals.md +8 -0
  329. devin/nodes/iterate/_archived_design_stages/coder_agent_design/03-tools-and-boundaries.md +14 -0
  330. devin/nodes/iterate/_archived_design_stages/coder_agent_design/04-harness-and-playground.md +12 -0
  331. devin/nodes/iterate/_archived_design_stages/framer_agent_design/01-objectives-requirements.md +20 -0
  332. devin/nodes/iterate/_archived_design_stages/framer_agent_design/02-evals.md +8 -0
  333. devin/nodes/iterate/_archived_design_stages/framer_agent_design/03-tools-and-boundaries.md +13 -0
  334. devin/nodes/iterate/_archived_design_stages/framer_agent_design/04-harness-and-playground.md +12 -0
  335. devin/nodes/iterate/_archived_design_stages/iterator_agent_design/01-objectives-requirements.md +25 -0
  336. devin/nodes/iterate/_archived_design_stages/iterator_agent_design/02-evals.md +9 -0
  337. devin/nodes/iterate/_archived_design_stages/iterator_agent_design/03-tools-and-boundaries.md +14 -0
  338. devin/nodes/iterate/_archived_design_stages/iterator_agent_design/04-harness-and-playground.md +12 -0
  339. devin/nodes/iterate/_archived_design_stages/observer_agent_design/01-objectives-requirements.md +20 -0
  340. devin/nodes/iterate/_archived_design_stages/observer_agent_design/02-evals.md +8 -0
  341. devin/nodes/iterate/_archived_design_stages/observer_agent_design/03-tools-and-boundaries.md +14 -0
  342. devin/nodes/iterate/_archived_design_stages/observer_agent_design/04-harness-and-playground.md +13 -0
  343. devin/nodes/iterate/agent-roles.md +89 -0
  344. devin/nodes/iterate/agents/README.md +10 -0
  345. devin/nodes/iterate/artifacts.md +504 -0
  346. devin/nodes/iterate/contract.md +100 -0
  347. devin/nodes/iterate/eval-plan.md +74 -0
  348. devin/nodes/iterate/node.py +100 -0
  349. devin/nodes/iterate/pipeline/README.md +13 -0
  350. devin/nodes/iterate/playground-contract.md +76 -0
  351. devin/nodes/iterate/prompt.md +11 -0
  352. devin/nodes/iterate/scenarios/README.md +38 -0
  353. devin/nodes/iterate/scenarios/artifact-and-loop-scenarios.md +101 -0
  354. devin/nodes/iterate/scenarios/coder_artifact_alignment.py +32 -0
  355. devin/nodes/iterate/scenarios/coder_artifact_alignment_evals.py +45 -0
  356. devin/nodes/iterate/scenarios/coder_bounded_fix.py +27 -0
  357. devin/nodes/iterate/scenarios/coder_bounded_fix_evals.py +45 -0
  358. devin/nodes/iterate/scenarios/devin_iterate_routing.py +21 -0
  359. devin/nodes/iterate/scenarios/devin_iterate_routing_evals.py +36 -0
  360. devin/nodes/iterate/scenarios/framer_scope_boundary.py +25 -0
  361. devin/nodes/iterate/scenarios/framer_scope_boundary_evals.py +57 -0
  362. devin/nodes/iterate/scenarios/framer_task_framing.py +25 -0
  363. devin/nodes/iterate/scenarios/framer_task_framing_evals.py +58 -0
  364. devin/nodes/iterate/scenarios/iterate_error_fix.py +21 -0
  365. devin/nodes/iterate/scenarios/iterate_error_fix_evals.py +39 -0
  366. devin/nodes/iterate/scenarios/iterate_quick_change.py +21 -0
  367. devin/nodes/iterate/scenarios/iterate_quick_change_evals.py +35 -0
  368. devin/nodes/iterate/scenarios/iterate_to_idea_promotion.py +23 -0
  369. devin/nodes/iterate/scenarios/iterate_to_idea_promotion_evals.py +53 -0
  370. devin/nodes/iterate/scenarios/iterate_to_insight_reroute.py +23 -0
  371. devin/nodes/iterate/scenarios/iterate_to_insight_reroute_evals.py +53 -0
  372. devin/nodes/iterate/scenarios/observer_evidence_seam.py +28 -0
  373. devin/nodes/iterate/scenarios/observer_evidence_seam_evals.py +55 -0
  374. devin/nodes/iterate/scenarios/observer_repro_creation.py +28 -0
  375. devin/nodes/iterate/scenarios/observer_repro_creation_evals.py +45 -0
  376. devin/nodes/iterate/scenarios/routing-matrix.md +45 -0
  377. devin/nodes/shared/__init__.py +0 -0
  378. devin/nodes/shared/filemaker_expert.md +80 -0
  379. devin/nodes/shared/filemaker_expert.py +354 -0
  380. devin/nodes/shared/filemaker_expert_eval/runner.py +176 -0
  381. devin/nodes/shared/filemaker_expert_eval/scenarios.json +65 -0
  382. devin/nodes/shared/goldilocks_advisor_eval/runner.py +214 -0
  383. devin/nodes/shared/goldilocks_advisor_eval/scenarios.json +58 -0
  384. devin/nodes/shared/helpers.py +156 -0
  385. devin/nodes/shared/idea_compliance_advisor_eval/runner.py +252 -0
  386. devin/nodes/shared/idea_compliance_advisor_eval/scenarios.json +75 -0
  387. devin/nodes/shared/models.py +44 -0
  388. devin/nodes/shared/post.py +40 -0
  389. devin/nodes/shared/router.py +107 -0
  390. devin/nodes/shared/tools.py +191 -0
  391. devin/shared/devin-chat-rubric.md +237 -0
  392. devin/shared/devin-chat-scenario-suite.md +90 -0
  393. devin/shared/eval_doctrine.md +9 -0
@@ -0,0 +1,357 @@
1
+ from __future__ import annotations
2
+
3
+ import base64
4
+ import binascii
5
+ import hashlib
6
+ import hmac
7
+ import json
8
+ import os
9
+ import subprocess
10
+ import time
11
+ from dataclasses import dataclass
12
+ from datetime import UTC, datetime
13
+ from hashlib import sha256
14
+ from typing import Any
15
+ from urllib.error import HTTPError
16
+ from urllib.parse import quote
17
+ from urllib.request import Request, urlopen
18
+ from uuid import UUID
19
+
20
+
21
+ _KEYCHAIN_SERVICE = "devflow-engine.provider-api-key"
22
+ _TRANSPORT_GRANT_PURPOSE = "devflow_settings_transport_wrap"
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class ProviderSecretSpec:
27
+ provider: str
28
+ env_var: str
29
+ aliases: tuple[str, ...] = ()
30
+
31
+
32
+ _PROVIDER_SPECS: tuple[ProviderSecretSpec, ...] = (
33
+ ProviderSecretSpec("anthropic", "ANTHROPIC_API_KEY", aliases=("claude",)),
34
+ ProviderSecretSpec("openai", "OPENAI_API_KEY", aliases=("codex",)),
35
+ ProviderSecretSpec("google", "GOOGLE_API_KEY", aliases=("gemini", "gemini-cli")),
36
+ ProviderSecretSpec("ollama", "OLLAMA_API_KEY"),
37
+ ProviderSecretSpec("openrouter", "OPENROUTER_API_KEY"),
38
+ ProviderSecretSpec("mistral", "MISTRAL_API_KEY"),
39
+ ProviderSecretSpec("deepseek", "DEEPSEEK_API_KEY"),
40
+ ProviderSecretSpec("xai", "XAI_API_KEY", aliases=("grok",)),
41
+ ProviderSecretSpec("minimax", "MINIMAX_API_KEY"),
42
+ )
43
+ _PROVIDER_INDEX = {
44
+ alias: spec
45
+ for spec in _PROVIDER_SPECS
46
+ for alias in (spec.provider, *spec.aliases)
47
+ }
48
+ _RUNTIME_PROVIDER_KEYS: dict[str, str] = {}
49
+
50
+
51
+ def _resolve_provider_spec(provider: str) -> ProviderSecretSpec:
52
+ normalized = str(provider or "").strip().lower()
53
+ if not normalized:
54
+ raise RuntimeError("API-key provider is required")
55
+ spec = _PROVIDER_INDEX.get(normalized)
56
+ if spec is None:
57
+ raise RuntimeError(f"Unsupported API-key provider: {normalized}")
58
+ return spec
59
+
60
+
61
+ def _run_security_command(args: list[str]) -> subprocess.CompletedProcess[str]:
62
+ return subprocess.run(
63
+ ["security", *args],
64
+ capture_output=True,
65
+ text=True,
66
+ check=False,
67
+ timeout=10,
68
+ )
69
+
70
+
71
+ def _keychain_get(service: str, account: str) -> str | None:
72
+ try:
73
+ proc = _run_security_command(["find-generic-password", "-s", service, "-a", account, "-w"])
74
+ except Exception:
75
+ return None
76
+ if proc.returncode != 0:
77
+ return None
78
+ value = proc.stdout.strip()
79
+ return value or None
80
+
81
+
82
+ def load_provider_api_key_from_keychain(provider: str) -> str | None:
83
+ spec = _resolve_provider_spec(provider)
84
+ try:
85
+ proc = _run_security_command(["find-generic-password", "-s", _KEYCHAIN_SERVICE, "-a", spec.provider, "-w"])
86
+ except Exception:
87
+ return None
88
+ if proc.returncode != 0:
89
+ return None
90
+ value = proc.stdout.strip()
91
+ return value or None
92
+
93
+
94
+ def store_provider_api_key(provider: str, api_key: str) -> None:
95
+ spec = _resolve_provider_spec(provider)
96
+ credential = validate_provider_api_key(provider=spec.provider, api_key=api_key)
97
+ try:
98
+ proc = _run_security_command(
99
+ ["add-generic-password", "-U", "-s", _KEYCHAIN_SERVICE, "-a", spec.provider, "-w", credential]
100
+ )
101
+ except Exception as exc:
102
+ raise RuntimeError(f"Failed to write macOS keychain entry for provider {spec.provider}") from exc
103
+ if proc.returncode != 0:
104
+ raise RuntimeError(f"Failed to write macOS keychain entry for provider {spec.provider}")
105
+
106
+
107
+ def set_runtime_provider_api_key(provider: str, api_key: str, *, env: dict[str, str] | None = None) -> str:
108
+ spec = _resolve_provider_spec(provider)
109
+ credential = validate_provider_api_key(provider=spec.provider, api_key=api_key)
110
+ target_env = os.environ if env is None else env
111
+ target_env[spec.env_var] = credential
112
+ _RUNTIME_PROVIDER_KEYS[spec.provider] = credential
113
+ return spec.env_var
114
+
115
+
116
+ def get_provider_api_key(provider: str, *, env: dict[str, str] | None = None) -> str | None:
117
+ spec = _resolve_provider_spec(provider)
118
+ target_env = os.environ if env is None else env
119
+ env_value = str(target_env.get(spec.env_var) or "").strip()
120
+ if env_value:
121
+ _RUNTIME_PROVIDER_KEYS[spec.provider] = env_value
122
+ return env_value
123
+ cached = _RUNTIME_PROVIDER_KEYS.get(spec.provider)
124
+ if cached:
125
+ return cached
126
+ stored = load_provider_api_key_from_keychain(spec.provider)
127
+ if stored:
128
+ set_runtime_provider_api_key(spec.provider, stored, env=target_env)
129
+ return stored
130
+ return None
131
+
132
+
133
+ def bootstrap_provider_api_keys(*, env: dict[str, str] | None = None) -> dict[str, str]:
134
+ loaded: dict[str, str] = {}
135
+ for spec in _PROVIDER_SPECS:
136
+ value = load_provider_api_key_from_keychain(spec.provider)
137
+ if not value:
138
+ continue
139
+ set_runtime_provider_api_key(spec.provider, value, env=env)
140
+ loaded[spec.provider] = spec.env_var
141
+ return loaded
142
+
143
+
144
+ def validate_provider_api_key(*, provider: str, api_key: str) -> str:
145
+ _resolve_provider_spec(provider)
146
+ credential = str(api_key or "").strip()
147
+ if not credential:
148
+ raise RuntimeError("API-key credential is required")
149
+ if any(token in credential for token in ("\n", "\r", "\x00")):
150
+ raise RuntimeError("API-key credential failed validation")
151
+ if len(credential) < 8:
152
+ raise RuntimeError("API-key credential failed validation")
153
+ return credential
154
+
155
+
156
+ class DevflowTransportGrantStore:
157
+ def __init__(self, *, endpoint_url: str, auth_secret: str | None = None):
158
+ self.endpoint_url = endpoint_url.rstrip("/")
159
+ self.auth_secret = str(auth_secret or "").strip() or None
160
+
161
+ @staticmethod
162
+ def from_env() -> "DevflowTransportGrantStore":
163
+ endpoint_url = (
164
+ os.environ.get("DEVFLOW_TRANSPORT_GRANT_RESOLUTION_URL")
165
+ or os.environ.get("CLARITY_TRANSPORT_GRANT_RESOLUTION_URL")
166
+ )
167
+ if not endpoint_url:
168
+ backend_url = os.environ.get("DEVFLOW_BACKEND_URL") or os.environ.get("CLARITY_BACKEND_URL")
169
+ if backend_url:
170
+ normalized_backend_url = backend_url.rstrip("/")
171
+ if normalized_backend_url.endswith("/api"):
172
+ endpoint_url = f"{normalized_backend_url}/devflow/settings/transport-grant"
173
+ else:
174
+ endpoint_url = f"{normalized_backend_url}/api/devflow/settings/transport-grant"
175
+ if not endpoint_url:
176
+ raise RuntimeError("DevFlow transport grant resolution endpoint is not configured")
177
+ auth_secret = (
178
+ os.environ.get("DEVFLOW_TRANSPORT_GRANT_RESOLUTION_SECRET")
179
+ or os.environ.get("CLARITY_SECRET_KEY")
180
+ or os.environ.get("DEVFLOW_BACKEND_SECRET_KEY")
181
+ or os.environ.get("SECRET_KEY")
182
+ )
183
+ return DevflowTransportGrantStore(endpoint_url=endpoint_url, auth_secret=auth_secret)
184
+
185
+ @staticmethod
186
+ def _build_hmac_bearer_token(secret: str, payload: str) -> str:
187
+ timestamp = str(int(time.time()))
188
+ message = f"{timestamp}.{payload}"
189
+ signature = hmac.new(
190
+ secret.encode("utf-8"),
191
+ message.encode("utf-8"),
192
+ hashlib.sha256,
193
+ ).hexdigest()
194
+ return f"Bearer {signature}.{timestamp}"
195
+
196
+ def fetch(self, *, grant_id: UUID | str) -> dict[str, Any] | None:
197
+ url = f"{self.endpoint_url}/{quote(str(grant_id), safe='')}"
198
+ req = Request(url, method="GET")
199
+ req.add_header("Accept", "application/json")
200
+ if self.auth_secret:
201
+ req.add_header("Authorization", self._build_hmac_bearer_token(self.auth_secret, ""))
202
+ try:
203
+ with urlopen(req, timeout=30) as resp:
204
+ raw = resp.read().decode("utf-8")
205
+ except HTTPError as exc:
206
+ if exc.code == 404:
207
+ return None
208
+ detail = ""
209
+ try:
210
+ detail = exc.read().decode("utf-8").strip()
211
+ except Exception:
212
+ detail = ""
213
+ message = detail or exc.reason or f"HTTP {exc.code}"
214
+ raise RuntimeError(f"DevFlow transport grant resolution request failed: {message}") from exc
215
+ except Exception as exc:
216
+ raise RuntimeError("DevFlow transport grant resolution request failed") from exc
217
+ if not raw:
218
+ return None
219
+ try:
220
+ payload = json.loads(raw)
221
+ except json.JSONDecodeError:
222
+ return None
223
+ if not isinstance(payload, dict):
224
+ return None
225
+ normalized = dict(payload)
226
+ aliases = {
227
+ "grantId": "grant_id",
228
+ "grantToken": "grant_token",
229
+ "wrappedKey": "wrapped_key",
230
+ "wrappingAlgorithm": "wrapping_algorithm",
231
+ "wrappingKeyId": "wrapping_key_id",
232
+ "expiresAt": "expires_at",
233
+ }
234
+ for source_key, target_key in aliases.items():
235
+ if source_key in normalized:
236
+ normalized.setdefault(target_key, normalized.pop(source_key))
237
+ if normalized.get("grant_token") and "purpose" not in normalized:
238
+ normalized["purpose"] = _TRANSPORT_GRANT_PURPOSE
239
+ grant = normalized.get("grant")
240
+ if isinstance(grant, dict):
241
+ return grant
242
+ return normalized
243
+
244
+ def close(self) -> None:
245
+ return None
246
+
247
+
248
+ def resolve_transport_grant(*, grant_id: str, grant_store: DevflowTransportGrantStore | None = None) -> dict[str, Any]:
249
+ own_store = grant_store is None
250
+ store = grant_store or DevflowTransportGrantStore.from_env()
251
+ try:
252
+ payload = store.fetch(grant_id=grant_id)
253
+ finally:
254
+ if own_store:
255
+ store.close()
256
+ if not isinstance(payload, dict):
257
+ raise RuntimeError("DevFlow transport grant is unavailable or expired")
258
+ if str(payload.get("purpose") or "") != _TRANSPORT_GRANT_PURPOSE:
259
+ raise RuntimeError("DevFlow transport grant purpose is invalid")
260
+ grant_token = str(payload.get("grant_token") or "").strip()
261
+ if not grant_token:
262
+ raise RuntimeError("DevFlow transport grant is missing unwrap material")
263
+ expires_at = str(payload.get("expires_at") or "").strip()
264
+ if expires_at:
265
+ try:
266
+ expires_dt = datetime.fromisoformat(expires_at.replace("Z", "+00:00"))
267
+ except ValueError as exc:
268
+ raise RuntimeError("DevFlow transport grant metadata is invalid") from exc
269
+ if expires_dt.astimezone(UTC) <= datetime.now(UTC):
270
+ raise RuntimeError("DevFlow transport grant is unavailable or expired")
271
+ return payload
272
+
273
+
274
+ def decrypt_transport_payload(*, grant_token: str, transport_payload: dict[str, Any]) -> dict[str, Any]:
275
+ try:
276
+ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
277
+ except ImportError as exc:
278
+ raise RuntimeError("cryptography package is required for DevFlow API-key transport unwrap") from exc
279
+
280
+ ciphertext_b64 = str(transport_payload.get("ciphertext") or "")
281
+ iv_b64 = str(transport_payload.get("iv") or "")
282
+ metadata = transport_payload.get("metadata") or {}
283
+ if not ciphertext_b64 or not iv_b64 or not isinstance(metadata, dict):
284
+ raise RuntimeError("DevFlow API-key transport payload is incomplete")
285
+ if str(metadata.get("algorithm") or "") != "AES-GCM":
286
+ raise RuntimeError("Unsupported DevFlow transport algorithm")
287
+ if str(metadata.get("key_derivation") or "") != "SHA-256":
288
+ raise RuntimeError("Unsupported DevFlow transport key derivation")
289
+ if str(metadata.get("key_material") or "") != "transport-grant-token":
290
+ raise RuntimeError("Unsupported DevFlow transport key material")
291
+ if str(metadata.get("version") or "") != "devflow.api_key.v1":
292
+ raise RuntimeError("Unsupported DevFlow transport payload version")
293
+
294
+ try:
295
+ ciphertext = base64.b64decode(ciphertext_b64, validate=True)
296
+ iv = base64.b64decode(iv_b64, validate=True)
297
+ except (ValueError, binascii.Error) as exc:
298
+ raise RuntimeError("DevFlow API-key transport payload is malformed") from exc
299
+
300
+ key = sha256(grant_token.encode("utf-8")).digest()
301
+ try:
302
+ plaintext = AESGCM(key).decrypt(iv, ciphertext, None)
303
+ except Exception as exc:
304
+ raise RuntimeError("Unable to decrypt DevFlow API-key transport payload") from exc
305
+
306
+ try:
307
+ payload = json.loads(plaintext.decode("utf-8"))
308
+ except (UnicodeDecodeError, json.JSONDecodeError) as exc:
309
+ raise RuntimeError("Decrypted DevFlow API-key transport payload is invalid") from exc
310
+ if not isinstance(payload, dict):
311
+ raise RuntimeError("Decrypted DevFlow API-key transport payload is invalid")
312
+ return payload
313
+
314
+
315
+ def unwrap_api_key_event_payload(
316
+ *,
317
+ payload: dict[str, Any],
318
+ grant_store: DevflowTransportGrantStore | None = None,
319
+ ) -> dict[str, str | None]:
320
+ transport = payload.get("transport")
321
+ transport_payload = payload.get("transport_payload")
322
+ if not isinstance(transport, dict):
323
+ raise RuntimeError("devflow_API_KEY requires payload.transport object")
324
+ if not isinstance(transport_payload, dict):
325
+ raise RuntimeError("devflow_API_KEY requires payload.transport_payload object")
326
+
327
+ grant_id = str(transport.get("grant_id") or "").strip()
328
+ if not grant_id:
329
+ raise RuntimeError("devflow_API_KEY requires payload.transport.grant_id")
330
+ grant = resolve_transport_grant(grant_id=grant_id, grant_store=grant_store)
331
+ decrypted = decrypt_transport_payload(grant_token=str(grant["grant_token"]), transport_payload=transport_payload)
332
+
333
+ secret = decrypted.get("secret")
334
+ if not isinstance(secret, dict):
335
+ raise RuntimeError("Decrypted DevFlow API-key payload is missing secret material")
336
+ provider_spec = _resolve_provider_spec(str(secret.get("provider") or ""))
337
+ credential = validate_provider_api_key(provider=provider_spec.provider, api_key=str(secret.get("credential") or ""))
338
+ tier = str(secret.get("tier") or "").strip() or None
339
+
340
+ descriptor = payload.get("secret_descriptor")
341
+ if isinstance(descriptor, dict):
342
+ descriptor_provider = str(descriptor.get("provider") or "").strip().lower()
343
+ if descriptor_provider and _resolve_provider_spec(descriptor_provider).provider != provider_spec.provider:
344
+ raise RuntimeError("devflow_API_KEY provider descriptor mismatch")
345
+ descriptor_last4 = descriptor.get("last4")
346
+ if descriptor_last4 is not None and str(descriptor_last4) != credential[-4:]:
347
+ raise RuntimeError("devflow_API_KEY credential descriptor mismatch")
348
+ descriptor_length = descriptor.get("length")
349
+ if descriptor_length is not None and int(descriptor_length) != len(credential):
350
+ raise RuntimeError("devflow_API_KEY credential descriptor mismatch")
351
+
352
+ return {
353
+ "provider": provider_spec.provider,
354
+ "api_key": credential,
355
+ "tier": tier,
356
+ "env_var": provider_spec.env_var,
357
+ }
@@ -0,0 +1,2 @@
1
+ """Bootstrap helpers for project initialization flows."""
2
+
@@ -0,0 +1,84 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import re
6
+ from pathlib import Path
7
+
8
+ CLARIFY_COMMAND_REFERENCE = (
9
+ "python3 <(gh api repos/Nuosis/clarify/contents/scripts/provision_from_template.py "
10
+ "--jq '.content' | base64 -d)"
11
+ )
12
+ COPY_PROVISION_STRATEGY = "COPY_PROVISION_SCRIPT"
13
+ LOCAL_ONLY_UNTIL_APPROVED = "LOCAL_ONLY_UNTIL_APPROVED"
14
+
15
+
16
+ def _write(path: Path, text: str) -> None:
17
+ path.parent.mkdir(parents=True, exist_ok=True)
18
+ path.write_text(text, encoding="utf-8")
19
+
20
+
21
+ def _slug(value: str) -> str:
22
+ raw = re.sub(r"[^a-z0-9]+", "-", value.strip().lower()).strip("-")
23
+ return raw or "python-backend"
24
+
25
+
26
+ def _pkg_name(value: str) -> str:
27
+ raw = re.sub(r"[^a-z0-9]+", "_", value.strip().lower()).strip("_")
28
+ return raw or "python_backend"
29
+
30
+
31
+ def main(argv: list[str] | None = None) -> int:
32
+ parser = argparse.ArgumentParser(description="Provision a deterministic Python backend scaffold.")
33
+ parser.add_argument("--dest", required=True, type=Path)
34
+ parser.add_argument("--project-name", required=True)
35
+ args = parser.parse_args(argv)
36
+
37
+ dest = args.dest.resolve()
38
+ project_name = args.project_name.strip() or "Python Backend"
39
+ slug = _slug(project_name)
40
+ package_name = _pkg_name(project_name)
41
+
42
+ _write(dest / "README.md", f"# {project_name}\n\nProvisioned via Clarify COPY/provision-script semantics.\n")
43
+ _write(
44
+ dest / "pyproject.toml",
45
+ "\n".join(
46
+ [
47
+ "[project]",
48
+ f'name = "{slug}"',
49
+ 'version = "0.1.0"',
50
+ 'requires-python = ">=3.11"',
51
+ "",
52
+ "[build-system]",
53
+ 'requires = ["hatchling"]',
54
+ 'build-backend = "hatchling.build"',
55
+ "",
56
+ ]
57
+ ),
58
+ )
59
+ _write(dest / "src" / package_name / "__init__.py", "__all__ = []\n")
60
+ _write(
61
+ dest / "src" / package_name / "app.py",
62
+ "def healthcheck() -> dict[str, str]:\n"
63
+ " return {\"status\": \"ok\"}\n",
64
+ )
65
+ _write(
66
+ dest / ".devflow-backend-bootstrap.json",
67
+ json.dumps(
68
+ {
69
+ "provisioning_strategy": COPY_PROVISION_STRATEGY,
70
+ "clarify_command_reference": CLARIFY_COMMAND_REFERENCE,
71
+ "backend_default_deploy_behavior": LOCAL_ONLY_UNTIL_APPROVED,
72
+ "project_name": project_name,
73
+ "package_name": package_name,
74
+ },
75
+ indent=2,
76
+ sort_keys=True,
77
+ )
78
+ + "\n",
79
+ )
80
+ return 0
81
+
82
+
83
+ if __name__ == "__main__":
84
+ raise SystemExit(main())
File without changes