graphite-code 1.0.0__tar.gz → 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. {graphite_code-1.0.0 → graphite_code-1.0.1}/ARCHITECTURE.md +6 -5
  2. {graphite_code-1.0.0 → graphite_code-1.0.1}/CHANGELOG.md +183 -0
  3. {graphite_code-1.0.0 → graphite_code-1.0.1}/CONTRIBUTING.md +11 -6
  4. {graphite_code-1.0.0 → graphite_code-1.0.1}/PKG-INFO +50 -22
  5. {graphite_code-1.0.0 → graphite_code-1.0.1}/README.md +49 -21
  6. {graphite_code-1.0.0 → graphite_code-1.0.1}/RELEASING.md +9 -0
  7. {graphite_code-1.0.0 → graphite_code-1.0.1}/pyproject.toml +35 -5
  8. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/__init__.py +1 -1
  9. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/cache.py +93 -3
  10. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/cli.py +129 -52
  11. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/graph.py +1 -1
  12. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/probe_process.py +16 -1
  13. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/replacement_audit.py +42 -37
  14. graphite_code-1.0.1/tests/test_cache_entry_pruning.py +245 -0
  15. graphite_code-1.0.1/tests/test_cli_reference.py +182 -0
  16. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_doctor.py +81 -15
  17. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_documentation.py +1 -1
  18. graphite_code-1.0.1/tests/test_mutation_tests.py +365 -0
  19. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_replacement_audit.py +6 -6
  20. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_synthetic_repo.py +36 -0
  21. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_verify_published_release.py +13 -0
  22. graphite_code-1.0.0/tests/test_cli_reference.py +0 -66
  23. {graphite_code-1.0.0 → graphite_code-1.0.1}/.gitignore +0 -0
  24. {graphite_code-1.0.0 → graphite_code-1.0.1}/LICENSE +0 -0
  25. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/__main__.py +0 -0
  26. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/_cleanup_worker.py +0 -0
  27. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/_win32_ctypes.py +0 -0
  28. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/activation.py +0 -0
  29. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/agent_hooks.py +0 -0
  30. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/agent_settings.py +0 -0
  31. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/analyze.py +0 -0
  32. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/answer_contract.py +0 -0
  33. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/bootstrap.py +0 -0
  34. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/buildlock.py +0 -0
  35. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/channel.py +0 -0
  36. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/cluster.py +0 -0
  37. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/config.py +0 -0
  38. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/context.py +0 -0
  39. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/daemon.py +0 -0
  40. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/daemon_health.py +0 -0
  41. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/daemon_launch.py +0 -0
  42. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/debt.py +0 -0
  43. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/dependency_install.py +0 -0
  44. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/detach.py +0 -0
  45. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/doctor.py +0 -0
  46. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/doctor_probes.py +0 -0
  47. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/engine_identity.py +0 -0
  48. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/export/__init__.py +0 -0
  49. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/export/html.py +0 -0
  50. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/export/json.py +0 -0
  51. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/export/md.py +0 -0
  52. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/extract/__init__.py +0 -0
  53. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/extract/ast.py +0 -0
  54. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/freshness.py +0 -0
  55. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/git.py +0 -0
  56. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/graph_io.py +0 -0
  57. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/health.py +0 -0
  58. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/hook_entry.py +0 -0
  59. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/hookinstall.py +0 -0
  60. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/hookshim.py +0 -0
  61. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/incident_ledger.py +0 -0
  62. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/ingest.py +0 -0
  63. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/init.py +0 -0
  64. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/io.py +0 -0
  65. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/launchd_agent.py +0 -0
  66. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/listing.py +0 -0
  67. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/llm.py +0 -0
  68. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/llm_probe.py +0 -0
  69. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/mcp.py +0 -0
  70. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/mcp_server.py +0 -0
  71. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/natural_query.py +0 -0
  72. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/overlays.py +0 -0
  73. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/probe_workspace.py +0 -0
  74. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/process_contracts.py +0 -0
  75. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/provider_observer.py +0 -0
  76. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/py.typed +0 -0
  77. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/query.py +0 -0
  78. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/query_plan.py +0 -0
  79. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/resolve.py +0 -0
  80. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/review.py +0 -0
  81. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/__init__.py +0 -0
  82. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/approval.py +0 -0
  83. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/classifier.py +0 -0
  84. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/claude_executor.py +0 -0
  85. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/claude_probe.py +0 -0
  86. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/cli_identity.py +0 -0
  87. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/codex_executor.py +0 -0
  88. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/codex_probe.py +0 -0
  89. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/context_builder.py +0 -0
  90. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/contracts.py +0 -0
  91. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/diff_policy.py +0 -0
  92. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/edit_apply.py +0 -0
  93. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/effort.py +0 -0
  94. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/lifecycle.py +0 -0
  95. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/lifecycle_operator.py +0 -0
  96. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/lifecycle_service.py +0 -0
  97. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/lifecycle_storage.py +0 -0
  98. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/ollama_executor.py +0 -0
  99. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/ollama_probe.py +0 -0
  100. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/openrouter_executor.py +0 -0
  101. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/openrouter_probe.py +0 -0
  102. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/policy.py +0 -0
  103. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/probe_runner.py +0 -0
  104. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/process_runner.py +0 -0
  105. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/profiles.py +0 -0
  106. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/prompt.py +0 -0
  107. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/registry.py +0 -0
  108. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/route_pool.py +0 -0
  109. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/route_pool_execution.py +0 -0
  110. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/schema_validation.py +0 -0
  111. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/service.py +0 -0
  112. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/settings.py +0 -0
  113. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/shadow.py +0 -0
  114. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/storage.py +0 -0
  115. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/telemetry.py +0 -0
  116. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/worktree.py +0 -0
  117. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/zai_edit.py +0 -0
  118. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/zai_executor.py +0 -0
  119. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/zai_probe.py +0 -0
  120. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/savings.py +0 -0
  121. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/systemd_unit.py +0 -0
  122. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/ts_bridge.py +0 -0
  123. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/ts_resolver.mjs +0 -0
  124. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/typescript_activation.py +0 -0
  125. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/usage_ledger.py +0 -0
  126. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/validation.py +0 -0
  127. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/watch.py +0 -0
  128. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/windows_job.py +0 -0
  129. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/windows_startup.py +0 -0
  130. {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/windows_task.py +0 -0
  131. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/conftest.py +0 -0
  132. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/data/sqloracle/blindspots.py.txt +0 -0
  133. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/data/sqloracle/round69.py.txt +0 -0
  134. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/fake_clis/fake_cli.py +0 -0
  135. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/fixtures/provider_lifecycle_schema_v1.sql +0 -0
  136. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/fixtures/routing_schema_v2_ca77600.sql +0 -0
  137. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/fixtures/routing_schema_v3_94eb333.sql +0 -0
  138. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/fixtures/routing_schema_v4_lifecycle_migration.sql +0 -0
  139. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_activation.py +0 -0
  140. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_activation_backstop.py +0 -0
  141. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_agent_hook_activation.py +0 -0
  142. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_agent_hooks.py +0 -0
  143. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_agent_settings.py +0 -0
  144. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_answer_contract.py +0 -0
  145. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_arrow_and_constructor_binding.py +0 -0
  146. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_atomic_write.py +0 -0
  147. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_bootstrap.py +0 -0
  148. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_build_detach.py +0 -0
  149. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_buildlock.py +0 -0
  150. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cache_engine_identity.py +0 -0
  151. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cache_file_set.py +0 -0
  152. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cache_pruning.py +0 -0
  153. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_call_graph.py +0 -0
  154. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_cli.py +0 -0
  155. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_core.py +0 -0
  156. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_lock.py +0 -0
  157. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_mcp.py +0 -0
  158. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_register.py +0 -0
  159. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_report.py +0 -0
  160. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_status.py +0 -0
  161. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_class_field_arrow_binding.py +0 -0
  162. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cli_channel.py +0 -0
  163. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cli_version.py +0 -0
  164. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_compare_dist.py +0 -0
  165. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_configuration_reference.py +0 -0
  166. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_context.py +0 -0
  167. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cwd_relative_config.py +0 -0
  168. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cycle_search.py +0 -0
  169. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon.py +0 -0
  170. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_activation.py +0 -0
  171. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_build_lock.py +0 -0
  172. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_child_lock.py +0 -0
  173. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_engine_staleness.py +0 -0
  174. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_health.py +0 -0
  175. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_health_activation.py +0 -0
  176. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_launch.py +0 -0
  177. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_service_cli.py +0 -0
  178. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_debt.py +0 -0
  179. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_destructured_binding.py +0 -0
  180. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_determinism.py +0 -0
  181. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_dispatch_evidence.py +0 -0
  182. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_doctor_agent_hooks.py +0 -0
  183. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_doctor_hooks.py +0 -0
  184. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_doctor_managed_docs.py +0 -0
  185. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_edit_apply.py +0 -0
  186. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_engine_identity.py +0 -0
  187. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_exit_codes_reference.py +0 -0
  188. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_external_calls.py +0 -0
  189. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_git_security.py +0 -0
  190. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_go_rust.py +0 -0
  191. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_graph_io.py +0 -0
  192. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_graph_provider_isolation.py +0 -0
  193. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_hardening.py +0 -0
  194. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_health.py +0 -0
  195. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_hook_entry.py +0 -0
  196. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_hook_template.py +0 -0
  197. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_hookinstall.py +0 -0
  198. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_hookshim.py +0 -0
  199. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_html_security.py +0 -0
  200. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_incident_ledger.py +0 -0
  201. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_init.py +0 -0
  202. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_init_activation_doctrine.py +0 -0
  203. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_init_hooks.py +0 -0
  204. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_init_validation_exit.py +0 -0
  205. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_launchd_agent.py +0 -0
  206. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_lifecycle_operator.py +0 -0
  207. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_listing.py +0 -0
  208. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_listing_surfaces.py +0 -0
  209. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_llm.py +0 -0
  210. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_mcp.py +0 -0
  211. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_method_dispatch_scope.py +0 -0
  212. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_monorepo.py +0 -0
  213. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_natural_query.py +0 -0
  214. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_node_identity.py +0 -0
  215. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_overlays.py +0 -0
  216. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_path_leak_fixture.py +0 -0
  217. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_probe_diagnostics.py +0 -0
  218. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_probe_workspace.py +0 -0
  219. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_claude_probe.py +0 -0
  220. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_codex_probe.py +0 -0
  221. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_lifecycle.py +0 -0
  222. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_lifecycle_service.py +0 -0
  223. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_lifecycle_storage.py +0 -0
  224. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_observer.py +0 -0
  225. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_ollama_probe.py +0 -0
  226. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_openrouter_probe.py +0 -0
  227. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_probe_runner.py +0 -0
  228. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_public_surface.py +0 -0
  229. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_published_schemas.py +0 -0
  230. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_python_resolver.py +0 -0
  231. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_query_plan.py +0 -0
  232. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_reliability.py +0 -0
  233. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_resolve.py +0 -0
  234. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_review.py +0 -0
  235. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_route_pool.py +0 -0
  236. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_approval.py +0 -0
  237. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_benchmark.py +0 -0
  238. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_classifier.py +0 -0
  239. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_claude_executor.py +0 -0
  240. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_cli.py +0 -0
  241. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_cli_contracts.py +0 -0
  242. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_cli_recovery.py +0 -0
  243. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_codex_executor.py +0 -0
  244. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_context.py +0 -0
  245. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_contracts.py +0 -0
  246. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_diff_policy.py +0 -0
  247. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_executor.py +0 -0
  248. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_openrouter_executor.py +0 -0
  249. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_policy.py +0 -0
  250. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_process_runner.py +0 -0
  251. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_profiles.py +0 -0
  252. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_registry.py +0 -0
  253. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_schema_validation.py +0 -0
  254. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_security.py +0 -0
  255. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_service.py +0 -0
  256. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_shadow.py +0 -0
  257. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_storage.py +0 -0
  258. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_telemetry.py +0 -0
  259. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_worktree.py +0 -0
  260. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_zai_executor.py +0 -0
  261. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_zai_probe.py +0 -0
  262. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_savings.py +0 -0
  263. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_search.py +0 -0
  264. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_smoke.py +0 -0
  265. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_sqloracle.py +0 -0
  266. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_systemd_unit.py +0 -0
  267. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_typescript_activation.py +0 -0
  268. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_typescript_resolver.py +0 -0
  269. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_usage_ledger.py +0 -0
  270. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_verify_artifact.py +0 -0
  271. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_watch.py +0 -0
  272. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_windows_startup.py +0 -0
  273. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_windows_task.py +0 -0
  274. {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_zai_edit.py +0 -0
@@ -24,10 +24,10 @@ The implementation stages are:
24
24
  1. **Collection — `ingest.py`, `config.py`, `git.py`.** Configuration establishes file-count and file-size limits and the cache and output locations. Ingestion normalizes project-relative paths, resolves candidates beneath the repository root, skips unsafe or ineligible files, and sorts accepted entries. Git-backed enumeration uses `GitRunner` with a trusted executable outside the repository, an argument vector, no shell, a filtered Git environment, a timeout, and a stdout cap. The filesystem fallback is also capped by configured file limits, but it does not provide every process control because no child process is involved.
25
25
  2. **Extraction — `extract/ast.py`, `cache.py`, `ts_bridge.py`, `ts_resolver.mjs`.** Per-language Tree-sitter extractors handle JavaScript/TypeScript, Python, Go, and Rust, while unsupported or unavailable parsers degrade to a file-level record. Extraction emits symbols, imports, calls, and containment edges in deterministic order. The content-addressed cache avoids repeated AST work. TypeScript/JavaScript may additionally use the Node compiler bridge for compiler-backed module resolution; bridge failure falls back to heuristic resolution rather than making Node mandatory.
26
26
  3. **Resolution — `resolve.py`.** `SourceIndex` builds the set of normalized, project-relative source identities, reads TypeScript aliases and workspace package entry points, prefers compiler-backed TypeScript results when available, and otherwise applies bounded heuristics. Global merge logic also resolves supported call identities and deterministically removes duplicates.
27
- 4. **Graph and analysis — `graph.py`, `cluster.py`, `analyze.py`, `query.py`.** `graph.py` constructs a NetworkX `DiGraph` after sorting nodes and edges and normalizing IDs. Analysis filters to project nodes where appropriate and returns bounded, ordered results. Community detection constructs a deterministic undirected view and uses the configured seed (42 by default). JSON conversion preserves the graph's deterministic insertion order.
27
+ 4. **Graph and analysis — `graph.py`, `cluster.py`, `analyze.py`, `query.py`.** `graph.py` constructs a NetworkX `DiGraph` after sorting nodes and edges and normalizing IDs. Analysis filters to project nodes where appropriate and returns bounded, ordered results; the cycle report is a bounded search (per strongly connected component, one length level at a time up to length 8, under a 10 000-cycle budget) and `analysis.cycle_search` records whether the enumeration completed exactly or was truncated, so a repository with dense import cycles cannot make a build exhaust memory. Community detection constructs a deterministic undirected view and uses the configured seed (42 by default). JSON conversion preserves the graph's deterministic insertion order.
28
28
  5. **Validation and review — `validation.py`, `context.py`, `review.py`.** Bundle validation checks structural types, node and edge identity, referential integrity, metadata counts, and unsafe `source_file` paths. Review validates a supplied bundle before deriving graph impact evidence; its Git discovery also normalizes status records and rejects malformed or unsafe paths. By contrast, `cmd_query`, `cmd_impact`, `cmd_context`, and `GraphiteMCPServer._load` currently read JSON and call `graph_from_json` without `validate_graph_bundle` or a bounded-read helper. Those direct consumers therefore rely on callers to supply an already validated, reasonably sized artifact.
29
29
  6. **Export — `export/json.py`, `export/md.py`, `export/html.py`, `io.py`.** Exporters consume only canonical graph, cluster, analysis, and manifest data. JSON serialization provides the data encoding; HTML separately JSON-encodes script data, escapes `<`, `>`, and `&`, HTML-escapes the title, and uses text DOM APIs for runtime labels. Text and JSON outputs use temporary files, `fsync`, and `os.replace` for atomic replacement of each file.
30
- 7. **Operations — `watch.py`, `daemon.py`, `daemon_health.py`, `bootstrap.py`, `init.py`, `windows_task.py`, `windows_startup.py`.** These modules watch for changes, maintain multi-project daemon status, evaluate health, generate integration instructions, and manage platform startup. Watch and daemon canonicalize inherited configuration; daemon child builds use fixed `--llm none` argv and a provider-scrubbed environment.
30
+ 7. **Operations — `watch.py`, `daemon.py`, `daemon_health.py`, `bootstrap.py`, `init.py`, `daemon_launch.py`, `windows_task.py`, `windows_startup.py`, `systemd_unit.py`, `launchd_agent.py`.** These modules watch for changes, maintain multi-project daemon status, evaluate health, generate integration instructions, and manage platform supervision. `daemon_launch.py` holds the one daemon argument vector (`python -P -m graphite daemon <base> …`); the Windows scheduled task, the Windows Startup-folder launcher, the systemd user unit and the launchd agent are each rendered from it, so every supervisor starts the same bounded, zero-LLM daemon under `-P`. Watch and daemon canonicalize inherited configuration; daemon child builds use fixed `--llm none` argv and a provider-scrubbed environment.
31
31
  8. **Provider lifecycle — `routing/lifecycle.py`, `routing/lifecycle_storage.py`, `routing/lifecycle_service.py`, and `routing/lifecycle_operator.py`.** Runtime observations, compatibility decisions, lifecycle authority, and invalidations live in an isolated database. Operator reads use an existing-database, query-only connection and bounded public records. Policy and verification preparation create non-activating content-hashed candidates; neither surface invokes a provider.
32
32
  9. **Optional overlays — `overlays.py` and `llm.py`.** Provider adapters may consume an already-built, fresh, validated graph only through `graphite overlay build`. The overlay manifest binds the canonical bundle fingerprint, exact lifecycle/model/routing identities, limits, creation time, outcome, and schema. Identity-derived contained paths, restrictive permissions, content-addressed payloads, and manifest-last atomic replacement isolate the output below `graph-out/overlays/`. Overlay staleness is independent of canonical freshness and cannot grant graph or routing authority.
33
33
 
@@ -42,9 +42,10 @@ The implementation stages are:
42
42
  | Validation and evidence | `validation.py`, `context.py`, `review.py` | Validate bundles and derive review/context evidence | Graph structures; review may use the Git adapter |
43
43
  | Export | `export/json.py`, `export/md.py`, `export/html.py`, `io.py` | Encode and atomically replace individual artifacts | Validated graph, analysis, clusters, manifest |
44
44
  | Optional model overlays | `overlays.py`, `llm.py` | Validate identity and canonical freshness; produce fingerprint-bound, non-authoritative annotations outside canonical artifacts | Existing canonical graph, explicit provider configuration, network only when separately authorized |
45
- | Operations and integration | `watch.py`, `daemon.py`, `daemon_health.py`, `bootstrap.py`, `init.py`, `windows_task.py`, `windows_startup.py` | Freshness, daemon health, generated instructions, and OS startup | Public core operations and explicit platform/process boundaries |
45
+ | Operations and integration | `watch.py`, `daemon.py`, `daemon_health.py`, `bootstrap.py`, `init.py`, `daemon_launch.py`, `windows_task.py`, `windows_startup.py`, `systemd_unit.py`, `launchd_agent.py` | Freshness, daemon health, generated instructions, and OS supervision on Windows, Linux and macOS | Public core operations and explicit platform/process boundaries |
46
+ | Platform shims | `_win32_ctypes.py`, `_cleanup_worker.py` | Typed call-time views of platform-only stdlib surfaces (Win32 ctypes, POSIX-only `os` members) so the portable core type-checks on every OS without `sys.platform` guards | Standard library only |
46
47
 
47
- The intended dependency direction is observable in current imports but is not enforced by a dedicated architecture linter. CLI and MCP adapt inputs; portable core modules do not import those UI entry points. Export consumes canonical graph and analysis data; extraction does not depend on exporters. Canonical graph construction, validation, and read operations do not depend on model providers. Windows startup and task management remain outside the portable core. External execution crosses explicit subprocess boundaries; Git uses the hardened `GitRunner`, while the TypeScript and Windows adapters have their own, not necessarily identical, controls. Contributors must preserve these directions and add tests if a boundary becomes mechanically important.
48
+ The intended dependency direction is observable in current imports but is not enforced by a dedicated architecture linter. CLI and MCP adapt inputs; portable core modules do not import those UI entry points. Export consumes canonical graph and analysis data; extraction does not depend on exporters. Canonical graph construction, validation, and read operations do not depend on model providers. Platform supervision — the Windows scheduled task and Startup launcher, the systemd user unit, the launchd agent — remains outside the portable core. External execution crosses explicit subprocess boundaries; Git uses the hardened `GitRunner`, while the TypeScript and platform-supervisor adapters have their own, not necessarily identical, controls. Contributors must preserve these directions and add tests if a boundary becomes mechanically important.
48
49
 
49
50
  ## Trust boundaries
50
51
 
@@ -86,7 +87,7 @@ Treat paths, bytes, symlinks, encodings, file counts, and file sizes as hostile.
86
87
 
87
88
  **Process boundary.**
88
89
 
89
- Git, Node/TypeScript, and Windows task/startup integrations execute outside Python. `GitRunner` is the strongest current adapter: fixed executable discovery outside the repository, argv execution with `shell=False`, disabled stdin/stderr, filtered `GIT_*` environment, timeout, stdout cap, and typed sanitized failures. The TypeScript bridge uses argv, `subprocess.run`, captured output, a configured timeout, and a 500-character diagnostic cap, but it currently inherits the environment and does not impose an explicit output-byte cap. Windows adapters are platform-specific and must be reviewed on their own controls. Do not generalize Git's isolation guarantees to every subprocess.
90
+ Git, Node/TypeScript, and the platform supervisors (`schtasks`, `systemctl --user`, `launchctl`) execute outside Python. `GitRunner` is the strongest current adapter: fixed executable discovery outside the repository, argv execution with `shell=False`, disabled stdin/stderr, filtered `GIT_*` environment, timeout, stdout cap, and typed sanitized failures. The TypeScript bridge uses argv, `subprocess.run`, captured output, a configured timeout, and a 500-character diagnostic cap, but it currently inherits the environment and does not impose an explicit output-byte cap. The supervisor adapters are platform-specific, take an injected runner in tests, and must be reviewed on their own controls. Do not generalize Git's isolation guarantees to every subprocess.
90
91
 
91
92
  **Artifact and browser boundary.**
92
93
 
@@ -13,6 +13,189 @@ machine-checkable identity; the version is for humans.
13
13
 
14
14
  [Keep a Changelog]: https://keepachangelog.com/en/1.1.0/
15
15
 
16
+ ## [1.0.1] — 2026-09-05
17
+
18
+ A patch release. Measured against the deployed 1.0.0 engine on this repository,
19
+ the tree produces the same graph: 7260 of 7260 node ids survive, 20700 of 20700
20
+ edge triples unchanged, every relation count equal, `analysis.cycles` identical.
21
+ Only the engine fingerprint moves, because graphite's own bytes did.
22
+
23
+ ### Changed
24
+
25
+ **Vendor-neutral wording throughout the replacement audit and docs.** The
26
+ README opening, the `audit-replacement` help and reference text,
27
+ `skill/SKILL.md` and the audit's own messages no longer name the legacy
28
+ graph tool, and the README's opening comparative against it — an unmeasured
29
+ claim dating to the initial commit (`fd58583`) — is removed rather than
30
+ defended. In the audit's report, which is not a `schema_version`-stable
31
+ surface, the `graphify` block is renamed `legacy` and the warning codes
32
+ `graphify_paths_exist`, `graphify_text_references` and
33
+ `graphify_gitignore_entries` become `legacy_paths_exist`,
34
+ `legacy_text_references` and `legacy_gitignore_entries`. Detection is
35
+ unchanged: the on-disk path patterns and the text-scan needle still match
36
+ the legacy tool's literal artifact names — the one place the name must
37
+ remain for the audit to find anything.
38
+
39
+ ### Fixed
40
+
41
+ **The extraction cache grew without bound inside a partition (#66).** #23
42
+ reclaims whole partitions a build can never read again and left the one it
43
+ uses alone. Entries are keyed on the file's content hash, so every edit that
44
+ triggers a rebuild wrote a new entry and orphaned the previous one, and
45
+ nothing ever removed an orphan: a consumer checkout rebuilt by the daemon on
46
+ every change reached 15,406 entries / 419 MB in a single partition, 11,592 of
47
+ them from four days, against 1,780 / 62 MB for graphite's own tree on the
48
+ same engine. Same rule as #23, one level down -- reachability, not age or
49
+ size: a `Cache` now records every key it read (and found) or wrote, and after
50
+ a build has extracted the tree and built its graph, `prune_unreachable_entries`
51
+ deletes every other entry in the partition, reporting
52
+ `[graphite] reclaimed N unreachable cache entries (X MB)` when it removed any.
53
+ Older content checked out later re-extracts once (performance, never
54
+ correctness). Safe without the build lock: `read` already treats a vanished
55
+ file as a miss, so a concurrent reader re-extracts rather than fails. A build
56
+ that touched nothing prunes nothing, only the exact `<2 hex>/<64 hex>.json`
57
+ shape the cache writes is eligible, and a per-entry failure (a Windows handle
58
+ race) is swallowed.
59
+
60
+ **The deferred stdin close never fired on Linux or macOS.** `run_bounded_process`
61
+ reads the child's pipes with a fixed-size read, and its two transports hand
62
+ that reader different objects: on Windows a raw `io.FileIO`, whose `read(n)`
63
+ returns whatever the child has written, and on POSIX a default `Popen` pipe,
64
+ a `BufferedReader` whose `read(n)` keeps reading until it has n bytes or EOF.
65
+ Off Windows the reader therefore saw nothing until the child exited, the
66
+ `stdin_close_when` predicate never saw its marker, and every deferred close
67
+ was the budget fallback -- so the #29 fix was inert there and the doctor's MCP
68
+ deep probe spent its whole budget on every POSIX run. The reader now uses
69
+ `read1` on buffered pipes; the Windows path is unchanged. The tests that
70
+ pinned the deferral could not fail (one matched a marker that text-mode
71
+ stdout writes as CRLF on Windows, the other's lower bound was satisfied by
72
+ the child's own sleep) and now kill a never-defer mutant; the interval test
73
+ that blocked the pre-push gate measures from the close instead of from
74
+ launch, against the child's own life rather than a 0.25s constant.
75
+
76
+ **The post-publication verifier's provenance arm asked an endpoint that
77
+ never carries provenance.** `scripts/verify_published_release.py` read
78
+ `urls[].provenance` from PyPI's legacy `/pypi/<project>/<version>/json`
79
+ API, which has no such key, so the arm reported "no provenance" for 1.0.0
80
+ while the Integrity API was already serving both GitHub attestation bundles
81
+ (`jared0565/graphite`, `publish.yml`). The arm now reads the PEP 691 Simple
82
+ JSON index (`Accept: application/vnd.pypi.simple.v1+json`), where PEP 740
83
+ publishes a `provenance` URL per file; a test pins the endpoint so a
84
+ regression to the legacy API fails. Re-run against 1.0.0: 6 of 6 arms.
85
+
86
+ **Three findings from aramid's `llm-review` tier on the CI workflow and the
87
+ benchmark, all confirmed and closed:**
88
+
89
+ - The `coverage_floor` dispatch input could *lower* the floor for one run,
90
+ so a dispatched run could report green against a weaker gate than the
91
+ committed one. The enforcing step now refuses any requested value that is
92
+ not an integer at or above the committed `COVERAGE_FLOOR`; a dispatch can
93
+ only raise it (the negative control is unchanged). Proven with a fake
94
+ coverage across six arms: empty, 84 and 83 pass; 80, `abc` and -5 fail
95
+ before coverage is read.
96
+ - `test_core_probe_cleanup_timeout_uses_single_global_slot_and_recovers`
97
+ raced its 0.5 s probe budget against runner load (#65): more than 0.4 s of
98
+ scheduling before the workspace lease is acquired yields a pure `timeout`,
99
+ after it a `cleanup_timeout` carrying `masked_*` keys — two CI failures in
100
+ three runs on one day, both shapes reproduced with a paced fake clock. The
101
+ test now freezes its injected `_clock` like the sibling probe tests (the
102
+ subject is the classification of a hung cleanup, not phase pacing; the
103
+ cleanup join still runs on real time), and the frozen-clock test still
104
+ kills both guarding mutants: a hung cleanup reported as `None`, and a
105
+ probe slot that never releases.
106
+ - The `security` job's self-check asserted only that gitleaks and semgrep
107
+ ran, while the step's name claimed typecheck and a dependency audit. The
108
+ labels were measured from the job's own `prepush.json` artifact
109
+ (`gitleaks, mypy, python.exe, semgrep, shadow`): the assertion now covers
110
+ every configured scanner, and the step name, `SECURITY.md` and
111
+ `CONTRIBUTING.md` no longer claim a dependency audit — no gate run on
112
+ either machine has ever emitted one, although `aramid doctor` lists
113
+ pip-audit as present (reported to aramid). Measuring this exposed two
114
+ worse things: under aramid 0.6.0 the CI typecheck slot had **never run**
115
+ in `--all` mode (no `mypy` in `tools_ran`, nothing degraded) and the old
116
+ assertion called that clean; under 0.6.1 it runs over every `.py`, and
117
+ the job passed with exit 0 while its own report carried 786 block-tier
118
+ findings that the same report fails with on the maintainer's machine
119
+ (exit 1). Discriminated on the first run under the 0.7.0 pin (33286250634):
120
+ still 786 block-tier findings and exit 0 with CI's empty ledger, so
121
+ aramid's exit depends on ledger presence — `.aramid/` is gitignored, so
122
+ a fresh checkout cannot be gated by exit status at all. aramid confirmed
123
+ the mechanism from its code (channel round 151): its **fresh-ledger
124
+ rule** — the first pre-push run on a ledger with no baseline writes one
125
+ and downgrades findings the ratchet alone escalated to exit 0, so every
126
+ CI checkout is "the first run" — and from 0.7.1 the report says so
127
+ (`fresh_ledger_baseline`, `grandfathered`; both gate steps print them).
128
+ Both CI gate steps now
129
+ read the verdict from the report itself: any block-tier finding from a
130
+ non-mypy scanner, or from mypy inside the project's type-gate scope
131
+ (`src/graphite`), fails the step regardless of the exit status; mypy
132
+ findings on the deliberately untyped `tests/`, `scripts/` and
133
+ `benchmarks/` trees are counted and printed.
134
+ - `benchmarks/build_benchmark.py` prepended the repository root to
135
+ `sys.path` to import its sibling — the shape the `-P` launch contract
136
+ forbids. It loads `synthetic_repo.py` by location now, CI runs it under
137
+ `-P`, and two tests pin the shape (no `sys.path` access in the module; the
138
+ script starts under `-P`).
139
+
140
+ ### Changed
141
+
142
+ - CI pins `aramid==0.7.2`, the tool this machine runs (channel round 157;
143
+ 0.7.0 and 0.7.1 were pinned briefly at rounds 148 and 152). 0.7.2 fixes
144
+ the tests-slot skip-streak false alarm this repository reported — the
145
+ registry key `tests` rode into `run_started.expected` beside the slot's
146
+ label, so `status` counted every pre-push run as a skipped suite (channel
147
+ rounds 155–157) — and stamps `run_id`/`recorded` in the check report, so
148
+ a `--no-record` measurement is distinguishable from a recorded one.
149
+ 0.7.1's typecheck slot honours
150
+ `[tool.mypy] files`, so the 683 mypy rows that a whole-tree measurement
151
+ under 0.7.0 had written into the maintainer's ledger for `tests/` (675)
152
+ and `scripts/` (8) are retired with `ledger resolve --out-of-scope`, each
153
+ carrying the reason.
154
+ The two `mypy:syntax` ledger rows that 0.6.1 left unresolvable were NOT
155
+ retired with `ledger resolve --out-of-scope` as first written here: it
156
+ refused them (`is not open (status=fixed)`), because aramid's gate had
157
+ already marked them `fixed` on a push that ran mypy over other files
158
+ without opening `ci.yml` — a defect in aramid 0.6.1's examined-set
159
+ stamping, fixed on aramid's `main` (`e65f296`) for 0.7.1. The rows stay
160
+ `fixed`, the log being append-only; channel round 151 is their record.
161
+ - mypy's configuration is back under `[tool.mypy]` in `pyproject.toml` and
162
+ `setup.cfg` is gone. It had moved there only because aramid 0.6.0's
163
+ typecheck runner armed on `[tool.mypy]` and then fed every changed file to
164
+ mypy; aramid 0.6.1 hands mypy only `.py`/`.pyi` (channel round 144), so
165
+ the CI pin is now `aramid==0.6.1` and the two `mypy:syntax` suppression
166
+ entries that bridged the defect are deleted rather than kept — a
167
+ workaround that outlives its root cause misdirects the next reader.
168
+
169
+ ### Documentation
170
+
171
+ - **The generated CLI reference now renders nested subcommands.**
172
+ `scripts/gen_cli_reference.py` walked only the top level of the parser,
173
+ so the twenty-four commands that live one level down — under `route`,
174
+ `lifecycle`, `channel`, `incidents` and `overlay` — and every option they
175
+ own (`route reconcile --attempt-id`, for one) were absent from
176
+ `docs/reference/cli.md`, and the lockstep test could not see them drift.
177
+ Each nested command now has its own section under its group, and
178
+ `tests/test_cli_reference.py` requires every nested command and every
179
+ option it declares to appear there.
180
+ - **Every CLI argument now declares help text.** Rendering the nested
181
+ commands exposed sixty-two arguments with none — every nested `--json`,
182
+ the `lifecycle policy prepare` and `verification prepare` inputs,
183
+ `route accept|reject|cleanup|review --task-id`, `record-outcome`'s
184
+ flags, `reconcile --attempt-id`, `policy --promote/--rollback`, the
185
+ `incidents ack|resolve` positionals and options — so both `--help` and
186
+ the reference were silent about them. Each now says what it takes and
187
+ what it binds to; a test walks the whole parser and fails on any
188
+ argument without help, so none can be added back.
189
+ - New [user guide](docs/user-guide.md) and [knowledge base](docs/knowledge-base.md).
190
+ - README: installation is `pip install graphite-code` (it had still said
191
+ `git clone` + `pip install -e .`, wrong since the 0.3.0 wheel), the `-P`
192
+ launch rule is explained where the command is introduced, the MCP
193
+ examples launch with `-P`, and a documentation index points at every
194
+ support page. CONTRIBUTING puts the dev environment outside the clone
195
+ and lists what CI enforces. ARCHITECTURE covers the platform
196
+ supervisors and the bounded cycle search. The Claude Code skill is
197
+ machine-neutral and versioned 1.0.0.
198
+
16
199
  ## [1.0.0] — 2026-08-29
17
200
 
18
201
  The production-grade release. Nothing here is a claim CI cannot turn red:
@@ -4,17 +4,19 @@ Contributions should be focused, reviewable changes that preserve Graphite's det
4
4
 
5
5
  ## Development setup
6
6
 
7
- Graphite requires Python 3.11 or newer, Git, and an isolated virtual environment. Clone and enter the repository using paths appropriate for your system:
7
+ Graphite requires Python 3.11–3.14, Git, and an isolated virtual environment **outside the clone**. Clone and enter the repository using paths appropriate for your system, then create the environment beside it rather than inside it:
8
8
 
9
9
  ```bash
10
10
  git clone https://github.com/jared0565/graphite.git
11
11
  cd graphite
12
- python -m venv .venv
12
+ python -m venv ../.venvs/graphite-dev
13
13
  ```
14
14
 
15
+ Two reasons for the location. An environment inside the checkout is read by the MCP trusted-source probe as an import shadow of the repository it was asked to trust, so `doctor --deep` reports it. And the release checks (`aramid.toml`, the CI `security` job) run the test suite through exactly that interpreter, `../.venvs/graphite-dev`, so that the suite tests the editable clone rather than whatever `graphite-code` wheel the machine interpreter has installed — a green run against the wrong distribution proves nothing.
16
+
15
17
  If you contribute from a fork, clone the fork's verified URL instead. Keep URLs and other environment-specific values outside shell metacharacters.
16
18
 
17
- Activate `.venv` using the command for your shell. Before installing already-declared extras, inspect `pyproject.toml` and confirm the exact extra and dependency names. Then install the declared development extra:
19
+ Activate the environment using the command for your shell. Before installing already-declared extras, inspect `pyproject.toml` and confirm the exact extra and dependency names. Then install the declared development extra:
18
20
 
19
21
  ```bash
20
22
  python -m pip install -e ".[dev]"
@@ -87,15 +89,18 @@ Run a focused test while iterating. Replace the placeholder path with the test m
87
89
  python -m pytest tests/test_relevant_area.py -q
88
90
  ```
89
91
 
90
- Before requesting review, run all required checks:
92
+ Before requesting review, run all required checks through the dev environment's interpreter:
91
93
 
92
94
  ```bash
93
95
  python -m ruff check .
94
- python -m pytest -q
96
+ python -m mypy # [tool.mypy] in pyproject.toml; 0 errors is the gate
97
+ python -m pytest -q -rs # -rs: a skip is visible, not a silent pass
95
98
  python -m graphite --help
96
99
  ```
97
100
 
98
- Focused tests shorten the feedback loop; they do not replace the full Ruff, pytest, and CLI smoke checks. Add behavior-level tests for new or changed contracts and ensure failures are meaningful rather than dependent on local machine state.
101
+ Focused tests shorten the feedback loop; they do not replace the full Ruff, mypy, pytest, and CLI smoke checks. Add behavior-level tests for new or changed contracts and ensure failures are meaningful rather than dependent on local machine state.
102
+
103
+ What CI enforces on every push and pull request (`.github/workflows/ci.yml`): a `lint` job (ruff, mypy, the generated CLI reference in sync); a `test` matrix of Windows, Linux and macOS × Python 3.11–3.14 in which **every cell gates**; a `security` job that runs the same aramid pre-commit and pre-push gates as the local hooks (gitleaks, semgrep, ruff security rules, the repo-root shadow check, mypy, the suite) and asserts from the gate's JSON report that each scanner actually ran; the `coverage` floor; a `benchmark` job against the synthetic corpus; and an `artifact` job that builds the distribution twice and requires byte-identical results. The local git hooks are installed by `aramid` from the committed `aramid.toml`; do not push with `--no-verify`.
99
104
 
100
105
  Doctor changes require focused tests for stable doctor JSON, deterministic ordering, redaction, end-to-end deadlines, process cleanup, missing tools, and optional semantics. Cover both successful and adversarial outcomes. Cross-platform behavior must have Windows and POSIX coverage; use narrowly scoped platform skips only when an operating-system primitive truly has no counterpart, and test the portable contract on every platform.
101
106
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: graphite-code
3
- Version: 1.0.0
3
+ Version: 1.0.1
4
4
  Summary: Local-first, zero-LLM knowledge graph extraction for codebases.
5
5
  Project-URL: Homepage, https://github.com/jared0565/graphite
6
6
  Project-URL: Repository, https://github.com/jared0565/graphite
@@ -46,7 +46,22 @@ Description-Content-Type: text/markdown
46
46
 
47
47
  # Graphite
48
48
 
49
- Local-first, deterministic knowledge graph extraction for codebases. A safer, faster, cheaper replacement for `graphify`.
49
+ Local-first, deterministic knowledge graph extraction for codebases — zero-LLM, daemon-maintained, agent-agnostic.
50
+
51
+ **Status: 1.0.1, production/stable.** Published on PyPI as
52
+ [`graphite-code`](https://pypi.org/project/graphite-code/) with PEP 740
53
+ attestations; supported on Windows, Linux and macOS with Python 3.11–3.14
54
+ (every cell gates CI). What 1.x promises — CLI, JSON outputs, `graph.json`,
55
+ configuration, exit codes, the launch contract — is in
56
+ [docs/compatibility.md](docs/compatibility.md).
57
+
58
+ ## Documentation
59
+
60
+ - [User guide](docs/user-guide.md) — install, build the first graph, ask questions, onboard a repository for agents, keep graphs fresh with the daemon, upgrade and verify a release.
61
+ - [Knowledge base](docs/knowledge-base.md) — symptoms, causes and remedies collected from operating graphite; read it before filing an issue.
62
+ - [Agent integration guide](docs/agent-integration.md) — how a coding agent or script drives the query interface and grades its answers.
63
+ - Reference, each page kept in lockstep with the code by a test: [CLI](docs/reference/cli.md), [configuration](docs/reference/configuration.md), [exit codes](docs/reference/exit-codes.md), [compatibility and support](docs/compatibility.md), [benchmarks](docs/benchmarks.md).
64
+ - [Security policy](SECURITY.md) — supported versions and the private reporting path.
50
65
 
51
66
  ## Principles
52
67
 
@@ -68,16 +83,26 @@ Local-first, deterministic knowledge graph extraction for codebases. A safer, fa
68
83
  ## Installation
69
84
 
70
85
  ```bash
71
- git clone https://github.com/jared0565/graphite
72
- cd graphite
73
- pip install -e .
74
- ```
75
-
76
- Requires Python 3.11 or newer. No model SDK or provider credential is required
77
- for canonical graph operation.
78
-
79
- An editable install is what makes `python -m graphite` work from any repository
80
- on the machine, which is how every onboarded project reaches it.
86
+ python -m pip install --user graphite-code
87
+ graphite --version # version, engine fingerprint, cache and schema versions
88
+ ```
89
+
90
+ The distribution is `graphite-code` (PyPI's `graphite` is another project);
91
+ the import package is `graphite` and the console scripts are `graphite` and
92
+ `graphite-mcp`. Requires Python 3.11–3.14. No model SDK or provider
93
+ credential is required for canonical graph operation. Every release is built
94
+ by CI from its tag, published with PEP 740 attestations, and verifiable from
95
+ the index — see "Upgrading and verifying a release" in the
96
+ [user guide](docs/user-guide.md).
97
+
98
+ Installing for one interpreter is what makes `python -P -m graphite` work
99
+ from any repository on the machine, which is how every onboarded project
100
+ reaches it. Keep the `-P`: without it Python puts the current directory
101
+ first on `sys.path`, so a `graphite.py` or `graphite/__init__.py` planted at
102
+ a repository root would be imported instead of the installed package. The
103
+ console scripts are immune by construction. Contributors install the clone
104
+ editable into a virtual environment **outside** the checkout — see
105
+ [CONTRIBUTING.md](CONTRIBUTING.md).
81
106
 
82
107
  ## System readiness and optional integrations
83
108
 
@@ -130,7 +155,7 @@ node "$GRAPHITE_PACKAGE_VALIDATOR" mcp || exit 1
130
155
  Only after the applicable validator command succeeds, enable the declared extra:
131
156
 
132
157
  ```bash
133
- python -m pip install -e ".[mcp]"
158
+ python -m pip install --user "graphite-code[mcp]"
134
159
  ```
135
160
 
136
161
  The deep MCP probe launches an isolated interpreter from a guarded distribution-record import manifest. It rejects current working directory, user-site, and attacker-controlled selected-root shadows. The exact origin-verified trusted Graphite source may be inside the selected repository, but it is accepted only when its expected lexical, canonical, filesystem-identity, and module-origin checks all match; overlapping MCP dependency or distribution-metadata roots and alternate Graphite origins remain rejected.
@@ -162,7 +187,7 @@ Canonical commands ignore ambient `GRAPHITE_LLM*` settings and never read `GRAPH
162
187
 
163
188
  ## Machine-wide usage
164
189
 
165
- Installed editable, `python -m graphite` works from any project in any shell. The `graphite` / `graphite-mcp` console-script shims are equivalent wherever they are on PATH, but a shim directory that PowerShell and cmd see is not always on Git Bash's PATH — prefer `python -m graphite` in scripts and agent instructions.
190
+ Installed for an interpreter, `python -P -m graphite` works from any project in any shell. The `graphite` / `graphite-mcp` console scripts are equivalent wherever they are on PATH — and shadow-proof by construction — but a scripts directory that PowerShell and cmd see is not always on Git Bash's PATH, so prefer `python -P -m graphite` in scripts, hooks and agent instructions. Everything `graphite init` generates (hooks, `.mcp.json`, editor tasks, daemon launchers) already carries the `-P`.
166
191
 
167
192
  To onboard a new or existing project, run one command from anywhere:
168
193
 
@@ -173,9 +198,9 @@ python -m graphite bootstrap /path/to/MyApp # minimal variant: gitignore + AGE
173
198
 
174
199
  The machine-wide daemon (`graphite daemon /path/to/projects`) auto-discovers any project with standard markers (`.git`, `package.json`, `pyproject.toml`, `wrangler.toml`, `go.mod`, `Cargo.toml`) and keeps its graph fresh, so `init` is about wiring agent instructions, not registration. To exclude a directory (and its whole subtree) from supervision — e.g. a third-party SDK checkout — drop a `.graphite-ignore` file in it; the daemon skips it at the next discovery cycle.
175
200
 
176
- Set `GRAPHITE_PROJECTS_ROOT` to change the default base folder used by `daemon`, `daemon-status`, `daemon-health`, the Windows startup installers, and init/bootstrap daemon-visibility checks (defaults to the current directory when unset).
201
+ Set `GRAPHITE_PROJECTS_ROOT` to change the default base folder used by `daemon`, `daemon-status`, `daemon-health`, the platform daemon installers, and init/bootstrap daemon-visibility checks (defaults to the current directory when unset).
177
202
 
178
- After upgrading graphite itself, restart the daemon: a long-running daemon keeps executing the code it loaded at start, and daemon state is in-memory only, so a restart both loads the new code and rebuilds every supervised graph — clearing `engine_changed` staleness across all managed projects in one pass.
203
+ After upgrading graphite itself, restart the daemon — stop it, install, then start — because a long-running daemon keeps executing the code it loaded at start. A daemon started under the new code detects the engine change itself and rebuilds every supervised graph, clearing `engine_changed` staleness across all managed projects in one pass.
179
204
 
180
205
  ## Usage
181
206
 
@@ -257,13 +282,13 @@ graphite bootstrap C:/Projects/MyApp
257
282
  # Check daemon health
258
283
  graphite daemon-health C:/Projects
259
284
 
260
- # Audit whether Graphite can replace Graphify for a project
285
+ # Audit whether Graphite can replace legacy graph tooling in a project
261
286
  graphite audit-replacement C:/Projects/MyApp
262
287
  ```
263
288
 
264
- ## Graphify replacement audit
289
+ ## Legacy replacement audit
265
290
 
266
- Use the replacement audit before removing legacy Graphify files or ignore entries:
291
+ Use the replacement audit before removing a legacy graph tool's files or ignore entries:
267
292
 
268
293
  ```bash
269
294
  graphite audit-replacement C:/Projects/MyApp
@@ -271,7 +296,7 @@ graphite audit-replacement . --json
271
296
  graphite audit-replacement . --fail-on-blocker
272
297
  ```
273
298
 
274
- The audit checks Graphite bootstrap state, graph freshness and validity, daemon visibility, daemon health, physical Graphify remnants, and Graphify text/config references. It reports recommendations but never deletes files automatically.
299
+ The audit checks Graphite bootstrap state, graph freshness and validity, daemon visibility, daemon health, physical legacy-tool remnants, and legacy text/config references. It reports recommendations but never deletes files automatically.
275
300
 
276
301
  ## Daemon health
277
302
 
@@ -750,14 +775,17 @@ Then use `/graphite [path]` inside Claude Code. The skill defaults to zero-LLM m
750
775
 
751
776
  Complete the mandatory package-validation policy and MCP activation steps in [System readiness and optional integrations](#system-readiness-and-optional-integrations). Do not bypass or reorder the validator and install steps.
752
777
 
753
- Then configure Claude Code (Desktop) to use the local server. Add this to your `claude_desktop_config.json`:
778
+ `graphite init` writes a project-local `.mcp.json` entry for Claude Code and
779
+ Codex (and rewrites its own entry on every run, preserving foreign ones). To
780
+ configure a client by hand, launch the server with `-P` — or use the
781
+ `graphite-mcp` console script, which needs no flag:
754
782
 
755
783
  ```json
756
784
  {
757
785
  "mcpServers": {
758
786
  "graphite": {
759
787
  "command": "python",
760
- "args": ["-m", "graphite.mcp"],
788
+ "args": ["-P", "-m", "graphite.mcp"],
761
789
  "cwd": "C:/Projects/YourProject"
762
790
  }
763
791
  }
@@ -1,6 +1,21 @@
1
1
  # Graphite
2
2
 
3
- Local-first, deterministic knowledge graph extraction for codebases. A safer, faster, cheaper replacement for `graphify`.
3
+ Local-first, deterministic knowledge graph extraction for codebases — zero-LLM, daemon-maintained, agent-agnostic.
4
+
5
+ **Status: 1.0.1, production/stable.** Published on PyPI as
6
+ [`graphite-code`](https://pypi.org/project/graphite-code/) with PEP 740
7
+ attestations; supported on Windows, Linux and macOS with Python 3.11–3.14
8
+ (every cell gates CI). What 1.x promises — CLI, JSON outputs, `graph.json`,
9
+ configuration, exit codes, the launch contract — is in
10
+ [docs/compatibility.md](docs/compatibility.md).
11
+
12
+ ## Documentation
13
+
14
+ - [User guide](docs/user-guide.md) — install, build the first graph, ask questions, onboard a repository for agents, keep graphs fresh with the daemon, upgrade and verify a release.
15
+ - [Knowledge base](docs/knowledge-base.md) — symptoms, causes and remedies collected from operating graphite; read it before filing an issue.
16
+ - [Agent integration guide](docs/agent-integration.md) — how a coding agent or script drives the query interface and grades its answers.
17
+ - Reference, each page kept in lockstep with the code by a test: [CLI](docs/reference/cli.md), [configuration](docs/reference/configuration.md), [exit codes](docs/reference/exit-codes.md), [compatibility and support](docs/compatibility.md), [benchmarks](docs/benchmarks.md).
18
+ - [Security policy](SECURITY.md) — supported versions and the private reporting path.
4
19
 
5
20
  ## Principles
6
21
 
@@ -22,16 +37,26 @@ Local-first, deterministic knowledge graph extraction for codebases. A safer, fa
22
37
  ## Installation
23
38
 
24
39
  ```bash
25
- git clone https://github.com/jared0565/graphite
26
- cd graphite
27
- pip install -e .
28
- ```
29
-
30
- Requires Python 3.11 or newer. No model SDK or provider credential is required
31
- for canonical graph operation.
32
-
33
- An editable install is what makes `python -m graphite` work from any repository
34
- on the machine, which is how every onboarded project reaches it.
40
+ python -m pip install --user graphite-code
41
+ graphite --version # version, engine fingerprint, cache and schema versions
42
+ ```
43
+
44
+ The distribution is `graphite-code` (PyPI's `graphite` is another project);
45
+ the import package is `graphite` and the console scripts are `graphite` and
46
+ `graphite-mcp`. Requires Python 3.11–3.14. No model SDK or provider
47
+ credential is required for canonical graph operation. Every release is built
48
+ by CI from its tag, published with PEP 740 attestations, and verifiable from
49
+ the index — see "Upgrading and verifying a release" in the
50
+ [user guide](docs/user-guide.md).
51
+
52
+ Installing for one interpreter is what makes `python -P -m graphite` work
53
+ from any repository on the machine, which is how every onboarded project
54
+ reaches it. Keep the `-P`: without it Python puts the current directory
55
+ first on `sys.path`, so a `graphite.py` or `graphite/__init__.py` planted at
56
+ a repository root would be imported instead of the installed package. The
57
+ console scripts are immune by construction. Contributors install the clone
58
+ editable into a virtual environment **outside** the checkout — see
59
+ [CONTRIBUTING.md](CONTRIBUTING.md).
35
60
 
36
61
  ## System readiness and optional integrations
37
62
 
@@ -84,7 +109,7 @@ node "$GRAPHITE_PACKAGE_VALIDATOR" mcp || exit 1
84
109
  Only after the applicable validator command succeeds, enable the declared extra:
85
110
 
86
111
  ```bash
87
- python -m pip install -e ".[mcp]"
112
+ python -m pip install --user "graphite-code[mcp]"
88
113
  ```
89
114
 
90
115
  The deep MCP probe launches an isolated interpreter from a guarded distribution-record import manifest. It rejects current working directory, user-site, and attacker-controlled selected-root shadows. The exact origin-verified trusted Graphite source may be inside the selected repository, but it is accepted only when its expected lexical, canonical, filesystem-identity, and module-origin checks all match; overlapping MCP dependency or distribution-metadata roots and alternate Graphite origins remain rejected.
@@ -116,7 +141,7 @@ Canonical commands ignore ambient `GRAPHITE_LLM*` settings and never read `GRAPH
116
141
 
117
142
  ## Machine-wide usage
118
143
 
119
- Installed editable, `python -m graphite` works from any project in any shell. The `graphite` / `graphite-mcp` console-script shims are equivalent wherever they are on PATH, but a shim directory that PowerShell and cmd see is not always on Git Bash's PATH — prefer `python -m graphite` in scripts and agent instructions.
144
+ Installed for an interpreter, `python -P -m graphite` works from any project in any shell. The `graphite` / `graphite-mcp` console scripts are equivalent wherever they are on PATH — and shadow-proof by construction — but a scripts directory that PowerShell and cmd see is not always on Git Bash's PATH, so prefer `python -P -m graphite` in scripts, hooks and agent instructions. Everything `graphite init` generates (hooks, `.mcp.json`, editor tasks, daemon launchers) already carries the `-P`.
120
145
 
121
146
  To onboard a new or existing project, run one command from anywhere:
122
147
 
@@ -127,9 +152,9 @@ python -m graphite bootstrap /path/to/MyApp # minimal variant: gitignore + AGE
127
152
 
128
153
  The machine-wide daemon (`graphite daemon /path/to/projects`) auto-discovers any project with standard markers (`.git`, `package.json`, `pyproject.toml`, `wrangler.toml`, `go.mod`, `Cargo.toml`) and keeps its graph fresh, so `init` is about wiring agent instructions, not registration. To exclude a directory (and its whole subtree) from supervision — e.g. a third-party SDK checkout — drop a `.graphite-ignore` file in it; the daemon skips it at the next discovery cycle.
129
154
 
130
- Set `GRAPHITE_PROJECTS_ROOT` to change the default base folder used by `daemon`, `daemon-status`, `daemon-health`, the Windows startup installers, and init/bootstrap daemon-visibility checks (defaults to the current directory when unset).
155
+ Set `GRAPHITE_PROJECTS_ROOT` to change the default base folder used by `daemon`, `daemon-status`, `daemon-health`, the platform daemon installers, and init/bootstrap daemon-visibility checks (defaults to the current directory when unset).
131
156
 
132
- After upgrading graphite itself, restart the daemon: a long-running daemon keeps executing the code it loaded at start, and daemon state is in-memory only, so a restart both loads the new code and rebuilds every supervised graph — clearing `engine_changed` staleness across all managed projects in one pass.
157
+ After upgrading graphite itself, restart the daemon — stop it, install, then start — because a long-running daemon keeps executing the code it loaded at start. A daemon started under the new code detects the engine change itself and rebuilds every supervised graph, clearing `engine_changed` staleness across all managed projects in one pass.
133
158
 
134
159
  ## Usage
135
160
 
@@ -211,13 +236,13 @@ graphite bootstrap C:/Projects/MyApp
211
236
  # Check daemon health
212
237
  graphite daemon-health C:/Projects
213
238
 
214
- # Audit whether Graphite can replace Graphify for a project
239
+ # Audit whether Graphite can replace legacy graph tooling in a project
215
240
  graphite audit-replacement C:/Projects/MyApp
216
241
  ```
217
242
 
218
- ## Graphify replacement audit
243
+ ## Legacy replacement audit
219
244
 
220
- Use the replacement audit before removing legacy Graphify files or ignore entries:
245
+ Use the replacement audit before removing a legacy graph tool's files or ignore entries:
221
246
 
222
247
  ```bash
223
248
  graphite audit-replacement C:/Projects/MyApp
@@ -225,7 +250,7 @@ graphite audit-replacement . --json
225
250
  graphite audit-replacement . --fail-on-blocker
226
251
  ```
227
252
 
228
- The audit checks Graphite bootstrap state, graph freshness and validity, daemon visibility, daemon health, physical Graphify remnants, and Graphify text/config references. It reports recommendations but never deletes files automatically.
253
+ The audit checks Graphite bootstrap state, graph freshness and validity, daemon visibility, daemon health, physical legacy-tool remnants, and legacy text/config references. It reports recommendations but never deletes files automatically.
229
254
 
230
255
  ## Daemon health
231
256
 
@@ -704,14 +729,17 @@ Then use `/graphite [path]` inside Claude Code. The skill defaults to zero-LLM m
704
729
 
705
730
  Complete the mandatory package-validation policy and MCP activation steps in [System readiness and optional integrations](#system-readiness-and-optional-integrations). Do not bypass or reorder the validator and install steps.
706
731
 
707
- Then configure Claude Code (Desktop) to use the local server. Add this to your `claude_desktop_config.json`:
732
+ `graphite init` writes a project-local `.mcp.json` entry for Claude Code and
733
+ Codex (and rewrites its own entry on every run, preserving foreign ones). To
734
+ configure a client by hand, launch the server with `-P` — or use the
735
+ `graphite-mcp` console script, which needs no flag:
708
736
 
709
737
  ```json
710
738
  {
711
739
  "mcpServers": {
712
740
  "graphite": {
713
741
  "command": "python",
714
- "args": ["-m", "graphite.mcp"],
742
+ "args": ["-P", "-m", "graphite.mcp"],
715
743
  "cwd": "C:/Projects/YourProject"
716
744
  }
717
745
  }
@@ -418,6 +418,15 @@ Verify the remote branch commit and annotated tag object against the release evi
418
418
  If published, download the destination artifact into a new isolated environment, verify
419
419
  its SHA256 digest and provenance when provided, and repeat archive inspection and smoke
420
420
  testing. Do not use the local build as evidence that the published artifact is correct.
421
+ `scripts/verify_published_release.py <version> --wheel-sha256 <approved digest>` does
422
+ this from the index in six arms and prints `OVERALL: PASS` only when all six pass; run it
423
+ before publication as the negative control (every arm must fail) and after. Its
424
+ provenance arm reads the PEP 691 Simple JSON index — the legacy
425
+ `/pypi/<project>/<version>/json` endpoint never carries provenance — so a checkout older
426
+ than that fix reports 5 of 6 on an attested release; confirm with
427
+ `https://pypi.org/integrity/<project>/<version>/<file>/provenance` (HTTP 200 with the
428
+ bundle) before reading that as a missing attestation. The index lags uploads by minutes:
429
+ a lone listing failure with the digest arm passing is propagation, not a failed release.
421
430
 
422
431
  Recovery depends on the completed state:
423
432
 
@@ -225,8 +225,38 @@ select = ["E4", "E7", "E9", "F"]
225
225
  # gate as a blocking "pytest exited 2" while a local run read green.
226
226
  pythonpath = ["."]
227
227
 
228
- # The type gate (PRD WS-D) is configured in setup.cfg, NOT here -- see the
229
- # comment at the top of that file: aramid 0.6.0's typecheck runner arms on a
230
- # [tool.mypy] section and then feeds non-Python files to mypy (channel round
231
- # 140; fixed in 0.6.1). `python -m mypy` reads setup.cfg with the same
232
- # semantics; move the section back here once the pinned aramid is 0.6.1+.
228
+ # The type gate (PRD WS-D). This section lived in setup.cfg between 2026-08-29
229
+ # and the promotion of aramid 0.6.1 later that day: aramid 0.6.0's typecheck
230
+ # runner armed on a [tool.mypy] section and then fed EVERY changed file to
231
+ # mypy, so a push whose changed set held exactly one non-Python file was
232
+ # refused as `mypy:syntax`. 0.6.1 hands mypy only .py/.pyi (channel round
233
+ # 144), which is why the section is back here.
234
+ [tool.mypy]
235
+ files = ["src/graphite"]
236
+ python_version = "3.11"
237
+ check_untyped_defs = true
238
+ warn_unused_ignores = true
239
+ warn_redundant_casts = true
240
+ no_implicit_optional = true
241
+ show_error_codes = true
242
+ pretty = false
243
+
244
+ # No stubs are published for these. Scoped per module rather than set
245
+ # globally so a typo in an import elsewhere still fails the gate.
246
+ [[tool.mypy.overrides]]
247
+ module = [
248
+ "networkx",
249
+ "networkx.*",
250
+ "community",
251
+ "community.*",
252
+ "tree_sitter",
253
+ "tree_sitter_javascript",
254
+ "tree_sitter_typescript",
255
+ "tree_sitter_python",
256
+ "tree_sitter_go",
257
+ "tree_sitter_rust",
258
+ "louvain",
259
+ "mcp",
260
+ "mcp.*",
261
+ ]
262
+ ignore_missing_imports = true