zikaron 0.3.0__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.
- {zikaron-0.3.0/zikaron.egg-info → zikaron-0.3.2}/PKG-INFO +112 -23
- zikaron-0.3.0/PKG-INFO → zikaron-0.3.2/README.md +106 -46
- {zikaron-0.3.0 → zikaron-0.3.2}/pyproject.toml +19 -19
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_check_gate.py +2 -2
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_cli_front_door.py +12 -4
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_distribution.py +5 -2
- zikaron-0.3.2/tests/test_guard_claude_live.py +181 -0
- zikaron-0.3.2/tests/test_guard_docstring_examples.py +22 -0
- zikaron-0.3.2/tests/test_guard_main.py +289 -0
- zikaron-0.3.2/tests/test_guard_malformed.py +71 -0
- zikaron-0.3.2/tests/test_guard_nudge.py +82 -0
- zikaron-0.3.2/tests/test_guard_properties.py +104 -0
- zikaron-0.3.2/tests/test_guard_rule_table.py +134 -0
- zikaron-0.3.2/tests/test_guard_script_file.py +49 -0
- zikaron-0.3.2/tests/test_guard_selfmatch.py +327 -0
- zikaron-0.3.2/tests/test_guard_selfmatch_premise.py +99 -0
- zikaron-0.3.2/tests/test_guard_selfmatch_table.py +90 -0
- zikaron-0.3.2/tests/test_guard_texts.py +143 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_harness_table.py +17 -0
- zikaron-0.3.2/tests/test_hook_components.py +157 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_connect.py +76 -17
- zikaron-0.3.2/tests/test_hook_connect_edge_cases.py +273 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_connect_integration.py +77 -25
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_connect_race.py +59 -47
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_connect_real_service_integration.py +71 -46
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_failure.py +13 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_push.py +261 -43
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_rpc.py +120 -10
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_stdlib_only.py +7 -6
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_indexing_acquisition.py +4 -4
- zikaron-0.3.2/tests/test_install_components.py +379 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_install_limits.py +20 -3
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_project_scope.py +18 -1
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_diagnostics.py +16 -9
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_diagnostics_integration.py +14 -6
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_dispatch.py +35 -3
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_encoder_failure_stop.py +20 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_lifecycle.py +144 -2
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_lifecycle_integration.py +16 -1
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_main.py +214 -3
- zikaron-0.3.2/tests/test_service_ownership.py +123 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_server.py +25 -5
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/indexing/acquisition.py +3 -5
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/indexing/encoder.py +5 -0
- zikaron-0.3.2/zikaron/guard/__init__.py +1 -0
- zikaron-0.3.2/zikaron/guard/chars.py +60 -0
- zikaron-0.3.2/zikaron/guard/decision.py +140 -0
- zikaron-0.3.2/zikaron/guard/expression.py +416 -0
- zikaron-0.3.2/zikaron/guard/forms.py +161 -0
- zikaron-0.3.2/zikaron/guard/grammar.py +292 -0
- zikaron-0.3.2/zikaron/guard/grep_filter.py +190 -0
- zikaron-0.3.2/zikaron/guard/heredoc.py +216 -0
- zikaron-0.3.2/zikaron/guard/inplace.py +136 -0
- zikaron-0.3.2/zikaron/guard/interpreter.py +124 -0
- zikaron-0.3.2/zikaron/guard/lexer.py +141 -0
- zikaron-0.3.2/zikaron/guard/limits.py +8 -0
- zikaron-0.3.2/zikaron/guard/literal_text.py +74 -0
- zikaron-0.3.2/zikaron/guard/main.py +135 -0
- zikaron-0.3.2/zikaron/guard/messages.py +150 -0
- zikaron-0.3.2/zikaron/guard/nudge.py +69 -0
- zikaron-0.3.2/zikaron/guard/override.py +84 -0
- zikaron-0.3.2/zikaron/guard/patterns.py +47 -0
- zikaron-0.3.2/zikaron/guard/position.py +166 -0
- zikaron-0.3.2/zikaron/guard/programs.py +39 -0
- zikaron-0.3.2/zikaron/guard/quoting.py +83 -0
- zikaron-0.3.2/zikaron/guard/redirects.py +89 -0
- zikaron-0.3.2/zikaron/guard/scratch.py +155 -0
- zikaron-0.3.2/zikaron/guard/script_file.py +238 -0
- zikaron-0.3.2/zikaron/guard/selfmatch.py +278 -0
- zikaron-0.3.2/zikaron/guard/start_text.py +19 -0
- zikaron-0.3.2/zikaron/guard/writes.py +236 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/harness/spec.py +34 -0
- zikaron-0.3.2/zikaron/hook/components.py +60 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/hook/connect.py +248 -128
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/hook/failure.py +30 -22
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/hook/limits.py +4 -4
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/hook/main.py +58 -25
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/hook/push.py +94 -67
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/hook/rpc.py +55 -4
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/hook/subagent_policy.py +6 -1
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/hook/warm_helper.py +2 -1
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/install/entries.py +68 -31
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/install/main.py +39 -3
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/install/targets.py +173 -37
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/install/writer.py +6 -3
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/knowledge/client.py +2 -1
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/mcp/connection.py +5 -4
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/mcp/errors.py +4 -4
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/project/initialize.py +20 -14
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/asyncio_compat.py +3 -3
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/context.py +8 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/diagnostics.py +21 -5
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/dispatch.py +13 -4
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/lifecycle.py +104 -56
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/log.py +17 -3
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/main.py +87 -49
- zikaron-0.3.2/zikaron/service/ownership.py +109 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/paths.py +7 -1
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/server.py +30 -14
- zikaron-0.3.0/README.md → zikaron-0.3.2/zikaron.egg-info/PKG-INFO +135 -17
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron.egg-info/SOURCES.txt +44 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron.egg-info/entry_points.txt +1 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron.egg-info/requires.txt +5 -5
- zikaron-0.3.0/tests/test_hook_connect_edge_cases.py +0 -104
- {zikaron-0.3.0 → zikaron-0.3.2}/LICENSE +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/setup.cfg +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_access_log.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_agent_scan.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_asyncio_compat.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_background_encoder.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_ci_workflow.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_clock.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_config_keys.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_config_resolution.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_consolidation_grouping.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_consolidation_invariants.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_consolidation_observability.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_consolidation_planning.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_consolidation_refusals.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_consolidation_serving.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_consolidation_snapshot_planning.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_consolidation_verbs.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_ddl.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_definition_of_done_sites.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_design_pointers_resolve.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_design_tables.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_doctor.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_embedder.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_error_codes.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_event_kinds.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_harness_detect.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_harness_store_scope.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_harness_tier_guard.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_envelope.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_main.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_spawn_warm.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_subagent_policy.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_tripwire.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_warm_helper.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_warm_helper_integration.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_hook_write_policy.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_indexing_chunking.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_indexing_encoder.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_indexing_integration.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_indexing_model_cache.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_indexing_writes.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_injected_prose_log.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_install_assets.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_install_claude_live.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_install_e2e.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_install_harness.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_install_main.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_install_takeover.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_install_targets.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_install_writer.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_build_invariants.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_build_log.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_build_row_ordering.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_builds.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_chunking.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_cli.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_cli_integration.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_counters.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_database.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_ddl.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_detach.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_files.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_git.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_groups.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_indexer.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_integration.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_invariants.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_lifecycle.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_lock.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_lock_race.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_meta.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_registry.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_repair.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_reporting.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_roots.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_scan.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_scan_git.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_search.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_state.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_text.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_vectors.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_walk.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_knowledge_writes.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_markdown_renders_as_written.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_mcp_connection_ambiguous_failure.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_mcp_connection_cancellation.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_mcp_connection_concurrency.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_mcp_connection_integration.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_mcp_connection_labels.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_mcp_consolidator_bridge.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_mcp_errors.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_mcp_main.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_mcp_server.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_mcp_spill.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_mcp_tool_descriptions.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_mcp_wire_contracts.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_meta.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_permissions.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_publication_hygiene.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_quoted_design_prose_is_verbatim.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_readme_config_table.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_readme_internal_links.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_records_memory.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_records_receipts.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_records_supersession.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_retrieval_arms.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_retrieval_eligibility.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_retrieval_integration.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_retrieval_query.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_retrieval_ranking.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_retrieval_reads.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_context.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_context_assemble.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_dispatch_consolidation.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_dispatch_knowledge.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_envelope.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_knowledge_management.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_log.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_params.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_paths.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_read_contention.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_rpc.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_security.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_surface_deadline.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_write_contention.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_service_writer.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_signals_contention.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_signals_dedup.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_signals_horizon.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_signals_repair.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_signals_retirement.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_signals_sessions.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_signals_writes.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_socket_path_budget.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_store.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_store_connection.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_store_migration.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_store_pool.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_transaction_begin_sites.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_version_seam.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_write_dedup.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/tests/test_write_tools.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/cli/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/cli/main.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/clock.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/config/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/config/keys.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/config/resolution.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/consolidation/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/consolidation/authorization.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/consolidation/candidates.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/consolidation/context.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/consolidation/grouping.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/consolidation/groups.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/consolidation/payload.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/consolidation/planning.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/consolidation/rowstate.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/consolidation/runs.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/consolidation/serving.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/consolidation/verbs.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/errors.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/events.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/indexing/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/indexing/chunking.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/indexing/lexical.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/indexing/model_cache.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/indexing/model_pin.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/indexing/vectors.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/indexing/writes.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/arms.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/builds.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/candidates.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/changes.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/chunking.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/counters.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/database.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/ddl.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/disposal.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/errors.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/files.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/git.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/groups.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/lexical.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/lifecycle.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/lock.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/meta.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/paths.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/pending.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/registry.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/repair.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/reporting.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/roots.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/scan.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/search.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/state.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/text.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/vectors.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/walk.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/knowledge/writes.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/records/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/records/memory.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/records/receipts.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/records/supersession.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/retrieval/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/retrieval/arms.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/retrieval/block.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/retrieval/eligibility.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/retrieval/query.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/retrieval/ranking.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/retrieval/reads.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/retrieval/retrieve.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/retrieval/similarity.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/signals/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/signals/contention.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/signals/dedup.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/signals/horizon.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/signals/repair.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/signals/retirement.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/signals/sessions.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/signals/writes.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/store/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/store/connection.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/store/ddl.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/store/deadline.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/store/embedder.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/store/holders.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/store/meta.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/store/migration.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/store/permissions.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/store/pool.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/store/store.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/store/transactions.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/write/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/write/dedup.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/core/write/tools.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/doctor/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/doctor/checks.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/doctor/main.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/harness/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/harness/detect.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/hook/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/hook/envelope.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/hook/spawn_warm.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/hook/tripwire.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/hook/write_policy.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/install/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/install/__main__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/install/agent_scan.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/install/assets.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/install/harness.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/install/ownership.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/knowledge/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/knowledge/__main__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/knowledge/indexer/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/knowledge/indexer/__main__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/knowledge/indexer/build_log.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/knowledge/indexer/detach.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/knowledge/indexer/main.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/knowledge/main.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/knowledge/scope.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/mcp/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/mcp/consolidator.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/mcp/main.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/mcp/primary.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/mcp/server.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/mcp/spill.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/mcp/tool_names.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/project/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/project/__main__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/project/report.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/project/resolve.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/py.typed +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/__init__.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/access_log.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/dispatch_consolidation.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/dispatch_knowledge.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/envelope.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/methods.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/params.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/rpc.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/security.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/serialize.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron/service/serialize_knowledge.py +0 -0
- {zikaron-0.3.0 → zikaron-0.3.2}/zikaron.egg-info/dependency_links.txt +0 -0
- {zikaron-0.3.0 → 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.
|
|
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
|
|
@@ -11,16 +11,16 @@ Description-Content-Type: text/markdown
|
|
|
11
11
|
License-File: LICENSE
|
|
12
12
|
Requires-Dist: aiosqlite==0.22.1
|
|
13
13
|
Requires-Dist: sqlite-vec==0.1.9
|
|
14
|
-
Requires-Dist: fastembed==0.8.
|
|
15
|
-
Requires-Dist: huggingface_hub==1.
|
|
16
|
-
Requires-Dist: fastmcp==
|
|
14
|
+
Requires-Dist: fastembed==0.8.1
|
|
15
|
+
Requires-Dist: huggingface_hub==1.33.0
|
|
16
|
+
Requires-Dist: fastmcp==4.0.10
|
|
17
17
|
Provides-Extra: dev
|
|
18
|
-
Requires-Dist: ruff==0.16.
|
|
18
|
+
Requires-Dist: ruff==0.16.9; extra == "dev"
|
|
19
19
|
Requires-Dist: mypy==2.3.1; extra == "dev"
|
|
20
20
|
Requires-Dist: pytest==9.1.1; extra == "dev"
|
|
21
21
|
Requires-Dist: pytest-cov==7.1.0; extra == "dev"
|
|
22
22
|
Requires-Dist: pytest-asyncio==1.4.0; extra == "dev"
|
|
23
|
-
Requires-Dist: hypothesis==6.168.
|
|
23
|
+
Requires-Dist: hypothesis==6.168.3; extra == "dev"
|
|
24
24
|
Requires-Dist: pyyaml==6.0.3; extra == "dev"
|
|
25
25
|
Requires-Dist: types-PyYAML==6.0.12.20260906; extra == "dev"
|
|
26
26
|
Requires-Dist: build==1.3.0; extra == "dev"
|
|
@@ -61,6 +61,13 @@ 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, 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.
|
|
70
|
+
|
|
64
71
|
It runs entirely on your machine: SQLite databases under `.zikaron/`, a local embedding model, and a
|
|
65
72
|
small background service on a Unix socket. **Zikaron reaches the network for exactly one thing** —
|
|
66
73
|
the embedding-model download described under [Install](#install), pinned to one revision and
|
|
@@ -124,6 +131,7 @@ reads which one it is addressing before it reads a description. Consolidation ne
|
|
|
124
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. |
|
|
125
132
|
| **MCP server** | Translates the agent's tool calls into requests to the service. One process per agent instance; loads no model. |
|
|
126
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. |
|
|
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. |
|
|
127
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. |
|
|
128
136
|
|
|
129
137
|
The service exists for one measured reason: loading the embedding model costs about **780 ms**, and
|
|
@@ -235,6 +243,16 @@ cd /path/to/your/project
|
|
|
235
243
|
zikaron install --project . --harness claude-code # or: --harness kiro
|
|
236
244
|
```
|
|
237
245
|
|
|
246
|
+
Under Claude Code, `--components` adds the [guards](#guards-claude-code-on-request), or
|
|
247
|
+
installs them alone; without it you get the memory store only, exactly as before:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
zikaron install --project . --harness claude-code --components both # memory and guards
|
|
251
|
+
zikaron install --project . --harness claude-code --components guards # guards only
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Installing one later keeps the other: an install touches only what it was asked for.
|
|
255
|
+
|
|
238
256
|
**Name it on a first install, rather than leaving it to be detected.** Detection looks for a
|
|
239
257
|
`.kiro/` or `.claude/` directory in the project and for `CLAUDECODE` in the environment, and it
|
|
240
258
|
refuses rather than guessing when neither says. Running from an ordinary terminal, a first install
|
|
@@ -334,6 +352,12 @@ and under **Claude Code**:
|
|
|
334
352
|
| `.claude/settings.local.json` | three hooks — session start, per-message, and per-subagent — plus both approval keys, `enabledMcpjsonServers` and `permissions.allow` |
|
|
335
353
|
| `.mcp.json` | both servers: `zikaron` for your own tools, `zikaron-consolidator` for the consolidation verbs — each marked `alwaysLoad` so their descriptions are in context from the start rather than fetched per tool |
|
|
336
354
|
|
|
355
|
+
With `--components guards` the install writes `.claude/settings.local.json` alone, and in it only
|
|
356
|
+
hooks: the session-start and per-subagent hooks, which carry a short note about the guards, and the
|
|
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
|
|
359
|
+
the write policy and the guards' note.
|
|
360
|
+
|
|
337
361
|
**`settings.local.json`, not `settings.json`**, and it matters if you commit your settings: the hook
|
|
338
362
|
entries name absolute paths inside *your* virtualenv, so they are meaningless in anyone else's clone.
|
|
339
363
|
The third hook is the one with no kiro counterpart — it hands the write policy to each subagent you
|
|
@@ -451,6 +475,48 @@ guard, the receipts and the lease are untouched — but an unauthorized consolid
|
|
|
451
475
|
tokens and could write a poorly-judged long-term record. `permissions.deny` is **not** the fix: it is
|
|
452
476
|
global and unregisters the tool, after which the consolidator itself refuses to start.
|
|
453
477
|
|
|
478
|
+
### Guards (Claude Code, on request)
|
|
479
|
+
|
|
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`):
|
|
482
|
+
|
|
483
|
+
- **A find-replace edit to an authored file is refused** — `sed -i`, `perl -pi`, an inline Python
|
|
484
|
+
or node script that writes a file, a heredoc or `echo` redirected into one, and a script under
|
|
485
|
+
`/tmp` or `$TMPDIR` that the command runs and that does any of these. The refusal reaches the
|
|
486
|
+
agent as the tool's result and tells it to use `Read` and `Edit`, or `Write` for a new file.
|
|
487
|
+
Paths under `/tmp`, `/var/tmp` and `$TMPDIR` are exempt, and so is a command carrying the
|
|
488
|
+
override the refusal itself describes, for the files whose bytes a program owns.
|
|
489
|
+
- **After each edit, the agent is reminded** that the file has not been re-read, and asked for one
|
|
490
|
+
re-read of the edited material once that file's editing is done. A Bash command gets no such
|
|
491
|
+
reminder, so when the agent overrides a refusal, the guard's acknowledgement names what the
|
|
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`.
|
|
502
|
+
|
|
503
|
+
They are not a security boundary: a script the guard reads is one run from a scratch directory,
|
|
504
|
+
and a script anywhere else — one of the project's own programs — is never read, by design. A guard
|
|
505
|
+
that fails for any reason allows the call.
|
|
506
|
+
|
|
507
|
+
They write no log and no store record: a refusal, an override and its reason are in the session's
|
|
508
|
+
own transcript. `zikaron doctor` does not report on them. To see the refusal without a model in
|
|
509
|
+
the loop, hand the guard the payload Claude Code would send it, from the project directory — run
|
|
510
|
+
from a scratch directory such as `/tmp`, the same command is exempt and prints nothing:
|
|
511
|
+
|
|
512
|
+
```bash
|
|
513
|
+
printf '%s' '{"hook_event_name":"PreToolUse","tool_name":"Bash","cwd":"'"$PWD"'","tool_input":{"command":"sed -i s/a/b/ README.md"}}' | zikaron-guard
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
It prints the deny the agent would read as the command's result. Asking an agent to run `sed -i`
|
|
517
|
+
usually shows something else: told the rule when its session starts, it reaches for `Read` and
|
|
518
|
+
`Edit` without trying.
|
|
519
|
+
|
|
454
520
|
### Options
|
|
455
521
|
|
|
456
522
|
| Flag | Effect |
|
|
@@ -462,6 +528,7 @@ global and unregisters the tool, after which the consolidator itself refuses to
|
|
|
462
528
|
| `--model <id>` | the consolidator's model (default: `claude-sonnet-5` under kiro, `sonnet` under Claude Code) |
|
|
463
529
|
| `--format {object,array}` | **kiro only.** Which hook format to write when the target config has none yet |
|
|
464
530
|
| `--no-trust-tools` | do not pre-approve Zikaron's own tools, so every Zikaron tool call asks permission |
|
|
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 |
|
|
465
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 |
|
|
466
533
|
|
|
467
534
|
Both hook formats kiro accepts are supported, and a config that already uses one keeps it: kiro
|
|
@@ -508,7 +575,7 @@ write policy goes into the model's context, not to your terminal. Then, from the
|
|
|
508
575
|
# a service should be running for this project after your first message
|
|
509
576
|
pgrep -af zikaron.service.main
|
|
510
577
|
|
|
511
|
-
# 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
|
|
512
579
|
cat .zikaron/hook.log
|
|
513
580
|
```
|
|
514
581
|
|
|
@@ -699,9 +766,11 @@ it is `0600` or `0700`. The **installer** also writes harness config — the fil
|
|
|
699
766
|
config.toml your per-project overrides, if you wrote any
|
|
700
767
|
service.log the background service: startup, resolved config, errors, why it stopped,
|
|
701
768
|
any request running longer than 30 s, and the stack dumps below
|
|
702
|
-
hook.log one line per hook failure, write-policy-override note, or
|
|
703
|
-
mismatch. Absent means none happened. Not every line is a
|
|
704
|
-
|
|
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
|
|
705
774
|
warmup.log the small helper that warms the service when a session starts
|
|
706
775
|
write-policy.md your policy override, if you wrote one
|
|
707
776
|
```
|
|
@@ -714,19 +783,23 @@ shared by every project you use Zikaron in, under `$XDG_CACHE_HOME/zikaron/model
|
|
|
714
783
|
A copy inside each project would duplicate it for bytes that are identical by construction, since the
|
|
715
784
|
version fetched is pinned. Removing a project does not remove it; [Uninstall](#uninstall) says how.
|
|
716
785
|
|
|
717
|
-
The second is the service's Unix socket
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
[Secrets](#secrets) removes it by hand.
|
|
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.
|
|
726
796
|
|
|
727
797
|
**What `service.log` tells you about a service that stopped, or stopped answering.** A clean stop
|
|
728
|
-
writes one `stopping: reason=…` line: `idle`, `store_replaced`, `
|
|
729
|
-
|
|
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
|
|
730
803
|
`long request: method=… session=… age=…` on every poll until it ends — `session=unresolved` if it
|
|
731
804
|
never got that far. Two signals write a dump without stopping the service: `kill -USR2 <pid>` writes
|
|
732
805
|
the requests in flight and every asyncio task's stack, and `kill -USR1 <pid>` writes every thread's
|
|
@@ -735,8 +808,8 @@ raw text, without the timestamp and `pid=` every other line carries.
|
|
|
735
808
|
|
|
736
809
|
Two notes on reading the rest. `memory.db` can look implausibly small while `memory.db-wal` is large —
|
|
737
810
|
that is normal for a database held open by the service, since recent writes live in the log until a
|
|
738
|
-
checkpoint; the files together are the store. And `hook.log` records only
|
|
739
|
-
|
|
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.
|
|
740
813
|
|
|
741
814
|
There is one more log that is not a file: an event table inside `memory.db`. It records what happened
|
|
742
815
|
on every **memory** read and write — used to measure whether the write policy is working, and kept in
|
|
@@ -756,6 +829,16 @@ Zikaron is built to fail quietly rather than get in your way. A hook that cannot
|
|
|
756
829
|
prints a short note asking the agent to tell you, writes one line to `hook.log`, and exits cleanly. It
|
|
757
830
|
never blocks your message, and it never reads the store directly.
|
|
758
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
|
+
|
|
759
842
|
**Run `zikaron doctor` first for anything that smells environmental** — no search results at all, a
|
|
760
843
|
service that will not start, an MCP server that dies on contact. It checks the things about this
|
|
761
844
|
machine that can stop Zikaron working and names what to change for each. The table below is for
|
|
@@ -864,6 +947,12 @@ than deleted, because both hold settings that are not Zikaron's. **All three set
|
|
|
864
947
|
the install writes three** — leaving `enabledMcpjsonServers` behind names two servers that no longer
|
|
865
948
|
exist, which loads nothing and breaks nothing but is not an uninstall.
|
|
866
949
|
|
|
950
|
+
**The guards** live only in `.claude/settings.local.json`: remove the `PreToolUse` and
|
|
951
|
+
`PostToolUse` hook groups whose command is `zikaron-guard`, and the `SessionStart` and
|
|
952
|
+
`SubagentStart` groups whose command is `zikaron-hook`. To keep the memory store and drop only the
|
|
953
|
+
guards, re-running the installer will not do it — an install never removes a selection — so delete
|
|
954
|
+
the two guard groups and the `--components …` arguments from the two start groups' command.
|
|
955
|
+
|
|
867
956
|
Note that `rm -rf .zikaron` takes the knowledge bases with it. They are rebuildable — an index is a
|
|
868
957
|
view onto files you still have — but rebuilding one takes minutes per corpus.
|
|
869
958
|
|
|
@@ -1,32 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: zikaron
|
|
3
|
-
Version: 0.3.0
|
|
4
|
-
Summary: Memory and searchable project knowledge for coding agents
|
|
5
|
-
License-Expression: MIT
|
|
6
|
-
Project-URL: Homepage, https://github.com/nathan-shapiro/Zikaron
|
|
7
|
-
Project-URL: Repository, https://github.com/nathan-shapiro/Zikaron
|
|
8
|
-
Project-URL: Issues, https://github.com/nathan-shapiro/Zikaron/issues
|
|
9
|
-
Requires-Python: >=3.12
|
|
10
|
-
Description-Content-Type: text/markdown
|
|
11
|
-
License-File: LICENSE
|
|
12
|
-
Requires-Dist: aiosqlite==0.22.1
|
|
13
|
-
Requires-Dist: sqlite-vec==0.1.9
|
|
14
|
-
Requires-Dist: fastembed==0.8.0
|
|
15
|
-
Requires-Dist: huggingface_hub==1.26.0
|
|
16
|
-
Requires-Dist: fastmcp==3.4.7
|
|
17
|
-
Provides-Extra: dev
|
|
18
|
-
Requires-Dist: ruff==0.16.7; extra == "dev"
|
|
19
|
-
Requires-Dist: mypy==2.3.1; extra == "dev"
|
|
20
|
-
Requires-Dist: pytest==9.1.1; extra == "dev"
|
|
21
|
-
Requires-Dist: pytest-cov==7.1.0; extra == "dev"
|
|
22
|
-
Requires-Dist: pytest-asyncio==1.4.0; extra == "dev"
|
|
23
|
-
Requires-Dist: hypothesis==6.168.0; extra == "dev"
|
|
24
|
-
Requires-Dist: pyyaml==6.0.3; extra == "dev"
|
|
25
|
-
Requires-Dist: types-PyYAML==6.0.12.20260906; extra == "dev"
|
|
26
|
-
Requires-Dist: build==1.3.0; extra == "dev"
|
|
27
|
-
Requires-Dist: setuptools==84.0.0; extra == "dev"
|
|
28
|
-
Dynamic: license-file
|
|
29
|
-
|
|
30
1
|
# Zikaron
|
|
31
2
|
|
|
32
3
|
[](https://pypi.org/project/zikaron/)
|
|
@@ -61,6 +32,13 @@ yes, it is out of scope. That store is for what cost somebody time to discover,
|
|
|
61
32
|
be discovered again by the next agent, at full price. A knowledge base has no such test — it is
|
|
62
33
|
whatever corpus you point it at.
|
|
63
34
|
|
|
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.
|
|
41
|
+
|
|
64
42
|
It runs entirely on your machine: SQLite databases under `.zikaron/`, a local embedding model, and a
|
|
65
43
|
small background service on a Unix socket. **Zikaron reaches the network for exactly one thing** —
|
|
66
44
|
the embedding-model download described under [Install](#install), pinned to one revision and
|
|
@@ -124,6 +102,7 @@ reads which one it is addressing before it reads a description. Consolidation ne
|
|
|
124
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. |
|
|
125
103
|
| **MCP server** | Translates the agent's tool calls into requests to the service. One process per agent instance; loads no model. |
|
|
126
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. |
|
|
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. |
|
|
127
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. |
|
|
128
107
|
|
|
129
108
|
The service exists for one measured reason: loading the embedding model costs about **780 ms**, and
|
|
@@ -235,6 +214,16 @@ cd /path/to/your/project
|
|
|
235
214
|
zikaron install --project . --harness claude-code # or: --harness kiro
|
|
236
215
|
```
|
|
237
216
|
|
|
217
|
+
Under Claude Code, `--components` adds the [guards](#guards-claude-code-on-request), or
|
|
218
|
+
installs them alone; without it you get the memory store only, exactly as before:
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
zikaron install --project . --harness claude-code --components both # memory and guards
|
|
222
|
+
zikaron install --project . --harness claude-code --components guards # guards only
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Installing one later keeps the other: an install touches only what it was asked for.
|
|
226
|
+
|
|
238
227
|
**Name it on a first install, rather than leaving it to be detected.** Detection looks for a
|
|
239
228
|
`.kiro/` or `.claude/` directory in the project and for `CLAUDECODE` in the environment, and it
|
|
240
229
|
refuses rather than guessing when neither says. Running from an ordinary terminal, a first install
|
|
@@ -334,6 +323,12 @@ and under **Claude Code**:
|
|
|
334
323
|
| `.claude/settings.local.json` | three hooks — session start, per-message, and per-subagent — plus both approval keys, `enabledMcpjsonServers` and `permissions.allow` |
|
|
335
324
|
| `.mcp.json` | both servers: `zikaron` for your own tools, `zikaron-consolidator` for the consolidation verbs — each marked `alwaysLoad` so their descriptions are in context from the start rather than fetched per tool |
|
|
336
325
|
|
|
326
|
+
With `--components guards` the install writes `.claude/settings.local.json` alone, and in it only
|
|
327
|
+
hooks: the session-start and per-subagent hooks, which carry a short note about the guards, and the
|
|
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
|
|
330
|
+
the write policy and the guards' note.
|
|
331
|
+
|
|
337
332
|
**`settings.local.json`, not `settings.json`**, and it matters if you commit your settings: the hook
|
|
338
333
|
entries name absolute paths inside *your* virtualenv, so they are meaningless in anyone else's clone.
|
|
339
334
|
The third hook is the one with no kiro counterpart — it hands the write policy to each subagent you
|
|
@@ -451,6 +446,48 @@ guard, the receipts and the lease are untouched — but an unauthorized consolid
|
|
|
451
446
|
tokens and could write a poorly-judged long-term record. `permissions.deny` is **not** the fix: it is
|
|
452
447
|
global and unregisters the tool, after which the consolidator itself refuses to start.
|
|
453
448
|
|
|
449
|
+
### Guards (Claude Code, on request)
|
|
450
|
+
|
|
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`):
|
|
453
|
+
|
|
454
|
+
- **A find-replace edit to an authored file is refused** — `sed -i`, `perl -pi`, an inline Python
|
|
455
|
+
or node script that writes a file, a heredoc or `echo` redirected into one, and a script under
|
|
456
|
+
`/tmp` or `$TMPDIR` that the command runs and that does any of these. The refusal reaches the
|
|
457
|
+
agent as the tool's result and tells it to use `Read` and `Edit`, or `Write` for a new file.
|
|
458
|
+
Paths under `/tmp`, `/var/tmp` and `$TMPDIR` are exempt, and so is a command carrying the
|
|
459
|
+
override the refusal itself describes, for the files whose bytes a program owns.
|
|
460
|
+
- **After each edit, the agent is reminded** that the file has not been re-read, and asked for one
|
|
461
|
+
re-read of the edited material once that file's editing is done. A Bash command gets no such
|
|
462
|
+
reminder, so when the agent overrides a refusal, the guard's acknowledgement names what the
|
|
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`.
|
|
473
|
+
|
|
474
|
+
They are not a security boundary: a script the guard reads is one run from a scratch directory,
|
|
475
|
+
and a script anywhere else — one of the project's own programs — is never read, by design. A guard
|
|
476
|
+
that fails for any reason allows the call.
|
|
477
|
+
|
|
478
|
+
They write no log and no store record: a refusal, an override and its reason are in the session's
|
|
479
|
+
own transcript. `zikaron doctor` does not report on them. To see the refusal without a model in
|
|
480
|
+
the loop, hand the guard the payload Claude Code would send it, from the project directory — run
|
|
481
|
+
from a scratch directory such as `/tmp`, the same command is exempt and prints nothing:
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
printf '%s' '{"hook_event_name":"PreToolUse","tool_name":"Bash","cwd":"'"$PWD"'","tool_input":{"command":"sed -i s/a/b/ README.md"}}' | zikaron-guard
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
It prints the deny the agent would read as the command's result. Asking an agent to run `sed -i`
|
|
488
|
+
usually shows something else: told the rule when its session starts, it reaches for `Read` and
|
|
489
|
+
`Edit` without trying.
|
|
490
|
+
|
|
454
491
|
### Options
|
|
455
492
|
|
|
456
493
|
| Flag | Effect |
|
|
@@ -462,6 +499,7 @@ global and unregisters the tool, after which the consolidator itself refuses to
|
|
|
462
499
|
| `--model <id>` | the consolidator's model (default: `claude-sonnet-5` under kiro, `sonnet` under Claude Code) |
|
|
463
500
|
| `--format {object,array}` | **kiro only.** Which hook format to write when the target config has none yet |
|
|
464
501
|
| `--no-trust-tools` | do not pre-approve Zikaron's own tools, so every Zikaron tool call asks permission |
|
|
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 |
|
|
465
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 |
|
|
466
504
|
|
|
467
505
|
Both hook formats kiro accepts are supported, and a config that already uses one keeps it: kiro
|
|
@@ -508,7 +546,7 @@ write policy goes into the model's context, not to your terminal. Then, from the
|
|
|
508
546
|
# a service should be running for this project after your first message
|
|
509
547
|
pgrep -af zikaron.service.main
|
|
510
548
|
|
|
511
|
-
# 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
|
|
512
550
|
cat .zikaron/hook.log
|
|
513
551
|
```
|
|
514
552
|
|
|
@@ -699,9 +737,11 @@ it is `0600` or `0700`. The **installer** also writes harness config — the fil
|
|
|
699
737
|
config.toml your per-project overrides, if you wrote any
|
|
700
738
|
service.log the background service: startup, resolved config, errors, why it stopped,
|
|
701
739
|
any request running longer than 30 s, and the stack dumps below
|
|
702
|
-
hook.log one line per hook failure, write-policy-override note, or
|
|
703
|
-
mismatch. Absent means none happened. Not every line is a
|
|
704
|
-
|
|
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
|
|
705
745
|
warmup.log the small helper that warms the service when a session starts
|
|
706
746
|
write-policy.md your policy override, if you wrote one
|
|
707
747
|
```
|
|
@@ -714,19 +754,23 @@ shared by every project you use Zikaron in, under `$XDG_CACHE_HOME/zikaron/model
|
|
|
714
754
|
A copy inside each project would duplicate it for bytes that are identical by construction, since the
|
|
715
755
|
version fetched is pinned. Removing a project does not remove it; [Uninstall](#uninstall) says how.
|
|
716
756
|
|
|
717
|
-
The second is the service's Unix socket
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
[Secrets](#secrets) removes it by hand.
|
|
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.
|
|
726
767
|
|
|
727
768
|
**What `service.log` tells you about a service that stopped, or stopped answering.** A clean stop
|
|
728
|
-
writes one `stopping: reason=…` line: `idle`, `store_replaced`, `
|
|
729
|
-
|
|
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
|
|
730
774
|
`long request: method=… session=… age=…` on every poll until it ends — `session=unresolved` if it
|
|
731
775
|
never got that far. Two signals write a dump without stopping the service: `kill -USR2 <pid>` writes
|
|
732
776
|
the requests in flight and every asyncio task's stack, and `kill -USR1 <pid>` writes every thread's
|
|
@@ -735,8 +779,8 @@ raw text, without the timestamp and `pid=` every other line carries.
|
|
|
735
779
|
|
|
736
780
|
Two notes on reading the rest. `memory.db` can look implausibly small while `memory.db-wal` is large —
|
|
737
781
|
that is normal for a database held open by the service, since recent writes live in the log until a
|
|
738
|
-
checkpoint; the files together are the store. And `hook.log` records only
|
|
739
|
-
|
|
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.
|
|
740
784
|
|
|
741
785
|
There is one more log that is not a file: an event table inside `memory.db`. It records what happened
|
|
742
786
|
on every **memory** read and write — used to measure whether the write policy is working, and kept in
|
|
@@ -756,6 +800,16 @@ Zikaron is built to fail quietly rather than get in your way. A hook that cannot
|
|
|
756
800
|
prints a short note asking the agent to tell you, writes one line to `hook.log`, and exits cleanly. It
|
|
757
801
|
never blocks your message, and it never reads the store directly.
|
|
758
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
|
+
|
|
759
813
|
**Run `zikaron doctor` first for anything that smells environmental** — no search results at all, a
|
|
760
814
|
service that will not start, an MCP server that dies on contact. It checks the things about this
|
|
761
815
|
machine that can stop Zikaron working and names what to change for each. The table below is for
|
|
@@ -864,6 +918,12 @@ than deleted, because both hold settings that are not Zikaron's. **All three set
|
|
|
864
918
|
the install writes three** — leaving `enabledMcpjsonServers` behind names two servers that no longer
|
|
865
919
|
exist, which loads nothing and breaks nothing but is not an uninstall.
|
|
866
920
|
|
|
921
|
+
**The guards** live only in `.claude/settings.local.json`: remove the `PreToolUse` and
|
|
922
|
+
`PostToolUse` hook groups whose command is `zikaron-guard`, and the `SessionStart` and
|
|
923
|
+
`SubagentStart` groups whose command is `zikaron-hook`. To keep the memory store and drop only the
|
|
924
|
+
guards, re-running the installer will not do it — an install never removes a selection — so delete
|
|
925
|
+
the two guard groups and the `--components …` arguments from the two start groups' command.
|
|
926
|
+
|
|
867
927
|
Note that `rm -rf .zikaron` takes the knowledge bases with it. They are rebuildable — an index is a
|
|
868
928
|
view onto files you still have — but rebuilding one takes minutes per corpus.
|
|
869
929
|
|
|
@@ -4,16 +4,14 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "zikaron"
|
|
7
|
-
# Semver,
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
# `design/distribution.md` §"The version scheme" is normative.
|
|
13
|
-
version = "0.3.0"
|
|
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
|
|
@@ -32,11 +30,11 @@ requires-python = ">=3.12"
|
|
|
32
30
|
dependencies = [
|
|
33
31
|
"aiosqlite==0.22.1",
|
|
34
32
|
"sqlite-vec==0.1.9",
|
|
35
|
-
"fastembed==0.8.
|
|
33
|
+
"fastembed==0.8.1",
|
|
36
34
|
# Direct, not transitive: `core/indexing/acquisition.py` calls `snapshot_download` itself, so
|
|
37
35
|
# that the revision and the digests are Zikaron's rather than whatever upstream head fastembed
|
|
38
36
|
# would resolve. §6 pins direct dependencies exactly.
|
|
39
|
-
"huggingface_hub==1.
|
|
37
|
+
"huggingface_hub==1.33.0",
|
|
40
38
|
# `zikaron-mcp` only. Deliberately not stdlib-only, unlike `zikaron-hook` — see
|
|
41
39
|
# coding-standards.md §6 for the cost-model reasoning (once per agent spawn, not once per
|
|
42
40
|
# message) and architecture.md §Components for the measured import cost.
|
|
@@ -45,7 +43,7 @@ dependencies = [
|
|
|
45
43
|
# changes how a client's connection — and therefore the session label this client adopts and
|
|
46
44
|
# reuses across calls — is carried. That is a transport change worth its own measurement, so
|
|
47
45
|
# the bump is deliberate rather than absorbed into an ordinary dependency refresh.
|
|
48
|
-
"fastmcp==
|
|
46
|
+
"fastmcp==4.0.10",
|
|
49
47
|
]
|
|
50
48
|
|
|
51
49
|
# Absent until now, which is why the PyPI page M30 will publish would have rendered blank. The
|
|
@@ -64,12 +62,13 @@ Homepage = "https://github.com/nathan-shapiro/Zikaron"
|
|
|
64
62
|
Repository = "https://github.com/nathan-shapiro/Zikaron"
|
|
65
63
|
Issues = "https://github.com/nathan-shapiro/Zikaron/issues"
|
|
66
64
|
|
|
67
|
-
# The
|
|
68
|
-
#
|
|
69
|
-
# `
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
65
|
+
# The commands a shipped harness config names — `zikaron-hook` and `zikaron-mcp` for either harness,
|
|
66
|
+
# `zikaron-guard` for Claude Code's guards — and the reason they are console scripts rather than
|
|
67
|
+
# `python -m` command lines: a hook entry's `command` and an `mcpServers` entry's `command` each need
|
|
68
|
+
# one absolute path, and a console script's shebang pins the interpreter Zikaron is installed into —
|
|
69
|
+
# which is also the interpreter start-if-absent will spawn the service with, via `sys.executable`.
|
|
70
|
+
# Measured, so the choice costs nothing: the two forms differ by about 1.4 ms median over a full hook
|
|
71
|
+
# process (architecture.md §"The install contract").
|
|
73
72
|
#
|
|
74
73
|
# `zikaron-service` is deliberately *not* here. No config names it: it is spawned by
|
|
75
74
|
# `sys.executable -m zikaron.service.main` from whichever client finds the socket absent, which is
|
|
@@ -84,17 +83,18 @@ Issues = "https://github.com/nathan-shapiro/Zikaron/issues"
|
|
|
84
83
|
zikaron = "zikaron.cli.main:main"
|
|
85
84
|
zikaron-hook = "zikaron.hook.main:main"
|
|
86
85
|
zikaron-mcp = "zikaron.mcp.main:main"
|
|
86
|
+
zikaron-guard = "zikaron.guard.main:main"
|
|
87
87
|
|
|
88
88
|
[project.optional-dependencies]
|
|
89
89
|
dev = [
|
|
90
|
-
"ruff==0.16.
|
|
90
|
+
"ruff==0.16.9",
|
|
91
91
|
"mypy==2.3.1",
|
|
92
92
|
"pytest==9.1.1",
|
|
93
93
|
"pytest-cov==7.1.0",
|
|
94
94
|
"pytest-asyncio==1.4.0",
|
|
95
95
|
# Property-based tests, for the places the design states a property rather than a case:
|
|
96
96
|
# chunking never loses content, and no chunk exceeds the budget it was cut to.
|
|
97
|
-
"hypothesis==6.168.
|
|
97
|
+
"hypothesis==6.168.3",
|
|
98
98
|
# Tests only, and never imported by shipped code. Two of Claude Code's four installed
|
|
99
99
|
# artefacts are YAML-frontmatter Markdown, and the installer emits that frontmatter by string
|
|
100
100
|
# formatting — so the only way to assert it is *valid* is to parse it with something that did
|
|
@@ -140,7 +140,7 @@ def test_the_project_table_still_holds_the_keys_a_later_table_can_swallow() -> N
|
|
|
140
140
|
still *in `[project]`*, which is the property an inserted table destroys.
|
|
141
141
|
"""
|
|
142
142
|
project = tomllib.loads((_ROOT / "pyproject.toml").read_text(encoding="utf-8"))["project"]
|
|
143
|
-
|
|
143
|
+
keys = ("name", "version", "readme", "license", "requires-python", "dependencies", "scripts")
|
|
144
|
+
for key in keys:
|
|
144
145
|
assert key in project, f"`{key}` has left [project] — a table header was inserted above it"
|
|
145
146
|
assert len(project["dependencies"]) == 5, "the runtime dependency list changed size"
|
|
146
|
-
assert set(project["scripts"]) == {"zikaron", "zikaron-hook", "zikaron-mcp"}
|
|
@@ -25,10 +25,18 @@ _ROOT: Final = Path(__file__).resolve().parent.parent
|
|
|
25
25
|
_SUBCOMMANDS: Final = ("init", "install", "knowledge", "doctor")
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
_SCRIPTS: Final[dict[str, str]] = tomllib.loads(
|
|
29
|
+
(_ROOT / "pyproject.toml").read_text(encoding="utf-8")
|
|
30
|
+
)["project"]["scripts"]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_the_front_door_is_a_declared_console_script() -> None:
|
|
34
|
+
assert NAME in _SCRIPTS
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.mark.parametrize("script", sorted(_SCRIPTS))
|
|
38
|
+
def test_every_console_script_resolves_to_something_callable(script: str) -> None:
|
|
39
|
+
module_path, _, attribute = _SCRIPTS[script].partition(":")
|
|
32
40
|
entry = getattr(importlib.import_module(module_path), attribute)
|
|
33
41
|
assert callable(entry)
|
|
34
42
|
|
|
@@ -143,8 +143,11 @@ def test_the_wheel_declares_every_console_script(built: tuple[Path, Path]) -> No
|
|
|
143
143
|
with zipfile.ZipFile(wheel) as archive:
|
|
144
144
|
(entry_points,) = [n for n in archive.namelist() if n.endswith("entry_points.txt")]
|
|
145
145
|
declared = archive.read(entry_points).decode()
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
scripts = tomllib.loads((_ROOT / "pyproject.toml").read_text(encoding="utf-8"))["project"][
|
|
147
|
+
"scripts"
|
|
148
|
+
]
|
|
149
|
+
for script in scripts:
|
|
150
|
+
assert f"{script} =" in declared, f"{script} is not in the built wheel"
|
|
148
151
|
|
|
149
152
|
|
|
150
153
|
def test_nothing_published_names_this_machine(built: tuple[Path, Path]) -> None:
|