voodoo-framework 2.4.0__tar.gz → 2.5.1__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 (230) hide show
  1. {voodoo_framework-2.4.0/src/voodoo_framework.egg-info → voodoo_framework-2.5.1}/PKG-INFO +6 -4
  2. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/README.md +5 -3
  3. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/__init__.py +1 -1
  4. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/__init__.py +2 -0
  5. voodoo_framework-2.5.1/src/voodoo/cli/create.py +361 -0
  6. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/dev.py +54 -0
  7. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/protocol/schemas.py +81 -15
  8. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/execution.py +53 -1
  9. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/execution/sqlite.py +5 -1
  10. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1/src/voodoo_framework.egg-info}/PKG-INFO +6 -4
  11. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo_framework.egg-info/SOURCES.txt +2 -0
  12. voodoo_framework-2.5.1/tests/test_create.py +150 -0
  13. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/LICENSE +0 -0
  14. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/pyproject.toml +0 -0
  15. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/setup.cfg +0 -0
  16. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/adapters/__init__.py +0 -0
  17. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/adapters/capabilities.py +0 -0
  18. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/adapters/registry.py +0 -0
  19. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/adapters/tailwind.py +0 -0
  20. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/adapters/voodoo_css.py +0 -0
  21. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/agent.py +0 -0
  22. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/agents/__init__.py +0 -0
  23. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/agents/models.py +0 -0
  24. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/agents/registry.py +0 -0
  25. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ai/__init__.py +0 -0
  26. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ai/agent.py +0 -0
  27. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ai/providers/__init__.py +0 -0
  28. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ai/providers/anthropic.py +0 -0
  29. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ai/providers/gemini.py +0 -0
  30. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ai/providers/mock.py +0 -0
  31. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ai/providers/ollama.py +0 -0
  32. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ai/providers/openai.py +0 -0
  33. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ai/tools/__init__.py +0 -0
  34. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ai/tools/registry.py +0 -0
  35. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/api.py +0 -0
  36. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/auth/__init__.py +0 -0
  37. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/auth/cookies.py +0 -0
  38. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/auth/guards.py +0 -0
  39. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/auth/jwt.py +0 -0
  40. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/auth/middleware.py +0 -0
  41. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/auth/passwords.py +0 -0
  42. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/auth/user.py +0 -0
  43. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/__main__.py +0 -0
  44. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/agents.py +0 -0
  45. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/ai.py +0 -0
  46. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/approvals.py +0 -0
  47. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/auth.py +0 -0
  48. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/doctor.py +0 -0
  49. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/executions.py +0 -0
  50. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/generate.py +0 -0
  51. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/inspect.py +0 -0
  52. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/new.py +0 -0
  53. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/objects.py +0 -0
  54. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/protocol.py +0 -0
  55. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/recover.py +0 -0
  56. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/routes.py +0 -0
  57. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/scaffolding.py +0 -0
  58. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/schedules.py +0 -0
  59. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/status.py +0 -0
  60. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/tasks.py +0 -0
  61. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/terminal.py +0 -0
  62. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/theme.py +0 -0
  63. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/version.py +0 -0
  64. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/cli/workers_cmd.py +0 -0
  65. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/components.py +0 -0
  66. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/config.py +0 -0
  67. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/core/__init__.py +0 -0
  68. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/core/app.py +0 -0
  69. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/core/errors.py +0 -0
  70. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/core/events.py +0 -0
  71. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/core/render.py +0 -0
  72. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/core/routing.py +0 -0
  73. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/core/sitemap.py +0 -0
  74. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/core/state.py +0 -0
  75. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/data/__init__.py +0 -0
  76. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/data/base.py +0 -0
  77. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/data/model.py +0 -0
  78. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/i18n.py +0 -0
  79. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/mcp/__init__.py +0 -0
  80. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/mcp/client.py +0 -0
  81. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/memory/__init__.py +0 -0
  82. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/memory/interfaces.py +0 -0
  83. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/memory/sqlite.py +0 -0
  84. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/mesh/__init__.py +0 -0
  85. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/mesh/client.py +0 -0
  86. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/mesh/event_bus.py +0 -0
  87. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/primitives/__init__.py +0 -0
  88. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/primitives/capability.py +0 -0
  89. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/primitives/compute.py +0 -0
  90. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/primitives/constraint.py +0 -0
  91. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/primitives/effect.py +0 -0
  92. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/primitives/intent.py +0 -0
  93. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/primitives/resource.py +0 -0
  94. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/primitives/state.py +0 -0
  95. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/primitives/time.py +0 -0
  96. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/protocol/__init__.py +0 -0
  97. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/protocol/export.py +0 -0
  98. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/py.typed +0 -0
  99. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/queue.py +0 -0
  100. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/routing/api.py +0 -0
  101. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/routing/pages.py +0 -0
  102. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/__init__.py +0 -0
  103. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/adaptive.py +0 -0
  104. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/capability.py +0 -0
  105. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/constraint.py +0 -0
  106. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/context.py +0 -0
  107. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/engine.py +0 -0
  108. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/errors.py +0 -0
  109. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/graph.py +0 -0
  110. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/human.py +0 -0
  111. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/persistence.py +0 -0
  112. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/planner.py +0 -0
  113. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/scheduler.py +0 -0
  114. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/task.py +0 -0
  115. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/runtime/workflow.py +0 -0
  116. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/schedule.py +0 -0
  117. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/security/__init__.py +0 -0
  118. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/security/cors.py +0 -0
  119. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/security/csrf.py +0 -0
  120. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/security/headers.py +0 -0
  121. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/security/passwords.py +0 -0
  122. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/security/rate_limit.py +0 -0
  123. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/security/redaction.py +0 -0
  124. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/security/secrets.py +0 -0
  125. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/seo.py +0 -0
  126. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/static/client.js +0 -0
  127. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/status.py +0 -0
  128. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/__init__.py +0 -0
  129. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/cache/__init__.py +0 -0
  130. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/cache/interfaces.py +0 -0
  131. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/cache/memory.py +0 -0
  132. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/cache/redis.py +0 -0
  133. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/database/__init__.py +0 -0
  134. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/database/interfaces.py +0 -0
  135. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/database/postgres.py +0 -0
  136. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/database/sqlite.py +0 -0
  137. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/events/__init__.py +0 -0
  138. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/events/interfaces.py +0 -0
  139. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/events/local.py +0 -0
  140. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/events/postgres.py +0 -0
  141. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/events/sqlite.py +0 -0
  142. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/execution/__init__.py +0 -0
  143. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/execution/migrations.py +0 -0
  144. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/execution/postgres.py +0 -0
  145. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/manager.py +0 -0
  146. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/objects/__init__.py +0 -0
  147. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/objects/interfaces.py +0 -0
  148. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/objects/local.py +0 -0
  149. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/objects/s3.py +0 -0
  150. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/queue/__init__.py +0 -0
  151. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/queue/interfaces.py +0 -0
  152. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/queue/memory.py +0 -0
  153. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/queue/postgres.py +0 -0
  154. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/queue/redis.py +0 -0
  155. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/queue/sqlite.py +0 -0
  156. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/scheduler/__init__.py +0 -0
  157. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/storage/scheduler/sqlite.py +0 -0
  158. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/telemetry/__init__.py +0 -0
  159. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/telemetry/api.py +0 -0
  160. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/telemetry/middleware.py +0 -0
  161. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/telemetry/otlp.py +0 -0
  162. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/telemetry/store.py +0 -0
  163. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/theme.py +0 -0
  164. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/tools/__init__.py +0 -0
  165. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/tools/registry.py +0 -0
  166. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ui/__init__.py +0 -0
  167. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ui/component.py +0 -0
  168. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ui/events.py +0 -0
  169. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ui/library.py +0 -0
  170. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ui/markdown.py +0 -0
  171. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ui/rendering.py +0 -0
  172. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ui/state.py +0 -0
  173. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ui/styles/__init__.py +0 -0
  174. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ui/styles/presets.py +0 -0
  175. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/ui/styles/theme.py +0 -0
  176. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/workers/__init__.py +0 -0
  177. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo/workers/queue.py +0 -0
  178. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo_framework.egg-info/dependency_links.txt +0 -0
  179. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo_framework.egg-info/entry_points.txt +0 -0
  180. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo_framework.egg-info/requires.txt +0 -0
  181. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/src/voodoo_framework.egg-info/top_level.txt +0 -0
  182. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_agent.py +0 -0
  183. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_agent_registry.py +0 -0
  184. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_agent_runtime.py +0 -0
  185. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_app.py +0 -0
  186. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_auth.py +0 -0
  187. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_capability_security.py +0 -0
  188. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_checkpoint_resume.py +0 -0
  189. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_chrome.py +0 -0
  190. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_cli.py +0 -0
  191. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_cli_inspect.py +0 -0
  192. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_components.py +0 -0
  193. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_config.py +0 -0
  194. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_contract_api.py +0 -0
  195. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_data.py +0 -0
  196. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_design_system.py +0 -0
  197. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_durable_hitl.py +0 -0
  198. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_events.py +0 -0
  199. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_execution_sqlite_store.py +0 -0
  200. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_http_runtime.py +0 -0
  201. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_human.py +0 -0
  202. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_i18n.py +0 -0
  203. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_integration.py +0 -0
  204. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_mcp.py +0 -0
  205. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_mcp_runtime.py +0 -0
  206. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_memory.py +0 -0
  207. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_mesh.py +0 -0
  208. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_mesh_event_bus.py +0 -0
  209. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_model.py +0 -0
  210. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_object_store.py +0 -0
  211. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_observability.py +0 -0
  212. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_persistence.py +0 -0
  213. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_planner_adaptive.py +0 -0
  214. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_primitives.py +0 -0
  215. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_protocol.py +0 -0
  216. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_provider_switching.py +0 -0
  217. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_providers.py +0 -0
  218. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_queue.py +0 -0
  219. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_reactive.py +0 -0
  220. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_runtime.py +0 -0
  221. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_scheduler.py +0 -0
  222. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_security.py +0 -0
  223. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_seo.py +0 -0
  224. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_state.py +0 -0
  225. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_theme.py +0 -0
  226. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_theme_presets.py +0 -0
  227. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_tools.py +0 -0
  228. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_ui.py +0 -0
  229. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_websocket.py +0 -0
  230. {voodoo_framework-2.4.0 → voodoo_framework-2.5.1}/tests/test_workers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: voodoo-framework
3
- Version: 2.4.0
3
+ Version: 2.5.1
4
4
  Summary: The programmable runtime for adaptive applications and operational systems — web, APIs, agents, workers, human workflows, distributed systems, and physical systems in one runtime.
5
5
  Author-email: Helder Perez <contact@helderperez.com>
6
6
  Maintainer-email: Helder Perez <contact@helderperez.com>
@@ -119,14 +119,16 @@ Voodoo is **not** a wrapper around other frameworks. It's a unified runtime wher
119
119
 
120
120
  ```bash
121
121
  pip install voodoo-framework
122
- voodoo new my_app
122
+ voodoo create my_app
123
123
  cd my_app
124
124
  voodoo dev
125
125
  ```
126
126
 
127
127
  Open `http://localhost:8000` — that's it. No npm, no bundler, no config files.
128
128
 
129
- The scaffold produces only `app/page.py`, `voodoo.toml`, and `pyproject.toml` — nothing else. No `main.py`, no `.env`, no placeholder directories.
129
+ `voodoo create` scaffolds a full local runtime app with durable tasks, scheduler, events, and agent runtime — all on zero infrastructure. The generated app includes a crash/restart demo proving durability.
130
+
131
+ > **Want a minimal scaffold?** Use `voodoo new` instead for a bare-bones app with just UI routing.
130
132
 
131
133
  > **Want AI features?** Install with `pip install "voodoo-framework[ai]"` to add OpenAI, Anthropic, Gemini, and Ollama SDKs.
132
134
 
@@ -232,7 +234,7 @@ if __name__ == "__main__":
232
234
  | **Human-in-the-Loop** | `ask_human()` + `approve()`/`deny()` — humans as compute participants, not afterthoughts |
233
235
  | **Adaptive execution** | Planner resolves capabilities to compute participants; supervisor steers with retry, fallback, budget control |
234
236
  | **Durable by default** | Tasks, executions, schedules, and events survive process restarts — backed by SQLite out of the box |
235
- | **Zero-config runtime** | `voodoo new` → `voodoo dev` → working app. No build step. Add `voodoo.toml` when you need configuration |
237
+ | **Zero-config runtime** | `voodoo create` → `voodoo dev` → working app. No build step. Add `voodoo.toml` when you need configuration |
236
238
  | **Local-first, cloud-capable** | SQLite by default; PostgreSQL, Redis, and S3/R2 are optional adapters behind the same contracts |
237
239
 
238
240
  ## The Computational Model
@@ -52,14 +52,16 @@ Voodoo is **not** a wrapper around other frameworks. It's a unified runtime wher
52
52
 
53
53
  ```bash
54
54
  pip install voodoo-framework
55
- voodoo new my_app
55
+ voodoo create my_app
56
56
  cd my_app
57
57
  voodoo dev
58
58
  ```
59
59
 
60
60
  Open `http://localhost:8000` — that's it. No npm, no bundler, no config files.
61
61
 
62
- The scaffold produces only `app/page.py`, `voodoo.toml`, and `pyproject.toml` — nothing else. No `main.py`, no `.env`, no placeholder directories.
62
+ `voodoo create` scaffolds a full local runtime app with durable tasks, scheduler, events, and agent runtime — all on zero infrastructure. The generated app includes a crash/restart demo proving durability.
63
+
64
+ > **Want a minimal scaffold?** Use `voodoo new` instead for a bare-bones app with just UI routing.
63
65
 
64
66
  > **Want AI features?** Install with `pip install "voodoo-framework[ai]"` to add OpenAI, Anthropic, Gemini, and Ollama SDKs.
65
67
 
@@ -165,7 +167,7 @@ if __name__ == "__main__":
165
167
  | **Human-in-the-Loop** | `ask_human()` + `approve()`/`deny()` — humans as compute participants, not afterthoughts |
166
168
  | **Adaptive execution** | Planner resolves capabilities to compute participants; supervisor steers with retry, fallback, budget control |
167
169
  | **Durable by default** | Tasks, executions, schedules, and events survive process restarts — backed by SQLite out of the box |
168
- | **Zero-config runtime** | `voodoo new` → `voodoo dev` → working app. No build step. Add `voodoo.toml` when you need configuration |
170
+ | **Zero-config runtime** | `voodoo create` → `voodoo dev` → working app. No build step. Add `voodoo.toml` when you need configuration |
169
171
  | **Local-first, cloud-capable** | SQLite by default; PostgreSQL, Redis, and S3/R2 are optional adapters behind the same contracts |
170
172
 
171
173
  ## The Computational Model
@@ -102,7 +102,7 @@ from .ui.styles import (
102
102
  from .ui.styles.theme import Theme, ThemeColors, create_theme
103
103
  from .workers import task
104
104
 
105
- __version__ = "2.4.0"
105
+ __version__ = "2.5.1"
106
106
 
107
107
  __all__ = [
108
108
  # Core runtime
@@ -4,6 +4,7 @@ from voodoo.cli import (
4
4
  agents,
5
5
  ai,
6
6
  approvals,
7
+ create,
7
8
  dev,
8
9
  doctor,
9
10
  executions,
@@ -32,6 +33,7 @@ app = typer.Typer(
32
33
  )
33
34
 
34
35
  app.command()(new.new)
36
+ app.command()(create.create)
35
37
  app.command()(dev.dev)
36
38
  app.command()(generate.generate)
37
39
  app.add_typer(auth_app, name="auth")
@@ -0,0 +1,361 @@
1
+ """CLI: ``voodoo create <app>`` — scaffold a full local runtime app.
2
+
3
+ Sprint 22: Local runtime DX. Evolves ``voodoo new`` to wire up the full
4
+ local runtime (durable tasks, scheduler, events, object store, agent runtime)
5
+ with a crash/restart demo proving durability.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import subprocess
11
+ import sys
12
+ from pathlib import Path
13
+
14
+ import typer
15
+
16
+ from voodoo.cli import terminal
17
+
18
+ __all__ = ["create"]
19
+
20
+ # ---------------------------------------------------------------------------
21
+ # Template: main.py — full local runtime
22
+ # ---------------------------------------------------------------------------
23
+
24
+ _MAIN_PY = '''"""{name} — a Voodoo autonomous app.
25
+
26
+ This app demonstrates the full local runtime:
27
+ - Durable tasks (queue + workers) that survive restarts
28
+ - Scheduler for recurring jobs
29
+ - Mesh events for real-time communication
30
+ - Agent runtime with mock provider (no network needed)
31
+
32
+ Run: python main.py or voodoo dev
33
+ """
34
+
35
+ from voodoo import (
36
+ Agent,
37
+ App,
38
+ Button,
39
+ Card,
40
+ Container,
41
+ Heading,
42
+ Stack,
43
+ Text,
44
+ event,
45
+ page,
46
+ state,
47
+ tool,
48
+ )
49
+ from voodoo.workers.queue import enqueue, queue
50
+
51
+ app = App()
52
+
53
+ # ---------------------------------------------------------------------------
54
+ # State
55
+ # ---------------------------------------------------------------------------
56
+
57
+ counter = state("counter", 0)
58
+ log_lines = state("log_lines", [])
59
+ agent_result = state("agent_result", "Click to run the agent")
60
+
61
+
62
+ def _log(msg: str) -> None:
63
+ """Append a timestamped line to the on-screen log."""
64
+ from datetime import datetime
65
+
66
+ ts = datetime.now().strftime("%H:%M:%S")
67
+ lines = log_lines.get()
68
+ lines.append(f"[{{ts}}] {{msg}}")
69
+ # Keep last 20 lines
70
+ log_lines.set(lines[-20:])
71
+
72
+
73
+ # ---------------------------------------------------------------------------
74
+ # Durable task — survives restarts
75
+ # ---------------------------------------------------------------------------
76
+
77
+ @queue("increment")
78
+ async def increment_worker(payload: dict) -> None:
79
+ """Durable worker: increments the counter and logs the result."""
80
+ n = counter.get() + 1
81
+ counter.set(n)
82
+ _log(f"increment task done → counter = {{n}}")
83
+
84
+
85
+ # ---------------------------------------------------------------------------
86
+ # Agent (mock provider — no network needed)
87
+ # ---------------------------------------------------------------------------
88
+
89
+ @tool
90
+ async def get_counter() -> str:
91
+ """Return the current counter value."""
92
+ return str(counter.get())
93
+
94
+
95
+ agent = Agent(
96
+ model="mock:test",
97
+ tools=["get_counter"],
98
+ )
99
+
100
+
101
+ # ---------------------------------------------------------------------------
102
+ # Routes
103
+ # ---------------------------------------------------------------------------
104
+
105
+ @page("/")
106
+ def home():
107
+ return Container(
108
+ Stack(
109
+ Heading("{name}", level=1),
110
+ Text(
111
+ "A Voodoo autonomous app — durable tasks, scheduler, "
112
+ "events, and agents, all running on zero infrastructure.",
113
+ tone="muted",
114
+ ),
115
+ _status_card(),
116
+ _task_card(),
117
+ _agent_card(),
118
+ _log_card(),
119
+ gap="lg",
120
+ )
121
+ )
122
+
123
+
124
+ def _status_card():
125
+ return Card(
126
+ Stack(
127
+ Heading("Runtime", level=2),
128
+ Text(f"Counter: {{counter.get()}}"),
129
+ Text(f"Log entries: {{len(log_lines.get())}}"),
130
+ gap="sm",
131
+ )
132
+ )
133
+
134
+
135
+ def _task_card():
136
+ return Card(
137
+ Stack(
138
+ Heading("Durable Tasks", level=2),
139
+ Text(
140
+ "Enqueue a durable task. It survives restarts — "
141
+ "stop the server, start it again, and watch the counter increment.",
142
+ tone="muted",
143
+ ),
144
+ Button(
145
+ "Enqueue increment",
146
+ onclick="vd.event('enqueue_task')",
147
+ variant="primary",
148
+ ),
149
+ gap="sm",
150
+ )
151
+ )
152
+
153
+
154
+ def _agent_card():
155
+ return Card(
156
+ Stack(
157
+ Heading("Agent", level=2),
158
+ Text(f"Result: {{agent_result.get()}}"),
159
+ Button(
160
+ "Run agent",
161
+ onclick="vd.event('run_agent')",
162
+ variant="secondary",
163
+ ),
164
+ gap="sm",
165
+ )
166
+ )
167
+
168
+
169
+ def _log_card():
170
+ return Card(
171
+ Stack(
172
+ Heading("Event Log", level=2),
173
+ *[Text(line, tone="muted") for line in log_lines.get()],
174
+ gap="xs",
175
+ )
176
+ )
177
+
178
+
179
+ # ---------------------------------------------------------------------------
180
+ # Events
181
+ # ---------------------------------------------------------------------------
182
+
183
+ @event
184
+ async def enqueue_task(element_id, value):
185
+ """Enqueue a durable increment task."""
186
+ await enqueue("increment", {{"source": "ui"}})
187
+ _log("enqueued increment task")
188
+
189
+
190
+ @event
191
+ async def run_agent(element_id, value):
192
+ """Run the agent and display the result."""
193
+ _log("running agent...")
194
+ run = await agent.run("What is the current counter value?")
195
+ agent_result.set(run.output)
196
+ _log(f"agent done: {{run.output}}")
197
+
198
+
199
+ # ---------------------------------------------------------------------------
200
+ # Startup — enqueue a demo task on first boot
201
+ # ---------------------------------------------------------------------------
202
+
203
+ @app.on_startup
204
+ async def on_startup():
205
+ """On first boot, enqueue a demo task to prove durability."""
206
+ import os
207
+
208
+ marker = ".voodoo/state/.booted"
209
+ if not os.path.exists(marker):
210
+ os.makedirs(os.path.dirname(marker), exist_ok=True)
211
+ with open(marker, "w") as f:
212
+ f.write("booted")
213
+ await enqueue("increment", {{"source": "startup"}})
214
+ _log("first boot — enqueued demo task")
215
+ else:
216
+ _log("restart detected — pending tasks will be recovered")
217
+
218
+
219
+ if __name__ == "__main__":
220
+ app.run()
221
+ '''
222
+
223
+ # ---------------------------------------------------------------------------
224
+ # Template: voodoo.toml
225
+ # ---------------------------------------------------------------------------
226
+
227
+ _VOODOO_TOML = """[app]
228
+ name = "{name}"
229
+
230
+ # Local-first defaults — zero infrastructure required.
231
+ # The runtime uses SQLite, local filesystem, and in-memory queues by default.
232
+ # Override with env vars or this config for production:
233
+ # VOODOO_DATABASE_URL=postgresql://...
234
+ # VOODOO_QUEUE_PROVIDER=redis
235
+ # VOODOO_OBJECT_STORE_PROVIDER=s3
236
+ """
237
+
238
+ # ---------------------------------------------------------------------------
239
+ # Template: pyproject.toml
240
+ # ---------------------------------------------------------------------------
241
+
242
+ _PYPROJECT_TOML = """[project]
243
+ name = "{name}"
244
+ version = "0.1.0"
245
+ requires-python = ">=3.12"
246
+ dependencies = [
247
+ "voodoo-framework",
248
+ ]
249
+ """
250
+
251
+
252
+ # ---------------------------------------------------------------------------
253
+ # Command
254
+ # ---------------------------------------------------------------------------
255
+
256
+
257
+ def create(
258
+ project_name: str = typer.Argument(..., help="Name of the project to create"),
259
+ ) -> None:
260
+ """Scaffold a full local runtime app with durable tasks, scheduler, events, and agents.
261
+
262
+ The generated app runs on zero infrastructure (SQLite + local filesystem)
263
+ and includes a crash/restart demo proving durability.
264
+ """
265
+ project_dir = Path(project_name)
266
+ if project_dir.exists():
267
+ terminal.error(f"Directory '{project_name}' already exists")
268
+ raise typer.Exit(1)
269
+
270
+ terminal.wordmark()
271
+ terminal.blank()
272
+ terminal.status("creating", project_name)
273
+ terminal.blank()
274
+
275
+ # Create directory structure
276
+ project_dir.mkdir(parents=True)
277
+ (project_dir / "app").mkdir()
278
+ (project_dir / ".voodoo" / "state").mkdir(parents=True)
279
+
280
+ # Write files
281
+ (project_dir / "main.py").write_text(_MAIN_PY.format(name=project_name))
282
+ (project_dir / "voodoo.toml").write_text(_VOODOO_TOML.format(name=project_name))
283
+ (project_dir / "pyproject.toml").write_text(
284
+ _PYPROJECT_TOML.format(name=project_name)
285
+ )
286
+
287
+ terminal.label_value("created", f"{project_name}/")
288
+ terminal.tree(
289
+ [
290
+ "main.py # App entry point — full runtime demo",
291
+ "voodoo.toml # Runtime configuration",
292
+ "pyproject.toml # Python project metadata",
293
+ "app/ # Folder-based routes (add page.py files here)",
294
+ ".voodoo/state/ # Local state (SQLite, queue, schedules)",
295
+ ]
296
+ )
297
+ terminal.blank()
298
+
299
+ # Install dependencies
300
+ terminal.status("installing", "dependencies")
301
+ terminal.blank()
302
+
303
+ local_venv = project_dir / ".venv"
304
+ try:
305
+ subprocess.run(
306
+ [sys.executable, "-m", "uv", "venv", str(local_venv)],
307
+ check=True,
308
+ capture_output=True,
309
+ )
310
+ subprocess.run(
311
+ [
312
+ str(local_venv / "bin" / "python"),
313
+ "-m",
314
+ "uv",
315
+ "pip",
316
+ "install",
317
+ "-e",
318
+ ".",
319
+ ],
320
+ cwd=str(project_dir),
321
+ check=True,
322
+ capture_output=True,
323
+ )
324
+ terminal.muted("installed via uv")
325
+ except (subprocess.CalledProcessError, FileNotFoundError):
326
+ # Fallback to plain venv + pip
327
+ try:
328
+ subprocess.run(
329
+ [sys.executable, "-m", "venv", str(local_venv)],
330
+ check=True,
331
+ capture_output=True,
332
+ )
333
+ subprocess.run(
334
+ [
335
+ str(local_venv / "bin" / "pip"),
336
+ "install",
337
+ "-e",
338
+ ".",
339
+ ],
340
+ cwd=str(project_dir),
341
+ check=True,
342
+ capture_output=True,
343
+ )
344
+ terminal.muted("installed via pip")
345
+ except subprocess.CalledProcessError as exc:
346
+ terminal.warning(f"dependency install failed: {exc}")
347
+ terminal.muted("run 'cd {project_name} && pip install -e .' manually")
348
+
349
+ terminal.blank()
350
+ terminal.success("ready")
351
+ terminal.blank()
352
+ terminal.next_steps(
353
+ [
354
+ f"cd {project_name}",
355
+ "voodoo dev",
356
+ "",
357
+ "Then open http://localhost:8000 and click 'Enqueue increment'.",
358
+ "Stop the server (Ctrl+C), run 'voodoo dev' again — the counter",
359
+ "increments because the task is durable.",
360
+ ]
361
+ )
@@ -70,6 +70,9 @@ def dev(
70
70
  terminal.label_value("docs", f"{local_url}/docs")
71
71
  terminal.blank()
72
72
 
73
+ # Sprint 22: runtime banner — show providers and runtime state
74
+ _print_runtime_banner()
75
+
73
76
  local_venv_python = (
74
77
  Path(".venv/bin/python")
75
78
  if os.name != "nt"
@@ -117,3 +120,54 @@ def dev(
117
120
  except KeyboardInterrupt:
118
121
  terminal.blank()
119
122
  terminal.status("runtime", "stopped")
123
+
124
+
125
+ def _print_runtime_banner() -> None:
126
+ """Print runtime providers and state (Sprint 22)."""
127
+ from voodoo.config import get_config
128
+
129
+ cfg = get_config()
130
+
131
+ # Providers
132
+ terminal.heading("providers")
133
+ db_provider = cfg.database.provider.lower()
134
+ terminal.status("database", db_provider)
135
+
136
+ queue_provider = cfg.queue.provider.lower()
137
+ terminal.status("queue", queue_provider)
138
+
139
+ # Object store
140
+ terminal.status("objects", cfg.objects.provider.lower())
141
+
142
+ # Agent runtime
143
+ try:
144
+ from voodoo.ai.providers import _PROVIDER_CLASSES
145
+
146
+ providers = list(_PROVIDER_CLASSES.keys())
147
+ terminal.status("agents", ", ".join(providers) if providers else "none")
148
+ except Exception:
149
+ terminal.status("agents", "mock")
150
+
151
+ # MCP endpoint
152
+ terminal.label_value("mcp", "/mcp")
153
+
154
+ # Registered workers
155
+ try:
156
+ from voodoo.workers.queue import _workers
157
+
158
+ worker_names = list(_workers.keys())
159
+ if worker_names:
160
+ terminal.label_value("workers", ", ".join(worker_names))
161
+ else:
162
+ terminal.label_value("workers", "none")
163
+ except Exception:
164
+ terminal.label_value("workers", "none")
165
+
166
+ # Schedules DB
167
+ schedule_path = Path(".voodoo/state/schedules.db")
168
+ if schedule_path.exists():
169
+ terminal.status("scheduler", "ready")
170
+ else:
171
+ terminal.status("scheduler", "will be created")
172
+
173
+ terminal.blank()
@@ -17,7 +17,7 @@ Compatibility policy (see ``docs/protocol.md``):
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- from datetime import datetime
20
+ from datetime import UTC, datetime
21
21
  from enum import StrEnum
22
22
  from typing import Any
23
23
 
@@ -150,8 +150,8 @@ class Identity(BaseModel):
150
150
  id: str = Field(description="Globally unique entity ID (UUID4).")
151
151
  kind: str = Field(description="Entity kind (e.g. 'agent', 'execution', 'task').")
152
152
  owner: str | None = None
153
- created_at: datetime = Field(default_factory=datetime.utcnow)
154
- updated_at: datetime = Field(default_factory=datetime.utcnow)
153
+ created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
154
+ updated_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
155
155
  metadata: dict[str, Any] = Field(default_factory=dict)
156
156
 
157
157
 
@@ -165,7 +165,7 @@ class Capability(BaseModel):
165
165
  delegate_to: str | None = None
166
166
  expires_at: datetime | None = None
167
167
  revoked: bool = False
168
- issued_at: datetime = Field(default_factory=datetime.utcnow)
168
+ issued_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
169
169
  issued_by: str | None = None
170
170
 
171
171
 
@@ -228,8 +228,8 @@ class Intent(BaseModel):
228
228
  requires: list[str] = Field(default_factory=list)
229
229
  constraints: list[Constraint] = Field(default_factory=list)
230
230
  effect_ids: list[str] = Field(default_factory=list)
231
- created_at: datetime = Field(default_factory=datetime.utcnow)
232
- updated_at: datetime = Field(default_factory=datetime.utcnow)
231
+ created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
232
+ updated_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
233
233
  result: Any = None
234
234
  error: str | None = None
235
235
 
@@ -248,7 +248,7 @@ class Effect(BaseModel):
248
248
  status: EffectStatus = EffectStatus.PENDING
249
249
  result: Any = None
250
250
  error: str | None = None
251
- created_at: datetime = Field(default_factory=datetime.utcnow)
251
+ created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
252
252
  executed_at: datetime | None = None
253
253
  actor: str | None = None
254
254
  principal: str | None = None
@@ -275,10 +275,76 @@ class Execution(BaseModel):
275
275
  error: str | None = None
276
276
  metadata: dict[str, Any] = Field(default_factory=dict)
277
277
  checkpoint: dict[str, Any] | None = None
278
- created_at: datetime = Field(default_factory=datetime.utcnow)
278
+ created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
279
279
  started_at: datetime | None = None
280
280
  completed_at: datetime | None = None
281
281
 
282
+ # -- runtime conversion ------------------------------------------------
283
+
284
+ @classmethod
285
+ def from_runtime_execution(
286
+ cls,
287
+ exec: Any, # noqa: ANN401 — runtime.Execution
288
+ ) -> Execution:
289
+ """Convert a runtime ``Execution`` to a protocol ``Execution``.
290
+
291
+ Runtime ``State`` objects in ``state_changes`` are converted to dicts
292
+ via ``model_dump()`` so the protocol representation is JSON-safe.
293
+ """
294
+ return cls(
295
+ id=exec.id,
296
+ trace_id=exec.trace_id,
297
+ parent_execution_id=exec.parent_execution_id,
298
+ status=ExecutionStatus(exec.status.value),
299
+ intent=exec.intent,
300
+ actor=exec.actor,
301
+ compute=exec.compute,
302
+ capabilities=list(exec.capabilities),
303
+ resources=exec.resources,
304
+ effects=list(exec.effects),
305
+ state_changes=[
306
+ s.model_dump() if hasattr(s, "model_dump") else s
307
+ for s in exec.state_changes
308
+ ],
309
+ result=exec.result,
310
+ error=exec.error,
311
+ metadata=dict(exec.metadata),
312
+ checkpoint=exec.checkpoint,
313
+ created_at=exec.created_at,
314
+ started_at=exec.started_at,
315
+ completed_at=exec.completed_at,
316
+ )
317
+
318
+ def to_runtime_execution(self) -> Any: # noqa: ANN401
319
+ """Convert this protocol ``Execution`` back to a runtime ``Execution``.
320
+
321
+ Requires ``voodoo.runtime.execution.Execution`` to be importable.
322
+ Uses a lazy import to avoid circular dependencies.
323
+ """
324
+ from voodoo.runtime.execution import Execution as RuntimeExecution
325
+ from voodoo.runtime.execution import ExecutionStatus as RuntimeStatus
326
+
327
+ return RuntimeExecution(
328
+ id=self.id,
329
+ trace_id=self.trace_id,
330
+ parent_execution_id=self.parent_execution_id,
331
+ status=RuntimeStatus(self.status.value),
332
+ intent=self.intent,
333
+ actor=self.actor,
334
+ compute=self.compute,
335
+ capabilities=list(self.capabilities),
336
+ resources=self.resources,
337
+ effects=list(self.effects),
338
+ state_changes=self.state_changes,
339
+ result=self.result,
340
+ error=self.error,
341
+ metadata=dict(self.metadata),
342
+ checkpoint=self.checkpoint,
343
+ created_at=self.created_at,
344
+ started_at=self.started_at,
345
+ completed_at=self.completed_at,
346
+ )
347
+
282
348
 
283
349
  class Task(BaseModel):
284
350
  """A queued work item (worker task)."""
@@ -326,7 +392,7 @@ class ObjectRef(BaseModel):
326
392
  content_type: str | None = None
327
393
  checksum: str | None = None
328
394
  metadata: dict[str, Any] = Field(default_factory=dict)
329
- created_at: datetime = Field(default_factory=datetime.utcnow)
395
+ created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
330
396
 
331
397
 
332
398
  class Error(BaseModel):
@@ -339,7 +405,7 @@ class Error(BaseModel):
339
405
  trace_id: str | None = None
340
406
  details: dict[str, Any] = Field(default_factory=dict)
341
407
  cause: str | None = None
342
- timestamp: datetime = Field(default_factory=datetime.utcnow)
408
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(UTC))
343
409
 
344
410
 
345
411
  class TelemetrySpan(BaseModel):
@@ -370,7 +436,7 @@ class Approval(BaseModel):
370
436
  decided_by: str | None = None
371
437
  decided_at: datetime | None = None
372
438
  reason: str | None = None
373
- created_at: datetime = Field(default_factory=datetime.utcnow)
439
+ created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
374
440
  participant: str | None = None
375
441
 
376
442
 
@@ -389,8 +455,8 @@ class AgentEntity(BaseModel):
389
455
  config: dict[str, Any] = Field(default_factory=dict)
390
456
  state: str = "active"
391
457
  metadata: dict[str, Any] = Field(default_factory=dict)
392
- created_at: datetime = Field(default_factory=datetime.utcnow)
393
- updated_at: datetime = Field(default_factory=datetime.utcnow)
458
+ created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
459
+ updated_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
394
460
 
395
461
 
396
462
  class AgentRun(BaseModel):
@@ -424,8 +490,8 @@ class MemoryEntry(BaseModel):
424
490
  tags: list[str] = Field(default_factory=list)
425
491
  source_execution_id: str | None = None
426
492
  importance: float = 0.5
427
- created_at: datetime = Field(default_factory=datetime.utcnow)
428
- updated_at: datetime = Field(default_factory=datetime.utcnow)
493
+ created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
494
+ updated_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
429
495
  expires_at: datetime | None = None
430
496
 
431
497