grain-kit 0.2.0__tar.gz → 0.3.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 (334) hide show
  1. {grain_kit-0.2.0/src/grain_kit.egg-info → grain_kit-0.3.1}/PKG-INFO +146 -1
  2. {grain_kit-0.2.0 → grain_kit-0.3.1}/README.md +141 -0
  3. {grain_kit-0.2.0 → grain_kit-0.3.1}/pyproject.toml +6 -1
  4. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/adapters/manifest.py +104 -0
  5. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/__init__.py +145 -1
  6. grain_kit-0.3.1/src/grain/cli/archive.py +233 -0
  7. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/context.py +21 -0
  8. grain_kit-0.3.1/src/grain/cli/docs.py +192 -0
  9. grain_kit-0.3.1/src/grain/cli/doctor.py +107 -0
  10. grain_kit-0.3.1/src/grain/cli/hooks.py +132 -0
  11. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/init.py +9 -1
  12. grain_kit-0.3.1/src/grain/cli/mcp.py +44 -0
  13. grain_kit-0.3.1/src/grain/cli/notes.py +151 -0
  14. grain_kit-0.3.1/src/grain/cli/office.py +291 -0
  15. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/phase.py +3 -2
  16. grain_kit-0.3.1/src/grain/cli/status.py +292 -0
  17. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/task.py +109 -6
  18. grain_kit-0.3.1/src/grain/cli/tui.py +19 -0
  19. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/upgrade.py +35 -5
  20. grain_kit-0.3.1/src/grain/cli/verify.py +135 -0
  21. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/workflow.py +151 -0
  22. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/task.execute.md +1 -0
  23. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/tasks.close.md +5 -0
  24. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/tasks.next_and_implement.md +3 -0
  25. grain_kit-0.3.1/src/grain/data/prompts/workflow.resume.md +84 -0
  26. grain_kit-0.3.1/src/grain/data/runtime/CHANGELOG.md +19 -0
  27. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/runtime/PROJECT_RULES.md +33 -1
  28. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/runtime/adapter_profiles.md +201 -0
  29. grain_kit-0.3.1/src/grain/data/runtime/architecture.md +19 -0
  30. grain_kit-0.3.1/src/grain/data/runtime/backlog.md +19 -0
  31. grain_kit-0.3.1/src/grain/data/runtime/change_proposals.md +30 -0
  32. grain_kit-0.3.1/src/grain/data/runtime/current_focus.md +17 -0
  33. grain_kit-0.3.1/src/grain/data/runtime/current_task_template.md +7 -0
  34. grain_kit-0.3.1/src/grain/data/runtime/decisions.md +25 -0
  35. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/runtime/docs_manifest.yaml +72 -1
  36. grain_kit-0.3.1/src/grain/data/runtime/landscape_canonical.md +14 -0
  37. grain_kit-0.3.1/src/grain/data/runtime/landscape_working.md +13 -0
  38. grain_kit-0.3.1/src/grain/data/runtime/open_questions.md +35 -0
  39. grain_kit-0.3.1/src/grain/data/runtime/product_scope.md +19 -0
  40. grain_kit-0.3.1/src/grain/data/runtime/roadmap.md +16 -0
  41. grain_kit-0.3.1/src/grain/data/runtime/workflow_metrics.md +30 -0
  42. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/__init__.py +20 -0
  43. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/documents.py +1 -1
  44. grain_kit-0.3.1/src/grain/domain/office_writes.py +111 -0
  45. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/workflow.py +8 -0
  46. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/agents_md_service.py +22 -13
  47. grain_kit-0.3.1/src/grain/services/archive_service.py +495 -0
  48. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/context_service.py +319 -3
  49. grain_kit-0.3.1/src/grain/services/docs_audit_service.py +1002 -0
  50. grain_kit-0.3.1/src/grain/services/doctor_service.py +194 -0
  51. grain_kit-0.3.1/src/grain/services/docx_write_service.py +153 -0
  52. grain_kit-0.3.1/src/grain/services/guard_service.py +442 -0
  53. grain_kit-0.3.1/src/grain/services/hooks_service.py +194 -0
  54. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/impact_ranking_service.py +1 -1
  55. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/init_service.py +26 -0
  56. grain_kit-0.3.1/src/grain/services/mcp_service.py +269 -0
  57. grain_kit-0.3.1/src/grain/services/office_artifact_review_service.py +196 -0
  58. grain_kit-0.3.1/src/grain/services/office_write_service.py +82 -0
  59. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/phase_close_service.py +20 -1
  60. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/reconcile_service.py +1 -1
  61. grain_kit-0.3.1/src/grain/services/spreadsheet_write_service.py +112 -0
  62. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/task_advice_service.py +1 -1
  63. grain_kit-0.3.1/src/grain/services/task_observability_service.py +112 -0
  64. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/upgrade_service.py +108 -0
  65. grain_kit-0.3.1/src/grain/services/verification_service.py +460 -0
  66. grain_kit-0.3.1/src/grain/services/workflow_diagnostics_service.py +248 -0
  67. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/workflow_loop_service.py +8 -5
  68. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/workflow_run_service.py +129 -3
  69. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/workflow_service.py +331 -47
  70. grain_kit-0.3.1/src/grain/templates/__init__.py +0 -0
  71. grain_kit-0.3.1/src/grain/tui/__init__.py +23 -0
  72. grain_kit-0.3.1/src/grain/tui/app.py +730 -0
  73. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/validators/packet_validator.py +21 -1
  74. {grain_kit-0.2.0 → grain_kit-0.3.1/src/grain_kit.egg-info}/PKG-INFO +146 -1
  75. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain_kit.egg-info/SOURCES.txt +54 -0
  76. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain_kit.egg-info/requires.txt +5 -0
  77. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_adapter_config_loader.py +23 -0
  78. grain_kit-0.3.1/tests/test_archive_cmd.py +388 -0
  79. grain_kit-0.3.1/tests/test_branch_policy.py +337 -0
  80. grain_kit-0.3.1/tests/test_cli_ergonomics.py +296 -0
  81. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_closure_validation.py +18 -1
  82. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_command_groups.py +3 -1
  83. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_context_build_cmd.py +20 -0
  84. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_context_export_cmd.py +2 -0
  85. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_doc_existence_validator.py +0 -1
  86. grain_kit-0.3.1/tests/test_docs_audit_cmd.py +595 -0
  87. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_docs_index_cmd.py +0 -1
  88. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_docs_validate_cmd.py +0 -1
  89. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_document_adapters_integration.py +271 -0
  90. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_document_registry.py +1 -2
  91. grain_kit-0.3.1/tests/test_docx_write_service.py +140 -0
  92. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_error_handler.py +0 -3
  93. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_filesystem_adapter.py +0 -1
  94. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_impact_ranking_service.py +0 -1
  95. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_init_service.py +73 -2
  96. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_manifest_loader.py +0 -1
  97. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_manifest_validator.py +0 -1
  98. grain_kit-0.3.1/tests/test_mcp_cmd.py +173 -0
  99. grain_kit-0.3.1/tests/test_office_artifact_review_service.py +149 -0
  100. grain_kit-0.3.1/tests/test_office_cmd.py +261 -0
  101. grain_kit-0.3.1/tests/test_office_write_service.py +156 -0
  102. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_packet_file_validation.py +20 -4
  103. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_packet_status.py +0 -1
  104. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase15_integration.py +3 -3
  105. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase_archive_cmd.py +1 -1
  106. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_prompt_show_cmd.py +19 -6
  107. grain_kit-0.3.1/tests/test_release_surface.py +124 -0
  108. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_runner_integration.py +5 -5
  109. grain_kit-0.3.1/tests/test_spreadsheet_write_service.py +150 -0
  110. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_task_close_cmd.py +30 -0
  111. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_task_create_dir.py +0 -1
  112. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_task_id.py +0 -2
  113. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_task_next_cmd.py +1 -1
  114. grain_kit-0.3.1/tests/test_task_observe_cmd.py +134 -0
  115. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_template_loader.py +0 -1
  116. grain_kit-0.3.1/tests/test_tui_cmd.py +524 -0
  117. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_upgrade_cmd.py +62 -1
  118. grain_kit-0.3.1/tests/test_upgrade_enforcement.py +339 -0
  119. grain_kit-0.3.1/tests/test_verify_submit_cmd.py +248 -0
  120. grain_kit-0.3.1/tests/test_workflow_explain_cmd.py +130 -0
  121. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_workflow_loop_cmd.py +8 -1
  122. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_workflow_next_cmd.py +58 -1
  123. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_workflow_run_cmd.py +57 -1
  124. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_workflow_state_service.py +148 -7
  125. grain_kit-0.2.0/src/grain/cli/docs.py +0 -89
  126. grain_kit-0.2.0/src/grain/data/runtime/workflow_metrics.md +0 -3
  127. grain_kit-0.2.0/tests/test_release_surface.py +0 -43
  128. {grain_kit-0.2.0 → grain_kit-0.3.1}/LICENSE +0 -0
  129. {grain_kit-0.2.0 → grain_kit-0.3.1}/setup.cfg +0 -0
  130. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/__init__.py +0 -0
  131. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/adapters/__init__.py +0 -0
  132. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/adapters/adapter_config.py +0 -0
  133. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/adapters/capabilities.py +0 -0
  134. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/adapters/export.py +0 -0
  135. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/adapters/filesystem.py +0 -0
  136. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/adapters/model_config.py +0 -0
  137. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/adapter.py +0 -0
  138. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/embedding.py +0 -0
  139. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/error_handler.py +0 -0
  140. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/model.py +0 -0
  141. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/onboard.py +0 -0
  142. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/orchestrate.py +0 -0
  143. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/output.py +0 -0
  144. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/prompt.py +0 -0
  145. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/cli/review.py +0 -0
  146. {grain_kit-0.2.0/src/grain/services → grain_kit-0.3.1/src/grain/contracts}/__init__.py +0 -0
  147. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/README.md +0 -0
  148. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/close.md +0 -0
  149. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/context.build.md +0 -0
  150. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/context.export.md +0 -0
  151. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/context.show.md +0 -0
  152. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/docs.canonical.generate.md +0 -0
  153. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/docs.change.apply.md +0 -0
  154. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/docs.working.generate.md +0 -0
  155. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/docs.working.reconcile.md +0 -0
  156. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/execute.md +0 -0
  157. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/feature.classify.md +0 -0
  158. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/model.escalate.md +0 -0
  159. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/model.select.md +0 -0
  160. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/model.show.md +0 -0
  161. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/open_questions.resolve.md +0 -0
  162. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/phase.close.md +0 -0
  163. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/phase.plan.next.md +0 -0
  164. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/phase.replan.md +0 -0
  165. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/phase.review.md +0 -0
  166. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/phase.review_and_close.md +0 -0
  167. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/phase.tasks.generate.md +0 -0
  168. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/phase.tasks.seed.md +0 -0
  169. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/project.health.md +0 -0
  170. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/review.check.md +0 -0
  171. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/review.handoff.md +0 -0
  172. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/review.md +0 -0
  173. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/review.summary.md +0 -0
  174. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/task.close.md +0 -0
  175. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/task.plan.next.md +0 -0
  176. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/task.review.md +0 -0
  177. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/tasks.implement.md +0 -0
  178. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/tasks.packet.first.md +0 -0
  179. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/tasks.packet.next.md +0 -0
  180. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/tasks.packet.phase.md +0 -0
  181. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/tasks.plan.next.md +0 -0
  182. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/tasks.review.md +0 -0
  183. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/tasks.validate.packet.md +0 -0
  184. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/workflow.init.md +0 -0
  185. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/workflow.onboard.existing.md +0 -0
  186. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/prompts/workflow.onboard.new.md +0 -0
  187. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/runtime/agent_profiles.md +0 -0
  188. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/runtime/context_loading.md +0 -0
  189. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/runtime/docs_index.md +0 -0
  190. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/runtime/implementation_plan.md +0 -0
  191. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/runtime/tooling_notes.md +0 -0
  192. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/runtime/workflow_loop.yaml +0 -0
  193. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/templates/tasks/context.md +0 -0
  194. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/templates/tasks/deliverable_spec.md +0 -0
  195. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/templates/tasks/handoff.md +0 -0
  196. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/templates/tasks/plan.md +0 -0
  197. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/templates/tasks/results.md +0 -0
  198. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/templates/tasks/task.md +0 -0
  199. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/data/templates/tasks/task_packet.md +0 -0
  200. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/adapters.py +0 -0
  201. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/completion_policy.py +0 -0
  202. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/context.py +0 -0
  203. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/embedding.py +0 -0
  204. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/errors.py +0 -0
  205. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/onboard.py +0 -0
  206. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/orchestrator.py +0 -0
  207. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/packets.py +0 -0
  208. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/ranking.py +0 -0
  209. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/review_bundle.py +0 -0
  210. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/routing.py +0 -0
  211. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/scan_result.py +0 -0
  212. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/domain/workflow_loop.py +0 -0
  213. {grain_kit-0.2.0/src/grain/templates → grain_kit-0.3.1/src/grain/services}/__init__.py +0 -0
  214. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/adapter_install_service.py +0 -0
  215. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/adapter_package_service.py +0 -0
  216. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/bm25_provider.py +0 -0
  217. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/codebase_scanner.py +0 -0
  218. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/data_artifact_extractor.py +0 -0
  219. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/docs_extractor.py +0 -0
  220. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/docs_service.py +0 -0
  221. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/embedding_resolver.py +0 -0
  222. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/embedding_service.py +0 -0
  223. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/graph_service.py +0 -0
  224. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/handoff_service.py +0 -0
  225. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/local_provider.py +0 -0
  226. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/model_service.py +0 -0
  227. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/notebook_extractor.py +0 -0
  228. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/ollama_provider.py +0 -0
  229. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/onboard_doc_generator.py +0 -0
  230. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/onboard_service.py +0 -0
  231. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/openai_provider.py +0 -0
  232. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/orchestration_service.py +0 -0
  233. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/pdf_extractor.py +0 -0
  234. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/phase_archive_service.py +0 -0
  235. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/prompt_service.py +0 -0
  236. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/ranking_service.py +0 -0
  237. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/review_service.py +0 -0
  238. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/spreadsheet_extractor.py +0 -0
  239. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/structural_intelligence_service.py +0 -0
  240. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/task_prepare_service.py +0 -0
  241. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/task_service.py +0 -0
  242. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/services/workflow_loop_config_service.py +0 -0
  243. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/templates/loader.py +0 -0
  244. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/validators/__init__.py +0 -0
  245. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/validators/authority_validator.py +0 -0
  246. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/validators/doc_existence_validator.py +0 -0
  247. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/validators/manifest_validator.py +0 -0
  248. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain/validators/orchestrator_validator.py +0 -0
  249. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain_kit.egg-info/dependency_links.txt +0 -0
  250. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain_kit.egg-info/entry_points.txt +0 -0
  251. {grain_kit-0.2.0 → grain_kit-0.3.1}/src/grain_kit.egg-info/top_level.txt +0 -0
  252. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_adapter_capability.py +0 -0
  253. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_adapter_cmd.py +0 -0
  254. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_adapter_context.py +0 -0
  255. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_adapter_domain.py +0 -0
  256. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_adapter_install_service.py +0 -0
  257. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_adapter_loading.py +0 -0
  258. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_adapter_package_service.py +0 -0
  259. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_agents_md_cmd.py +0 -0
  260. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_authority_validator.py +0 -0
  261. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_bm25_provider.py +0 -0
  262. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_bump_version_script.py +0 -0
  263. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_canonical_doc_selection.py +0 -0
  264. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_cli_entrypoint.py +0 -0
  265. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_codebase_scanner.py +0 -0
  266. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_context_build.py +0 -0
  267. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_context_bundle.py +0 -0
  268. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_context_export.py +0 -0
  269. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_context_show_cmd.py +0 -0
  270. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_context_sources.py +0 -0
  271. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_data_artifact_extractor.py +0 -0
  272. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_docs_extractor.py +0 -0
  273. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_docs_show_cmd.py +0 -0
  274. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_embedding_domain.py +0 -0
  275. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_embedding_resolver.py +0 -0
  276. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_embedding_show_cmd.py +0 -0
  277. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_grain_config.py +0 -0
  278. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_graph_adapter_capability.py +0 -0
  279. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_graph_service.py +0 -0
  280. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_handoff_service.py +0 -0
  281. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_help_ergonomics.py +0 -0
  282. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_imports.py +0 -0
  283. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_local_provider.py +0 -0
  284. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_model_config_loader.py +0 -0
  285. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_model_escalate_cmd.py +0 -0
  286. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_model_routing.py +0 -0
  287. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_model_select_cmd.py +0 -0
  288. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_model_service.py +0 -0
  289. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_model_show_cmd.py +0 -0
  290. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_notebook_extractor.py +0 -0
  291. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_ollama_provider.py +0 -0
  292. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_onboard_cmd.py +0 -0
  293. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_onboard_doc_generator.py +0 -0
  294. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_openai_provider.py +0 -0
  295. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_orchestrate_cmd.py +0 -0
  296. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_orchestration_integration.py +0 -0
  297. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_orchestration_service.py +0 -0
  298. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_orchestrator_domain.py +0 -0
  299. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_orchestrator_validator.py +0 -0
  300. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_output_formatter.py +0 -0
  301. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_pdf_extractor.py +0 -0
  302. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase10_integration_pipeline.py +0 -0
  303. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase13_integration.py +0 -0
  304. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase16_integration.py +0 -0
  305. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase17_integration.py +0 -0
  306. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase18_integration.py +0 -0
  307. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase19_integration.py +0 -0
  308. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase19_registry_ci_docs.py +0 -0
  309. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase19_registry_scaffold.py +0 -0
  310. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase5_integration.py +0 -0
  311. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase7_integration.py +0 -0
  312. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase_close_cmd.py +0 -0
  313. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_phase_next_cmd.py +0 -0
  314. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_ranking_domain.py +0 -0
  315. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_ranking_service.py +0 -0
  316. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_review_check_cmd.py +0 -0
  317. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_review_handoff_cmd.py +0 -0
  318. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_review_service.py +0 -0
  319. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_review_summary_cmd.py +0 -0
  320. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_smoke.py +0 -0
  321. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_spreadsheet_extractor.py +0 -0
  322. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_structural_intelligence_service.py +0 -0
  323. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_task_advice_service.py +0 -0
  324. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_task_create_cmd.py +0 -0
  325. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_task_lifecycle.py +0 -0
  326. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_task_list_cmd.py +0 -0
  327. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_task_prepare_cmd.py +0 -0
  328. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_task_show_cmd.py +0 -0
  329. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_task_status_cmd.py +0 -0
  330. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_task_validate_cmd.py +0 -0
  331. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_workflow_loop_config_service.py +0 -0
  332. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_workflow_onboard_existing_prompt.py +0 -0
  333. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_workflow_reconcile_cmd.py +0 -0
  334. {grain_kit-0.2.0 → grain_kit-0.3.1}/tests/test_working_doc_selection.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: grain-kit
3
- Version: 0.2.0
3
+ Version: 0.3.1
4
4
  Summary: CLI-first workflow toolkit for structured AI-assisted software development.
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/Diwata-Labs/Grain
@@ -22,11 +22,15 @@ License-File: LICENSE
22
22
  Requires-Dist: click>=8.1
23
23
  Requires-Dist: PyYAML>=6.0
24
24
  Requires-Dist: networkx>=3.3
25
+ Requires-Dist: textual>=0.67
25
26
  Requires-Dist: tree-sitter>=0.25.2
26
27
  Requires-Dist: tree-sitter-language-pack>=0.13.0
27
28
  Requires-Dist: openpyxl>=3.1
28
29
  Requires-Dist: python-docx>=1.1
29
30
  Requires-Dist: pdfplumber>=0.11
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=8.0; extra == "dev"
33
+ Requires-Dist: ruff>=0.4; extra == "dev"
30
34
  Provides-Extra: release
31
35
  Requires-Dist: build>=1.4.3; extra == "release"
32
36
  Requires-Dist: twine>=5.1; extra == "release"
@@ -235,6 +239,87 @@ In practice, the agent should use Grain as the workflow layer for the repository
235
239
  The CLI is the delivery surface.
236
240
  The product value is the workflow structure it gives the agent.
237
241
 
242
+ ### Codex and CLI-first usage
243
+
244
+ For Codex or any environment that can invoke local commands directly, the canonical integration path is still the Grain CLI.
245
+
246
+ Preferred operating pattern:
247
+
248
+ ```bash
249
+ grain --format json workflow next
250
+ grain prompt show --format json
251
+ ```
252
+
253
+ Use JSON output when the calling environment wants structured state.
254
+ Use text output when a human operator is driving the loop directly.
255
+
256
+ For Codex-style usage:
257
+ - call `grain` commands directly
258
+ - prefer `grain workflow next` to decide the next legal state transition
259
+ - use `grain prompt show` to surface the stable prompt entrypoint
260
+ - keep task execution packet-first and file-backed
261
+ - treat `grain mcp` as optional, not required
262
+
263
+ ### Claude Desktop and MCP-style usage
264
+
265
+ For desktop clients that prefer MCP tools over direct CLI execution, use the local MCP wrapper:
266
+
267
+ ```bash
268
+ grain --format json mcp manifest
269
+ grain mcp serve
270
+ ```
271
+
272
+ Current intent:
273
+ - Codex/tool-execution path: direct CLI
274
+ - Claude/Desktop-style path: local stdio MCP wrapper over the same Grain services
275
+ - both paths preserve the same workflow rules and packet-first boundaries
276
+
277
+ ### Assay verification loop
278
+
279
+ Phase 28 adds the first packet-local verification bridge for Assay-backed review.
280
+
281
+ Current commands:
282
+
283
+ ```bash
284
+ grain verify submit --id TASK-0001
285
+ grain verify status --verification-id VERIFY-0001-001
286
+ grain verify ingest --verification-id VERIFY-0001-001 --payload payload.json
287
+ ```
288
+
289
+ Operator rules for this slice:
290
+ - submit verification only after the packet has `results.md` and is in `review` or `done`
291
+ - treat `verification_request.json` and `verification_result.json` as packet-local workflow artifacts
292
+ - do not close a task while verification is `pending`
293
+ - if verification is `failed`, resolve the findings or explicitly waive verification before closure
294
+ - keep the loop file-backed: Assay can produce the payload elsewhere, but Grain only reads and records the packet-local artifacts
295
+
296
+ ### Obsidian vault usage
297
+
298
+ For Obsidian vault work, keep the CLI and packet workflow canonical:
299
+
300
+ - declare `obsidian_adapter` on the active packet when the task is about vault notes
301
+ - let `grain context build` and the normal workflow loop assemble context from the target note and nearby wiki-linked notes
302
+ - treat `.obsidian/` config as secondary context unless the task is explicitly about vault settings
303
+ - use the local MCP wrapper only as a desktop invocation surface; it does not replace the Grain workflow rules
304
+
305
+ ### Database workflow usage
306
+
307
+ For database work, keep the same packet-first and local-first posture:
308
+
309
+ - declare `database_adapter` on the active packet when the task is about schema, migrations, queries, or persistence layers
310
+ - let `grain context build` assemble focused schema, migration, query, and repository context instead of loading broad app code by default
311
+ - review destructive migration risk, rollback expectations, and schema/query drift before closing the task
312
+ - treat database execution or live mutation tooling as separate future work; the current `v0.3.0` slice is about context, review, and validation guidance
313
+
314
+ ### Crawler workflow usage
315
+
316
+ For crawler work, keep the same packet-first and local-first posture:
317
+
318
+ - declare `crawler_adapter` on the active packet when the task is about crawl configs, selectors, extraction schemas, or output validation
319
+ - let `grain context build` assemble focused crawl, selector, extraction, and validation context instead of loading broad app code by default
320
+ - review robots constraints, rate limits, retry policy risk, selector brittleness, and extraction drift before closing the task
321
+ - treat broad crawl execution or live scraping automation as separate future work; the current `v0.3.0` slice is about context, review, and validation guidance
322
+
238
323
  Example instruction for an agent:
239
324
 
240
325
  ```text
@@ -257,6 +342,8 @@ Your role is to execute work through Grain's state-driven workflow.
257
342
 
258
343
  Rules:
259
344
  - Run `grain workflow next` before deciding what to do.
345
+ - If Grain stops or the repo state looks inconsistent, run `grain workflow explain` before improvising.
346
+ - If the explanation points to drift, run `grain workflow reconcile --dry-run` before making manual repairs.
260
347
  - Run `grain prompt show` before executing the next step.
261
348
  - Follow the recommended prompt exactly.
262
349
  - Work on only one active task packet at a time.
@@ -293,11 +380,20 @@ Typical commands:
293
380
 
294
381
  ```bash
295
382
  grain workflow next
383
+ grain workflow explain
384
+ grain workflow reconcile --dry-run
296
385
  grain prompt show
297
386
  grain review check --id TASK-0001
298
387
  grain task close --id TASK-0001
388
+ grain tui
299
389
  ```
300
390
 
391
+ When Grain stops:
392
+
393
+ - use `grain workflow explain` to translate the current gate into concrete operator actions
394
+ - use `grain workflow reconcile --dry-run` when the explanation points to packet/backlog drift
395
+ - return to `grain workflow next` only after the file-backed issue is repaired
396
+
301
397
  If you want Grain to execute one legal state transition and stop at gates:
302
398
 
303
399
  ```bash
@@ -318,6 +414,55 @@ Grain controls:
318
414
  The agent controls:
319
415
  - executing the current step correctly
320
416
 
417
+ ## Terminal UI
418
+
419
+ `grain tui` is the first operator shell over Grain’s existing CLI and file-backed workflow.
420
+
421
+ Current TUI surfaces:
422
+ - workflow dashboard and current task status
423
+ - phase backlog and packet artifact inspection
424
+ - prompt preview and compact context summary
425
+ - blocker detail and action feedback
426
+ - execute, review, and close launchers that delegate to the normal Grain workflow services
427
+
428
+ The TUI is intentionally thin:
429
+ - it reads the same repo files and service outputs the CLI already uses
430
+ - it does not maintain hidden workflow state
431
+ - it does not bypass review or close gates
432
+
433
+ Current deferrals:
434
+ - deep packet content editors
435
+ - full prompt-body rendering
436
+ - full context export rendering
437
+ - embedded agent terminals
438
+ - multi-project views
439
+ - broad GUI beyond the terminal shell
440
+
441
+ ## Writable office artifacts
442
+
443
+ Phase 23 adds the first packet-first office mutation workflow for `.docx` and spreadsheets.
444
+
445
+ Current commands:
446
+
447
+ ```bash
448
+ grain office docx propose --source docs/brief.docx --replace "old=new"
449
+ grain office docx export --source docs/brief.docx --replace "old=new"
450
+ grain office spreadsheet propose --source data/report.xlsx --set "Sheet1!B2=14"
451
+ grain office spreadsheet export --source data/report.xlsx --set "Sheet1!B2=14"
452
+ grain office review show --task-id TASK-0001
453
+ ```
454
+
455
+ Operator rules for this slice:
456
+ - run office commands inside an active task packet, or pass `--task-id` explicitly
457
+ - `.docx` and spreadsheet writes currently support `propose` and `export-as-new-file`
458
+ - every office command persists `office_review.json` into the packet for review inspection
459
+ - review the artifact summary and validator results before closing the packet
460
+
461
+ What this does not do yet:
462
+ - in-place `apply` for `.docx` or spreadsheets
463
+ - TUI-native office editors
464
+ - desktop/MCP office invocation layers
465
+
321
466
  ## Onboarding flow
322
467
 
323
468
  Onboarding is one of the most important workflows in Grain because it gives the agent the initial structure it will follow later.
@@ -198,6 +198,87 @@ In practice, the agent should use Grain as the workflow layer for the repository
198
198
  The CLI is the delivery surface.
199
199
  The product value is the workflow structure it gives the agent.
200
200
 
201
+ ### Codex and CLI-first usage
202
+
203
+ For Codex or any environment that can invoke local commands directly, the canonical integration path is still the Grain CLI.
204
+
205
+ Preferred operating pattern:
206
+
207
+ ```bash
208
+ grain --format json workflow next
209
+ grain prompt show --format json
210
+ ```
211
+
212
+ Use JSON output when the calling environment wants structured state.
213
+ Use text output when a human operator is driving the loop directly.
214
+
215
+ For Codex-style usage:
216
+ - call `grain` commands directly
217
+ - prefer `grain workflow next` to decide the next legal state transition
218
+ - use `grain prompt show` to surface the stable prompt entrypoint
219
+ - keep task execution packet-first and file-backed
220
+ - treat `grain mcp` as optional, not required
221
+
222
+ ### Claude Desktop and MCP-style usage
223
+
224
+ For desktop clients that prefer MCP tools over direct CLI execution, use the local MCP wrapper:
225
+
226
+ ```bash
227
+ grain --format json mcp manifest
228
+ grain mcp serve
229
+ ```
230
+
231
+ Current intent:
232
+ - Codex/tool-execution path: direct CLI
233
+ - Claude/Desktop-style path: local stdio MCP wrapper over the same Grain services
234
+ - both paths preserve the same workflow rules and packet-first boundaries
235
+
236
+ ### Assay verification loop
237
+
238
+ Phase 28 adds the first packet-local verification bridge for Assay-backed review.
239
+
240
+ Current commands:
241
+
242
+ ```bash
243
+ grain verify submit --id TASK-0001
244
+ grain verify status --verification-id VERIFY-0001-001
245
+ grain verify ingest --verification-id VERIFY-0001-001 --payload payload.json
246
+ ```
247
+
248
+ Operator rules for this slice:
249
+ - submit verification only after the packet has `results.md` and is in `review` or `done`
250
+ - treat `verification_request.json` and `verification_result.json` as packet-local workflow artifacts
251
+ - do not close a task while verification is `pending`
252
+ - if verification is `failed`, resolve the findings or explicitly waive verification before closure
253
+ - keep the loop file-backed: Assay can produce the payload elsewhere, but Grain only reads and records the packet-local artifacts
254
+
255
+ ### Obsidian vault usage
256
+
257
+ For Obsidian vault work, keep the CLI and packet workflow canonical:
258
+
259
+ - declare `obsidian_adapter` on the active packet when the task is about vault notes
260
+ - let `grain context build` and the normal workflow loop assemble context from the target note and nearby wiki-linked notes
261
+ - treat `.obsidian/` config as secondary context unless the task is explicitly about vault settings
262
+ - use the local MCP wrapper only as a desktop invocation surface; it does not replace the Grain workflow rules
263
+
264
+ ### Database workflow usage
265
+
266
+ For database work, keep the same packet-first and local-first posture:
267
+
268
+ - declare `database_adapter` on the active packet when the task is about schema, migrations, queries, or persistence layers
269
+ - let `grain context build` assemble focused schema, migration, query, and repository context instead of loading broad app code by default
270
+ - review destructive migration risk, rollback expectations, and schema/query drift before closing the task
271
+ - treat database execution or live mutation tooling as separate future work; the current `v0.3.0` slice is about context, review, and validation guidance
272
+
273
+ ### Crawler workflow usage
274
+
275
+ For crawler work, keep the same packet-first and local-first posture:
276
+
277
+ - declare `crawler_adapter` on the active packet when the task is about crawl configs, selectors, extraction schemas, or output validation
278
+ - let `grain context build` assemble focused crawl, selector, extraction, and validation context instead of loading broad app code by default
279
+ - review robots constraints, rate limits, retry policy risk, selector brittleness, and extraction drift before closing the task
280
+ - treat broad crawl execution or live scraping automation as separate future work; the current `v0.3.0` slice is about context, review, and validation guidance
281
+
201
282
  Example instruction for an agent:
202
283
 
203
284
  ```text
@@ -220,6 +301,8 @@ Your role is to execute work through Grain's state-driven workflow.
220
301
 
221
302
  Rules:
222
303
  - Run `grain workflow next` before deciding what to do.
304
+ - If Grain stops or the repo state looks inconsistent, run `grain workflow explain` before improvising.
305
+ - If the explanation points to drift, run `grain workflow reconcile --dry-run` before making manual repairs.
223
306
  - Run `grain prompt show` before executing the next step.
224
307
  - Follow the recommended prompt exactly.
225
308
  - Work on only one active task packet at a time.
@@ -256,11 +339,20 @@ Typical commands:
256
339
 
257
340
  ```bash
258
341
  grain workflow next
342
+ grain workflow explain
343
+ grain workflow reconcile --dry-run
259
344
  grain prompt show
260
345
  grain review check --id TASK-0001
261
346
  grain task close --id TASK-0001
347
+ grain tui
262
348
  ```
263
349
 
350
+ When Grain stops:
351
+
352
+ - use `grain workflow explain` to translate the current gate into concrete operator actions
353
+ - use `grain workflow reconcile --dry-run` when the explanation points to packet/backlog drift
354
+ - return to `grain workflow next` only after the file-backed issue is repaired
355
+
264
356
  If you want Grain to execute one legal state transition and stop at gates:
265
357
 
266
358
  ```bash
@@ -281,6 +373,55 @@ Grain controls:
281
373
  The agent controls:
282
374
  - executing the current step correctly
283
375
 
376
+ ## Terminal UI
377
+
378
+ `grain tui` is the first operator shell over Grain’s existing CLI and file-backed workflow.
379
+
380
+ Current TUI surfaces:
381
+ - workflow dashboard and current task status
382
+ - phase backlog and packet artifact inspection
383
+ - prompt preview and compact context summary
384
+ - blocker detail and action feedback
385
+ - execute, review, and close launchers that delegate to the normal Grain workflow services
386
+
387
+ The TUI is intentionally thin:
388
+ - it reads the same repo files and service outputs the CLI already uses
389
+ - it does not maintain hidden workflow state
390
+ - it does not bypass review or close gates
391
+
392
+ Current deferrals:
393
+ - deep packet content editors
394
+ - full prompt-body rendering
395
+ - full context export rendering
396
+ - embedded agent terminals
397
+ - multi-project views
398
+ - broad GUI beyond the terminal shell
399
+
400
+ ## Writable office artifacts
401
+
402
+ Phase 23 adds the first packet-first office mutation workflow for `.docx` and spreadsheets.
403
+
404
+ Current commands:
405
+
406
+ ```bash
407
+ grain office docx propose --source docs/brief.docx --replace "old=new"
408
+ grain office docx export --source docs/brief.docx --replace "old=new"
409
+ grain office spreadsheet propose --source data/report.xlsx --set "Sheet1!B2=14"
410
+ grain office spreadsheet export --source data/report.xlsx --set "Sheet1!B2=14"
411
+ grain office review show --task-id TASK-0001
412
+ ```
413
+
414
+ Operator rules for this slice:
415
+ - run office commands inside an active task packet, or pass `--task-id` explicitly
416
+ - `.docx` and spreadsheet writes currently support `propose` and `export-as-new-file`
417
+ - every office command persists `office_review.json` into the packet for review inspection
418
+ - review the artifact summary and validator results before closing the packet
419
+
420
+ What this does not do yet:
421
+ - in-place `apply` for `.docx` or spreadsheets
422
+ - TUI-native office editors
423
+ - desktop/MCP office invocation layers
424
+
284
425
  ## Onboarding flow
285
426
 
286
427
  Onboarding is one of the most important workflows in Grain because it gives the agent the initial structure it will follow later.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "grain-kit"
7
- version = "0.2.0"
7
+ version = "0.3.1"
8
8
  description = "CLI-first workflow toolkit for structured AI-assisted software development."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -31,6 +31,7 @@ dependencies = [
31
31
  "click>=8.1",
32
32
  "PyYAML>=6.0",
33
33
  "networkx>=3.3",
34
+ "textual>=0.67",
34
35
  "tree-sitter>=0.25.2",
35
36
  "tree-sitter-language-pack>=0.13.0",
36
37
  "openpyxl>=3.1",
@@ -42,6 +43,10 @@ dependencies = [
42
43
  grain = "grain.cli:cli"
43
44
 
44
45
  [project.optional-dependencies]
46
+ dev = [
47
+ "pytest>=8.0",
48
+ "ruff>=0.4",
49
+ ]
45
50
  release = [
46
51
  "build>=1.4.3",
47
52
  "twine>=5.1",
@@ -98,6 +98,110 @@ def load_grain_config(root: Path) -> GrainConfig:
98
98
  )
99
99
 
100
100
 
101
+ @dataclass
102
+ class UpgradePolicy:
103
+ """upgrade_policy block from docs_manifest.yaml."""
104
+
105
+ min_version: str = ""
106
+ min_version_set_at: str = ""
107
+ enforce: bool = False
108
+ enforce_after_days: int = 0
109
+ message: str = ""
110
+
111
+
112
+ def load_upgrade_policy(root: Path) -> UpgradePolicy:
113
+ """Read the optional ``upgrade_policy:`` block from docs_manifest.yaml.
114
+
115
+ Returns an :class:`UpgradePolicy` with defaults for any field not present.
116
+ Never raises.
117
+ """
118
+ try:
119
+ manifest = load_manifest(root)
120
+ except Exception:
121
+ return UpgradePolicy()
122
+
123
+ raw = manifest.get("upgrade_policy")
124
+ if not isinstance(raw, dict):
125
+ return UpgradePolicy()
126
+
127
+ def _str(key: str) -> str:
128
+ val = raw.get(key, "")
129
+ return str(val).strip() if val is not None else ""
130
+
131
+ def _bool_val(key: str) -> bool:
132
+ val = raw.get(key, False)
133
+ return val if isinstance(val, bool) else False
134
+
135
+ def _int_val(key: str) -> int:
136
+ val = raw.get(key, 0)
137
+ try:
138
+ return int(val)
139
+ except (TypeError, ValueError):
140
+ return 0
141
+
142
+ return UpgradePolicy(
143
+ min_version=_str("min_version"),
144
+ min_version_set_at=_str("min_version_set_at"),
145
+ enforce=_bool_val("enforce"),
146
+ enforce_after_days=_int_val("enforce_after_days"),
147
+ message=_str("message"),
148
+ )
149
+
150
+
151
+ @dataclass
152
+ class BranchPolicy:
153
+ """branch_policy block from docs_manifest.yaml."""
154
+
155
+ mode: str = "off" # "phase" | "task" | "off"
156
+ pattern: str = "" # optional override; empty = use mode default
157
+ enforce: bool = False
158
+ enforce_after_days: int = 0
159
+ message: str = ""
160
+
161
+
162
+ def load_branch_policy(root: Path) -> BranchPolicy:
163
+ """Read the optional ``branch_policy:`` block from docs_manifest.yaml.
164
+
165
+ Returns a :class:`BranchPolicy` with defaults (mode: off) for any field not present.
166
+ Never raises.
167
+ """
168
+ try:
169
+ manifest = load_manifest(root)
170
+ except Exception:
171
+ return BranchPolicy()
172
+
173
+ raw = manifest.get("branch_policy")
174
+ if not isinstance(raw, dict):
175
+ return BranchPolicy()
176
+
177
+ def _str(key: str, default: str = "") -> str:
178
+ val = raw.get(key, default)
179
+ return str(val).strip() if val is not None else default
180
+
181
+ def _bool_val(key: str) -> bool:
182
+ val = raw.get(key, False)
183
+ return val if isinstance(val, bool) else False
184
+
185
+ def _int_val(key: str) -> int:
186
+ val = raw.get(key, 0)
187
+ try:
188
+ return int(val)
189
+ except (TypeError, ValueError):
190
+ return 0
191
+
192
+ mode = _str("mode", "off")
193
+ if mode not in {"phase", "task", "off"}:
194
+ mode = "off"
195
+
196
+ return BranchPolicy(
197
+ mode=mode,
198
+ pattern=_str("pattern"),
199
+ enforce=_bool_val("enforce"),
200
+ enforce_after_days=_int_val("enforce_after_days"),
201
+ message=_str("message"),
202
+ )
203
+
204
+
101
205
  def load_completion_policy(root: Path) -> CompletionPolicy:
102
206
  try:
103
207
  manifest = load_manifest(root)