leyline-code 0.8.1__tar.gz → 0.10.0__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.
- leyline_code-0.10.0/PKG-INFO +397 -0
- leyline_code-0.10.0/README.md +364 -0
- leyline_code-0.10.0/docs/changes.md +407 -0
- leyline_code-0.10.0/docs/indexing.md +251 -0
- leyline_code-0.10.0/docs/mcp-tools.md +68 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/docs/quick-reference.md +12 -4
- leyline_code-0.10.0/docs/understanding.md +361 -0
- leyline_code-0.10.0/openspec/changes/asset-edges/leyline.md +517 -0
- leyline_code-0.10.0/openspec/changes/asset-edges/proposal.md +37 -0
- leyline_code-0.10.0/openspec/changes/asset-edges/specs/indexing/spec.md +90 -0
- leyline_code-0.10.0/openspec/changes/asset-edges/tasks.md +57 -0
- leyline_code-0.10.0/openspec/changes/context-bodies/leyline.md +411 -0
- leyline_code-0.10.0/openspec/changes/context-bodies/proposal.md +36 -0
- leyline_code-0.10.0/openspec/changes/context-bodies/specs/understanding/spec.md +70 -0
- leyline_code-0.10.0/openspec/changes/context-bodies/tasks.md +31 -0
- leyline_code-0.10.0/openspec/changes/hash-fallback/leyline.md +276 -0
- leyline_code-0.10.0/openspec/changes/hash-fallback/proposal.md +17 -0
- leyline_code-0.10.0/openspec/changes/hash-fallback/specs/indexing/spec.md +8 -0
- leyline_code-0.10.0/openspec/changes/hash-fallback/tasks.md +3 -0
- leyline_code-0.10.0/openspec/changes/node-summaries/leyline.md +403 -0
- leyline_code-0.10.0/openspec/changes/node-summaries/proposal.md +30 -0
- leyline_code-0.10.0/openspec/changes/node-summaries/specs/understanding/spec.md +49 -0
- leyline_code-0.10.0/openspec/changes/node-summaries/tasks.md +30 -0
- leyline_code-0.10.0/openspec/changes/orientation-from-named-parts/leyline.md +386 -0
- leyline_code-0.10.0/openspec/changes/orientation-from-named-parts/proposal.md +30 -0
- leyline_code-0.10.0/openspec/changes/orientation-from-named-parts/specs/orientation/spec.md +31 -0
- leyline_code-0.10.0/openspec/changes/orientation-from-named-parts/tasks.md +21 -0
- leyline_code-0.10.0/openspec/changes/outline-splits-large-group/leyline.md +245 -0
- leyline_code-0.10.0/openspec/changes/outline-splits-large-group/proposal.md +26 -0
- leyline_code-0.10.0/openspec/changes/outline-splits-large-group/specs/outline/spec.md +22 -0
- leyline_code-0.10.0/openspec/changes/outline-splits-large-group/tasks.md +8 -0
- leyline_code-0.10.0/openspec/changes/read-tool-budgets/leyline.md +315 -0
- leyline_code-0.10.0/openspec/changes/read-tool-budgets/proposal.md +21 -0
- leyline_code-0.10.0/openspec/changes/read-tool-budgets/specs/mcp/spec.md +22 -0
- leyline_code-0.10.0/openspec/changes/read-tool-budgets/tasks.md +13 -0
- leyline_code-0.10.0/openspec/changes/server-in-another-checkout/leyline.md +323 -0
- leyline_code-0.10.0/openspec/changes/server-in-another-checkout/proposal.md +29 -0
- leyline_code-0.10.0/openspec/changes/server-in-another-checkout/specs/mcp/spec.md +30 -0
- leyline_code-0.10.0/openspec/changes/server-in-another-checkout/tasks.md +20 -0
- leyline_code-0.10.0/openspec/changes/show-tests-reaching/leyline.md +371 -0
- leyline_code-0.10.0/openspec/changes/show-tests-reaching/proposal.md +23 -0
- leyline_code-0.10.0/openspec/changes/show-tests-reaching/specs/understanding/spec.md +23 -0
- leyline_code-0.10.0/openspec/changes/show-tests-reaching/tasks.md +10 -0
- leyline_code-0.10.0/openspec/changes/unasserted-changes/leyline.md +472 -0
- leyline_code-0.10.0/openspec/changes/unasserted-changes/proposal.md +49 -0
- leyline_code-0.10.0/openspec/changes/unasserted-changes/specs/verdicts/spec.md +105 -0
- leyline_code-0.10.0/openspec/changes/unasserted-changes/tasks.md +54 -0
- leyline_code-0.10.0/openspec/leyline-anchors.json +2748 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/pyproject.toml +1 -1
- {leyline_code-0.8.1 → leyline_code-0.10.0}/skills/leyline-adversarial-review/SKILL.md +1 -1
- {leyline_code-0.8.1 → leyline_code-0.10.0}/skills/leyline-ask/SKILL.md +12 -6
- {leyline_code-0.8.1 → leyline_code-0.10.0}/skills/leyline-explain-flow/SKILL.md +5 -3
- {leyline_code-0.8.1 → leyline_code-0.10.0}/skills/leyline-explore-module/SKILL.md +2 -2
- {leyline_code-0.8.1 → leyline_code-0.10.0}/skills/leyline-pr-review/SKILL.md +1 -1
- {leyline_code-0.8.1 → leyline_code-0.10.0}/skills/leyline-quick-change/SKILL.md +1 -1
- {leyline_code-0.8.1 → leyline_code-0.10.0}/skills/leyline-spec/SKILL.md +9 -2
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/__init__.py +1 -1
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/adapters/__init__.py +6 -3
- leyline_code-0.10.0/src/leyline/adapters/godot.py +94 -0
- leyline_code-0.10.0/src/leyline/adapters/unity.py +77 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/cli.py +342 -27
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/cluster.py +17 -7
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/context.py +303 -13
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/coupling.py +2 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/coverage.py +6 -2
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/explain.py +65 -45
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/export.py +21 -13
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/fncoupling.py +2 -1
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/incremental.py +43 -11
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/indexer.py +232 -16
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/loop.py +117 -20
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/model.py +12 -0
- leyline_code-0.10.0/src/leyline/mutants.py +669 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/outline.py +117 -18
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/query.py +196 -18
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/server.py +230 -83
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/spec.py +37 -2
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/store.py +28 -0
- leyline_code-0.10.0/src/leyline/summaries.py +97 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/tours.py +47 -16
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/verdicts.py +13 -4
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/viewer/viewer.html +18 -6
- leyline_code-0.10.0/tests/test_assets.py +400 -0
- leyline_code-0.10.0/tests/test_bodies.py +308 -0
- leyline_code-0.10.0/tests/test_budgets.py +97 -0
- leyline_code-0.10.0/tests/test_checkouts.py +127 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_flows_explain.py +5 -5
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_incremental.py +17 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_index.py +4 -2
- leyline_code-0.10.0/tests/test_mutants.py +440 -0
- leyline_code-0.10.0/tests/test_orientation.py +113 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_outline.py +71 -0
- leyline_code-0.10.0/tests/test_reaching.py +109 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_resolve.py +1 -1
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_server.py +44 -4
- leyline_code-0.10.0/tests/test_summaries.py +171 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_surface.py +73 -2
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_verdicts.py +1 -1
- leyline_code-0.8.1/PKG-INFO +0 -1325
- leyline_code-0.8.1/README.md +0 -1292
- {leyline_code-0.8.1 → leyline_code-0.10.0}/.github/workflows/publish.yml +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/.github/workflows/test.yml +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/.gitignore +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/LICENSE +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/skills/leyline-change-impact/SKILL.md +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/skills/leyline-tour/SKILL.md +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/adapters/csharp.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/adapters/generic.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/adapters/python.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/adapters/typescript.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/affected.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/agent_skills.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/change.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/channels.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/diagrams.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/diff.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/drift.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/exact.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/formats.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/grade.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/learnings.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/packing.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/patterns.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/pr.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/props.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/quick.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/related.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/removal.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/renames.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/rereview.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/roslyn_refs/Program.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/roslyn_refs/RoslynRefs.csproj +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/rules.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/schema.sql +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/src/leyline/scip_pb2.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/conftest.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture/App/App.csproj +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture/App/Checks.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture/App/Program.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture/Lib/Bus.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture/Lib/Lib.csproj +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture/Lib/Program.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture/Lib/Shapes.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture/scripts/launch.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture/scripts/run.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture/scripts/util.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/cs/Mod/Boxes.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/cs/Mod/Fluent.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/cs/Mod/Hard.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/cs/Mod/Made.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/cs/Mod/Mod.csproj +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/cs/Mod/Reports.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/cs/Mod/Runner.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/cs/Mod/Shapes.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/cs/Mod/State.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/py/src/pkg/__init__.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/py/src/pkg/core.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/py/tests/conftest.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/py/tests/test_engine.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/py/web/app.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture2/py/web/client.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture3/package.json +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture3/pkg/app/package.json +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture3/pkg/app/src/main.test.ts +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture3/pkg/app/src/main.tsx +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture3/pkg/app/src/server.ts +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture3/pkg/core/package.json +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture3/pkg/core/src/graph.ts +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture3/pkg/core/src/ids.ts +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture3/pkg/core/src/index.ts +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture4/go/go.mod +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture4/go/main.go +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture4/go/main_test.go +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture4/go/shapes/shape.go +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture4/java/com/acme/App.java +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture4/java/com/acme/Counter.java +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture4/rs/Cargo.toml +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture4/rs/src/geo.rs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture4/rs/src/main.rs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/py/app.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/py/audit.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/py/client.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/py/consumer.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/py/container.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/py/db.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/py/migrations/0001_audit.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/py/models.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/py/tasks.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/py/tests/test_models.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/rpc/py/client.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/rpc/py/server.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/shop/Billing.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/shop/OrderService.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/shop/Program.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/shop/Shop.csproj +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/shop/Store.cs +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/ts/events.ts +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/ts/nest.ts +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/ts/repo.ts +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture5/ts/subs.ts +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture6/tests/test_web.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture6/web/__init__.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture6/web/app.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture6/web/config.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture6/web/globals.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture_props/fastcheck_vitest_tap.txt +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture_props/fscheck_dotnet_test.txt +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture_props/hypothesis_6.100.txt +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture_props/hypothesis_6.168.txt +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture_ws/wsapp/pyproject.toml +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture_ws/wsapp/src/apppkg/__init__.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture_ws/wsapp/src/apppkg/main.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture_ws/wsapp/tests/test_main.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture_ws/wslib/pyproject.toml +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture_ws/wslib/src/libpkg/__init__.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/fixture_ws/wslib/src/libpkg/core.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/store_identity.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_adapters.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_before.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_channels.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_context.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_coupling.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_diagrams.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_drift.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_fixes.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_fncoupling.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_formats.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_handlers.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_learnings.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_learnings_synonyms.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_learnings_workspace.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_memory.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_pr.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_props.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_quick.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_rereview.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_robust.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_scenario_coverage.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_security.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_shapes.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_signalfix.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_skills.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_state.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_trust.py +0 -0
- {leyline_code-0.8.1 → leyline_code-0.10.0}/tests/test_viewer.py +0 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: leyline-code
|
|
3
|
+
Version: 0.10.0
|
|
4
|
+
Summary: Map a codebase so a person can plan a change, have an agent write the code, and check that it was done as agreed.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Orbitope/leyline
|
|
6
|
+
Project-URL: Issues, https://github.com/Orbitope/leyline/issues
|
|
7
|
+
License-Expression: GPL-3.0-only
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Requires-Dist: mcp>=1.0
|
|
11
|
+
Requires-Dist: networkx>=3.0
|
|
12
|
+
Requires-Dist: tree-sitter-c-sharp>=0.23
|
|
13
|
+
Requires-Dist: tree-sitter-python>=0.23
|
|
14
|
+
Requires-Dist: tree-sitter-typescript>=0.23
|
|
15
|
+
Requires-Dist: tree-sitter>=0.23
|
|
16
|
+
Provides-Extra: languages
|
|
17
|
+
Requires-Dist: tree-sitter-bash; extra == 'languages'
|
|
18
|
+
Requires-Dist: tree-sitter-c; extra == 'languages'
|
|
19
|
+
Requires-Dist: tree-sitter-cpp; extra == 'languages'
|
|
20
|
+
Requires-Dist: tree-sitter-gdscript; extra == 'languages'
|
|
21
|
+
Requires-Dist: tree-sitter-go; extra == 'languages'
|
|
22
|
+
Requires-Dist: tree-sitter-java; extra == 'languages'
|
|
23
|
+
Requires-Dist: tree-sitter-kotlin; extra == 'languages'
|
|
24
|
+
Requires-Dist: tree-sitter-lua; extra == 'languages'
|
|
25
|
+
Requires-Dist: tree-sitter-php; extra == 'languages'
|
|
26
|
+
Requires-Dist: tree-sitter-ruby; extra == 'languages'
|
|
27
|
+
Requires-Dist: tree-sitter-rust; extra == 'languages'
|
|
28
|
+
Requires-Dist: tree-sitter-scala; extra == 'languages'
|
|
29
|
+
Requires-Dist: tree-sitter-swift; extra == 'languages'
|
|
30
|
+
Provides-Extra: scip
|
|
31
|
+
Requires-Dist: protobuf>=7.35; extra == 'scip'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# Leyline
|
|
35
|
+
|
|
36
|
+
## Working through an agent
|
|
37
|
+
|
|
38
|
+
Leyline is meant to be driven by a coding agent: you ask in plain words, the agent uses Leyline's map and follows
|
|
39
|
+
one of its skills, and you read the answer or the page it writes. Set it up once, in the repository you will work on:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install leyline-code # or, from a checkout: pip install -e .
|
|
43
|
+
claude mcp add leyline -- leyline serve # connect Claude Code to Leyline's MCP server
|
|
44
|
+
leyline skills install # copy the skills into .claude/skills (and .agents/skills if you have one)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Start a new agent session, then ask. Nothing needs mapping first: the agent maps the code when it needs to.
|
|
48
|
+
|
|
49
|
+
| Skill | What it does | Ask, for example |
|
|
50
|
+
| --- | --- | --- |
|
|
51
|
+
| `leyline-ask` | Answers a question about the code, citing it, and says how sure it is | "Who calls `saveOne`, and is that link certain?" |
|
|
52
|
+
| `leyline-explain-flow` | Explains how something runs, step by step, from the map | "What happens when a user saves a dialogue?" |
|
|
53
|
+
| `leyline-explore-module` | Says what one part of the code holds and where to start reading | "What is in `editor/host`, and where do I start?" |
|
|
54
|
+
| `leyline-change-impact` | Says what a described change would touch, break and need tested | "What would changing the validator's output format affect?" |
|
|
55
|
+
| `leyline-spec` | Plans a change as an OpenSpec folder, checked against the code, then checks it after | "Plan adding an export button, with tests." |
|
|
56
|
+
| `leyline-quick-change` | Makes a small fix with no spec and says whether it was done; says when it needs a spec | "Make the retry count 3." |
|
|
57
|
+
| `leyline-pr-review` | Reviews a pull request: what changed, what it breaks, findings, what to fix first | "Review pull request 123." |
|
|
58
|
+
| `leyline-adversarial-review` | Attacks a plan or a pull request as a logic or a performance reviewer | "Stress-test the plan for loud-engine." |
|
|
59
|
+
| `leyline-tour` | Writes a guided reading order through the code, saved on the map | "Write a tour of the payment code for a new hire." |
|
|
60
|
+
|
|
61
|
+
`leyline skills list` describes them, `leyline skills show <name>` prints one, and running `leyline skills install`
|
|
62
|
+
again updates them, leaving alone any you edited (`--force` replaces those). An agent connected to `leyline serve`
|
|
63
|
+
can also load each skill as an MCP prompt of the same name, or through the `skills` tool, without installing them.
|
|
64
|
+
The rest of this page is what the agent does underneath, and the commands for doing it yourself.
|
|
65
|
+
|
|
66
|
+
## Start here
|
|
67
|
+
|
|
68
|
+
To understand a codebase, map it and look around. Names work wherever an id does (`Engine.start`, a file path):
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
leyline map path/to/repo # once; writes .leyline/map.html, which opens on a guided tour
|
|
72
|
+
leyline tour # what this repository is, and where to start reading
|
|
73
|
+
leyline show Engine.start # one thing: what it is, who uses it, what it uses, the code around it
|
|
74
|
+
leyline show "what happens when a user saves" # where a behavior described in words starts
|
|
75
|
+
leyline outline editor/core # a large module split into parts, with what each holds
|
|
76
|
+
leyline explain-path DialogueCanvas.save # what runs from there, step by step, with a diagram
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Or ask your agent in plain words (see [Working through an agent](#working-through-an-agent)). One page of what to
|
|
80
|
+
ask and the command or tool behind it: [docs/quick-reference.md](docs/quick-reference.md).
|
|
81
|
+
|
|
82
|
+
Leyline also lets a person design a change to a codebase while a coding agent writes it. Before any code is
|
|
83
|
+
written it shows, on one page, what code will be written, what it will affect and how you will know it
|
|
84
|
+
was done; afterwards it says on the same page whether the change was done as agreed. Everything on that
|
|
85
|
+
page comes from the code and the test results, not from the agent's account of its own work.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install -e . # Python 3.10 or later; installs the `leyline` command
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Three commands, in this order. Each one ends with a `Next:` line saying what to do after it.
|
|
92
|
+
|
|
93
|
+
| Command | When | What you read |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| `leyline map [repo ...]` | Once, before the first change | Ten lines on what was found, and a map page to browse |
|
|
96
|
+
| `leyline plan <change>` | After the change is written as a spec, and after every edit to it | The page, `leyline.md`, and what is still needed before implementation |
|
|
97
|
+
| `leyline check <change> --tests FILE` | After the code is written | The verdict, added to the same page |
|
|
98
|
+
|
|
99
|
+
A change is an [OpenSpec](https://openspec.dev) folder, `openspec/changes/<id>/`: a proposal, the
|
|
100
|
+
requirements with scenarios, and a task list. You describe the change in words and your agent writes the
|
|
101
|
+
folder; `skills/leyline-spec/SKILL.md` tells it how. `<change>` is the folder or just its id.
|
|
102
|
+
|
|
103
|
+
A change someone else already wrote (a branch, a pull request) has no spec. Check it out and run
|
|
104
|
+
`leyline pr [base]` instead: see [Reviewing a pull request](docs/changes.md#reviewing-a-pull-request).
|
|
105
|
+
|
|
106
|
+
A one-line fix needs no spec either: `leyline quick "make the retry count 3" --about RETRIES` before, and
|
|
107
|
+
`leyline quick --done quick-make-the-retry-count-3 --tests -` after. See [A quick change](docs/changes.md#a-quick-change).
|
|
108
|
+
|
|
109
|
+
### A worked example
|
|
110
|
+
|
|
111
|
+
The repository `tests/fixture2` has a small Python package with an `Engine` class and its tests.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
cp -r tests/fixture2 /tmp/engine-repo && cd /tmp/engine-repo
|
|
115
|
+
leyline map .
|
|
116
|
+
```
|
|
117
|
+
```
|
|
118
|
+
Mapped engine-repo in 0.8 s: 14 files, 354 lines, 4 modules.
|
|
119
|
+
Found 34 types, 73 functions, 5 tests and 1 entry point (where a program starts).
|
|
120
|
+
Modules: cs/Mod (8 files), py/src/pkg (2 files), py/tests (2 files), py/web (2 files)
|
|
121
|
+
Design patterns found: builder, composite, decorator, factory 2, singleton, strategy, template method
|
|
122
|
+
Store: .leyline/leyline.db
|
|
123
|
+
Map page: .leyline/map.html (open it in a browser)
|
|
124
|
+
Next: write the change you want as an OpenSpec folder, openspec/changes/<id>/ (ask your agent; ...
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
You tell your agent: "engine names should come back in upper case, and add a `shout`". It writes
|
|
128
|
+
`openspec/changes/loud-engine/` with this `tasks.md`
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
- [ ] 1.1 Change `Engine.start` to return the name in upper case
|
|
132
|
+
- [ ] 1.2 Add `Engine.shout`, the name with an exclamation mark
|
|
133
|
+
- [ ] 1.3 Add the test "Shout"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
and two scenarios, `Start` and `Shout`, in `specs/engine/spec.md`. Then you plan it, passing the tests'
|
|
137
|
+
output from before any code changes so that `check` can tell a test the change breaks from one that
|
|
138
|
+
already failed (TAP from vitest, node --test or tap, `pytest -rA`, `go test -v`, `jest --verbose`,
|
|
139
|
+
`dotnet test --logger "console;verbosity=detailed"`, or any runner
|
|
140
|
+
that prints one PASS or FAIL line per test):
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
(cd py && PYTHONPATH=src pytest -rA tests) | leyline plan loud-engine --tests -
|
|
144
|
+
```
|
|
145
|
+
```
|
|
146
|
+
# Loud engine
|
|
147
|
+
...
|
|
148
|
+
**State: ready to implement.** It has not been reviewed.
|
|
149
|
+
|
|
150
|
+
Names are hard to read in logs. The plan has 3 tasks: it changes Engine.start and adds Engine.shout.
|
|
151
|
+
Nothing else must be edited with it; 4 places in 1 module run into the changed code and may behave
|
|
152
|
+
differently; 3 existing tests already run through it. It is done when 2 scenarios pass: 1 already has a
|
|
153
|
+
test, 1 needs a test written.
|
|
154
|
+
...
|
|
155
|
+
**Shares a caller or a field with the change, and no task names it.** Each line is either right to
|
|
156
|
+
leave alone or a missing task:
|
|
157
|
+
- Engine.name (used by Engine.start) is also used by Engine.child
|
|
158
|
+
...
|
|
159
|
+
Next: have the plan reviewed (logic and performance) before code is written (ask your agent to run the
|
|
160
|
+
leyline-adversarial-review skill), then run `leyline plan loud-engine` again. Or, if you accept the plan
|
|
161
|
+
as it is, implement it.
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The agent implements the tasks. Then:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
(cd py && PYTHONPATH=src pytest -rA tests) | leyline check loud-engine --tests -
|
|
168
|
+
```
|
|
169
|
+
```
|
|
170
|
+
## 4. Was it done as agreed
|
|
171
|
+
**Yes.** Every task is done, every scenario is proven, and nothing outside the spec changed.
|
|
172
|
+
|
|
173
|
+
| Task | Result | Verdict | Missing |
|
|
174
|
+
| 1.1 Change `Engine.start` to return the name in upper case | done | proven | |
|
|
175
|
+
...
|
|
176
|
+
| Scenario | Result | Verdict | Evidence |
|
|
177
|
+
| Start | passes | proven | its test reaches the changed code on the map |
|
|
178
|
+
| Shout | passes | proven | its test reaches the changed code on the map |
|
|
179
|
+
|
|
180
|
+
Verdicts: 5 proven. Blocking: partial, contradicted, inconclusive. Not blocking: needs you. (The default.)
|
|
181
|
+
|
|
182
|
+
Tests: 5 of 5 passed before, 6 of 6 after.
|
|
183
|
+
Next: nothing left to check; the change was done as agreed. Review the diff and commit it.
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`check` exits 0 only when the change was done as agreed. Had the agent also edited `Engine.child`, the
|
|
187
|
+
verdict would read "Not yet: 1 edit is outside the spec", and `Next:` would ask you to add a task for it or
|
|
188
|
+
undo it.
|
|
189
|
+
|
|
190
|
+
### What you read
|
|
191
|
+
|
|
192
|
+
`openspec/changes/<id>/leyline.md` is the one page for a change. It opens with its state (not ready,
|
|
193
|
+
ready, done as agreed or not) and a paragraph in plain words, then:
|
|
194
|
+
|
|
195
|
+
1. **What code will be written**: each task and the code it touches.
|
|
196
|
+
2. **What it will affect**: what must be edited with it, what runs into it, the risks, and code that
|
|
197
|
+
shares a caller or a field with the change that no task names.
|
|
198
|
+
3. **How you will know it was done**: each scenario and the test that proves it.
|
|
199
|
+
4. **Review findings** and **Before implementation**: what blocks implementation, and what is left to
|
|
200
|
+
decide. Only you resolve a finding.
|
|
201
|
+
5. **Was it done as agreed**, added by `check`.
|
|
202
|
+
|
|
203
|
+
### With an agent
|
|
204
|
+
|
|
205
|
+
The agent uses the same loop through Leyline's MCP server. To connect it to Claude Code, run this in
|
|
206
|
+
the root of the repository you will work on:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
claude mcp add leyline -- leyline serve # this repository only
|
|
210
|
+
claude mcp add -s user leyline -- leyline serve # or: every project you open
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
and `leyline skills install` to give Claude Code the skills (see [Working through an agent](#working-through-an-agent)).
|
|
214
|
+
|
|
215
|
+
Claude Code starts the server in the directory it was opened in, and the server reads the store there (an agent that
|
|
216
|
+
works in another checkout of the same repository, a git worktree, passes that checkout's absolute path to `map`: it is mapped
|
|
217
|
+
as itself, its store is the one inside it, and the server reads that store until it restarts),
|
|
218
|
+
`.leyline/leyline.db`, or, from a folder inside the repository, the nearest such store above it. Nothing needs to be mapped first: the agent's first call is `map`. If `leyline` is
|
|
219
|
+
installed in a virtual environment, give its full path (`-- /path/to/venv/bin/leyline serve`); for a
|
|
220
|
+
store elsewhere, such as a workspace mapped from another directory, add `-e LEYLINE_DB=/full/path/leyline.db`
|
|
221
|
+
before the `--`. `claude mcp list` should then show `leyline` as connected.
|
|
222
|
+
|
|
223
|
+
The agent's path is the same three tools, `map`, `plan` and `check`, each returning `next`, with the
|
|
224
|
+
review tools between plan and implementation; the server's instructions give the agent that order.
|
|
225
|
+
The skills in `skills/` say how to write the spec (`leyline-spec`), review it
|
|
226
|
+
(`leyline-adversarial-review`), assess any change (`leyline-change-impact`), explain the code
|
|
227
|
+
(`leyline-tour`) and answer how something works (`leyline-explain-flow`). Answers are kept short enough for an agent's context: long lists are cut, and the
|
|
228
|
+
answer says what was cut (`cut`) and how to see the rest (`more`).
|
|
229
|
+
|
|
230
|
+
Everything below is the detail: the other commands, how the map is built, and how far to trust it.
|
|
231
|
+
`leyline --help` lists the other commands under "advanced".
|
|
232
|
+
|
|
233
|
+
## What Leyline is
|
|
234
|
+
|
|
235
|
+
Leyline maps a codebase into one SQLite graph that people and coding agents can both query.
|
|
236
|
+
Every record belongs to one of three layers:
|
|
237
|
+
|
|
238
|
+
- **fact**: extracted deterministically from the source, rebuilt on every index run
|
|
239
|
+
- **inferred**: written by an LLM, with evidence and a confidence
|
|
240
|
+
- **intent**: written by you, such as boundaries and rules
|
|
241
|
+
|
|
242
|
+
Every function and type also carries one line saying what it is for: its author's comment or docstring, or the
|
|
243
|
+
`responsibility` an agent wrote after reading it (see [understanding.md](docs/understanding.md#what-a-function-or-type-is-for)).
|
|
244
|
+
|
|
245
|
+
This version builds the fact layer for C# and Python, proposes systems by clustering, labels design
|
|
246
|
+
patterns by their shape, generates an orientation tour, assesses a described change before it is made,
|
|
247
|
+
reviews it after, and checks architecture rules.
|
|
248
|
+
|
|
249
|
+
Godot scenes and Unity prefabs are on the map too, linked to the scripts they run and the methods their signals and
|
|
250
|
+
events name, so renaming a method shows the scene that wires it ([indexing.md](docs/indexing.md#game-engine-assets)).
|
|
251
|
+
|
|
252
|
+
## Use
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
pip install -e .
|
|
256
|
+
leyline map path/to/repo # writes path/to/repo/.leyline/leyline.db and .leyline/map.html
|
|
257
|
+
leyline index path/to/repo # the same index, printing the full statistics instead
|
|
258
|
+
leyline --db ... coverage .coverage # import measured test coverage
|
|
259
|
+
leyline --db path/to/repo/.leyline/leyline.db overview
|
|
260
|
+
leyline --db ... search "Simulation Step"
|
|
261
|
+
leyline --db ... show "Simulation.Step" # one thing in detail (expand --json for every field)
|
|
262
|
+
leyline --db ... tour # a guided walk through the repository
|
|
263
|
+
leyline --db ... patterns # design patterns found by their shape
|
|
264
|
+
leyline --db ... state # fields assigned from outside their own type
|
|
265
|
+
leyline --db ... serve # MCP server over stdio
|
|
266
|
+
leyline --db ... view # the map, served on http://127.0.0.1:8765
|
|
267
|
+
leyline --db ... export -o map.html # the map as one self-contained page
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
To use it from an MCP client, register the command `leyline --db <path> serve`.
|
|
271
|
+
|
|
272
|
+
### Several repositories
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
leyline map flask/ werkzeug/ # one workspace; writes ./.leyline/leyline.db
|
|
276
|
+
leyline --db .leyline/leyline.db index werkzeug/ # re-indexes flask too
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Repositories named together are indexed in one run, so a name in one resolves to its declaration in
|
|
280
|
+
the other: `import werkzeug` in Flask reaches Werkzeug's source (a package under `src/` by its package
|
|
281
|
+
name), a Flask class extends Werkzeug's, and a Werkzeug method that calls `self.open()` dispatches
|
|
282
|
+
into Flask's override. Ids keep their own repo's prefix, so a store indexed one repository at a time
|
|
283
|
+
reads the same. The store remembers its members: indexing any one of them later indexes all of them
|
|
284
|
+
again, which keeps the links between them. A member whose directory has gone is left as stored, and `map` says so.
|
|
285
|
+
Name its new place and it is the same member, under its old id, not a second copy, when Leyline can tell it is the
|
|
286
|
+
same repository: both are git repositories with the same first commit, and the same `origin` where both have one.
|
|
287
|
+
Anything less sure (not under git, or a store mapped before Leyline recorded first commits) is mapped as a new
|
|
288
|
+
member; drop the old one with `leyline map --forget <id>`. That drops a member's facts, where it was and its place
|
|
289
|
+
in the workspace, then maps the others again in full so no link into it is left; notes and review decisions about
|
|
290
|
+
its code are kept, as when code is deleted.
|
|
291
|
+
|
|
292
|
+
`overview` lists the links between repositories; the `cross_repo` tool adds the functions most called
|
|
293
|
+
across and the flows that cross and come back. An edge between repositories carries `to_repo`;
|
|
294
|
+
`impact` and a change assessment count what they reach per repo and flag a change that reaches into
|
|
295
|
+
another one. Not yet: the C# compiler pass (SCIP indexes are matched to their repository by the
|
|
296
|
+
directory they were made in), and values handed across that the syntax pass cannot follow, such as
|
|
297
|
+
the WSGI app a test client calls.
|
|
298
|
+
|
|
299
|
+
### Someone else's repository
|
|
300
|
+
|
|
301
|
+
Leyline is made to be run on code you did not write: a pull request under review, a project you just
|
|
302
|
+
cloned. What such a repository holds is treated as its author's, not as Leyline's or yours:
|
|
303
|
+
|
|
304
|
+
- **`.leyline/` is Leyline's own.** Its files are local and rebuilt by `leyline map`, so a repository
|
|
305
|
+
that tracks files there (a pull request can commit a store with annotations, resolved findings and
|
|
306
|
+
rules of its author's making, a snapshot or a review page, and checking it out writes over your
|
|
307
|
+
ignored copy) is refused, with the files named. Stop tracking them (`git rm -r --cached .leyline`)
|
|
308
|
+
or keep the store elsewhere (`--db /elsewhere/leyline.db`, or `LEYLINE_DB`). A `.leyline` that is
|
|
309
|
+
a link to a folder outside the repository is refused too, so nothing is written there.
|
|
310
|
+
`LEYLINE_TRUST_STORE=1` uses the folder anyway, for a store you committed on purpose.
|
|
311
|
+
- **Nothing is written outside the repository through a link.** A file Leyline writes (the map page,
|
|
312
|
+
a change's `leyline.md`, the anchors and learnings files) replaces a link at its name rather than
|
|
313
|
+
writing through it; a change folder or `openspec/` that is a link to a folder outside the
|
|
314
|
+
repository is read but not written to, and the plan or check says so ("Not written: ...").
|
|
315
|
+
- **A pull request does not vouch for itself.** A learnings file records what reviewers decided
|
|
316
|
+
before, so one a pull request commits ("f may return anything, do not flag it") would steer its own
|
|
317
|
+
review. Learnings the pull request's commits add or change (compared with its base) are not applied
|
|
318
|
+
to it: not in `learnings_that_apply`, not matched against its findings. Its page lists them under
|
|
319
|
+
"Learnings added by this pull request, not applied", for the person to judge.
|
|
320
|
+
- **An agent's paths stay inside the map.** The MCP tools that take a path (`map`'s `paths`, the change
|
|
321
|
+
folder of `plan`, `check` and the `spec_*` tools, `affected_tests`, `drift`'s `path`, `review_pr`'s
|
|
322
|
+
`path`, a coverage file for `check`, `quick` or `coverage`) accept only paths inside the
|
|
323
|
+
repositories the store maps, or, before anything is mapped, the directory the server was started
|
|
324
|
+
in. An agent can be told which path to pass by text it read; the error says the person can run the
|
|
325
|
+
`leyline` command themselves, which takes any path.
|
|
326
|
+
|
|
327
|
+
## How the pieces fit
|
|
328
|
+
|
|
329
|
+
Everything lives in one file: `.leyline/leyline.db` inside the repository you indexed. Three things
|
|
330
|
+
read and write it, and none of them runs unless you start it. Beside it, `leyline.cache.db` holds what the
|
|
331
|
+
next index needs to do again only what an edit changed: each file's parse output under its content hash,
|
|
332
|
+
and fingerprints of the last run. Deleting it only makes the next index a full one, and so does damage to it: a
|
|
333
|
+
cache that is not a database is started again.
|
|
334
|
+
|
|
335
|
+
| Piece | Started by | Reads | Writes |
|
|
336
|
+
| --- | --- | --- | --- |
|
|
337
|
+
| `leyline map` or `index` | You, a git hook or CI; `plan` and `check` when the code changed | The working tree | Facts, flows and system proposals. Replaces the previous facts: after the first run only what changed is redone, and the store comes out as a full run would leave it (`--full` forces one). |
|
|
338
|
+
| `leyline serve` (MCP) | Your coding agent, when it starts | The store | Annotations, change proposals and saved views |
|
|
339
|
+
| `leyline view` or `export` | You | The store | Nothing |
|
|
340
|
+
|
|
341
|
+
One index runs at a time per store. A second one that starts while another is running (a `map` while a `plan`
|
|
342
|
+
re-maps) says so on stderr, naming the other process and how long it has been going, waits for it to finish,
|
|
343
|
+
and then maps what changed since. It waits up to an hour (`LEYLINE_WAIT`, in seconds), and past that stops with
|
|
344
|
+
the same message. A run that dies lets go of the store with its process.
|
|
345
|
+
|
|
346
|
+
Annotations, proposals and views are not facts, so re-indexing keeps them. An annotation is flagged
|
|
347
|
+
stale when the code behind its evidence changes.
|
|
348
|
+
|
|
349
|
+
## Further reading
|
|
350
|
+
|
|
351
|
+
The rest of the documentation is in `docs/`:
|
|
352
|
+
|
|
353
|
+
- [quick-reference.md](docs/quick-reference.md): one page of what to ask, and the command or tool behind it.
|
|
354
|
+
- [changes.md](docs/changes.md): planning, reviewing and checking a change: the spec loop, spec drift, assessing a
|
|
355
|
+
change, reviewing a pull request, a quick change, learning from rejected findings, sequence diagrams, rules.
|
|
356
|
+
- [understanding.md](docs/understanding.md): what the map finds and how to ask it: exact references, measured
|
|
357
|
+
coverage, field reads and writes, design patterns, tours, change coupling, outlines, asking how something works,
|
|
358
|
+
large modules, the map page.
|
|
359
|
+
- [mcp-tools.md](docs/mcp-tools.md): every MCP tool and its arguments.
|
|
360
|
+
- [indexing.md](docs/indexing.md): which files and languages are read, how calls and channels are resolved, systems,
|
|
361
|
+
annotations, flows, and how well it holds up.
|
|
362
|
+
|
|
363
|
+
## Identity
|
|
364
|
+
|
|
365
|
+
Node ids are stable across file moves within a project:
|
|
366
|
+
|
|
367
|
+
- C#: `repo:csharp:Project::Namespace.Type.Member(ParamTypes)`. The project is part of the id
|
|
368
|
+
because two projects may declare the same type name.
|
|
369
|
+
- Python: `repo:python:package.module.Class.method`
|
|
370
|
+
- TypeScript, JavaScript and the generic languages: `repo:language:dir.file.Name`, the file named without its
|
|
371
|
+
extension. Two files of one language in one directory that differ only in their extension (`a.js` beside
|
|
372
|
+
`a.ts`, `m.c` beside `m.h`) would name their contents alike: the first by path keeps that id, and the others
|
|
373
|
+
keep their extension in it (`repo:typescript:dir.a.ts.Name`). Adding or removing such a neighbour can change
|
|
374
|
+
the ids of the files after it.
|
|
375
|
+
- Files and modules: `repo:file:path` and `repo:module:path`
|
|
376
|
+
|
|
377
|
+
A name defined twice in one file (`def load()` in both branches of an `if` or a `try`, a property's getter and
|
|
378
|
+
setter) is one node: which definition runs is not known from the text. Its span runs from the first definition
|
|
379
|
+
to the last, its `definitions` attribute lists each one's lines, its text hash reads every body, and its calls
|
|
380
|
+
come from all of them.
|
|
381
|
+
|
|
382
|
+
## Tests
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
pytest
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
A new skill is a folder under `skills/` with a `SKILL.md`. That folder is the only copy: the wheel carries it as
|
|
389
|
+
`leyline/skills/`, and `leyline skills`, the MCP prompts and the `skills` tool pick it up with no other edit.
|
|
390
|
+
`tests/test_skills.py` checks each skill's frontmatter and that the wheel's copy matches.
|
|
391
|
+
|
|
392
|
+
## License
|
|
393
|
+
|
|
394
|
+
Copyright (C) 2026 Matthew Burke.
|
|
395
|
+
|
|
396
|
+
Leyline is free software, licensed under the GNU General Public License, version 3.
|
|
397
|
+
See [LICENSE](LICENSE) for the full text. It comes with no warranty.
|