zikaron 0.3.1__tar.gz → 0.3.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 (395) hide show
  1. {zikaron-0.3.1 → zikaron-0.3.2}/PKG-INFO +58 -32
  2. {zikaron-0.3.1 → zikaron-0.3.2}/README.md +57 -31
  3. {zikaron-0.3.1 → zikaron-0.3.2}/pyproject.toml +7 -9
  4. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_guard_claude_live.py +65 -12
  5. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_guard_main.py +54 -13
  6. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_guard_malformed.py +5 -3
  7. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_guard_nudge.py +2 -2
  8. zikaron-0.3.2/tests/test_guard_properties.py +104 -0
  9. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_guard_rule_table.py +6 -4
  10. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_guard_script_file.py +1 -1
  11. zikaron-0.3.2/tests/test_guard_selfmatch.py +327 -0
  12. zikaron-0.3.2/tests/test_guard_selfmatch_premise.py +99 -0
  13. zikaron-0.3.2/tests/test_guard_selfmatch_table.py +90 -0
  14. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_guard_texts.py +36 -14
  15. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_harness_table.py +6 -6
  16. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_components.py +1 -1
  17. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_connect.py +76 -17
  18. zikaron-0.3.2/tests/test_hook_connect_edge_cases.py +273 -0
  19. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_connect_integration.py +77 -25
  20. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_connect_race.py +59 -47
  21. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_connect_real_service_integration.py +71 -46
  22. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_failure.py +13 -0
  23. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_push.py +261 -43
  24. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_rpc.py +120 -10
  25. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_stdlib_only.py +1 -1
  26. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_indexing_acquisition.py +4 -4
  27. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_install_components.py +24 -7
  28. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_install_limits.py +20 -3
  29. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_project_scope.py +18 -1
  30. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_dispatch.py +35 -3
  31. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_encoder_failure_stop.py +20 -0
  32. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_lifecycle.py +144 -2
  33. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_lifecycle_integration.py +16 -1
  34. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_main.py +214 -3
  35. zikaron-0.3.2/tests/test_service_ownership.py +123 -0
  36. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_server.py +25 -5
  37. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/indexing/acquisition.py +3 -5
  38. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/indexing/encoder.py +5 -0
  39. zikaron-0.3.2/zikaron/guard/__init__.py +1 -0
  40. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/chars.py +1 -1
  41. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/decision.py +34 -29
  42. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/expression.py +1 -1
  43. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/forms.py +1 -1
  44. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/grammar.py +1 -1
  45. zikaron-0.3.2/zikaron/guard/grep_filter.py +190 -0
  46. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/heredoc.py +9 -2
  47. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/inplace.py +1 -1
  48. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/interpreter.py +1 -1
  49. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/lexer.py +1 -1
  50. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/limits.py +1 -1
  51. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/literal_text.py +1 -1
  52. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/main.py +25 -16
  53. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/messages.py +55 -10
  54. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/nudge.py +1 -1
  55. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/override.py +1 -1
  56. zikaron-0.3.2/zikaron/guard/patterns.py +47 -0
  57. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/position.py +5 -5
  58. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/programs.py +1 -1
  59. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/quoting.py +1 -1
  60. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/redirects.py +19 -2
  61. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/scratch.py +1 -1
  62. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/script_file.py +2 -2
  63. zikaron-0.3.2/zikaron/guard/selfmatch.py +278 -0
  64. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/start_text.py +1 -1
  65. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/guard/writes.py +1 -1
  66. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/harness/spec.py +11 -10
  67. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/components.py +2 -2
  68. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/connect.py +248 -128
  69. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/failure.py +30 -22
  70. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/limits.py +4 -4
  71. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/main.py +1 -1
  72. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/push.py +94 -67
  73. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/rpc.py +55 -4
  74. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/warm_helper.py +2 -1
  75. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/install/entries.py +3 -3
  76. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/install/main.py +8 -8
  77. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/install/targets.py +1 -1
  78. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/install/writer.py +1 -1
  79. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/knowledge/client.py +2 -1
  80. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/mcp/connection.py +5 -4
  81. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/mcp/errors.py +4 -4
  82. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/project/initialize.py +20 -14
  83. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/asyncio_compat.py +3 -3
  84. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/context.py +8 -0
  85. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/dispatch.py +13 -4
  86. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/lifecycle.py +104 -56
  87. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/log.py +17 -3
  88. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/main.py +87 -49
  89. zikaron-0.3.2/zikaron/service/ownership.py +109 -0
  90. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/paths.py +7 -1
  91. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/server.py +30 -14
  92. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron.egg-info/PKG-INFO +58 -32
  93. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron.egg-info/SOURCES.txt +8 -0
  94. zikaron-0.3.1/tests/test_guard_properties.py +0 -78
  95. zikaron-0.3.1/tests/test_hook_connect_edge_cases.py +0 -104
  96. zikaron-0.3.1/zikaron/guard/__init__.py +0 -1
  97. {zikaron-0.3.1 → zikaron-0.3.2}/LICENSE +0 -0
  98. {zikaron-0.3.1 → zikaron-0.3.2}/setup.cfg +0 -0
  99. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_access_log.py +0 -0
  100. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_agent_scan.py +0 -0
  101. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_asyncio_compat.py +0 -0
  102. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_background_encoder.py +0 -0
  103. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_check_gate.py +0 -0
  104. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_ci_workflow.py +0 -0
  105. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_cli_front_door.py +0 -0
  106. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_clock.py +0 -0
  107. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_config_keys.py +0 -0
  108. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_config_resolution.py +0 -0
  109. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_consolidation_grouping.py +0 -0
  110. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_consolidation_invariants.py +0 -0
  111. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_consolidation_observability.py +0 -0
  112. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_consolidation_planning.py +0 -0
  113. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_consolidation_refusals.py +0 -0
  114. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_consolidation_serving.py +0 -0
  115. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_consolidation_snapshot_planning.py +0 -0
  116. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_consolidation_verbs.py +0 -0
  117. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_ddl.py +0 -0
  118. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_definition_of_done_sites.py +0 -0
  119. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_design_pointers_resolve.py +0 -0
  120. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_design_tables.py +0 -0
  121. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_distribution.py +0 -0
  122. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_doctor.py +0 -0
  123. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_embedder.py +0 -0
  124. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_error_codes.py +0 -0
  125. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_event_kinds.py +0 -0
  126. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_guard_docstring_examples.py +0 -0
  127. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_harness_detect.py +0 -0
  128. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_harness_store_scope.py +0 -0
  129. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_harness_tier_guard.py +0 -0
  130. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_envelope.py +0 -0
  131. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_main.py +0 -0
  132. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_spawn_warm.py +0 -0
  133. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_subagent_policy.py +0 -0
  134. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_tripwire.py +0 -0
  135. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_warm_helper.py +0 -0
  136. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_warm_helper_integration.py +0 -0
  137. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_hook_write_policy.py +0 -0
  138. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_indexing_chunking.py +0 -0
  139. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_indexing_encoder.py +0 -0
  140. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_indexing_integration.py +0 -0
  141. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_indexing_model_cache.py +0 -0
  142. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_indexing_writes.py +0 -0
  143. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_injected_prose_log.py +0 -0
  144. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_install_assets.py +0 -0
  145. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_install_claude_live.py +0 -0
  146. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_install_e2e.py +0 -0
  147. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_install_harness.py +0 -0
  148. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_install_main.py +0 -0
  149. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_install_takeover.py +0 -0
  150. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_install_targets.py +0 -0
  151. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_install_writer.py +0 -0
  152. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_build_invariants.py +0 -0
  153. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_build_log.py +0 -0
  154. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_build_row_ordering.py +0 -0
  155. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_builds.py +0 -0
  156. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_chunking.py +0 -0
  157. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_cli.py +0 -0
  158. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_cli_integration.py +0 -0
  159. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_counters.py +0 -0
  160. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_database.py +0 -0
  161. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_ddl.py +0 -0
  162. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_detach.py +0 -0
  163. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_files.py +0 -0
  164. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_git.py +0 -0
  165. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_groups.py +0 -0
  166. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_indexer.py +0 -0
  167. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_integration.py +0 -0
  168. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_invariants.py +0 -0
  169. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_lifecycle.py +0 -0
  170. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_lock.py +0 -0
  171. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_lock_race.py +0 -0
  172. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_meta.py +0 -0
  173. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_registry.py +0 -0
  174. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_repair.py +0 -0
  175. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_reporting.py +0 -0
  176. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_roots.py +0 -0
  177. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_scan.py +0 -0
  178. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_scan_git.py +0 -0
  179. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_search.py +0 -0
  180. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_state.py +0 -0
  181. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_text.py +0 -0
  182. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_vectors.py +0 -0
  183. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_walk.py +0 -0
  184. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_knowledge_writes.py +0 -0
  185. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_markdown_renders_as_written.py +0 -0
  186. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_mcp_connection_ambiguous_failure.py +0 -0
  187. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_mcp_connection_cancellation.py +0 -0
  188. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_mcp_connection_concurrency.py +0 -0
  189. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_mcp_connection_integration.py +0 -0
  190. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_mcp_connection_labels.py +0 -0
  191. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_mcp_consolidator_bridge.py +0 -0
  192. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_mcp_errors.py +0 -0
  193. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_mcp_main.py +0 -0
  194. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_mcp_server.py +0 -0
  195. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_mcp_spill.py +0 -0
  196. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_mcp_tool_descriptions.py +0 -0
  197. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_mcp_wire_contracts.py +0 -0
  198. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_meta.py +0 -0
  199. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_permissions.py +0 -0
  200. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_publication_hygiene.py +0 -0
  201. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_quoted_design_prose_is_verbatim.py +0 -0
  202. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_readme_config_table.py +0 -0
  203. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_readme_internal_links.py +0 -0
  204. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_records_memory.py +0 -0
  205. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_records_receipts.py +0 -0
  206. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_records_supersession.py +0 -0
  207. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_retrieval_arms.py +0 -0
  208. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_retrieval_eligibility.py +0 -0
  209. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_retrieval_integration.py +0 -0
  210. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_retrieval_query.py +0 -0
  211. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_retrieval_ranking.py +0 -0
  212. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_retrieval_reads.py +0 -0
  213. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_context.py +0 -0
  214. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_context_assemble.py +0 -0
  215. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_diagnostics.py +0 -0
  216. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_diagnostics_integration.py +0 -0
  217. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_dispatch_consolidation.py +0 -0
  218. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_dispatch_knowledge.py +0 -0
  219. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_envelope.py +0 -0
  220. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_knowledge_management.py +0 -0
  221. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_log.py +0 -0
  222. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_params.py +0 -0
  223. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_paths.py +0 -0
  224. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_read_contention.py +0 -0
  225. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_rpc.py +0 -0
  226. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_security.py +0 -0
  227. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_surface_deadline.py +0 -0
  228. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_write_contention.py +0 -0
  229. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_service_writer.py +0 -0
  230. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_signals_contention.py +0 -0
  231. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_signals_dedup.py +0 -0
  232. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_signals_horizon.py +0 -0
  233. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_signals_repair.py +0 -0
  234. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_signals_retirement.py +0 -0
  235. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_signals_sessions.py +0 -0
  236. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_signals_writes.py +0 -0
  237. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_socket_path_budget.py +0 -0
  238. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_store.py +0 -0
  239. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_store_connection.py +0 -0
  240. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_store_migration.py +0 -0
  241. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_store_pool.py +0 -0
  242. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_transaction_begin_sites.py +0 -0
  243. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_version_seam.py +0 -0
  244. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_write_dedup.py +0 -0
  245. {zikaron-0.3.1 → zikaron-0.3.2}/tests/test_write_tools.py +0 -0
  246. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/__init__.py +0 -0
  247. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/cli/__init__.py +0 -0
  248. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/cli/main.py +0 -0
  249. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/__init__.py +0 -0
  250. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/clock.py +0 -0
  251. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/config/__init__.py +0 -0
  252. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/config/keys.py +0 -0
  253. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/config/resolution.py +0 -0
  254. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/consolidation/__init__.py +0 -0
  255. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/consolidation/authorization.py +0 -0
  256. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/consolidation/candidates.py +0 -0
  257. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/consolidation/context.py +0 -0
  258. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/consolidation/grouping.py +0 -0
  259. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/consolidation/groups.py +0 -0
  260. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/consolidation/payload.py +0 -0
  261. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/consolidation/planning.py +0 -0
  262. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/consolidation/rowstate.py +0 -0
  263. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/consolidation/runs.py +0 -0
  264. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/consolidation/serving.py +0 -0
  265. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/consolidation/verbs.py +0 -0
  266. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/errors.py +0 -0
  267. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/events.py +0 -0
  268. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/indexing/__init__.py +0 -0
  269. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/indexing/chunking.py +0 -0
  270. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/indexing/lexical.py +0 -0
  271. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/indexing/model_cache.py +0 -0
  272. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/indexing/model_pin.py +0 -0
  273. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/indexing/vectors.py +0 -0
  274. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/indexing/writes.py +0 -0
  275. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/__init__.py +0 -0
  276. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/arms.py +0 -0
  277. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/builds.py +0 -0
  278. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/candidates.py +0 -0
  279. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/changes.py +0 -0
  280. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/chunking.py +0 -0
  281. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/counters.py +0 -0
  282. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/database.py +0 -0
  283. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/ddl.py +0 -0
  284. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/disposal.py +0 -0
  285. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/errors.py +0 -0
  286. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/files.py +0 -0
  287. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/git.py +0 -0
  288. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/groups.py +0 -0
  289. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/lexical.py +0 -0
  290. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/lifecycle.py +0 -0
  291. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/lock.py +0 -0
  292. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/meta.py +0 -0
  293. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/paths.py +0 -0
  294. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/pending.py +0 -0
  295. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/registry.py +0 -0
  296. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/repair.py +0 -0
  297. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/reporting.py +0 -0
  298. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/roots.py +0 -0
  299. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/scan.py +0 -0
  300. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/search.py +0 -0
  301. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/state.py +0 -0
  302. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/text.py +0 -0
  303. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/vectors.py +0 -0
  304. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/walk.py +0 -0
  305. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/knowledge/writes.py +0 -0
  306. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/records/__init__.py +0 -0
  307. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/records/memory.py +0 -0
  308. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/records/receipts.py +0 -0
  309. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/records/supersession.py +0 -0
  310. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/retrieval/__init__.py +0 -0
  311. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/retrieval/arms.py +0 -0
  312. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/retrieval/block.py +0 -0
  313. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/retrieval/eligibility.py +0 -0
  314. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/retrieval/query.py +0 -0
  315. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/retrieval/ranking.py +0 -0
  316. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/retrieval/reads.py +0 -0
  317. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/retrieval/retrieve.py +0 -0
  318. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/retrieval/similarity.py +0 -0
  319. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/signals/__init__.py +0 -0
  320. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/signals/contention.py +0 -0
  321. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/signals/dedup.py +0 -0
  322. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/signals/horizon.py +0 -0
  323. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/signals/repair.py +0 -0
  324. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/signals/retirement.py +0 -0
  325. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/signals/sessions.py +0 -0
  326. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/signals/writes.py +0 -0
  327. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/store/__init__.py +0 -0
  328. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/store/connection.py +0 -0
  329. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/store/ddl.py +0 -0
  330. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/store/deadline.py +0 -0
  331. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/store/embedder.py +0 -0
  332. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/store/holders.py +0 -0
  333. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/store/meta.py +0 -0
  334. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/store/migration.py +0 -0
  335. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/store/permissions.py +0 -0
  336. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/store/pool.py +0 -0
  337. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/store/store.py +0 -0
  338. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/store/transactions.py +0 -0
  339. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/write/__init__.py +0 -0
  340. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/write/dedup.py +0 -0
  341. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/core/write/tools.py +0 -0
  342. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/doctor/__init__.py +0 -0
  343. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/doctor/checks.py +0 -0
  344. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/doctor/main.py +0 -0
  345. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/harness/__init__.py +0 -0
  346. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/harness/detect.py +0 -0
  347. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/__init__.py +0 -0
  348. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/envelope.py +0 -0
  349. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/spawn_warm.py +0 -0
  350. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/subagent_policy.py +0 -0
  351. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/tripwire.py +0 -0
  352. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/hook/write_policy.py +0 -0
  353. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/install/__init__.py +0 -0
  354. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/install/__main__.py +0 -0
  355. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/install/agent_scan.py +0 -0
  356. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/install/assets.py +0 -0
  357. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/install/harness.py +0 -0
  358. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/install/ownership.py +0 -0
  359. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/knowledge/__init__.py +0 -0
  360. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/knowledge/__main__.py +0 -0
  361. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/knowledge/indexer/__init__.py +0 -0
  362. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/knowledge/indexer/__main__.py +0 -0
  363. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/knowledge/indexer/build_log.py +0 -0
  364. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/knowledge/indexer/detach.py +0 -0
  365. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/knowledge/indexer/main.py +0 -0
  366. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/knowledge/main.py +0 -0
  367. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/knowledge/scope.py +0 -0
  368. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/mcp/__init__.py +0 -0
  369. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/mcp/consolidator.py +0 -0
  370. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/mcp/main.py +0 -0
  371. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/mcp/primary.py +0 -0
  372. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/mcp/server.py +0 -0
  373. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/mcp/spill.py +0 -0
  374. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/mcp/tool_names.py +0 -0
  375. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/project/__init__.py +0 -0
  376. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/project/__main__.py +0 -0
  377. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/project/report.py +0 -0
  378. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/project/resolve.py +0 -0
  379. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/py.typed +0 -0
  380. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/__init__.py +0 -0
  381. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/access_log.py +0 -0
  382. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/diagnostics.py +0 -0
  383. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/dispatch_consolidation.py +0 -0
  384. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/dispatch_knowledge.py +0 -0
  385. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/envelope.py +0 -0
  386. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/methods.py +0 -0
  387. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/params.py +0 -0
  388. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/rpc.py +0 -0
  389. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/security.py +0 -0
  390. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/serialize.py +0 -0
  391. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron/service/serialize_knowledge.py +0 -0
  392. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron.egg-info/dependency_links.txt +0 -0
  393. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron.egg-info/entry_points.txt +0 -0
  394. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron.egg-info/requires.txt +0 -0
  395. {zikaron-0.3.1 → zikaron-0.3.2}/zikaron.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zikaron
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: Memory and searchable project knowledge for coding agents
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/nathan-shapiro/Zikaron
@@ -61,11 +61,12 @@ yes, it is out of scope. That store is for what cost somebody time to discover,
61
61
  be discovered again by the next agent, at full price. A knowledge base has no such test — it is
62
62
  whatever corpus you point it at.
63
63
 
64
- **And, on request, two edit guards for Claude Code** — independent of both stores. One refuses a
65
- find-replace edit to an authored file (`sed -i`, an inline script, a heredoc into the file) and
66
- points the agent at `Read` and `Edit`; the other reminds it, after each edit, to re-read what it
67
- changed. See [Edit guards](#edit-guards-claude-code-on-request); a project may install the memory
68
- store, the guards, or both.
64
+ **And, on request, guards for Claude Code** — two deterministic hooks, independent of both stores.
65
+ One refuses two kinds of command: a find-replace edit to an authored file (`sed -i`, an inline
66
+ script, a heredoc into the file), pointing the agent at `Read` and `Edit`, and a `pgrep -f` or
67
+ `pkill -f` whose pattern matches the shell running it. The other reminds the agent, after each
68
+ edit, to re-read what it changed. See [Guards](#guards-claude-code-on-request); a project may install the memory store, the
69
+ guards, or both.
69
70
 
70
71
  It runs entirely on your machine: SQLite databases under `.zikaron/`, a local embedding model, and a
71
72
  small background service on a Unix socket. **Zikaron reaches the network for exactly one thing** —
@@ -130,7 +131,7 @@ reads which one it is addressing before it reads a description. Consolidation ne
130
131
  | **service** | A long-running process per project. Holds the embedding model in memory and the databases open, and answers requests over a Unix socket. Starts itself when needed and stops itself when idle. |
131
132
  | **MCP server** | Translates the agent's tool calls into requests to the service. One process per agent instance; loads no model. |
132
133
  | **hook** | A single-shot executable your agent runs on start, before each message, and — under Claude Code — when it spawns a subagent. Deliberately tiny; loads no model and never touches the databases directly. |
133
- | **guard** | Claude Code only, installed on request: a single-shot executable the harness runs before each Bash call and after each edit. Regular expressions over the call, plus one bounded read of a script the call runs from a scratch directory — no model, no service, no store. |
134
+ | **guard** | Claude Code only, installed on request: a single-shot executable the harness runs before each `Bash` or `Monitor` call and after each edit. Regular expressions over the call, plus one bounded read of a script the call runs from a scratch directory — no model, no service, no store. |
134
135
  | **indexer** | A detached process started per knowledge-base build — by the service on every `add`/`refresh`, whether an agent asked or you did, or by you running the foreground command a build result prints. It outlives the call that started it, loads a model, saturates a core for a minute or more, and exits when the build finishes. If you see one in `ps`, that is a corpus building, not a runaway. |
135
136
 
136
137
  The service exists for one measured reason: loading the embedding model costs about **780 ms**, and
@@ -242,7 +243,7 @@ cd /path/to/your/project
242
243
  zikaron install --project . --harness claude-code # or: --harness kiro
243
244
  ```
244
245
 
245
- Under Claude Code, `--components` adds the [edit guards](#edit-guards-claude-code-on-request), or
246
+ Under Claude Code, `--components` adds the [guards](#guards-claude-code-on-request), or
246
247
  installs them alone; without it you get the memory store only, exactly as before:
247
248
 
248
249
  ```bash
@@ -353,8 +354,8 @@ and under **Claude Code**:
353
354
 
354
355
  With `--components guards` the install writes `.claude/settings.local.json` alone, and in it only
355
356
  hooks: the session-start and per-subagent hooks, which carry a short note about the guards, and the
356
- two guard hooks — before each Bash call, after each edit. No server, no approval key, no
357
- consolidator. With `--components both` you get all of the above together, and the start hooks carry
357
+ two guard hooks — before each `Bash` or `Monitor` call, after each edit. No server, no approval
358
+ key, no consolidator. With `--components both` you get all of the above together, and the start hooks carry
358
359
  the write policy and the guards' note.
359
360
 
360
361
  **`settings.local.json`, not `settings.json`**, and it matters if you commit your settings: the hook
@@ -474,10 +475,10 @@ guard, the receipts and the lease are untouched — but an unauthorized consolid
474
475
  tokens and could write a poorly-judged long-term record. `permissions.deny` is **not** the fix: it is
475
476
  global and unregisters the tool, after which the consolidator itself refuses to start.
476
477
 
477
- ### Edit guards (Claude Code, on request)
478
+ ### Guards (Claude Code, on request)
478
479
 
479
- `--components guards` (or `both`) installs two deterministic hooks that hold an agent to two rules,
480
- with no model and no store behind them (`design/edit-guards.md`):
480
+ `--components guards` (or `both`) installs two deterministic hooks that hold an agent to three
481
+ rules, with no model and no store behind them (`design/guards.md`):
481
482
 
482
483
  - **A find-replace edit to an authored file is refused** — `sed -i`, `perl -pi`, an inline Python
483
484
  or node script that writes a file, a heredoc or `echo` redirected into one, and a script under
@@ -489,6 +490,15 @@ with no model and no store behind them (`design/edit-guards.md`):
489
490
  re-read of the edited material once that file's editing is done. A Bash command gets no such
490
491
  reminder, so when the agent overrides a refusal, the guard's acknowledgement names what the
491
492
  command changes and asks for that re-read instead.
493
+ - **A `pgrep -f` or `pkill -f` whose pattern matches its own command is refused.** Claude Code
494
+ runs each command inside a shell whose command line carries the command's text, so on Linux such
495
+ a pattern matches that shell: `pkill` kills it, and `pgrep` always finds it, so a check for a
496
+ process that has exited never sees it gone. The refusal shows where the pattern matched and gives
497
+ the fix: `-A`, where `pgrep` has it, or a bracketed character (`[m]onth_monitor.py`). On macOS,
498
+ whose `pgrep` already leaves out the shell, only `-a` brings it back.
499
+
500
+ Both refusals judge `Bash` and `Monitor` commands alike. An install made by an earlier version
501
+ judges `Bash` alone; re-running it with the same `--components` adds `Monitor`.
492
502
 
493
503
  They are not a security boundary: a script the guard reads is one run from a scratch directory,
494
504
  and a script anywhere else — one of the project's own programs — is never read, by design. A guard
@@ -518,7 +528,7 @@ usually shows something else: told the rule when its session starts, it reaches
518
528
  | `--model <id>` | the consolidator's model (default: `claude-sonnet-5` under kiro, `sonnet` under Claude Code) |
519
529
  | `--format {object,array}` | **kiro only.** Which hook format to write when the target config has none yet |
520
530
  | `--no-trust-tools` | do not pre-approve Zikaron's own tools, so every Zikaron tool call asks permission |
521
- | `--components {memory,guards,both}` | what to install: the memory store (the default), the edit guards below, or both. **Claude Code only** for `guards` and `both`; `--model` is refused with `guards`, which ships no consolidator |
531
+ | `--components {memory,guards,both}` | what to install: the memory store (the default), the guards below, or both. **Claude Code only** for `guards` and `both`; `--model` is refused with `guards`, which ships no consolidator |
522
532
  | `--force` | replace a symlink at a shipped path, and overwrite entries wired to a different Zikaron install that would otherwise be refused. It also stops merging: a server entry — `.mcp.json`'s, or kiro's `mcpServers` — is replaced **whole**, so a key you added to Zikaron's own entry goes, and under Claude Code a Zikaron hook group is replaced whole, so a hook of your own inside it goes too. Both are named in the output |
523
533
 
524
534
  Both hook formats kiro accepts are supported, and a config that already uses one keeps it: kiro
@@ -565,7 +575,7 @@ write policy goes into the model's context, not to your terminal. Then, from the
565
575
  # a service should be running for this project after your first message
566
576
  pgrep -af zikaron.service.main
567
577
 
568
- # one line per hook failure, write-policy-override note, or session/environment mismatch; absent means none happened
578
+ # one line per hook failure, missed cold start, write-policy-override note, or session/environment mismatch; absent means none happened
569
579
  cat .zikaron/hook.log
570
580
  ```
571
581
 
@@ -756,9 +766,11 @@ it is `0600` or `0700`. The **installer** also writes harness config — the fil
756
766
  config.toml your per-project overrides, if you wrote any
757
767
  service.log the background service: startup, resolved config, errors, why it stopped,
758
768
  any request running longer than 30 s, and the stack dumps below
759
- hook.log one line per hook failure, write-policy-override note, or session/environment
760
- mismatch. Absent means none happened. Not every line is a failure: an override
761
- that is used but exceeds the injection budget is printed anyway and logged
769
+ hook.log one line per hook failure, missed cold start, write-policy-override note, or
770
+ session/environment mismatch. Absent means none happened. Not every line is a
771
+ failure: `starting` is a message that arrived while the service was still
772
+ starting, and an override that is used but exceeds the injection budget is
773
+ printed anyway and logged
762
774
  warmup.log the small helper that warms the service when a session starts
763
775
  write-policy.md your policy override, if you wrote one
764
776
  ```
@@ -771,19 +783,23 @@ shared by every project you use Zikaron in, under `$XDG_CACHE_HOME/zikaron/model
771
783
  A copy inside each project would duplicate it for bytes that are identical by construction, since the
772
784
  version fetched is pinned. Removing a project does not remove it; [Uninstall](#uninstall) says how.
773
785
 
774
- The second is the service's Unix socket, which with its lock file sits in
775
- `$XDG_RUNTIME_DIR/zikaron/` — or `/tmp/zikaron-<uid>/` where that variable is unset, which is every
776
- Mac — named by a hash of the store's path, `0600` inside a `0700` directory. A socket belongs on a
777
- runtime filesystem rather than in your project. **Under Claude
778
- Code**, an over-large consolidator result also spills to a file beside them, carrying that group's
779
- record prose verbatim and named by the same store hash; it is deleted when the consolidator asks for
780
- its next group — or, if that process is killed first, by the next one that starts. It is the one
781
- copy of memory text that lives outside `.zikaron/`, which is why the erasure procedure under
782
- [Secrets](#secrets) removes it by hand. Nothing spills under kiro.
786
+ The second is the service's Unix socket. It sits in `$XDG_RUNTIME_DIR/zikaron/` — or
787
+ `/tmp/zikaron-<uid>/` where that variable is unset, which is every Mac — named by a hash of the
788
+ store's path, `0600` inside a `0700` directory, beside two lock files: one clients take while they
789
+ start the service, and one the service holds while it has the store open. A socket belongs on a
790
+ runtime filesystem rather than in your project. **Under Claude Code**, an over-large consolidator
791
+ result also spills to a file beside them, carrying that group's record prose verbatim and named by
792
+ the same store hash; it is deleted when the consolidator asks for its next group — or, if that
793
+ process is killed first, by the next one that starts. It is the one copy of memory text that lives
794
+ outside `.zikaron/`, which is why the erasure procedure under [Secrets](#secrets) removes it by hand.
795
+ Nothing spills under kiro.
783
796
 
784
797
  **What `service.log` tells you about a service that stopped, or stopped answering.** A clean stop
785
- writes one `stopping: reason=…` line: `idle`, `store_replaced`, `encoder_failed`, or `sigterm` /
786
- `sigint` when it was asked to stop. A request still running after the 30 s idle poll is logged as
798
+ writes one `stopping: reason=…` line: `idle`, `store_replaced`, `socket_lost` (its socket file was
799
+ removed, so nothing could reach it), `encoder_failed`, or `sigterm` / `sigint` when it was asked to
800
+ stop. A start that found another service already holding the store writes `not starting:
801
+ reason=another_service` and exits, leaving that one to serve it. A request still running after the
802
+ 30 s idle poll is logged as
787
803
  `long request: method=… session=… age=…` on every poll until it ends — `session=unresolved` if it
788
804
  never got that far. Two signals write a dump without stopping the service: `kill -USR2 <pid>` writes
789
805
  the requests in flight and every asyncio task's stack, and `kill -USR1 <pid>` writes every thread's
@@ -792,8 +808,8 @@ raw text, without the timestamp and `pid=` every other line carries.
792
808
 
793
809
  Two notes on reading the rest. `memory.db` can look implausibly small while `memory.db-wal` is large —
794
810
  that is normal for a database held open by the service, since recent writes live in the log until a
795
- checkpoint; the files together are the store. And `hook.log` records only a fixed failure label and an
796
- error code, never your prompt or a memory's text, so it cannot hold a leaked secret.
811
+ checkpoint; the files together are the store. And `hook.log` records only fixed labels and an error
812
+ code, never your prompt or a memory's text, so it cannot hold a leaked secret.
797
813
 
798
814
  There is one more log that is not a file: an event table inside `memory.db`. It records what happened
799
815
  on every **memory** read and write — used to measure whether the write policy is working, and kept in
@@ -813,6 +829,16 @@ Zikaron is built to fail quietly rather than get in your way. A hook that cannot
813
829
  prints a short note asking the agent to tell you, writes one line to `hook.log`, and exits cleanly. It
814
830
  never blocks your message, and it never reads the store directly.
815
831
 
832
+ The service stops itself after a stretch of idleness, and the next message starts it again. That
833
+ message waits a few seconds longer — the hook allows a start more time than a running service — and
834
+ if the start still is not finished, the message goes without memories and the agent is told so, without
835
+ being asked to report it. `hook.log` records that as `starting`, followed by what the hook was still
836
+ waiting on — `lock` or `poll` before the service answered, or the lateness of its answer after — and
837
+ memories return once it has started, usually with the next message. A run of `starting` lines means
838
+ starts are slower than the hook allows, not that the service is broken; a start that never finishes is
839
+ reported as `transport` once it has gone a minute without a sign of life — which a first run still
840
+ fetching its model over a slow link can also do, until it finishes.
841
+
816
842
  **Run `zikaron doctor` first for anything that smells environmental** — no search results at all, a
817
843
  service that will not start, an MCP server that dies on contact. It checks the things about this
818
844
  machine that can stop Zikaron working and names what to change for each. The table below is for
@@ -921,7 +947,7 @@ than deleted, because both hold settings that are not Zikaron's. **All three set
921
947
  the install writes three** — leaving `enabledMcpjsonServers` behind names two servers that no longer
922
948
  exist, which loads nothing and breaks nothing but is not an uninstall.
923
949
 
924
- **The edit guards** live only in `.claude/settings.local.json`: remove the `PreToolUse` and
950
+ **The guards** live only in `.claude/settings.local.json`: remove the `PreToolUse` and
925
951
  `PostToolUse` hook groups whose command is `zikaron-guard`, and the `SessionStart` and
926
952
  `SubagentStart` groups whose command is `zikaron-hook`. To keep the memory store and drop only the
927
953
  guards, re-running the installer will not do it — an install never removes a selection — so delete
@@ -32,11 +32,12 @@ yes, it is out of scope. That store is for what cost somebody time to discover,
32
32
  be discovered again by the next agent, at full price. A knowledge base has no such test — it is
33
33
  whatever corpus you point it at.
34
34
 
35
- **And, on request, two edit guards for Claude Code** — independent of both stores. One refuses a
36
- find-replace edit to an authored file (`sed -i`, an inline script, a heredoc into the file) and
37
- points the agent at `Read` and `Edit`; the other reminds it, after each edit, to re-read what it
38
- changed. See [Edit guards](#edit-guards-claude-code-on-request); a project may install the memory
39
- store, the guards, or both.
35
+ **And, on request, guards for Claude Code** — two deterministic hooks, independent of both stores.
36
+ One refuses two kinds of command: a find-replace edit to an authored file (`sed -i`, an inline
37
+ script, a heredoc into the file), pointing the agent at `Read` and `Edit`, and a `pgrep -f` or
38
+ `pkill -f` whose pattern matches the shell running it. The other reminds the agent, after each
39
+ edit, to re-read what it changed. See [Guards](#guards-claude-code-on-request); a project may install the memory store, the
40
+ guards, or both.
40
41
 
41
42
  It runs entirely on your machine: SQLite databases under `.zikaron/`, a local embedding model, and a
42
43
  small background service on a Unix socket. **Zikaron reaches the network for exactly one thing** —
@@ -101,7 +102,7 @@ reads which one it is addressing before it reads a description. Consolidation ne
101
102
  | **service** | A long-running process per project. Holds the embedding model in memory and the databases open, and answers requests over a Unix socket. Starts itself when needed and stops itself when idle. |
102
103
  | **MCP server** | Translates the agent's tool calls into requests to the service. One process per agent instance; loads no model. |
103
104
  | **hook** | A single-shot executable your agent runs on start, before each message, and — under Claude Code — when it spawns a subagent. Deliberately tiny; loads no model and never touches the databases directly. |
104
- | **guard** | Claude Code only, installed on request: a single-shot executable the harness runs before each Bash call and after each edit. Regular expressions over the call, plus one bounded read of a script the call runs from a scratch directory — no model, no service, no store. |
105
+ | **guard** | Claude Code only, installed on request: a single-shot executable the harness runs before each `Bash` or `Monitor` call and after each edit. Regular expressions over the call, plus one bounded read of a script the call runs from a scratch directory — no model, no service, no store. |
105
106
  | **indexer** | A detached process started per knowledge-base build — by the service on every `add`/`refresh`, whether an agent asked or you did, or by you running the foreground command a build result prints. It outlives the call that started it, loads a model, saturates a core for a minute or more, and exits when the build finishes. If you see one in `ps`, that is a corpus building, not a runaway. |
106
107
 
107
108
  The service exists for one measured reason: loading the embedding model costs about **780 ms**, and
@@ -213,7 +214,7 @@ cd /path/to/your/project
213
214
  zikaron install --project . --harness claude-code # or: --harness kiro
214
215
  ```
215
216
 
216
- Under Claude Code, `--components` adds the [edit guards](#edit-guards-claude-code-on-request), or
217
+ Under Claude Code, `--components` adds the [guards](#guards-claude-code-on-request), or
217
218
  installs them alone; without it you get the memory store only, exactly as before:
218
219
 
219
220
  ```bash
@@ -324,8 +325,8 @@ and under **Claude Code**:
324
325
 
325
326
  With `--components guards` the install writes `.claude/settings.local.json` alone, and in it only
326
327
  hooks: the session-start and per-subagent hooks, which carry a short note about the guards, and the
327
- two guard hooks — before each Bash call, after each edit. No server, no approval key, no
328
- consolidator. With `--components both` you get all of the above together, and the start hooks carry
328
+ two guard hooks — before each `Bash` or `Monitor` call, after each edit. No server, no approval
329
+ key, no consolidator. With `--components both` you get all of the above together, and the start hooks carry
329
330
  the write policy and the guards' note.
330
331
 
331
332
  **`settings.local.json`, not `settings.json`**, and it matters if you commit your settings: the hook
@@ -445,10 +446,10 @@ guard, the receipts and the lease are untouched — but an unauthorized consolid
445
446
  tokens and could write a poorly-judged long-term record. `permissions.deny` is **not** the fix: it is
446
447
  global and unregisters the tool, after which the consolidator itself refuses to start.
447
448
 
448
- ### Edit guards (Claude Code, on request)
449
+ ### Guards (Claude Code, on request)
449
450
 
450
- `--components guards` (or `both`) installs two deterministic hooks that hold an agent to two rules,
451
- with no model and no store behind them (`design/edit-guards.md`):
451
+ `--components guards` (or `both`) installs two deterministic hooks that hold an agent to three
452
+ rules, with no model and no store behind them (`design/guards.md`):
452
453
 
453
454
  - **A find-replace edit to an authored file is refused** — `sed -i`, `perl -pi`, an inline Python
454
455
  or node script that writes a file, a heredoc or `echo` redirected into one, and a script under
@@ -460,6 +461,15 @@ with no model and no store behind them (`design/edit-guards.md`):
460
461
  re-read of the edited material once that file's editing is done. A Bash command gets no such
461
462
  reminder, so when the agent overrides a refusal, the guard's acknowledgement names what the
462
463
  command changes and asks for that re-read instead.
464
+ - **A `pgrep -f` or `pkill -f` whose pattern matches its own command is refused.** Claude Code
465
+ runs each command inside a shell whose command line carries the command's text, so on Linux such
466
+ a pattern matches that shell: `pkill` kills it, and `pgrep` always finds it, so a check for a
467
+ process that has exited never sees it gone. The refusal shows where the pattern matched and gives
468
+ the fix: `-A`, where `pgrep` has it, or a bracketed character (`[m]onth_monitor.py`). On macOS,
469
+ whose `pgrep` already leaves out the shell, only `-a` brings it back.
470
+
471
+ Both refusals judge `Bash` and `Monitor` commands alike. An install made by an earlier version
472
+ judges `Bash` alone; re-running it with the same `--components` adds `Monitor`.
463
473
 
464
474
  They are not a security boundary: a script the guard reads is one run from a scratch directory,
465
475
  and a script anywhere else — one of the project's own programs — is never read, by design. A guard
@@ -489,7 +499,7 @@ usually shows something else: told the rule when its session starts, it reaches
489
499
  | `--model <id>` | the consolidator's model (default: `claude-sonnet-5` under kiro, `sonnet` under Claude Code) |
490
500
  | `--format {object,array}` | **kiro only.** Which hook format to write when the target config has none yet |
491
501
  | `--no-trust-tools` | do not pre-approve Zikaron's own tools, so every Zikaron tool call asks permission |
492
- | `--components {memory,guards,both}` | what to install: the memory store (the default), the edit guards below, or both. **Claude Code only** for `guards` and `both`; `--model` is refused with `guards`, which ships no consolidator |
502
+ | `--components {memory,guards,both}` | what to install: the memory store (the default), the guards below, or both. **Claude Code only** for `guards` and `both`; `--model` is refused with `guards`, which ships no consolidator |
493
503
  | `--force` | replace a symlink at a shipped path, and overwrite entries wired to a different Zikaron install that would otherwise be refused. It also stops merging: a server entry — `.mcp.json`'s, or kiro's `mcpServers` — is replaced **whole**, so a key you added to Zikaron's own entry goes, and under Claude Code a Zikaron hook group is replaced whole, so a hook of your own inside it goes too. Both are named in the output |
494
504
 
495
505
  Both hook formats kiro accepts are supported, and a config that already uses one keeps it: kiro
@@ -536,7 +546,7 @@ write policy goes into the model's context, not to your terminal. Then, from the
536
546
  # a service should be running for this project after your first message
537
547
  pgrep -af zikaron.service.main
538
548
 
539
- # one line per hook failure, write-policy-override note, or session/environment mismatch; absent means none happened
549
+ # one line per hook failure, missed cold start, write-policy-override note, or session/environment mismatch; absent means none happened
540
550
  cat .zikaron/hook.log
541
551
  ```
542
552
 
@@ -727,9 +737,11 @@ it is `0600` or `0700`. The **installer** also writes harness config — the fil
727
737
  config.toml your per-project overrides, if you wrote any
728
738
  service.log the background service: startup, resolved config, errors, why it stopped,
729
739
  any request running longer than 30 s, and the stack dumps below
730
- hook.log one line per hook failure, write-policy-override note, or session/environment
731
- mismatch. Absent means none happened. Not every line is a failure: an override
732
- that is used but exceeds the injection budget is printed anyway and logged
740
+ hook.log one line per hook failure, missed cold start, write-policy-override note, or
741
+ session/environment mismatch. Absent means none happened. Not every line is a
742
+ failure: `starting` is a message that arrived while the service was still
743
+ starting, and an override that is used but exceeds the injection budget is
744
+ printed anyway and logged
733
745
  warmup.log the small helper that warms the service when a session starts
734
746
  write-policy.md your policy override, if you wrote one
735
747
  ```
@@ -742,19 +754,23 @@ shared by every project you use Zikaron in, under `$XDG_CACHE_HOME/zikaron/model
742
754
  A copy inside each project would duplicate it for bytes that are identical by construction, since the
743
755
  version fetched is pinned. Removing a project does not remove it; [Uninstall](#uninstall) says how.
744
756
 
745
- The second is the service's Unix socket, which with its lock file sits in
746
- `$XDG_RUNTIME_DIR/zikaron/` — or `/tmp/zikaron-<uid>/` where that variable is unset, which is every
747
- Mac — named by a hash of the store's path, `0600` inside a `0700` directory. A socket belongs on a
748
- runtime filesystem rather than in your project. **Under Claude
749
- Code**, an over-large consolidator result also spills to a file beside them, carrying that group's
750
- record prose verbatim and named by the same store hash; it is deleted when the consolidator asks for
751
- its next group — or, if that process is killed first, by the next one that starts. It is the one
752
- copy of memory text that lives outside `.zikaron/`, which is why the erasure procedure under
753
- [Secrets](#secrets) removes it by hand. Nothing spills under kiro.
757
+ The second is the service's Unix socket. It sits in `$XDG_RUNTIME_DIR/zikaron/` — or
758
+ `/tmp/zikaron-<uid>/` where that variable is unset, which is every Mac — named by a hash of the
759
+ store's path, `0600` inside a `0700` directory, beside two lock files: one clients take while they
760
+ start the service, and one the service holds while it has the store open. A socket belongs on a
761
+ runtime filesystem rather than in your project. **Under Claude Code**, an over-large consolidator
762
+ result also spills to a file beside them, carrying that group's record prose verbatim and named by
763
+ the same store hash; it is deleted when the consolidator asks for its next group — or, if that
764
+ process is killed first, by the next one that starts. It is the one copy of memory text that lives
765
+ outside `.zikaron/`, which is why the erasure procedure under [Secrets](#secrets) removes it by hand.
766
+ Nothing spills under kiro.
754
767
 
755
768
  **What `service.log` tells you about a service that stopped, or stopped answering.** A clean stop
756
- writes one `stopping: reason=…` line: `idle`, `store_replaced`, `encoder_failed`, or `sigterm` /
757
- `sigint` when it was asked to stop. A request still running after the 30 s idle poll is logged as
769
+ writes one `stopping: reason=…` line: `idle`, `store_replaced`, `socket_lost` (its socket file was
770
+ removed, so nothing could reach it), `encoder_failed`, or `sigterm` / `sigint` when it was asked to
771
+ stop. A start that found another service already holding the store writes `not starting:
772
+ reason=another_service` and exits, leaving that one to serve it. A request still running after the
773
+ 30 s idle poll is logged as
758
774
  `long request: method=… session=… age=…` on every poll until it ends — `session=unresolved` if it
759
775
  never got that far. Two signals write a dump without stopping the service: `kill -USR2 <pid>` writes
760
776
  the requests in flight and every asyncio task's stack, and `kill -USR1 <pid>` writes every thread's
@@ -763,8 +779,8 @@ raw text, without the timestamp and `pid=` every other line carries.
763
779
 
764
780
  Two notes on reading the rest. `memory.db` can look implausibly small while `memory.db-wal` is large —
765
781
  that is normal for a database held open by the service, since recent writes live in the log until a
766
- checkpoint; the files together are the store. And `hook.log` records only a fixed failure label and an
767
- error code, never your prompt or a memory's text, so it cannot hold a leaked secret.
782
+ checkpoint; the files together are the store. And `hook.log` records only fixed labels and an error
783
+ code, never your prompt or a memory's text, so it cannot hold a leaked secret.
768
784
 
769
785
  There is one more log that is not a file: an event table inside `memory.db`. It records what happened
770
786
  on every **memory** read and write — used to measure whether the write policy is working, and kept in
@@ -784,6 +800,16 @@ Zikaron is built to fail quietly rather than get in your way. A hook that cannot
784
800
  prints a short note asking the agent to tell you, writes one line to `hook.log`, and exits cleanly. It
785
801
  never blocks your message, and it never reads the store directly.
786
802
 
803
+ The service stops itself after a stretch of idleness, and the next message starts it again. That
804
+ message waits a few seconds longer — the hook allows a start more time than a running service — and
805
+ if the start still is not finished, the message goes without memories and the agent is told so, without
806
+ being asked to report it. `hook.log` records that as `starting`, followed by what the hook was still
807
+ waiting on — `lock` or `poll` before the service answered, or the lateness of its answer after — and
808
+ memories return once it has started, usually with the next message. A run of `starting` lines means
809
+ starts are slower than the hook allows, not that the service is broken; a start that never finishes is
810
+ reported as `transport` once it has gone a minute without a sign of life — which a first run still
811
+ fetching its model over a slow link can also do, until it finishes.
812
+
787
813
  **Run `zikaron doctor` first for anything that smells environmental** — no search results at all, a
788
814
  service that will not start, an MCP server that dies on contact. It checks the things about this
789
815
  machine that can stop Zikaron working and names what to change for each. The table below is for
@@ -892,7 +918,7 @@ than deleted, because both hold settings that are not Zikaron's. **All three set
892
918
  the install writes three** — leaving `enabledMcpjsonServers` behind names two servers that no longer
893
919
  exist, which loads nothing and breaks nothing but is not an uninstall.
894
920
 
895
- **The edit guards** live only in `.claude/settings.local.json`: remove the `PreToolUse` and
921
+ **The guards** live only in `.claude/settings.local.json`: remove the `PreToolUse` and
896
922
  `PostToolUse` hook groups whose command is `zikaron-guard`, and the `SessionStart` and
897
923
  `SubagentStart` groups whose command is `zikaron-hook`. To keep the memory store and drop only the
898
924
  guards, re-running the installer will not do it — an install never removes a selection — so delete
@@ -4,16 +4,14 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "zikaron"
7
- # Semver, and `0.x` for as long as the *install contract* may still change — the shapes and
8
- # locations of the artefacts the installer writes into a harness's config. The one rule that
9
- # matters for an upgrade: **a release whose installed artefacts differ in shape from the previous
10
- # one is a minor bump, never a patch**, because those paths are written into harness config that an
11
- # upgrade has to be able to refresh, and a patch bump tells a reader nothing needs refreshing.
12
- # `design/distribution.md` §"The version scheme" is normative.
13
- version = "0.3.1"
7
+ # Semver, `0.x`. **A minor bump means one thing: `meta.schema_version` moved**, so a release that
8
+ # cannot open a store an earlier one wrote says so in its number. Every other change is a patch, a
9
+ # changed installed artifact included; a release that needs an existing install refreshed says so
10
+ # in its release note. `design/distribution.md` §"The version scheme" is normative.
11
+ version = "0.3.2"
14
12
  # What a package index renders as the one-line summary, so it must name both stores: the memory
15
13
  # store, for what was learned by working here, and the knowledge index, for what the project already
16
- # wrote down.
14
+ # wrote down. The guards, which ship on request, are the README's to describe.
17
15
  description = "Memory and searchable project knowledge for coding agents"
18
16
  readme = "README.md"
19
17
  # An SPDX expression plus `license-files`, which is the PEP 639 shape. **No
@@ -65,7 +63,7 @@ Repository = "https://github.com/nathan-shapiro/Zikaron"
65
63
  Issues = "https://github.com/nathan-shapiro/Zikaron/issues"
66
64
 
67
65
  # The commands a shipped harness config names — `zikaron-hook` and `zikaron-mcp` for either harness,
68
- # `zikaron-guard` for Claude Code's edit guards — and the reason they are console scripts rather than
66
+ # `zikaron-guard` for Claude Code's guards — and the reason they are console scripts rather than
69
67
  # `python -m` command lines: a hook entry's `command` and an `mcpServers` entry's `command` each need
70
68
  # one absolute path, and a console script's shebang pins the interpreter Zikaron is installed into —
71
69
  # which is also the interpreter start-if-absent will spawn the service with, via `sys.executable`.
@@ -1,15 +1,18 @@
1
- """The edit guards in a real Claude Code session (`design/build-plan.md` §M37, "A live test").
1
+ """The guards in a real Claude Code session (`design/build-plan.md` §M37, "A live test", and
2
+ §M38's done-when 3).
2
3
 
3
- One headless session under `--permission-mode bypassPermissions` is given exact commands, so that
4
- neither the edit nor the override is the model's choice: a `sed -i` the guard must deny, the same
5
- form with a valid override, and an `Edit`. What is asserted is what the harness recorded, never what
6
- the model says:
4
+ Each headless session under `--permission-mode bypassPermissions` is given exact commands, so that
5
+ neither the edit nor the override is the model's choice. The first runs a `sed -i` the guard must
6
+ deny, the same form with a valid override, and an `Edit`; the second a self-matching `pkill -f`,
7
+ the same command with `-A`, and a self-matching `pgrep -f` through `Monitor`. What is asserted is
8
+ what the harness recorded, never what the model says:
7
9
 
8
- - the deny is the `sed -i` call's `tool_result` in the `stream-json` output, and the file is
9
- unchanged by it — under `bypassPermissions`, which is itself one of §2's rows;
10
+ - each deny is its call's `tool_result` in the `stream-json` output, and the file is unchanged by
11
+ the denied `sed` — under `bypassPermissions`, which is itself one of §2's rows;
10
12
  - the override's command ran (the file changed), and its acknowledgement reached the model, which is
11
13
  recorded only in the session's transcript, as an attachment;
12
- - the `Edit` was followed by the nudge, also an attachment.
14
+ - the `Edit` was followed by the nudge, also an attachment;
15
+ - the `-A` call ran rather than being denied.
13
16
 
14
17
  **The project lives under `~/.cache/zikaron-live-tests/`, never `tmp_path`**: pytest's temporary
15
18
  directories lie under `/tmp` or `$TMPDIR`, where the guard exempts the commands and suppresses the
@@ -31,6 +34,7 @@ from typing import Any, Final
31
34
 
32
35
  import pytest
33
36
 
37
+ from zikaron.guard import messages
34
38
  from zikaron.harness.spec import CLAUDE_CODE
35
39
  from zikaron.install import harness
36
40
  from zikaron.install import main as install_main
@@ -49,6 +53,22 @@ _PROMPT: Final = (
49
53
  "Step 3: use the Edit tool to replace the word alpha with ALPHA in target.txt. Then reply with "
50
54
  "the single word: done."
51
55
  )
56
+ #: A pattern no process carries but the command running it, so only the shell can match it.
57
+ _NONCE: Final = f"zikaron_live_selfmatch_{uuid.uuid4().hex[:12]}"
58
+ _SELF_MATCHING: Final = f"pkill -f {_NONCE}"
59
+ _ANCESTORS_IGNORED: Final = f"pkill -A -f {_NONCE}"
60
+ _MONITORED: Final = f"pgrep -f {_NONCE}"
61
+ #: Measured: told only to run the steps, a small model declines a `pkill` it has no reason for, so
62
+ #: the prompt says what the commands are for and why they are safe.
63
+ _SELF_MATCH_PROMPT: Final = (
64
+ "This is a test of a hook installed in this throwaway project. Its pattern is a random string "
65
+ "that no process on this machine carries, so none of these commands can stop anything. "
66
+ "Do these three steps in order, each exactly as written, and carry on to the next even if one "
67
+ f"fails. Step 1: run this Bash command, character for character: `{_SELF_MATCHING}`. Step 2: "
68
+ f"run this Bash command, character for character: `{_ANCESTORS_IGNORED}`. Step 3: use the "
69
+ f"Monitor tool to run this command, character for character: `{_MONITORED}`. Then reply with "
70
+ "the single word: done."
71
+ )
52
72
 
53
73
 
54
74
  @pytest.fixture
@@ -62,7 +82,7 @@ def project() -> Iterator[Path]:
62
82
  shutil.rmtree(root)
63
83
 
64
84
 
65
- def _session(project: Path) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
85
+ def _session(project: Path, prompt: str) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
66
86
  """One headless turn: the `stream-json` records, and the session transcript's records."""
67
87
  assert harness.binary_is_available(CLAUDE_CODE.harness_binary), (
68
88
  f"{CLAUDE_CODE.harness_binary!r} is not on PATH: do not run -m integration_claude here, "
@@ -72,7 +92,7 @@ def _session(project: Path) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]
72
92
  [
73
93
  CLAUDE_CODE.harness_binary,
74
94
  "-p",
75
- _PROMPT,
95
+ prompt,
76
96
  "--model",
77
97
  "haiku",
78
98
  "--permission-mode",
@@ -108,12 +128,33 @@ def _tool_results(stream: list[dict[str, Any]]) -> list[str]:
108
128
  return results
109
129
 
110
130
 
111
- def test_the_guards_deny_acknowledge_and_nudge_in_a_real_session(project: Path) -> None:
131
+ def _results_by_command(stream: list[dict[str, Any]]) -> dict[str, str]:
132
+ """Each `Bash` or `Monitor` call's command, mapped to its `tool_result`."""
133
+ commands: dict[str, str] = {}
134
+ results: dict[str, str] = {}
135
+ for record in stream:
136
+ for block in (record.get("message") or {}).get("content") or []:
137
+ if not isinstance(block, dict):
138
+ continue
139
+ if block.get("type") == "tool_use" and block.get("name") in ("Bash", "Monitor"):
140
+ commands[block["id"]] = block["input"].get("command", "")
141
+ elif block.get("type") == "tool_result":
142
+ content = block.get("content")
143
+ text = content if isinstance(content, str) else json.dumps(content)
144
+ results[block["tool_use_id"]] = text
145
+ return {command: results.get(use_id, "") for use_id, command in commands.items()}
146
+
147
+
148
+ def _install_guards(project: Path) -> None:
112
149
  status = install_main.main(
113
150
  ["--project", str(project), "--harness", "claude-code", "--components", "guards"]
114
151
  )
115
152
  assert status == 0
116
- stream, transcript = _session(project)
153
+
154
+
155
+ def test_the_guards_deny_acknowledge_and_nudge_in_a_real_session(project: Path) -> None:
156
+ _install_guards(project)
157
+ stream, transcript = _session(project, _PROMPT)
117
158
  text = (project / "target.txt").read_text(encoding="utf-8")
118
159
 
119
160
  denials = [r for r in _tool_results(stream) if "PreToolUse:Bash hook error" in r]
@@ -126,3 +167,15 @@ def test_the_guards_deny_acknowledge_and_nudge_in_a_real_session(project: Path)
126
167
  assert "#ZIKARON-FORCE accepted by Zikaron's find-replace guard" in recorded
127
168
  assert "PostToolUse:Edit hook additional context" in recorded
128
169
  assert "target.txt` was edited" in recorded
170
+
171
+
172
+ def test_the_self_match_rule_denies_on_bash_and_monitor_in_a_real_session(project: Path) -> None:
173
+ _install_guards(project)
174
+ results = _results_by_command(_session(project, _SELF_MATCH_PROMPT)[0])
175
+ refused = messages.SELF_MATCH_TEMPLATE.split("{", 1)[0]
176
+
177
+ assert "PreToolUse:Bash hook error" in results[_SELF_MATCHING], results
178
+ assert refused in results[_SELF_MATCHING], results
179
+ assert "hook error" not in results[_ANCESTORS_IGNORED], results
180
+ assert "PreToolUse:Monitor hook error" in results[_MONITORED], results
181
+ assert refused in results[_MONITORED], results