microcoreos 0.2.0__tar.gz → 0.2.2__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 (211) hide show
  1. microcoreos-0.2.2/.agent/skills/microcoreos-architecture/SKILL.md +34 -0
  2. {microcoreos-0.2.0 → microcoreos-0.2.2}/.agent/skills/microcoreos-architecture/agent.md +1 -1
  3. {microcoreos-0.2.0 → microcoreos-0.2.2}/.agent/workflows/feature-plan.md +34 -9
  4. microcoreos-0.2.2/.agent/workflows/multi-domain-plan.md +88 -0
  5. {microcoreos-0.2.0 → microcoreos-0.2.2}/.agent/workflows/new-domain.md +41 -73
  6. {microcoreos-0.2.0 → microcoreos-0.2.2}/AGENTS.md +104 -65
  7. {microcoreos-0.2.0 → microcoreos-0.2.2}/AI_CONTEXT.md +32 -9
  8. {microcoreos-0.2.0 → microcoreos-0.2.2}/INSTRUCTIONS_FOR_AI.md +12 -53
  9. {microcoreos-0.2.0 → microcoreos-0.2.2}/PKG-INFO +12 -2
  10. {microcoreos-0.2.0 → microcoreos-0.2.2}/README.md +11 -1
  11. {microcoreos-0.2.0 → microcoreos-0.2.2}/ROADMAP.md +1 -1
  12. {microcoreos-0.2.0 → microcoreos-0.2.2}/docs/CLI.md +101 -4
  13. {microcoreos-0.2.0 → microcoreos-0.2.2}/docs/INDEX.md +2 -2
  14. {microcoreos-0.2.0 → microcoreos-0.2.2}/docs/PARALLEL_DEVELOPMENT.md +21 -12
  15. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_tools/redis_state/redis_state_tool.py +1 -0
  16. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_tools/s3/s3_tool.py +1 -0
  17. {microcoreos-0.2.0 → microcoreos-0.2.2}/microcoreos/cli.py +65 -71
  18. microcoreos-0.2.2/microcoreos/project.py +97 -0
  19. microcoreos-0.2.2/microcoreos/scaffold.py +449 -0
  20. microcoreos-0.2.2/microcoreos_dev/__init__.py +11 -0
  21. microcoreos-0.2.2/microcoreos_dev/cli.py +75 -0
  22. microcoreos-0.2.0/dev_infra/plan_fuzzer.py → microcoreos-0.2.2/microcoreos_dev/fuzzer.py +49 -30
  23. microcoreos-0.2.2/microcoreos_dev/pipeline.py +526 -0
  24. microcoreos-0.2.2/microcoreos_dev/plan/__init__.py +68 -0
  25. microcoreos-0.2.0/domains/devtools/plugins/plan_validator_plugin.py → microcoreos-0.2.2/microcoreos_dev/plan/rules.py +375 -492
  26. microcoreos-0.2.2/microcoreos_dev/plan/scan.py +241 -0
  27. microcoreos-0.2.2/microcoreos_dev/plan/schema.py +202 -0
  28. microcoreos-0.2.2/microcoreos_dev/probe.py +247 -0
  29. {microcoreos-0.2.0 → microcoreos-0.2.2}/plans/README.md +55 -20
  30. {microcoreos-0.2.0 → microcoreos-0.2.2}/plans/active_plan.md +13 -0
  31. microcoreos-0.2.2/plans/active_plan.yaml +119 -0
  32. {microcoreos-0.2.0 → microcoreos-0.2.2}/pyproject.toml +23 -7
  33. microcoreos-0.2.2/tests/dev/corpus/README.md +14 -0
  34. microcoreos-0.2.2/tests/dev/corpus/qwen_twitter_plan.yaml +136 -0
  35. microcoreos-0.2.2/tests/dev/test_pipeline.py +678 -0
  36. {microcoreos-0.2.0/tests → microcoreos-0.2.2/tests/dev}/test_plan_validator.py +572 -124
  37. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_cli.py +91 -5
  38. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_context_tool.py +57 -0
  39. microcoreos-0.2.2/tests/test_core_purity.py +183 -0
  40. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_scaffold.py +131 -7
  41. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/context/authoring_guide.md +31 -5
  42. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/context/context_tool.py +15 -3
  43. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/sqlite/sqlite_tool.py +1 -0
  44. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/state/state_tool.py +1 -0
  45. {microcoreos-0.2.0 → microcoreos-0.2.2}/uv.lock +1 -1
  46. microcoreos-0.2.0/.agent/skills/microcoreos-architecture/SKILL.md +0 -24
  47. microcoreos-0.2.0/.agent/workflows/multi-domain-plan.md +0 -96
  48. microcoreos-0.2.0/docs/PLAN_EVENT_LINTER.md +0 -95
  49. microcoreos-0.2.0/docs/RELEASING.md +0 -108
  50. microcoreos-0.2.0/docs/TECH_DEBT.md +0 -414
  51. microcoreos-0.2.0/microcoreos/scaffold.py +0 -220
  52. microcoreos-0.2.0/plans/PILOT.md +0 -99
  53. microcoreos-0.2.0/plans/active_plan.yaml +0 -48
  54. microcoreos-0.2.0/tests/test_core_purity.py +0 -97
  55. {microcoreos-0.2.0 → microcoreos-0.2.2}/.agent/workflows/new-tool.md +0 -0
  56. {microcoreos-0.2.0 → microcoreos-0.2.2}/.claude/settings.local.json +0 -0
  57. {microcoreos-0.2.0 → microcoreos-0.2.2}/.dockerignore +0 -0
  58. {microcoreos-0.2.0 → microcoreos-0.2.2}/.env.example +0 -0
  59. {microcoreos-0.2.0 → microcoreos-0.2.2}/.github/workflows/ci.yml +0 -0
  60. {microcoreos-0.2.0 → microcoreos-0.2.2}/.github/workflows/release.yml +0 -0
  61. {microcoreos-0.2.0 → microcoreos-0.2.2}/.gitignore +0 -0
  62. {microcoreos-0.2.0 → microcoreos-0.2.2}/.python-version +0 -0
  63. {microcoreos-0.2.0 → microcoreos-0.2.2}/Dockerfile +0 -0
  64. {microcoreos-0.2.0 → microcoreos-0.2.2}/LICENSE +0 -0
  65. {microcoreos-0.2.0 → microcoreos-0.2.2}/cli.py +0 -0
  66. {microcoreos-0.2.0 → microcoreos-0.2.2}/dev_infra/cache_probe.py +0 -0
  67. {microcoreos-0.2.0 → microcoreos-0.2.2}/dev_infra/docker-compose.yml +0 -0
  68. {microcoreos-0.2.0 → microcoreos-0.2.2}/docs/CORE_INFRASTRUCTURE.md +0 -0
  69. {microcoreos-0.2.0 → microcoreos-0.2.2}/docs/ELASTIC_DEPLOYMENT.md +0 -0
  70. {microcoreos-0.2.0 → microcoreos-0.2.2}/docs/EVENT_BUS.md +0 -0
  71. {microcoreos-0.2.0 → microcoreos-0.2.2}/docs/HTTP_SERVER.md +0 -0
  72. {microcoreos-0.2.0 → microcoreos-0.2.2}/docs/OBSERVABILITY.md +0 -0
  73. {microcoreos-0.2.0 → microcoreos-0.2.2}/docs/OBSERVABILITY_API.md +0 -0
  74. {microcoreos-0.2.0 → microcoreos-0.2.2}/docs/translations/es/README.md +0 -0
  75. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/devtools/lint/plugin_sources.py +0 -0
  76. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/devtools/plugins/discovery_naming_linter_plugin.py +0 -0
  77. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/devtools/plugins/domain_isolation_linter_plugin.py +0 -0
  78. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/devtools/plugins/event_contract_linter_plugin.py +0 -0
  79. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/devtools/plugins/event_schemas_plugin.py +0 -0
  80. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/devtools/plugins/field_divergence_linter_plugin.py +0 -0
  81. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/devtools/plugins/route_collision_linter_plugin.py +0 -0
  82. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/devtools/plugins/table_ownership_linter_plugin.py +0 -0
  83. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/devtools/plugins/tool_doc_drift_linter_plugin.py +0 -0
  84. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/system/plugins/event_delivery_monitor_plugin.py +0 -0
  85. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/system/plugins/system_events_plugin.py +0 -0
  86. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/system/plugins/system_events_stream_plugin.py +0 -0
  87. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/system/plugins/system_logs_stream_plugin.py +0 -0
  88. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/system/plugins/system_metrics_plugin.py +0 -0
  89. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/system/plugins/system_status_plugin.py +0 -0
  90. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/system/plugins/system_traces_plugin.py +0 -0
  91. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/system/plugins/system_traces_stream_plugin.py +0 -0
  92. {microcoreos-0.2.0 → microcoreos-0.2.2}/domains/system/plugins/tool_health_plugin.py +0 -0
  93. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/chaos/plugins/blocking_boot_plugin.py +0 -0
  94. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/chaos/plugins/chaos_control_plugin.py +0 -0
  95. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/chaos/plugins/failing_plugin.py +0 -0
  96. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/chaos/plugins/stress_plugin.py +0 -0
  97. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/ping/plugins/ping_plugin.py +0 -0
  98. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/scheduler/migrations/001_scheduler_one_shots.sql +0 -0
  99. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/scheduler/models/scheduler_one_shot.py +0 -0
  100. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/scheduler/plugins/durable_one_shots_plugin.py +0 -0
  101. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/users/migrations/001_create_users.sql +0 -0
  102. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/users/models/user.py +0 -0
  103. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/users/plugins/create_user_plugin.py +0 -0
  104. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/users/plugins/delete_user_plugin.py +0 -0
  105. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/users/plugins/get_me_plugin.py +0 -0
  106. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/users/plugins/get_user_by_id_plugin.py +0 -0
  107. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/users/plugins/get_users_plugin.py +0 -0
  108. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/users/plugins/login_plugin.py +0 -0
  109. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/users/plugins/logout_plugin.py +0 -0
  110. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/users/plugins/update_user_plugin.py +0 -0
  111. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_domains/users/plugins/welcome_service_plugin.py +0 -0
  112. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_tools/auth/auth_tool.py +0 -0
  113. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_tools/chaos/chaos_tool.py +0 -0
  114. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_tools/kafka/kafka_driver.py +0 -0
  115. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_tools/postgresql/postgresql_tool.py +0 -0
  116. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_tools/rabbitmq/rabbitmq_driver.py +0 -0
  117. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_tools/s3/__init__.py +0 -0
  118. {microcoreos-0.2.0 → microcoreos-0.2.2}/extras/available_tools/scheduler/scheduler_tool.py +0 -0
  119. {microcoreos-0.2.0 → microcoreos-0.2.2}/hatch_build.py +0 -0
  120. {microcoreos-0.2.0 → microcoreos-0.2.2}/main.py +0 -0
  121. {microcoreos-0.2.0 → microcoreos-0.2.2}/microcoreos/__init__.py +0 -0
  122. {microcoreos-0.2.0 → microcoreos-0.2.2}/microcoreos/base_plugin.py +0 -0
  123. {microcoreos-0.2.0 → microcoreos-0.2.2}/microcoreos/base_tool.py +0 -0
  124. {microcoreos-0.2.0 → microcoreos-0.2.2}/microcoreos/catalog.py +0 -0
  125. {microcoreos-0.2.0 → microcoreos-0.2.2}/microcoreos/container.py +0 -0
  126. {microcoreos-0.2.0 → microcoreos-0.2.2}/microcoreos/context.py +0 -0
  127. {microcoreos-0.2.0 → microcoreos-0.2.2}/microcoreos/kernel.py +0 -0
  128. {microcoreos-0.2.0 → microcoreos-0.2.2}/microcoreos/project_readme.md +0 -0
  129. {microcoreos-0.2.0 → microcoreos-0.2.2}/microcoreos/registry.py +0 -0
  130. {microcoreos-0.2.0 → microcoreos-0.2.2}/microcoreos/upgrade.py +0 -0
  131. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/conftest.py +0 -0
  132. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/domains/ping/test_ping_plugin.py +0 -0
  133. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/domains/users/test_create_user_plugin.py +0 -0
  134. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/domains/users/test_delete_user_plugin.py +0 -0
  135. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/domains/users/test_get_me_plugin.py +0 -0
  136. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/domains/users/test_get_user_by_id_plugin.py +0 -0
  137. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/domains/users/test_get_users_plugin.py +0 -0
  138. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/domains/users/test_login_plugin.py +0 -0
  139. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/domains/users/test_logout_plugin.py +0 -0
  140. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/domains/users/test_update_user_plugin.py +0 -0
  141. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/domains/users/test_welcome_service_plugin.py +0 -0
  142. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/helpers/active_db.py +0 -0
  143. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/helpers/async_wait.py +0 -0
  144. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/helpers/mock_db.py +0 -0
  145. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/helpers/trace_chains.py +0 -0
  146. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_auth_tool.py +0 -0
  147. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_catalog.py +0 -0
  148. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_chaos_control.py +0 -0
  149. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_chaos_tool.py +0 -0
  150. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_config_tool.py +0 -0
  151. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_core.py +0 -0
  152. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_discovery_naming_linter.py +0 -0
  153. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_domain_isolation_linter.py +0 -0
  154. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_durable_one_shots.py +0 -0
  155. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_event_bus_groups.py +0 -0
  156. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_event_bus_tool.py +0 -0
  157. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_event_contract_linter.py +0 -0
  158. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_event_schemas_plugin.py +0 -0
  159. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_field_divergence_linter.py +0 -0
  160. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_http_params_hardening.py +0 -0
  161. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_http_server_tool.py +0 -0
  162. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_kernel.py +0 -0
  163. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_logger_tool.py +0 -0
  164. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_no_retry.py +0 -0
  165. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_plugin_di_fixtures.py +0 -0
  166. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_postgresql_describe_schema.py +0 -0
  167. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_postgresql_tool.py +0 -0
  168. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_registry_collisions.py +0 -0
  169. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_route_collision_linter.py +0 -0
  170. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_s3_tool.py +0 -0
  171. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_scheduler_singleton.py +0 -0
  172. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_scheduler_tool.py +0 -0
  173. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_security_hardening.py +0 -0
  174. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_sqlite_concurrency.py +0 -0
  175. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_sqlite_describe_schema.py +0 -0
  176. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_sqlite_migrations.py +0 -0
  177. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_sqlite_tool.py +0 -0
  178. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_state_tool.py +0 -0
  179. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_system_events_stats.py +0 -0
  180. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_system_traces_plugin.py +0 -0
  181. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_table_ownership_linter.py +0 -0
  182. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_tool_doc_drift_linter.py +0 -0
  183. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_tool_proxy.py +0 -0
  184. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_trace_chain_helper.py +0 -0
  185. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/test_upgrade.py +0 -0
  186. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/tools/test_db_parity.py +0 -0
  187. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/tools/test_event_bus_broker_parity.py +0 -0
  188. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/tools/test_event_bus_kafka_parity.py +0 -0
  189. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/tools/test_event_bus_rabbitmq_parity.py +0 -0
  190. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/tools/test_redis_streams_driver.py +0 -0
  191. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/tools/test_s3_parity.py +0 -0
  192. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/tools/test_sqlite_driver.py +0 -0
  193. {microcoreos-0.2.0 → microcoreos-0.2.2}/tests/tools/test_state_parity.py +0 -0
  194. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/config/config_tool.py +0 -0
  195. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/context/renderers.py +0 -0
  196. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/context/scanners.py +0 -0
  197. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/event_bus/drivers.py +0 -0
  198. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/event_bus/envelope.py +0 -0
  199. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/event_bus/event_bus_tool.py +0 -0
  200. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/event_bus/redis_streams_driver.py +0 -0
  201. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/event_bus/sqlite_driver.py +0 -0
  202. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/http_server/context.py +0 -0
  203. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/http_server/http_server_tool.py +0 -0
  204. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/http_server/pipeline.py +0 -0
  205. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/logger/logger_tool.py +0 -0
  206. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/sqlite/errors.py +0 -0
  207. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/sqlite/migrations.py +0 -0
  208. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/sqlite/transaction.py +0 -0
  209. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/system/registry_tool.py +0 -0
  210. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/telemetry/__init__.py +0 -0
  211. {microcoreos-0.2.0 → microcoreos-0.2.2}/tools/telemetry/telemetry_tool.py +0 -0
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: microcoreos-architecture
3
+ description: Ensures adherence to MicroCoreOS "Atomic Microkernel" architecture. Use when creating or modifying core, tools, plugins, or domains.
4
+ ---
5
+
6
+ # MicroCoreOS Architecture Skill
7
+
8
+ **Read `AGENTS.md` and follow the route for your role.** That table names the
9
+ one or two files your role needs and, just as importantly, the ones it must not
10
+ open — a Planner that also loads the plugin templates spends ~3,000 tokens on
11
+ code it will never write.
12
+
13
+ This file deliberately holds no rules, no reading path and no checklist of its
14
+ own. It used to hold all three, and all three had drifted: its reading path
15
+ sent plugin authors to `INSTRUCTIONS_FOR_AI.md` for templates that live in the
16
+ generated manifest, and its checklist was a fifth partial copy of the 13
17
+ Non-Negotiable Rules — one that never mentioned typed event payloads.
18
+
19
+ | You need | It is in |
20
+ |---|---|
21
+ | The rules | `AGENTS.md` § Non-Negotiable Rules (13, canonical) |
22
+ | Kernel/tool/event-bus laws | `AGENTS.md` § Core Architectural Laws |
23
+ | The plugin template | `AI_CONTEXT.md` § Plugin Authoring Guide (regenerated every boot) |
24
+ | What exists right now | `AI_CONTEXT.md` § Available Tools / § Domains |
25
+ | The plan format and its 18 rules | `docs/PARALLEL_DEVELOPMENT.md` § Phase 1 |
26
+ | Anti-patterns, testing, building a tool | `INSTRUCTIONS_FOR_AI.md` |
27
+
28
+ Before you finish, the gates are commands, not a checklist to eyeball:
29
+
30
+ ```bash
31
+ microcoreos plan validate # the plan is a contract — zero errors
32
+ uv run -m pytest # green
33
+ microcoreos status # manifest still describes the code on disk
34
+ ```
@@ -10,7 +10,7 @@ You are a **Systems Architect** specialized in high-performance, resilient micro
10
10
  ## Decision Framework
11
11
  - **Core First**: Is this change affecting the Core? If yes, look for an alternative in Plugins/Tools.
12
12
  - **Tool Isolation**: Does this Tool import another Tool? If so, REJECT the design and move the logic to a Plugin (Bridge).
13
- - **Sacred Rules Review**: Before implementation, verify against the "Three Golden Rules" in `SKILL.md`.
13
+ - **Rules Review**: Before implementing, check the 13 Non-Negotiable Rules in `AGENTS.md`. (This line used to cite "Three Golden Rules in SKILL.md" — a document that never existed.)
14
14
  - **Resilience**: Will a failure here crash the entire system?
15
15
  - **Observability**: Can this be monitored via the `registry`?
16
16
 
@@ -8,11 +8,36 @@ The smallest planning level: new plugins on a domain that already exists. No
8
8
  migrations, no new tools — if you need either, escalate to
9
9
  [new-domain.md](new-domain.md) or [multi-domain-plan.md](multi-domain-plan.md).
10
10
 
11
+ ## Before you plan — read these two, in this order
12
+
13
+ 1. **`plans/active_plan.yaml`** — the file you are about to overwrite. It ships
14
+ as a worked example of all three feature shapes. It **is** the format, not a
15
+ description of one, and it is the cheapest way to have it.
16
+ 2. **`AI_CONTEXT.md`**, down to `## 🧩 Plugin Authoring Guide` — the tables,
17
+ models, routes and events that already exist. Inherit their names exactly.
18
+
19
+ Then write to **`plans/active_plan.yaml`** — that exact path, overwriting it —
20
+ and run `microcoreos plan validate` until it reports zero errors. Errors carry
21
+ the YAML that fixes them: paste it.
22
+
23
+ **Write the file before you ask anything.** Checking in is fine — planning
24
+ often is a conversation — but never *instead of* writing: a plan that exists
25
+ only as prose in your reply is a plan the next phase cannot read, and the run
26
+ may not be interactive at all. So write the YAML, validate it, and then raise
27
+ whatever you wanted to raise; the operator answers against a real file instead
28
+ of a description. Where a detail is genuinely undecidable, take what the
29
+ existing vocabulary implies, put it in the YAML, and flag it in a comment.
30
+
31
+ `docs/PARALLEL_DEVELOPMENT.md` § Phase 1 holds the rules behind the format.
32
+ Read it when a validator error is unclear, not before — and never reach for
33
+ plugin source under `domains/`, `tools/` or `extras/` to infer the shape. A
34
+ planner that did produced a plan with every field renamed.
35
+
11
36
  ## Prerequisites
12
37
 
13
- - Read `AI_CONTEXT.md` — the live inventory (tools, domains, events, routes).
14
- - Check `GET /system/events/schemas` (or the "Events emitted" lines in
15
- `AI_CONTEXT.md`) for the payload contracts of any event you will consume.
38
+ Both files above. For an event you will consume, its payload contract is the
39
+ "Events emitted" line of the publishing domain in `AI_CONTEXT.md` (or
40
+ `GET /system/events/schemas` on a running system).
16
41
 
17
42
  ## Steps
18
43
 
@@ -37,7 +62,7 @@ plan:
37
62
  model: OrderCancelledPayload
38
63
  payload: { id: int, reason: str }
39
64
  consumes: []
40
- mocks: [db, event_bus]
65
+ tools: [http, db, event_bus, logger] # every tool __init__ takes
41
66
  test: tests/test_cancel_order.py
42
67
  flows:
43
68
  - name: order-cancellation
@@ -60,10 +85,10 @@ plan:
60
85
 
61
86
  ### 2. Validate before writing code
62
87
 
63
- `POST /system/plan/validate` with the plan (YAML or JSON) — it runs the 16
64
- validity rules of `docs/PARALLEL_DEVELOPMENT.md` against this plan AND the
65
- live system. Zero `errors` before any code; `warnings` are advisory. The main
66
- things it catches at this level:
88
+ `microcoreos plan validate` — it runs the 18 validity rules of
89
+ `docs/PARALLEL_DEVELOPMENT.md` against this plan AND what the repo already
90
+ occupies, with no server running. Zero `errors` before any code; `warnings` are
91
+ advisory. The main things it catches at this level:
67
92
 
68
93
  - The `route` and `file` collide with nothing live.
69
94
  - Every consumed event exists (live system or this plan) and provides the
@@ -82,7 +107,7 @@ Publish with `XxxPayload(...).model_dump()` — bare call, no arguments.
82
107
 
83
108
  - One test per plugin proving the black-box contract: input → output, DB
84
109
  effects on the declared tables, published payloads with the declared fields.
85
- Mock exactly the tools the plan's `mocks:` lists; run the rest as real
110
+ Mock exactly the tools the plan's `tools:` lists; run the rest as real
86
111
  in-memory instances (`INSTRUCTIONS_FOR_AI.md` § Testing).
87
112
  - One double-delivery test per idempotent link (same envelope twice → same
88
113
  final state), at the path declared in `idempotency_test`.
@@ -0,0 +1,88 @@
1
+ ---
2
+ description: Plan and build a large spec spanning multiple domains (full formal plan, parallel execution)
3
+ ---
4
+
5
+ # Multi-Domain Plan Workflow
6
+
7
+ The largest planning level: a spec that creates or touches several domains,
8
+ with event chains crossing domain boundaries. The methodology is fully
9
+ specified in `docs/PARALLEL_DEVELOPMENT.md` — this workflow is its checklist.
10
+
11
+ **Everything is decided before any code exists**: every migration, model,
12
+ tool, plugin, route, event (with its payload model), and every chain with its
13
+ happy path and sad paths. Code-time conflicts are structurally impossible;
14
+ what remains is getting the plan right.
15
+
16
+ ## Before you plan — read these two, in this order
17
+
18
+ 1. **`plans/active_plan.yaml`** — the file you are about to overwrite. It ships
19
+ as a worked example of all three feature shapes. It **is** the format, not a
20
+ description of one, and it is the cheapest way to have it.
21
+ 2. **`AI_CONTEXT.md`**, down to `## 🧩 Plugin Authoring Guide` — the tables,
22
+ models, routes and events that already exist. Inherit their names exactly.
23
+
24
+ Then write to **`plans/active_plan.yaml`** — that exact path, overwriting it —
25
+ and run `microcoreos plan validate` until it reports zero errors. Errors carry
26
+ the YAML that fixes them: paste it.
27
+
28
+ **Write the file before you ask anything.** Checking in is fine — planning
29
+ often is a conversation — but never *instead of* writing: a plan that exists
30
+ only as prose in your reply is a plan the next phase cannot read, and the run
31
+ may not be interactive at all. So write the YAML, validate it, and then raise
32
+ whatever you wanted to raise; the operator answers against a real file instead
33
+ of a description. Where a detail is genuinely undecidable, take what the
34
+ existing vocabulary implies, put it in the YAML, and flag it in a comment.
35
+
36
+ `docs/PARALLEL_DEVELOPMENT.md` § Phase 1 holds the rules behind the format.
37
+ Read it when a validator error is unclear, not before — and never reach for
38
+ plugin source under `domains/`, `tools/` or `extras/` to infer the shape. A
39
+ planner that did produced a plan with every field renamed.
40
+
41
+ ## Phase 1 — The full plan (the contract, authored FIRST)
42
+
43
+ Write the complete YAML plan of `docs/PARALLEL_DEVELOPMENT.md` ("Formal plan
44
+ format") to `plans/active_plan.yaml`: `phase_0` (every migration with its
45
+ `tables:` ownership AND its full `columns:` — phase 0 is built from the plan,
46
+ nothing is improvised later), `features` (one per plugin, with
47
+ `publishes.model` / `consumes.requires` / the `db:` persistence contract),
48
+ and `flows` — each with
49
+ its `durability` (may in-flight events die with the process? `durable` needs
50
+ the sqlite/redis driver) and the sad-path checklist per link:
51
+
52
+ - `retries` / `backoff` — re-delivery policy
53
+ - `idempotent` — MANDATORY `true` where `retries > 0` OR the flow is `durable`
54
+ (durable transports re-deliver after a crash even with zero retries)
55
+ - `idempotency_test` — the double-delivery proof for every idempotent link
56
+ - `dlq_watcher` — who consumes `_dlq.<event>` (`null` = loss explicitly
57
+ accepted; a non-null watcher must exist in the plan or live)
58
+ - `atomic_with_db` — `true` means this chain cannot lose the event between DB
59
+ commit and publish → it is the implementation trigger for the Transactional
60
+ Outbox (ROADMAP Issue 28); flag it, do not improvise one
61
+ - `compensation` — the event that undoes upstream work if the chain dies
62
+ (saga); it must be published AND consumed within the plan
63
+ - `sad_path_test` (flow-level) — mandatory when any link declares retries,
64
+ a DLQ watcher or a compensation
65
+ - `rpc_links` (flow-level) — every `request()` call, with `timeout` and
66
+ `on_timeout`
67
+
68
+ Then run the 18 validity rules mechanically: `microcoreos plan validate`
69
+ (offline — nothing needs to be booted) — zero `errors` before building
70
+ anything. An invalid plan is a task-allocation error — fix the plan,
71
+ never patch it in code.
72
+
73
+ ## Phases 0, 2 and 3
74
+
75
+ Identical to any other plan — `docs/PARALLEL_DEVELOPMENT.md` owns them, and
76
+ restating them here is how this file once kept prescribing a boot command that
77
+ had stopped regenerating the manifest.
78
+
79
+ Two things are specific to multi-domain work and are the only reason this
80
+ section exists:
81
+
82
+ - **Migration ordering across domains.** One author for the numbering, and
83
+ `-- depends: other_domain/001_file.sql` wherever a table in one domain must
84
+ exist before another's. The db tool resolves the order and prints each file
85
+ as it applies it.
86
+ - **Never assign two agents to the same feature**, and never let one agent
87
+ touch two domains. The wave is safe precisely because the write sets are
88
+ disjoint.
@@ -10,9 +10,36 @@ Creates a full domain from scratch: entity model, SQL migration, and one plugin
10
10
  > one new domain → this workflow · several domains / cross-domain chains →
11
11
  > [multi-domain-plan.md](multi-domain-plan.md) · new infrastructure → [new-tool.md](new-tool.md).
12
12
 
13
+ ## Before you plan — read these two, in this order
14
+
15
+ 1. **`plans/active_plan.yaml`** — the file you are about to overwrite. It ships
16
+ as a worked example of all three feature shapes. It **is** the format, not a
17
+ description of one, and it is the cheapest way to have it.
18
+ 2. **`AI_CONTEXT.md`**, down to `## 🧩 Plugin Authoring Guide` — the tables,
19
+ models, routes and events that already exist. Inherit their names exactly.
20
+
21
+ Then write to **`plans/active_plan.yaml`** — that exact path, overwriting it —
22
+ and run `microcoreos plan validate` until it reports zero errors. Errors carry
23
+ the YAML that fixes them: paste it.
24
+
25
+ **Write the file before you ask anything.** Checking in is fine — planning
26
+ often is a conversation — but never *instead of* writing: a plan that exists
27
+ only as prose in your reply is a plan the next phase cannot read, and the run
28
+ may not be interactive at all. So write the YAML, validate it, and then raise
29
+ whatever you wanted to raise; the operator answers against a real file instead
30
+ of a description. Where a detail is genuinely undecidable, take what the
31
+ existing vocabulary implies, put it in the YAML, and flag it in a comment.
32
+
33
+ `docs/PARALLEL_DEVELOPMENT.md` § Phase 1 holds the rules behind the format.
34
+ Read it when a validator error is unclear, not before — and never reach for
35
+ plugin source under `domains/`, `tools/` or `extras/` to infer the shape. A
36
+ planner that did produced a plan with every field renamed.
37
+
13
38
  ## Prerequisites
14
- - Read `AI_CONTEXT.md` for available tools.
15
- - Read `INSTRUCTIONS_FOR_AI.md` for rules and templates.
39
+
40
+ Both files above. Nothing else: the plugin template lives in `AI_CONTEXT.md`
41
+ § Plugin Authoring Guide, generated on every boot, and the rules are the 13
42
+ Non-Negotiable Rules in `AGENTS.md`.
16
43
 
17
44
  ## Steps
18
45
 
@@ -28,7 +55,8 @@ persistence contract), and — ONLY if any plugin publishes or consumes events
28
55
  the `atomic_with_db` outbox question — and the declared `idempotency_test` /
29
56
  `sad_path_test` files). A pure-CRUD domain has no `flows` section at all; a
30
57
  domain whose delete cascades through one event has exactly one flow.
31
- Validate with `POST /system/plan/validate` before writing code. Build in that
58
+ Validate with `microcoreos plan validate` before writing code (offline —
59
+ nothing needs to be booted). Build in that
32
60
  order — tools first if any, then migrations + models, then plugins with their
33
61
  events. Nothing below this line should require a decision the plan did not
34
62
  already make. Expected size for a CRUD domain with one event chain: ~80-120
@@ -77,75 +105,14 @@ CREATE TABLE IF NOT EXISTS {name}s (
77
105
 
78
106
  ### 4. Create plugins (1 file = 1 use case)
79
107
 
80
- For each operation (create, get_all, get_by_id, update, delete), create a separate plugin file in `domains/{name}/plugins/`.
81
-
82
- **Critical rules**:
83
- - Define the **request schema** (what the HTTP client sends) at the **top of the plugin file**, NOT in the models folder.
84
- - Define the **response schema** (what the HTTP client receives) at the **top of the plugin file** too — never import the Entity for this; only expose the fields you actually return.
85
- - Define the **event payload schema** for every event this plugin publishes, also at the top of the file: `{Name}CreatedPayload(BaseModel)`. Publish with `.model_dump()` (bare call, no arguments). The publisher owns the event contract — consumers in other domains never import it; they declare their own model with only the fields they need (tolerant reader).
86
- - Always pass `response_model=` to `add_endpoint` — this generates complete OpenAPI docs.
87
-
88
- Example for create:
89
-
90
- File: `domains/{name}/plugins/create_{name}_plugin.py`
91
-
92
- ```python
93
- from typing import Optional
94
- from pydantic import BaseModel
95
- from microcoreos import BasePlugin
96
-
97
- # ── Request schema lives HERE ──────────────────────
98
- class Create{Name}Request(BaseModel):
99
- # Only input fields — no id, no internal fields
100
- field1: str
101
- field2: int
102
-
103
- # ── Response schema lives HERE ─────────────────────
104
- class {Name}Data(BaseModel):
105
- id: int
106
- field1: str
107
- field2: int
108
-
109
- class Create{Name}Response(BaseModel):
110
- success: bool
111
- data: Optional[{Name}Data] = None
112
- error: Optional[str] = None
113
-
114
- # ── Event payload schema lives HERE (publisher owns the contract) ──
115
- class {Name}CreatedPayload(BaseModel):
116
- id: int
117
-
118
- class Create{Name}Plugin(BasePlugin):
119
- def __init__(self, http, db, event_bus, logger):
120
- self.http = http
121
- self.db = db
122
- self.bus = event_bus
123
- self.logger = logger
124
-
125
- async def on_boot(self):
126
- self.http.add_endpoint(
127
- "/{name}s", "POST", self.execute,
128
- tags=["{Name}s"], request_model=Create{Name}Request,
129
- response_model=Create{Name}Response,
130
- )
131
-
132
- async def execute(self, data: dict, context=None):
133
- try:
134
- req = Create{Name}Request(**data)
135
- new_id = await self.db.execute(
136
- "INSERT INTO {name}s (field1, field2) VALUES ($1, $2) RETURNING id",
137
- [req.field1, req.field2]
138
- )
139
- self.logger.info(f"{Name} created with ID {new_id}")
140
- await self.bus.publish("{name}.created", {Name}CreatedPayload(id=new_id).model_dump())
141
- return {"success": True, "data": {"id": new_id, "field1": req.field1, "field2": req.field2}}
142
- except Exception as e:
143
- # Safe Error Reporting: log technically, respond safely (never str(e)).
144
- self.logger.error(f"Failed to create {name}: {e}")
145
- return {"success": False, "error": "Database operation failed"}
146
- ```
108
+ One plugin file per operation in `domains/{name}/plugins/`. The template — with
109
+ request, response and event-payload schemas inline, and the rules that go with
110
+ them — is `AI_CONTEXT.md` § **Plugin Authoring Guide**, regenerated on every
111
+ boot and already inside every executor prompt. A fourth copy lived here.
147
112
 
148
- Repeat for: `get_{name}s_plugin.py`, `get_{name}_by_id_plugin.py`, `update_{name}_plugin.py`, `delete_{name}_plugin.py`.
113
+ The one thing that is this workflow's own decision: which operations exist.
114
+ A CRUD domain is create / get_all / get_by_id / update / delete, one file each,
115
+ each declared in the plan before any of them is written.
149
116
 
150
117
  ### 5. Verify
151
118
 
@@ -160,13 +127,14 @@ Check that:
160
127
  - `GET /system/lint` has no warnings and no `UNTYPED_PAYLOAD` for your events
161
128
  - `GET /system/events/schemas` lists every event the plan declared
162
129
  - `AI_CONTEXT.md` was regenerated with the new domain — **done when it matches the plan**
130
+ - `microcoreos schema` shows the new tables with the columns the plan declared
163
131
 
164
132
  ### 6. Generate tests
165
133
 
166
134
  Create `tests/test_{name}_plugin.py` with one test per plugin. Mock exactly
167
- the tools the plan's `mocks:` field lists; run the rest as real in-memory
135
+ the tools the plan's `tools:` field lists; run the rest as real in-memory
168
136
  instances (`INSTRUCTIONS_FOR_AI.md` § Testing). Example with everything
169
- mocked (`mocks: [http, db, event_bus, logger]`):
137
+ mocked (`tools: [http, db, event_bus, logger]`):
170
138
 
171
139
  ```python
172
140
  import pytest
@@ -4,21 +4,79 @@ This file is the single, absolute entry point for any AI agent (Gemini, Claude,
4
4
 
5
5
  ---
6
6
 
7
- ## 📖 Reading Path (minimize token usage)
7
+ ## 🚦 Start here: `microcoreos status`
8
8
 
9
- 1. **`plans/active_plan.md`** — The checklist for your assigned task (the formal contract lives in `plans/active_plan.yaml`).
10
- 2. **`AI_CONTEXT.md`** — Contains the live inventory of active tools (with exact signatures) and domain tables/endpoints. **Read only the tools and tables you need.**
11
- 3. **`domains/{domain}/models/{name}.py`** — Entity model (DB mirror). *Advisory: Table structures are already mirrored in AI_CONTEXT.md.*
12
- 4. **`INSTRUCTIONS_FOR_AI.md`** — Read ONLY for advanced tasks (building new tools, testing in-depth, or changing kernel internals).
13
- 5. **`docs/TECH_DEBT.md`** — What is knowingly unfinished and what it would cost to finish. Read ONLY when scoping work that might overlap an open item.
9
+ One command, before anything else. It answers the three questions that
10
+ silently derail a session: **which plan is actually active** (and whether it is
11
+ still the shipped template), **how much of it is done**, and **whether
12
+ `AI_CONTEXT.md` still describes the code on disk**.
13
+
14
+ There is exactly one plan path: **`plans/active_plan.yaml`**. The workflows,
15
+ the executor prompts and the checklist cross-check read that path and no other.
16
+ A plan written to `plans/my_feature.yaml` is a plan nothing will ever execute —
17
+ and because the shipped template is itself a valid plan, an agent that opens
18
+ `active_plan.yaml` and finds it untouched will build the *example* domain and
19
+ report success. That is why the template carries `template: true` and fails
20
+ validation until you delete the line.
14
21
 
15
22
  ---
16
23
 
17
- ## 🧭 Pick the Right Workflow (scale ladder)
24
+ ## 📖 Your reading route — find your role, read those files, stop
25
+
26
+ Four roles do the work, and **each needs a different slice**. Reading outside
27
+ your slice is not thoroughness, it is budget: the Planner that also loads the
28
+ plugin templates spends ~3,000 tokens on code it will never write.
29
+
30
+ | You are… | Read exactly this | **Write exactly this** | Not this |
31
+ |---|---|---|---|
32
+ | **Planner** — turning a request into a plan | **1.** `plans/active_plan.yaml` — the file you are about to overwrite. It ships as a worked example of all three feature shapes, and it is the cheapest, densest statement of the format there is. **2.** `AI_CONTEXT.md` **down to `## 🧩 Plugin Authoring Guide`** (existing tools, tables, models, routes, events). **3.** `docs/PARALLEL_DEVELOPMENT.md` **§ Phase 1** for the rules behind it | **`plans/active_plan.yaml` + `plans/active_plan.md`, overwriting them.** Never a new filename — `plans/twitter_plan.yaml` is a plan nothing will execute | The Authoring Guide, Phases 2-3, `domains/`, `tools/`, `tests/`, `extras/` |
33
+ | **Phase 0 Builder** — migrations, models, tools | `plans/active_plan.yaml` **§ phase_0** only | Exactly the files `phase_0` names: its migrations, its models, its tools | Everything else. The plan already decided every column |
34
+ | **Executor** — one plugin + its test | **Nothing.** Your prompt already contains `AI_CONTEXT.md` + the plan + your one task line | Exactly two files: the `file:` and `test:` your task declares | Any file at all — opening one only invites guessed paths |
35
+ | **Coordinator** — dispatch, verify, reconstruct | `plans/active_plan.md` (the checklist/state machine) + `docs/PARALLEL_DEVELOPMENT.md` **§ Phases 2-3** | Only the checkboxes in `plans/active_plan.md` | The plan's internals; the checklist is the state |
36
+
37
+ If you are the Planner, the first thing you write is `plans/active_plan.yaml`
38
+ itself — not a draft under another name that someone copies later. The copy
39
+ step is where the plan gets lost: a validated plan sat in `plans/twitter_plan.yaml`
40
+ while two sessions in a row built the template's example domain instead.
41
+
42
+ And write it **before you ask anything**. Planning is usually a conversation,
43
+ and checking in is welcome — but never *instead of* writing. A plan that ends
44
+ as prose in your reply and a *"shall I proceed?"* produced nothing: the next
45
+ phase reads files, not answers, and the session may not be interactive at all.
46
+ Write the YAML, run `microcoreos plan validate`, and then ask — the operator
47
+ reviews a real file rather than a description of one.
18
48
 
19
- Match the request to its workflow BEFORE planning. Over-planning a small
20
- request is a failure mode: **a plan must be proportional to its request**
21
- (see "Plan sizing" in `docs/PARALLEL_DEVELOPMENT.md`).
49
+ **And the commands your role may run — nothing else boots the system:**
50
+
51
+ | Role | May run |
52
+ |---|---|
53
+ | Planner | `microcoreos status`, `microcoreos plan validate` |
54
+ | Phase 0 Builder | `microcoreos migrate`, `microcoreos schema` |
55
+ | Executor | none — write your two files and stop |
56
+ | Coordinator | `uv run -m pytest`, `microcoreos status`, and `microcoreos` (the real boot) for the final lint |
57
+
58
+ **Never `microcoreos run` / `uv run main.py` outside that last row.** It serves
59
+ forever: in the foreground it hangs your session, in the background it leaves a
60
+ process holding the port that makes the next `microcoreos migrate` refuse to
61
+ run. `migrate` is the boot that ends; `status` and `schema` answer everything
62
+ you would have booted to find out.
63
+
64
+ **No `AI_CONTEXT.md` in the project?** It is generated, not shipped — a freshly
65
+ scaffolded project has none until something boots. Run `microcoreos migrate`
66
+ once and it appears. Do not go exploring `domains/` and `tools/` to reconstruct
67
+ what it would have said: that is the search the manifest exists to replace, and
68
+ it costs an order of magnitude more to arrive at less.
69
+
70
+ Read on demand, never up front: `INSTRUCTIONS_FOR_AI.md` (building tools,
71
+ testing in depth, kernel internals) · `docs/internal/TECH_DEBT.md` (only when scoping
72
+ work that may overlap an open item) · `domains/{domain}/models/{name}.py` (its
73
+ fields are already in `AI_CONTEXT.md`).
74
+
75
+ **Size the plan to the request** — over-planning a small one is a failure mode.
76
+ Every workflow below opens with the **same** two-file route as the Planner row
77
+ above, so following the ladder and following the table land in the same place;
78
+ each then adds only what is specific to its size. The phases themselves are in
79
+ `docs/PARALLEL_DEVELOPMENT.md` and are not repeated in any of them.
22
80
 
23
81
  | Request | Workflow | Expected plan size |
24
82
  |---|---|---|
@@ -42,6 +100,21 @@ uv run -m pytest tests/test_file.py # Run a single test
42
100
  docker compose -f dev_infra/docker-compose.yml up -d # Start dev infrastructure (PostgreSQL)
43
101
  ```
44
102
 
103
+ The plan pipeline — prefix with `uv run` if the package is installed in a venv:
104
+
105
+ ```bash
106
+ microcoreos status # Active plan, progress, manifest freshness
107
+ microcoreos plan validate # The 18 plan rules, OFFLINE (no server, no jq, no curl)
108
+ microcoreos migrate # Apply migrations AND regenerate AI_CONTEXT.md
109
+ microcoreos schema # The live tables and columns, read by the db tool itself
110
+ ```
111
+
112
+ `microcoreos schema` is how you verify a migration. Do not reach for `sqlite3`
113
+ (not installed) or `import aiosqlite` from the system interpreter (it lives in
114
+ `.venv`) — and do not read the DB file directly: `describe_schema()` normalizes
115
+ types to the closed vocabulary every engine shares, so it reports what a swap
116
+ must preserve.
117
+
45
118
  ---
46
119
 
47
120
  ## 🛡️ Non-Negotiable Rules
@@ -81,63 +154,29 @@ The Kernel (ToolProxy & Container) is infrastructure-blind:
81
154
 
82
155
  ---
83
156
 
84
- ## 🔄 Batch Parallel Execution Workflow (Coordinator Guidelines)
85
-
86
- The canonical methodology (and its phase numbering) is `docs/PARALLEL_DEVELOPMENT.md`.
87
- This is the coordinator's operational summary:
157
+ ## 🔄 The pipeline, in five lines
88
158
 
89
- 1. **Phase 1 — The Plan (contract)**: The formal YAML plan lives in `plans/active_plan.yaml`; the execution checklist (all tasks `[ ]`) in `plans/active_plan.md`. Validate with `POST /system/plan/validate` — **zero `errors` before anything else runs**. An invalid plan is fixed in the plan, never patched in code.
90
- 2. **Phase 0 — Foundation (Serial)**: Write the tools (if any), then all domain models and SQL migrations sequentially, exactly as the plan's `columns:` declare them. Run `uv run main.py --boot-tool db` (or `microcoreos run --boot-tool db` if installed) to migrate and regenerate `AI_CONTEXT.md`.
91
- 3. **Phase 2 — Parallel Write Wave**: Spawn N subagents (one per plugin), each with the **canonical executor prompt**: a byte-identical shared prefix (`AI_CONTEXT.md` → `plans/active_plan.yaml`, in that order — the manifest embeds the executor rules and templates as its "Plugin Authoring Guide" section) followed by ONE per-agent line at the end ("Implement feature `<PluginName>` from the plan above"). Subagents never open the plan or `AI_CONTEXT.md` themselves — dispatch them **write-only, scoped to their two files** (write capability restricted to the exact paths the plan declares for the task — `file:` + `test:`, or the flow's two test paths; no read/search/shell tools): the prefix is self-sufficient by construction (one complete template per deliverable type in `AI_CONTEXT.md` § Authoring Templates), so reading capability only invites redundant verification and guessed paths. The identical prefix lets any engine with prefix caching (local KV cache, hosted prompt caching) process the shared block once and reuse it for the whole wave — dispatch the first agent, let it start responding, then fire the rest. Each agent writes exactly two files: its plugin and its unit test.
92
- 4. **Phase 3 — Bulk Verification**: Once all subagents finish writing, run the entire test suite in a single execution (`uv run -m pytest`), then boot and check `GET /system/lint`.
93
- 5. **Cleanup & Reconstruct**:
94
- * For passing plugins: Mark their checkbox as `[x]` in `plans/active_plan.md`.
95
- * For failing plugins: **Delete** the created plugin and unit test files, keep their checkbox as `[ ]`, and spawn a new wave of clean agents to rewrite them from scratch.
96
- * Repeat until all checkboxes are `[x]`.
159
+ The methodology, the phase numbering and the executor-prompt mechanics live in
160
+ `docs/PARALLEL_DEVELOPMENT.md` — **canonically, and only there**. This used to
161
+ be a second copy of it, which is precisely how the copy drifted: it prescribed
162
+ `--boot-tool db` for phase 0 long after that stopped regenerating the manifest,
163
+ and no one compares two documents to notice.
97
164
 
98
- ---
99
-
100
- ## ⚡ Minimal Plugin Template
101
-
102
- ```python
103
- from typing import Optional
104
- from pydantic import BaseModel, Field
105
- from microcoreos import BasePlugin
106
-
107
- class CreateThingRequest(BaseModel):
108
- name: str = Field(min_length=1, max_length=100)
109
-
110
- class ThingData(BaseModel):
111
- id: int
112
- name: str
113
-
114
- class CreateThingResponse(BaseModel):
115
- success: bool
116
- data: Optional[ThingData] = None
117
- error: Optional[str] = None
118
-
119
- class CreateThingPlugin(BasePlugin):
120
- def __init__(self, http, db, logger):
121
- self.http = http
122
- self.db = db
123
- self.logger = logger
124
-
125
- async def on_boot(self):
126
- self.http.add_endpoint("/things", "POST", self.execute,
127
- tags=["Things"], request_model=CreateThingRequest,
128
- response_model=CreateThingResponse)
129
-
130
- async def execute(self, data: dict, context=None):
131
- try:
132
- req = CreateThingRequest(**data)
133
- new_id = await self.db.execute(
134
- "INSERT INTO things (name) VALUES ($1) RETURNING id", [req.name]
135
- )
136
- return {"success": True, "data": {"id": new_id, "name": req.name}}
137
- except Exception as e:
138
- self.logger.error(f"Failed to create thing: {e}")
139
- return {"success": False, "error": "Database error"}
140
- ```
165
+ | Phase | Command | Gate |
166
+ |---|---|---|
167
+ | 1 — Plan | *(the Planner writes `plans/active_plan.yaml` + `.md`)* | `microcoreos plan validate` → **zero errors** |
168
+ | 0 — Foundation | *(migrations + models, 1:1 from `phase_0`)* | `microcoreos migrate` then `microcoreos schema` |
169
+ | 2 — Wave | *(N executors, one plugin + one test each)* | every declared file exists |
170
+ | 3 — Verify | `uv run -m pytest` | green, then `GET /system/lint` clean |
171
+ | — Reconstruct | delete the failures, respawn fresh executors | all `[x]` in `plans/active_plan.md` |
172
+
173
+ Two rules the phases do not state on their own:
174
+
175
+ - **An invalid plan is fixed in the plan, never patched in code.** Errors carry
176
+ the YAML that fixes them — paste it, do not re-derive it.
177
+ - **A plan is only ever `plans/active_plan.yaml`.** Any other filename is a plan
178
+ nothing will execute, and the shipped template is itself valid, so nothing but
179
+ its `template: true` marker can tell it apart from yours.
141
180
 
142
181
  ---
143
182
 
@@ -293,13 +293,10 @@ Async SQLite Persistence Tool (sqlite):
293
293
  - **res**: EventSchemasData(schemas: dict)
294
294
  - `GET /system/lint`
295
295
  - **res**: SystemLintData(arch_violations: list[str], drift_warnings: list[str], event_contract_violations: list[LintFinding(code: str, severity: str, event: Optional[str], publisher: Optional[str], consumer: Optional[str], detail: str)], route_collisions: list[str], table_ownership_warnings: list[str], field_divergence_warnings: list[str])
296
- - `POST /system/plan/validate`
297
- - **req**: plan: Optional[dict], plan_yaml: Optional[str]
298
- - **res**: ValidatePlanData(valid: bool, errors: list[PlanViolation(rule: int, severity: str, where: str, detail: str)], warnings: list[PlanViolation(rule: int, severity: str, where: str, detail: str)])
299
296
  - **Events emitted**: none
300
297
  - **Events consumed**: none
301
298
  - **Dependencies**: container, http, logger
302
- - **Plugins**: devtools.DiscoveryNamingLinterPlugin, devtools.DomainIsolationLinterPlugin, devtools.EventContractLinterPlugin, devtools.EventSchemasPlugin, devtools.FieldDivergenceLinterPlugin, devtools.PlanValidatorPlugin, devtools.RouteCollisionLinterPlugin, devtools.TableOwnershipLinterPlugin, devtools.ToolDocDriftLinterPlugin
299
+ - **Plugins**: devtools.DiscoveryNamingLinterPlugin, devtools.DomainIsolationLinterPlugin, devtools.EventContractLinterPlugin, devtools.EventSchemasPlugin, devtools.FieldDivergenceLinterPlugin, devtools.RouteCollisionLinterPlugin, devtools.TableOwnershipLinterPlugin, devtools.ToolDocDriftLinterPlugin
303
300
 
304
301
  ### `system`
305
302
  - **Tables**: none
@@ -344,8 +341,10 @@ Your task line names either a **feature** or a **flow's tests**:
344
341
  - Flow-tests task → 1. the flow's `e2e_test` (trigger the happy path, assert
345
342
  the causal chain with `tests/helpers/trace_chains.py`:
346
343
  `assert_chain(build_tree(bus.get_trace_history()), [...])`) and 2. its
347
- `sad_path_test` (force the consumer to fail with a mock that raises, assert
348
- `_dlq.<event>` appears as a child of the failed event in the same tree).
344
+ `sad_path_test` (force the consumer to fail — the mock must raise on the
345
+ FIRST tool call the handler makes, since an idempotency guard runs before
346
+ the effect — and assert `_dlq.<event>` appears as a child of the failed
347
+ event in the same tree).
349
348
 
350
349
  Nothing else: no migrations, no entity models, no edits to `main.py`, no
351
350
  touching other domains or other tasks' files. When both files are written,
@@ -357,8 +356,11 @@ follow-ups.
357
356
  1. **Schemas inline** — request, response AND event payload models at the top
358
357
  of the plugin file. Never import them from `models/` or other domains.
359
358
  2. **DI by parameter name** — `__init__(self, http, db, logger)` receives the
360
- tools named `http`, `db`, `logger`. Inject exactly the tools your feature
361
- uses. No hardcoded imports from `tools/`.
359
+ tools named `http`, `db`, `logger`. No hardcoded imports from `tools/`.
360
+ **Your parameters are exactly your feature's `tools:` list in the plan, in
361
+ that order** — not what a template happens to show. The plan is the
362
+ contract, and the test is written against that same list: add a `logger`
363
+ nobody declared and the two no longer fit.
362
364
  3. **Return envelope** — `{"success": bool, "data": ..., "error": ...}`:
363
365
  `success` always present, `data` on success, `error` on failure. Responses
364
366
  serialize AS-IS — `response_model` does NOT backfill omitted keys, so an
@@ -398,6 +400,26 @@ follow-ups.
398
400
  coherent without any of you coordinating: your feature is written in
399
401
  isolation, but its vocabulary is shared.
400
402
 
403
+ 11. **Idempotent consumer** — when the plan's flow link says
404
+ `idempotent: true`, guard on `event.id` (the envelope is frozen, so a
405
+ redelivery carries the same one) and mark it **after** the effect:
406
+
407
+ ```python
408
+ if await self.state.has(event.id, namespace="thing-seen"):
409
+ return # duplicate: already applied
410
+ await self.state.increment(...) # the effect
411
+ await self.state.set(event.id, True, namespace="thing-seen", ttl=3600)
412
+ ```
413
+
414
+ Marking first drops the event: the effect raises, the retry hits the guard,
415
+ returns "already seen" — no work, no error, no DLQ. Write the
416
+ double-delivery test under the exact name `idempotency_test` gives, with a
417
+ real `StateTool()`: an `AsyncMock` returns truthy from `has()`, so the guard
418
+ swallows everything and the test proves nothing. Rule 6 says a *plugin*
419
+ never imports the envelope; a *test* has to build one —
420
+ `from tools.event_bus.envelope import EventEnvelope` — and deliver the same
421
+ instance twice.
422
+
401
423
  ### Templates — one per deliverable type, copy the one your task matches
402
424
 
403
425
  Each is a whole file, imports to last line; nothing a feature or flow-tests
@@ -600,7 +622,8 @@ x = tool.method.return_value.__aenter__.return_value # bound by `as x:`
600
622
  PLAN (route, envelope shape, declared tables, declared payload keys) —
601
623
  never from your own implementation. The test is the contract's proof; a
602
624
  test that mirrors the code proves nothing.
603
- - Mock exactly the tools your feature's `mocks:` lists
625
+ - Mock exactly the tools your feature's `tools:` lists — all of them; an
626
+ omitted `logger` is still a required positional argument
604
627
  (`unittest.mock.AsyncMock` / `MagicMock`); run every other injected tool as
605
628
  a real in-memory instance (SQLite `:memory:` with your domain's migration
606
629
  applied, in-process event bus).