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.
- {graphite_code-1.0.0 → graphite_code-1.0.1}/ARCHITECTURE.md +6 -5
- {graphite_code-1.0.0 → graphite_code-1.0.1}/CHANGELOG.md +183 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/CONTRIBUTING.md +11 -6
- {graphite_code-1.0.0 → graphite_code-1.0.1}/PKG-INFO +50 -22
- {graphite_code-1.0.0 → graphite_code-1.0.1}/README.md +49 -21
- {graphite_code-1.0.0 → graphite_code-1.0.1}/RELEASING.md +9 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/pyproject.toml +35 -5
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/__init__.py +1 -1
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/cache.py +93 -3
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/cli.py +129 -52
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/graph.py +1 -1
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/probe_process.py +16 -1
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/replacement_audit.py +42 -37
- graphite_code-1.0.1/tests/test_cache_entry_pruning.py +245 -0
- graphite_code-1.0.1/tests/test_cli_reference.py +182 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_doctor.py +81 -15
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_documentation.py +1 -1
- graphite_code-1.0.1/tests/test_mutation_tests.py +365 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_replacement_audit.py +6 -6
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_synthetic_repo.py +36 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_verify_published_release.py +13 -0
- graphite_code-1.0.0/tests/test_cli_reference.py +0 -66
- {graphite_code-1.0.0 → graphite_code-1.0.1}/.gitignore +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/LICENSE +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/__main__.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/_cleanup_worker.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/_win32_ctypes.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/activation.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/agent_hooks.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/agent_settings.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/analyze.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/answer_contract.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/bootstrap.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/buildlock.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/channel.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/cluster.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/config.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/context.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/daemon.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/daemon_health.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/daemon_launch.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/debt.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/dependency_install.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/detach.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/doctor.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/doctor_probes.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/engine_identity.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/export/__init__.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/export/html.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/export/json.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/export/md.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/extract/__init__.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/extract/ast.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/freshness.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/git.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/graph_io.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/health.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/hook_entry.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/hookinstall.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/hookshim.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/incident_ledger.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/ingest.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/init.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/io.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/launchd_agent.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/listing.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/llm.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/llm_probe.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/mcp.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/mcp_server.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/natural_query.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/overlays.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/probe_workspace.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/process_contracts.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/provider_observer.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/py.typed +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/query.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/query_plan.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/resolve.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/review.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/__init__.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/approval.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/classifier.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/claude_executor.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/claude_probe.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/cli_identity.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/codex_executor.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/codex_probe.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/context_builder.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/contracts.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/diff_policy.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/edit_apply.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/effort.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/lifecycle.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/lifecycle_operator.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/lifecycle_service.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/lifecycle_storage.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/ollama_executor.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/ollama_probe.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/openrouter_executor.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/openrouter_probe.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/policy.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/probe_runner.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/process_runner.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/profiles.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/prompt.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/registry.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/route_pool.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/route_pool_execution.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/schema_validation.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/service.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/settings.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/shadow.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/storage.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/telemetry.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/worktree.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/zai_edit.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/zai_executor.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/routing/zai_probe.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/savings.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/systemd_unit.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/ts_bridge.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/ts_resolver.mjs +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/typescript_activation.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/usage_ledger.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/validation.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/watch.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/windows_job.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/windows_startup.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/src/graphite/windows_task.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/conftest.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/data/sqloracle/blindspots.py.txt +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/data/sqloracle/round69.py.txt +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/fake_clis/fake_cli.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/fixtures/provider_lifecycle_schema_v1.sql +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/fixtures/routing_schema_v2_ca77600.sql +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/fixtures/routing_schema_v3_94eb333.sql +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/fixtures/routing_schema_v4_lifecycle_migration.sql +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_activation.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_activation_backstop.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_agent_hook_activation.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_agent_hooks.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_agent_settings.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_answer_contract.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_arrow_and_constructor_binding.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_atomic_write.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_bootstrap.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_build_detach.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_buildlock.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cache_engine_identity.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cache_file_set.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cache_pruning.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_call_graph.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_cli.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_core.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_lock.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_mcp.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_register.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_report.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_channel_status.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_class_field_arrow_binding.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cli_channel.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cli_version.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_compare_dist.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_configuration_reference.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_context.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cwd_relative_config.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_cycle_search.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_activation.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_build_lock.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_child_lock.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_engine_staleness.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_health.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_health_activation.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_launch.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_daemon_service_cli.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_debt.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_destructured_binding.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_determinism.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_dispatch_evidence.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_doctor_agent_hooks.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_doctor_hooks.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_doctor_managed_docs.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_edit_apply.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_engine_identity.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_exit_codes_reference.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_external_calls.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_git_security.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_go_rust.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_graph_io.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_graph_provider_isolation.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_hardening.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_health.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_hook_entry.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_hook_template.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_hookinstall.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_hookshim.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_html_security.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_incident_ledger.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_init.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_init_activation_doctrine.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_init_hooks.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_init_validation_exit.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_launchd_agent.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_lifecycle_operator.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_listing.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_listing_surfaces.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_llm.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_mcp.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_method_dispatch_scope.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_monorepo.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_natural_query.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_node_identity.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_overlays.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_path_leak_fixture.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_probe_diagnostics.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_probe_workspace.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_claude_probe.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_codex_probe.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_lifecycle.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_lifecycle_service.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_lifecycle_storage.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_observer.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_ollama_probe.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_openrouter_probe.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_provider_probe_runner.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_public_surface.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_published_schemas.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_python_resolver.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_query_plan.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_reliability.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_resolve.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_review.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_route_pool.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_approval.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_benchmark.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_classifier.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_claude_executor.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_cli.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_cli_contracts.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_cli_recovery.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_codex_executor.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_context.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_contracts.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_diff_policy.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_executor.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_openrouter_executor.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_policy.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_process_runner.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_profiles.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_registry.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_schema_validation.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_security.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_service.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_shadow.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_storage.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_telemetry.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_worktree.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_zai_executor.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_routing_zai_probe.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_savings.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_search.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_smoke.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_sqloracle.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_systemd_unit.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_typescript_activation.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_typescript_resolver.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_usage_ledger.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_verify_artifact.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_watch.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_windows_startup.py +0 -0
- {graphite_code-1.0.0 → graphite_code-1.0.1}/tests/test_windows_task.py +0 -0
- {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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
##
|
|
289
|
+
## Legacy replacement audit
|
|
265
290
|
|
|
266
|
-
Use the replacement audit before removing legacy
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
##
|
|
243
|
+
## Legacy replacement audit
|
|
219
244
|
|
|
220
|
-
Use the replacement audit before removing legacy
|
|
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
|
|
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
|
-
|
|
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)
|
|
229
|
-
#
|
|
230
|
-
# [tool.mypy] section and then
|
|
231
|
-
#
|
|
232
|
-
#
|
|
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
|