dotscope 0.1.0__tar.gz → 1.2.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.
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/.claude/hooks/pre-commit-check.sh +41 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/.claude/settings.json +15 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/.claude/settings.local.json +52 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/.git +1 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/AGENT_INSTRUCTIONS.md +129 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/README.md +90 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/docs/how-it-works.md +146 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/docs/scope-file.md +28 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/.scope +19 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/assertions.py +3 -4
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/cli.py +129 -15
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/composer.py +84 -2
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/discovery.py +36 -2
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/eval/.scope +27 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/eval/__init__.py +18 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/eval/bootstrap.py +231 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/eval/compare.py +147 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/eval/corpus.py +214 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/eval/harness.py +310 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/eval/replay.py +356 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/generate/.scope +24 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/generate/__init__.py +1 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/generate/atlas.py +341 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/generate/contracts.py +296 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/generate/engine.py +189 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/generate/models.py +27 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/generate/network.py +284 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/health.py +272 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/help.py +16 -2
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/ingest.py +134 -20
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/intent.py +6 -10
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/mcp_server.py +433 -57
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/merge/.scope +34 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/merge/__init__.py +1 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/merge/classifier.py +83 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/merge/composer.py +210 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/merge/differ.py +178 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/merge/driver.py +147 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/merge/imports.py +114 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/merge/models.py +62 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/merge/swarm.py +336 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/models/__init__.py +1 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/models/core.py +40 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/models/eval.py +96 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/models/intent.py +1 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/models/state.py +1 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/parser.py +16 -8
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/ast_analyzer.py +252 -3
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/passes/budget_allocator.py +343 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/convention_discovery.py +98 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/convention_parser.py +12 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/graph_builder.py +139 -1
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/passes/hint_generator.py +128 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/incremental.py +85 -13
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/lang/go.py +2 -1
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/lang/javascript.py +83 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/lazy.py +51 -26
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/passes/preflight.py +117 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/semantic_diff.py +5 -5
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/checker.py +47 -2
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/passes/sentinel/checks/network.py +91 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/passes/sentinel/checks/spatial.py +115 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/checks/voice.py +3 -3
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/passes/spatial_autofix.py +206 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/virtual.py +10 -2
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/voice.py +5 -6
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/passes/voice_defaults.py +68 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/voice_discovery.py +3 -3
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/paths.py +83 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/refresh.py +543 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/resolver.py +7 -12
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/runtime_overlay.py +403 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/search/.scope +29 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/search/__init__.py +1 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/search/chunker.py +343 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/search/expander.py +129 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/search/flattener.py +187 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/search/models.py +70 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/search/observation.py +279 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/search/reranker.py +85 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/search/retriever.py +368 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/search/synthesizer.py +292 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/storage/cache.py +63 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/storage/git_hooks.py +225 -2
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/storage/incremental_state.py +124 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/storage/swarm_state.py +144 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/textio.py +122 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/tokens.py +2 -2
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/visibility.py +54 -31
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/pyproject.toml +3 -2
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/tests/test_budget.py +124 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_cli.py +17 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/tests/test_composer.py +125 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/tests/test_eval_harness.py +376 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_health.py +68 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_ingest.py +104 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_parser.py +61 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/tests/test_refresh.py +251 -0
- dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/tests/test_textio.py +85 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_virtual.py +24 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_visibility.py +79 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_voice_check.py +12 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_voice_discovery.py +14 -0
- dotscope-1.2.0/.github/workflows/python-publish.yml +70 -0
- dotscope-1.2.0/.gitignore +10 -0
- dotscope-1.2.0/.scopes +28 -0
- dotscope-1.2.0/AGENT_INSTRUCTIONS.md +129 -0
- dotscope-1.2.0/LICENSE +21 -0
- dotscope-1.2.0/PKG-INFO +127 -0
- dotscope-1.2.0/README.md +90 -0
- dotscope-1.2.0/docs/architecture.md +72 -0
- dotscope-1.2.0/docs/cli-reference.md +67 -0
- dotscope-1.2.0/docs/how-it-works.md +146 -0
- dotscope-1.2.0/docs/mcp-setup.md +255 -0
- dotscope-1.2.0/docs/scope-file.md +285 -0
- dotscope-1.2.0/dotscope/.scope +82 -0
- dotscope-1.2.0/dotscope/__init__.py +3 -0
- dotscope-1.2.0/dotscope/absorber.py +390 -0
- dotscope-1.2.0/dotscope/assertions.py +127 -0
- dotscope-1.2.0/dotscope/ast_analyzer.py +2 -0
- dotscope-1.2.0/dotscope/backtest.py +2 -0
- dotscope-1.2.0/dotscope/bench.py +141 -0
- dotscope-1.2.0/dotscope/budget.py +3 -0
- dotscope-1.2.0/dotscope/cache.py +2 -0
- dotscope-1.2.0/dotscope/check/__init__.py +1 -0
- dotscope-1.2.0/dotscope/check/acknowledge.py +2 -0
- dotscope-1.2.0/dotscope/check/checker.py +3 -0
- dotscope-1.2.0/dotscope/check/checks/__init__.py +1 -0
- dotscope-1.2.0/dotscope/check/checks/antipattern.py +2 -0
- dotscope-1.2.0/dotscope/check/checks/boundary.py +2 -0
- dotscope-1.2.0/dotscope/check/checks/contracts.py +3 -0
- dotscope-1.2.0/dotscope/check/checks/direction.py +2 -0
- dotscope-1.2.0/dotscope/check/checks/intent.py +2 -0
- dotscope-1.2.0/dotscope/check/checks/stability.py +2 -0
- dotscope-1.2.0/dotscope/check/constraints.py +2 -0
- dotscope-1.2.0/dotscope/check/models.py +15 -0
- dotscope-1.2.0/dotscope/cli.py +1561 -0
- dotscope-1.2.0/dotscope/composer.py +229 -0
- dotscope-1.2.0/dotscope/constants.py +45 -0
- dotscope-1.2.0/dotscope/context.py +60 -0
- dotscope-1.2.0/dotscope/counterfactual.py +180 -0
- dotscope-1.2.0/dotscope/debug.py +220 -0
- dotscope-1.2.0/dotscope/discovery.py +138 -0
- dotscope-1.2.0/dotscope/eval/.scope +27 -0
- dotscope-1.2.0/dotscope/eval/__init__.py +18 -0
- dotscope-1.2.0/dotscope/eval/bootstrap.py +231 -0
- dotscope-1.2.0/dotscope/eval/compare.py +147 -0
- dotscope-1.2.0/dotscope/eval/corpus.py +214 -0
- dotscope-1.2.0/dotscope/eval/harness.py +310 -0
- dotscope-1.2.0/dotscope/eval/replay.py +356 -0
- dotscope-1.2.0/dotscope/formatter.py +157 -0
- dotscope-1.2.0/dotscope/generate/.scope +24 -0
- dotscope-1.2.0/dotscope/generate/__init__.py +1 -0
- dotscope-1.2.0/dotscope/generate/atlas.py +341 -0
- dotscope-1.2.0/dotscope/generate/contracts.py +296 -0
- dotscope-1.2.0/dotscope/generate/engine.py +189 -0
- dotscope-1.2.0/dotscope/generate/models.py +27 -0
- dotscope-1.2.0/dotscope/generate/network.py +284 -0
- dotscope-1.2.0/dotscope/graph.py +3 -0
- dotscope-1.2.0/dotscope/health.py +272 -0
- dotscope-1.2.0/dotscope/help.py +218 -0
- dotscope-1.2.0/dotscope/history.py +6 -0
- dotscope-1.2.0/dotscope/hooks.py +2 -0
- dotscope-1.2.0/dotscope/ingest.py +972 -0
- dotscope-1.2.0/dotscope/intent.py +614 -0
- dotscope-1.2.0/dotscope/lessons.py +223 -0
- dotscope-1.2.0/dotscope/matcher.py +104 -0
- dotscope-1.2.0/dotscope/mcp_server.py +1457 -0
- dotscope-1.2.0/dotscope/merge/.scope +34 -0
- dotscope-1.2.0/dotscope/merge/__init__.py +1 -0
- dotscope-1.2.0/dotscope/merge/classifier.py +83 -0
- dotscope-1.2.0/dotscope/merge/composer.py +210 -0
- dotscope-1.2.0/dotscope/merge/differ.py +178 -0
- dotscope-1.2.0/dotscope/merge/driver.py +147 -0
- dotscope-1.2.0/dotscope/merge/imports.py +114 -0
- dotscope-1.2.0/dotscope/merge/models.py +62 -0
- dotscope-1.2.0/dotscope/merge/swarm.py +336 -0
- dotscope-1.2.0/dotscope/models/.scope +45 -0
- dotscope-1.2.0/dotscope/models/__init__.py +8 -0
- dotscope-1.2.0/dotscope/models/core.py +328 -0
- dotscope-1.2.0/dotscope/models/eval.py +96 -0
- dotscope-1.2.0/dotscope/models/history.py +73 -0
- dotscope-1.2.0/dotscope/models/intent.py +214 -0
- dotscope-1.2.0/dotscope/models/passes.py +58 -0
- dotscope-1.2.0/dotscope/models/state.py +251 -0
- dotscope-1.2.0/dotscope/models.py +9 -0
- dotscope-1.2.0/dotscope/near_miss.py +3 -0
- dotscope-1.2.0/dotscope/onboarding.py +2 -0
- dotscope-1.2.0/dotscope/parser.py +395 -0
- dotscope-1.2.0/dotscope/passes/.scope +105 -0
- dotscope-1.2.0/dotscope/passes/__init__.py +1 -0
- dotscope-1.2.0/dotscope/passes/ast_analyzer.py +757 -0
- dotscope-1.2.0/dotscope/passes/backtest.py +198 -0
- dotscope-1.2.0/dotscope/passes/budget_allocator.py +343 -0
- dotscope-1.2.0/dotscope/passes/convention_compliance.py +40 -0
- dotscope-1.2.0/dotscope/passes/convention_discovery.py +345 -0
- dotscope-1.2.0/dotscope/passes/convention_parser.py +235 -0
- dotscope-1.2.0/dotscope/passes/graph_builder.py +437 -0
- dotscope-1.2.0/dotscope/passes/hint_generator.py +128 -0
- dotscope-1.2.0/dotscope/passes/history_miner.py +336 -0
- dotscope-1.2.0/dotscope/passes/incremental.py +221 -0
- dotscope-1.2.0/dotscope/passes/lang/__init__.py +38 -0
- dotscope-1.2.0/dotscope/passes/lang/_base.py +20 -0
- dotscope-1.2.0/dotscope/passes/lang/_treesitter.py +93 -0
- dotscope-1.2.0/dotscope/passes/lang/go.py +334 -0
- dotscope-1.2.0/dotscope/passes/lang/javascript.py +431 -0
- dotscope-1.2.0/dotscope/passes/lazy.py +177 -0
- dotscope-1.2.0/dotscope/passes/preflight.py +117 -0
- dotscope-1.2.0/dotscope/passes/semantic_diff.py +160 -0
- dotscope-1.2.0/dotscope/passes/sentinel/__init__.py +1 -0
- dotscope-1.2.0/dotscope/passes/sentinel/acknowledge.py +222 -0
- dotscope-1.2.0/dotscope/passes/sentinel/checker.py +428 -0
- dotscope-1.2.0/dotscope/passes/sentinel/checks/__init__.py +1 -0
- dotscope-1.2.0/dotscope/passes/sentinel/checks/antipattern.py +84 -0
- dotscope-1.2.0/dotscope/passes/sentinel/checks/boundary.py +46 -0
- dotscope-1.2.0/dotscope/passes/sentinel/checks/contracts.py +148 -0
- dotscope-1.2.0/dotscope/passes/sentinel/checks/convention.py +54 -0
- dotscope-1.2.0/dotscope/passes/sentinel/checks/direction.py +71 -0
- dotscope-1.2.0/dotscope/passes/sentinel/checks/intent.py +207 -0
- dotscope-1.2.0/dotscope/passes/sentinel/checks/network.py +91 -0
- dotscope-1.2.0/dotscope/passes/sentinel/checks/spatial.py +115 -0
- dotscope-1.2.0/dotscope/passes/sentinel/checks/stability.py +66 -0
- dotscope-1.2.0/dotscope/passes/sentinel/checks/voice.py +108 -0
- dotscope-1.2.0/dotscope/passes/sentinel/constraints.py +472 -0
- dotscope-1.2.0/dotscope/passes/sentinel/line_filter.py +88 -0
- dotscope-1.2.0/dotscope/passes/sentinel/models.py +15 -0
- dotscope-1.2.0/dotscope/passes/spatial_autofix.py +206 -0
- dotscope-1.2.0/dotscope/passes/virtual.py +247 -0
- dotscope-1.2.0/dotscope/passes/voice.py +161 -0
- dotscope-1.2.0/dotscope/passes/voice_defaults.py +68 -0
- dotscope-1.2.0/dotscope/passes/voice_discovery.py +245 -0
- dotscope-1.2.0/dotscope/paths.py +83 -0
- dotscope-1.2.0/dotscope/progress.py +44 -0
- dotscope-1.2.0/dotscope/refresh.py +543 -0
- dotscope-1.2.0/dotscope/regression.py +147 -0
- dotscope-1.2.0/dotscope/resolver.py +198 -0
- dotscope-1.2.0/dotscope/runtime_overlay.py +403 -0
- dotscope-1.2.0/dotscope/scanner.py +246 -0
- dotscope-1.2.0/dotscope/search/.scope +29 -0
- dotscope-1.2.0/dotscope/search/__init__.py +1 -0
- dotscope-1.2.0/dotscope/search/chunker.py +343 -0
- dotscope-1.2.0/dotscope/search/expander.py +129 -0
- dotscope-1.2.0/dotscope/search/flattener.py +187 -0
- dotscope-1.2.0/dotscope/search/models.py +70 -0
- dotscope-1.2.0/dotscope/search/observation.py +279 -0
- dotscope-1.2.0/dotscope/search/reranker.py +85 -0
- dotscope-1.2.0/dotscope/search/retriever.py +368 -0
- dotscope-1.2.0/dotscope/search/synthesizer.py +292 -0
- dotscope-1.2.0/dotscope/sessions.py +2 -0
- dotscope-1.2.0/dotscope/storage/.scope +64 -0
- dotscope-1.2.0/dotscope/storage/__init__.py +1 -0
- dotscope-1.2.0/dotscope/storage/cache.py +177 -0
- dotscope-1.2.0/dotscope/storage/claude_hooks.py +119 -0
- dotscope-1.2.0/dotscope/storage/git_hooks.py +500 -0
- dotscope-1.2.0/dotscope/storage/incremental_state.py +124 -0
- dotscope-1.2.0/dotscope/storage/mcp_config.py +98 -0
- dotscope-1.2.0/dotscope/storage/near_miss.py +183 -0
- dotscope-1.2.0/dotscope/storage/onboarding.py +150 -0
- dotscope-1.2.0/dotscope/storage/session_manager.py +195 -0
- dotscope-1.2.0/dotscope/storage/swarm_state.py +144 -0
- dotscope-1.2.0/dotscope/storage/timing.py +84 -0
- dotscope-1.2.0/dotscope/textio.py +122 -0
- dotscope-1.2.0/dotscope/timing.py +2 -0
- dotscope-1.2.0/dotscope/tokens.py +53 -0
- dotscope-1.2.0/dotscope/utility.py +123 -0
- dotscope-1.2.0/dotscope/virtual.py +3 -0
- dotscope-1.2.0/dotscope/visibility.py +687 -0
- dotscope-1.2.0/logo.png +0 -0
- dotscope-1.2.0/pyproject.toml +45 -0
- dotscope-1.2.0/tests/.scope +29 -0
- dotscope-1.2.0/tests/__init__.py +0 -0
- dotscope-1.2.0/tests/conftest.py +152 -0
- dotscope-1.2.0/tests/test_absorber.py +91 -0
- dotscope-1.2.0/tests/test_ast_analyzer.py +168 -0
- dotscope-1.2.0/tests/test_backtest.py +114 -0
- dotscope-1.2.0/tests/test_budget.py +124 -0
- dotscope-1.2.0/tests/test_canonical_snippet.py +70 -0
- dotscope-1.2.0/tests/test_cli.py +122 -0
- dotscope-1.2.0/tests/test_composer.py +125 -0
- dotscope-1.2.0/tests/test_context.py +52 -0
- dotscope-1.2.0/tests/test_enforcement.py +423 -0
- dotscope-1.2.0/tests/test_eval_harness.py +376 -0
- dotscope-1.2.0/tests/test_experience.py +237 -0
- dotscope-1.2.0/tests/test_graph.py +78 -0
- dotscope-1.2.0/tests/test_health.py +142 -0
- dotscope-1.2.0/tests/test_history.py +71 -0
- dotscope-1.2.0/tests/test_ingest.py +319 -0
- dotscope-1.2.0/tests/test_lessons.py +91 -0
- dotscope-1.2.0/tests/test_line_filter.py +67 -0
- dotscope-1.2.0/tests/test_loop.py +384 -0
- dotscope-1.2.0/tests/test_matcher.py +47 -0
- dotscope-1.2.0/tests/test_near_miss.py +161 -0
- dotscope-1.2.0/tests/test_parser.py +180 -0
- dotscope-1.2.0/tests/test_refresh.py +251 -0
- dotscope-1.2.0/tests/test_resolver.py +100 -0
- dotscope-1.2.0/tests/test_rigor.py +223 -0
- dotscope-1.2.0/tests/test_routing.py +207 -0
- dotscope-1.2.0/tests/test_scanner.py +54 -0
- dotscope-1.2.0/tests/test_sessions.py +122 -0
- dotscope-1.2.0/tests/test_textio.py +85 -0
- dotscope-1.2.0/tests/test_treesitter.py +359 -0
- dotscope-1.2.0/tests/test_utility.py +48 -0
- dotscope-1.2.0/tests/test_virtual.py +95 -0
- dotscope-1.2.0/tests/test_visibility.py +417 -0
- dotscope-1.2.0/tests/test_voice_check.py +123 -0
- dotscope-1.2.0/tests/test_voice_discovery.py +143 -0
- dotscope-1.2.0/uv.lock +2375 -0
- dotscope-0.1.0/PKG-INFO +0 -50
- dotscope-0.1.0/README.md +0 -18
- dotscope-0.1.0/docs/how-it-works.md +0 -86
- dotscope-0.1.0/dotscope/health.py +0 -212
- dotscope-0.1.0/dotscope/passes/budget_allocator.py +0 -164
- dotscope-0.1.0/dotscope/passes/voice_defaults.py +0 -28
- dotscope-0.1.0/dotscope/paths.py +0 -32
- dotscope-0.1.0/dotscope/storage/incremental_state.py +0 -61
- dotscope-0.1.0/tests/test_budget.py +0 -62
- dotscope-0.1.0/tests/test_composer.py +0 -65
- {dotscope-0.1.0 → dotscope-1.2.0}/.claude/hooks/pre-commit-check.sh +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0}/.claude/settings.json +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0}/.claude/settings.local.json +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/.gitignore +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/.scopes +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/LICENSE +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/docs/architecture.md +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/docs/cli-reference.md +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/docs/mcp-setup.md +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/__init__.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/absorber.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/ast_analyzer.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/backtest.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/bench.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/budget.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/cache.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/check/__init__.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/check/acknowledge.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/check/checker.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/check/checks/__init__.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/check/checks/antipattern.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/check/checks/boundary.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/check/checks/contracts.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/check/checks/direction.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/check/checks/intent.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/check/checks/stability.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/check/constraints.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/check/models.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/constants.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/context.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/counterfactual.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/debug.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/formatter.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/graph.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/history.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/hooks.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/lessons.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/matcher.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/models/.scope +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/models/history.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/models/passes.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/models.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/near_miss.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/onboarding.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/.scope +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/__init__.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/backtest.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/convention_compliance.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/history_miner.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/lang/__init__.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/lang/_base.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/lang/_treesitter.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/__init__.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/acknowledge.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/checks/__init__.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/checks/antipattern.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/checks/boundary.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/checks/contracts.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/checks/convention.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/checks/direction.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/checks/intent.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/checks/stability.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/constraints.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/line_filter.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/passes/sentinel/models.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/progress.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/regression.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/scanner.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/sessions.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/storage/.scope +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/storage/__init__.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/storage/claude_hooks.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/storage/mcp_config.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/storage/near_miss.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/storage/onboarding.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/storage/session_manager.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/storage/timing.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/timing.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/utility.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/dotscope/virtual.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/logo.png +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/.scope +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/__init__.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/conftest.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_absorber.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_ast_analyzer.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_backtest.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_canonical_snippet.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_context.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_enforcement.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_experience.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_graph.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_history.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_lessons.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_line_filter.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_loop.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_matcher.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_near_miss.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_resolver.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_rigor.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_routing.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_scanner.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_sessions.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_treesitter.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/tests/test_utility.py +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0/.claude/worktrees/hopeful-chatelet}/uv.lock +0 -0
- {dotscope-0.1.0 → dotscope-1.2.0}/.mcp.json +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# dotscope pre-commit enforcement for Claude Code
|
|
3
|
+
#
|
|
4
|
+
# Intercepts git commit commands and runs dotscope check on staged changes.
|
|
5
|
+
# Exit 2 blocks the commit and feeds the error back to the agent.
|
|
6
|
+
# Non-commit Bash commands pass through untouched.
|
|
7
|
+
|
|
8
|
+
set -e
|
|
9
|
+
|
|
10
|
+
INPUT=$(cat)
|
|
11
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
12
|
+
|
|
13
|
+
# Only intercept git commit commands
|
|
14
|
+
case "$COMMAND" in
|
|
15
|
+
git\ commit*) ;;
|
|
16
|
+
*) exit 0 ;;
|
|
17
|
+
esac
|
|
18
|
+
|
|
19
|
+
# Run dotscope check on staged changes (30s timeout, fail open)
|
|
20
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
21
|
+
OUTPUT=$(timeout 30 python3 -m dotscope.cli check 2>&1) || true
|
|
22
|
+
elif command -v gtimeout >/dev/null 2>&1; then
|
|
23
|
+
OUTPUT=$(gtimeout 30 python3 -m dotscope.cli check 2>&1) || true
|
|
24
|
+
else
|
|
25
|
+
OUTPUT=$(python3 -m dotscope.cli check 2>&1) || true
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Only GUARDs block. NUDGEs and NOTEs pass through.
|
|
29
|
+
if echo "$OUTPUT" | grep -qE "GUARD|HOLD"; then
|
|
30
|
+
echo "$OUTPUT" >&2
|
|
31
|
+
echo "" >&2
|
|
32
|
+
echo "dotscope: commit blocked -- address guards before committing" >&2
|
|
33
|
+
exit 2
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# NUDGEs and NOTEs are guidance, not gates
|
|
37
|
+
if echo "$OUTPUT" | grep -qE "NUDGE|NOTE"; then
|
|
38
|
+
echo "$OUTPUT" >&2
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
exit 0
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(python3 -c \"from dotscope.mcp_server import create_server; create_server\\(\\)\")",
|
|
5
|
+
"Bash(python3 -c \"from dotscope.mcp_server import main\")",
|
|
6
|
+
"Bash(chmod +x /Users/nigel/Documents/dotscope/.claude/hooks/pre-commit-check.sh)",
|
|
7
|
+
"Bash(python3 -m pytest tests/ -x -q)",
|
|
8
|
+
"WebSearch",
|
|
9
|
+
"WebFetch(domain:support.claude.com)",
|
|
10
|
+
"Bash(python3 -m pytest tests/test_line_filter.py -x -q)",
|
|
11
|
+
"Bash(git add:*)",
|
|
12
|
+
"Bash(python3 -m dotscope.cli check --acknowledge contract_dotscope_visibility__tests_test_visibilit_f05a15 --reason \"Large feature commit — visibility changes are internal\")",
|
|
13
|
+
"Bash(python3 -m dotscope.cli check --acknowledge contract_dotscope_mcp_server__dotscope_models_py_556414 --reason \"Large feature commit — models.py not affected by these changes\")",
|
|
14
|
+
"Bash(python3 -m dotscope.cli check --acknowledge contract_dotscope_mcp_server__dotscope_budget_py_8639b0 --reason \"Large feature commit — budget.py not affected\")",
|
|
15
|
+
"Bash(python3 -m dotscope.cli check --acknowledge contract_dotscope_mcp_server__tests_test_visibilit_57f45e --reason \"Large feature commit — visibility tests not affected\")",
|
|
16
|
+
"Bash(python3 -m dotscope.cli check --acknowledge contract_dotscope_cli_py_dotscope_models_py_42c554 --reason \"Large feature commit — models.py not affected\")",
|
|
17
|
+
"mcp__dotscope__dotscope_acknowledge",
|
|
18
|
+
"Bash(git commit:*)",
|
|
19
|
+
"Bash(git pull:*)",
|
|
20
|
+
"Bash(git push:*)",
|
|
21
|
+
"Bash(ls /Users/nigel/Downloads/dotscope*)",
|
|
22
|
+
"Bash(ls -t /Users/nigel/Downloads/*.png /Users/nigel/Downloads/*.jpg /Users/nigel/Downloads/*.svg)",
|
|
23
|
+
"Bash(python3 -c \"from dotscope.passes.sentinel import *\")",
|
|
24
|
+
"Bash(grep -n \"write_text\\\\|path.write\\\\|json.dump\" /Users/nigel/Documents/dotscope/dotscope/storage/*.py)",
|
|
25
|
+
"Bash(grep -n \"/ \" /Users/nigel/Documents/dotscope/dotscope/passes/*.py)",
|
|
26
|
+
"Bash(grep -n \"\\\\.get\\(\" /Users/nigel/Documents/dotscope/dotscope/passes/sentinel/*.py)",
|
|
27
|
+
"Bash(wc -l /Users/nigel/Documents/dotscope/dotscope/*.py)",
|
|
28
|
+
"Bash(grep -n \"\\\\[\"\"\" /Users/nigel/Documents/dotscope/dotscope/passes/sentinel/checks/*.py)",
|
|
29
|
+
"Bash(python3 -m py_compile dotscope/passes/convention_discovery.py dotscope/passes/convention_parser.py dotscope/passes/convention_compliance.py dotscope/passes/semantic_diff.py dotscope/passes/voice_discovery.py dotscope/passes/voice_defaults.py dotscope/passes/voice.py dotscope/passes/lazy.py dotscope/passes/incremental.py dotscope/passes/graph_builder.py dotscope/passes/history_miner.py dotscope/passes/budget_allocator.py dotscope/passes/backtest.py dotscope/passes/ast_analyzer.py dotscope/passes/virtual.py)",
|
|
30
|
+
"Bash(grep -n \"sys.exit\\(1\\)\" dotscope/*.py)",
|
|
31
|
+
"Bash(grep -n \"$\\\\|echo\\\\|grep\" /Users/nigel/Documents/dotscope/dotscope/storage/git_hooks.py)",
|
|
32
|
+
"Bash(grep -n \"\\\\.get.*\\\\[0\\\\]\" dotscope/passes/*.py)",
|
|
33
|
+
"Bash(python -m pytest tests/test_eval_harness.py -v)",
|
|
34
|
+
"Bash(python3 -m pytest tests/test_eval_harness.py -v)",
|
|
35
|
+
"Bash(python3 -m pytest tests/ -x --timeout=30)",
|
|
36
|
+
"Bash(python3 -c \":*)",
|
|
37
|
+
"Bash(python3 -c \"import inspect; from dotscope.resolver import resolve; print\\(inspect.signature\\(resolve\\)\\)\")",
|
|
38
|
+
"Bash(python3 -m pytest tests/test_eval_harness.py tests/ -x -q)",
|
|
39
|
+
"Bash(grep -E \"\\\\.\\(py|json\\)$\")",
|
|
40
|
+
"Bash(python3:*)",
|
|
41
|
+
"Bash(ls /Users/nigel/Documents/dotscope/.claude/worktrees/hopeful-chatelet/dotscope/*.py)",
|
|
42
|
+
"Bash(xargs -I{} basename {})",
|
|
43
|
+
"Bash(for K in 10 12 15 18 20)",
|
|
44
|
+
"Bash(do python3 -c \":*)",
|
|
45
|
+
"Bash(sort -t= -k2 -n)",
|
|
46
|
+
"Bash(for K in 8 10 12 14 16)",
|
|
47
|
+
"Bash(git fetch:*)",
|
|
48
|
+
"Bash(gh pr:*)",
|
|
49
|
+
"Bash(gh api:*)"
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gitdir: /Users/nigel/Documents/dotscope/.git/worktrees/hopeful-chatelet
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# dotscope Agent Instructions
|
|
2
|
+
|
|
3
|
+
## How This Codebase Works
|
|
4
|
+
|
|
5
|
+
This repository is managed by dotscope, a codebase compiler that provides you with architectural context, dependency analysis, and mutation safety. You have access to dotscope's MCP tools. Use them instead of manually reading files and guessing at architecture.
|
|
6
|
+
|
|
7
|
+
## The One Rule
|
|
8
|
+
|
|
9
|
+
**Start every task with `codebase_search`.** Do not read files manually. Do not guess which files are relevant. `codebase_search` returns the code, its dependency neighborhood, the bodies of functions it calls, the contracts you must honor, the conventions you must follow, and which files another agent is currently mutating. One call replaces five.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
# Wrong: manual discovery
|
|
13
|
+
1. Read src/billing/webhooks.py
|
|
14
|
+
2. Read src/billing/processor.py
|
|
15
|
+
3. Read tests/billing/test_webhooks.py
|
|
16
|
+
4. Guess at conventions
|
|
17
|
+
5. Hope nothing is locked
|
|
18
|
+
|
|
19
|
+
# Right: compiled retrieval
|
|
20
|
+
1. codebase_search("Stripe webhook retry logic")
|
|
21
|
+
→ code + dependencies + abstractions + contracts + locks — done
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Tool Reference
|
|
27
|
+
|
|
28
|
+
### Discovery Tools
|
|
29
|
+
|
|
30
|
+
**`codebase_search(query, budget?, limit?)`**
|
|
31
|
+
Your primary entry point. Natural-language query returns a compiled `ResolvedScope`:
|
|
32
|
+
- `files` — ranked by architectural relevance, budget-fitted
|
|
33
|
+
- `flattened_abstractions` — bodies of cross-file functions your code calls, with lock status
|
|
34
|
+
- `constraints` — implicit contracts, anti-patterns, intents you must respect
|
|
35
|
+
- `routing` — convention blueprints, voice rules for how to write new code
|
|
36
|
+
- `retrieval_metadata` — index freshness, scores, result count
|
|
37
|
+
|
|
38
|
+
Use for: any task where you don't already know the scope name.
|
|
39
|
+
|
|
40
|
+
**`resolve_scope(scope_name, task?)`**
|
|
41
|
+
When you already know which scope to work in (e.g., "billing", "auth"). Returns the same `ResolvedScope` structure without the retrieval layer. Useful for follow-up work after an initial `codebase_search`.
|
|
42
|
+
|
|
43
|
+
Use for: continuing work in a known scope, or when a constraint references a scope by name.
|
|
44
|
+
|
|
45
|
+
### Mutation Tools
|
|
46
|
+
|
|
47
|
+
**`dotscope_claim_scope(scope_name, task_description)`**
|
|
48
|
+
Claim exclusive write access before modifying files. The claim includes a blast radius: direct dependents get exclusive locks, two-hop dependents get shared locks. Other agents can still read but will be warned before claiming overlapping files.
|
|
49
|
+
|
|
50
|
+
Call this AFTER `codebase_search` / `resolve_scope` but BEFORE writing any code.
|
|
51
|
+
|
|
52
|
+
**`dotscope_renew_lock(scope_name)`**
|
|
53
|
+
If your task is taking longer than expected and you receive a lock expiry warning in a `resolve_scope` response, renew immediately. An expired lock means another agent can claim your files mid-work.
|
|
54
|
+
|
|
55
|
+
**`dotscope_check(diff)`**
|
|
56
|
+
Pre-commit verification. Runs your changes against the contract enforcement pipeline: implicit contracts, network contracts, convention compliance, co-change requirements. This is your safety net. Always run it before committing.
|
|
57
|
+
|
|
58
|
+
If `dotscope_check` returns violations, fix them before committing. The violations are structured descriptions — they tell you exactly what broke and why.
|
|
59
|
+
|
|
60
|
+
**`dotscope_escalate()`**
|
|
61
|
+
When you're stuck in a conflict you can't resolve: interlocking locks, merge conflicts, contract violations that require cross-scope changes beyond your claim. Escalation surfaces the full state to a human operator or supervisory agent.
|
|
62
|
+
|
|
63
|
+
### Documentation Tool
|
|
64
|
+
|
|
65
|
+
**`generate_artifacts(artifact?)`**
|
|
66
|
+
Generates human-readable architecture documents from dotscope's analysis. Useful when asked to "document the architecture" or "explain the system contracts." Produces: `ARCHITECTURE_CONTRACTS.md`, `NETWORK_MAP.md`, `CO_CHANGE_ATLAS.md`.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Reading a `codebase_search` Response
|
|
71
|
+
|
|
72
|
+
The response is JSON. Here's what to do with each section:
|
|
73
|
+
|
|
74
|
+
**`files`** — These are the files you'll be working in. They're already ranked by relevance and trimmed to your token budget. Trust the ranking.
|
|
75
|
+
|
|
76
|
+
**`flattened_abstractions`** — These are the bodies of functions your code calls in other files. Read them to understand the interface contracts. Check `lock_status`:
|
|
77
|
+
- `"unlocked"` — safe to modify if needed
|
|
78
|
+
- `"shared_locked"` — another agent has nearby work; modify with caution
|
|
79
|
+
- `"exclusive_locked"` — another agent owns this; do not modify, work with the current interface
|
|
80
|
+
|
|
81
|
+
**`constraints`** — These are the rules. If a constraint says "when `pricing_engine.py` changes, `tax_calculator.py` must also change," then you must change both or change neither. Constraints with `severity: "GUARD"` will block your commit if violated. Constraints with `severity: "NOTE"` are advisory.
|
|
82
|
+
|
|
83
|
+
**`routing`** — These are the conventions. If routing says "all ViewSet classes must include `permission_classes`," your new ViewSet must include it. If it specifies a voice (e.g., "docstrings use imperative mood, max 2 lines"), match it.
|
|
84
|
+
|
|
85
|
+
**`retrieval_metadata`** — Check `index_freshness`. If it says `"stale"`, the vector index is outdated and results are BM25-only (keyword matching). Execute `dotscope ingest` to rebuild the index before proceeding. Without a fresh index, you are flying blind on conceptual queries.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Standard Workflow
|
|
90
|
+
|
|
91
|
+
### For any code modification task:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
1. DISCOVER codebase_search("your task description")
|
|
95
|
+
2. UNDERSTAND Read the response: files, abstractions, constraints, routing
|
|
96
|
+
3. CLAIM dotscope_claim_scope("scope_name", "task description")
|
|
97
|
+
4. WRITE Make your changes, respecting constraints and conventions
|
|
98
|
+
5. CHECK dotscope_check(your_diff)
|
|
99
|
+
6. FIX If violations, fix and re-check
|
|
100
|
+
7. COMMIT Only after check passes
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**If step 3 is rejected** (overlapping exclusive locks), do not force the changes. You have three options: wait for the lock to release and retry, switch to a different task that doesn't overlap, or use `dotscope_escalate()` if the blocking lock appears stale or the task is urgent.
|
|
104
|
+
|
|
105
|
+
### For multi-file changes:
|
|
106
|
+
|
|
107
|
+
If `codebase_search` returns a co-change contract (e.g., `pricing_engine.py` ↔ `tax_calculator.py`), you must modify both files in the same commit. The contract exists because these files have historically always changed together. Changing one without the other will likely break something.
|
|
108
|
+
|
|
109
|
+
### For cross-scope work:
|
|
110
|
+
|
|
111
|
+
If your task requires changes in multiple scopes, claim each scope separately. If a scope is already claimed by another agent, either wait or escalate. Do not modify files outside your claimed scopes.
|
|
112
|
+
|
|
113
|
+
### When a merge conflict occurs:
|
|
114
|
+
|
|
115
|
+
If your `git merge` or `git rebase` fails, do NOT look for `<<<<<<< HEAD` markers. dotscope's AST Merge Driver intercepts the failure and injects a `ConflictDescriptor` JSON into your context. This descriptor contains: the conflicting function name, the other agent's version, the dependency footprint of each change, and the relevant architectural contracts. Read the conflict reason, refactor your code to align with the other agent's merged signature, and run `dotscope_check` again. If you cannot resolve the conflict programmatically, use `dotscope_escalate()`.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Anti-Patterns
|
|
120
|
+
|
|
121
|
+
**Do not manually crawl the repo.** Every `read_file` call you make instead of using `codebase_search` wastes context window and misses architectural signals. `codebase_search` already read the files, resolved the dependencies, flattened the abstractions, and checked the locks.
|
|
122
|
+
|
|
123
|
+
**Do not ignore constraints.** If a constraint says GUARD severity, `dotscope_check` will reject your commit. Fix the violation rather than working around it.
|
|
124
|
+
|
|
125
|
+
**Do not skip `dotscope_check`.** It catches contract violations, convention drift, and co-change requirements that are invisible from reading the code alone. A clean diff is not a safe diff.
|
|
126
|
+
|
|
127
|
+
**Do not modify exclusively-locked files.** If `lock_status` is `"exclusive_locked"`, another agent is actively working on that code. Your changes will conflict. Work with the current interface or escalate.
|
|
128
|
+
|
|
129
|
+
**Do not guess at conventions.** The `routing` section of the response tells you exactly how to write new code in this scope: naming patterns, import style, docstring format, required attributes. Match them.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="logo.png" alt="dotscope" width="400">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
You give an agent a task. It searches your codebase, finds the files,
|
|
6
|
+
writes the code, runs the tests, and ships. Sounds fine until you
|
|
7
|
+
realize it changed a backend endpoint without touching the frontend
|
|
8
|
+
that calls it. It put a utility function in `src/helpers/` instead of
|
|
9
|
+
next to the module that uses it. It ignored the naming convention every
|
|
10
|
+
other file follows. And when two agents worked at the same time, they
|
|
11
|
+
silently overwrote each other's changes.
|
|
12
|
+
|
|
13
|
+
The code compiled. The tests passed. Production broke.
|
|
14
|
+
|
|
15
|
+
This happens because agents don't have what you have — the full
|
|
16
|
+
picture. They see files. You see architecture.
|
|
17
|
+
|
|
18
|
+
**dotscope is the operating system for agent-driven codebases.**
|
|
19
|
+
|
|
20
|
+
One command scans your project and learns the architecture: which files
|
|
21
|
+
depend on which, what patterns your code follows, how your backend
|
|
22
|
+
talks to your frontend, and what breaks when something changes. From
|
|
23
|
+
that point on, every agent gets the full picture before it writes a
|
|
24
|
+
line.
|
|
25
|
+
|
|
26
|
+
It does five things:
|
|
27
|
+
|
|
28
|
+
1. **One search, everything you need.** An agent describes what it
|
|
29
|
+
wants to do. dotscope returns the relevant files, the functions
|
|
30
|
+
they call, the contracts they must honor, the conventions they must
|
|
31
|
+
follow, and which files are locked by other agents. One call. Not
|
|
32
|
+
five.
|
|
33
|
+
|
|
34
|
+
2. **Enforces contracts across languages.** Your Python backend and
|
|
35
|
+
TypeScript frontend share an invisible API contract. dotscope
|
|
36
|
+
extracts routes from FastAPI, Flask, and DRF. It extracts fetch
|
|
37
|
+
calls from React and Angular. It links them automatically. Change
|
|
38
|
+
a Django ViewSet without updating the Angular component? Blocked.
|
|
39
|
+
|
|
40
|
+
3. **Routes files to the right place.** Before an agent creates a
|
|
41
|
+
file, it asks dotscope where it should go. dotscope reads the
|
|
42
|
+
dependency graph and routes the file there. No more `src/utils/`
|
|
43
|
+
graveyards.
|
|
44
|
+
|
|
45
|
+
4. **Coordinates multiple agents.** When Agent A starts working on
|
|
46
|
+
billing, dotscope locks the blast radius. Agent B works on auth
|
|
47
|
+
without collision. If they touch the same function, the AST merge
|
|
48
|
+
driver resolves it semantically — not with conflict markers.
|
|
49
|
+
|
|
50
|
+
5. **Gets smarter with every commit.** Which search results did agents
|
|
51
|
+
actually use? Which did they ignore? dotscope tracks this and
|
|
52
|
+
adjusts. Conventions that hold up get enforced harder. Rules that
|
|
53
|
+
get overridden get quieter.
|
|
54
|
+
|
|
55
|
+
Here's what it looks like on a real codebase:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
$ dotscope ingest
|
|
59
|
+
|
|
60
|
+
Analyzing dependency graph...
|
|
61
|
+
Mining git history...
|
|
62
|
+
Discovering conventions...
|
|
63
|
+
|
|
64
|
+
Discoveries:
|
|
65
|
+
- version.py and environment.prod.ts always change together
|
|
66
|
+
- workflow-edit-dialog.component.ts and models.py are tightly coupled
|
|
67
|
+
|
|
68
|
+
Validation (49 commits backtested):
|
|
69
|
+
- Overall recall: 78%
|
|
70
|
+
- Token reduction: 67% (1.3M → 437K avg)
|
|
71
|
+
|
|
72
|
+
Output: 3 .scope files written.
|
|
73
|
+
|
|
74
|
+
$ dotscope check --backtest
|
|
75
|
+
|
|
76
|
+
13 issues flagged across 7 commits:
|
|
77
|
+
- models.py changes need the Angular component updated
|
|
78
|
+
- consumer.py changes need matching parser test updates
|
|
79
|
+
- views.py changes typically need test_api_search.py updated
|
|
80
|
+
|
|
81
|
+
3 commits were clean.
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
One command. Point it at anything.
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
pip install dotscope && dotscope init
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
[How It Works](docs/how-it-works.md) · [Scope Files](docs/scope-file.md) · [Agent Instructions](AGENT_INSTRUCTIONS.md) · [MIT](LICENSE)
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# How It Works
|
|
2
|
+
|
|
3
|
+
You run `dotscope init`. It scans your codebase. From that point on, every agent that touches your code gets the full picture — what files matter, what patterns to follow, what not to break, and who else is working.
|
|
4
|
+
|
|
5
|
+
## What happens when you run `dotscope init`
|
|
6
|
+
|
|
7
|
+
dotscope reads every file in your project and learns three things:
|
|
8
|
+
|
|
9
|
+
**Which files are connected.** If `billing.py` and `webhook_handler.py` always change together in your git history, dotscope knows. When an agent changes one, it gets told to check the other.
|
|
10
|
+
|
|
11
|
+
**What patterns your code follows.** If every file in `api/routes/` uses the same decorator and never touches the database directly, dotscope recognizes that as a convention. New files in that folder will follow the same pattern automatically.
|
|
12
|
+
|
|
13
|
+
**How your code is written.** Type hints on most functions? Google-style docstrings? No bare `except:` blocks? dotscope measures the style of your existing code and teaches agents to match it.
|
|
14
|
+
|
|
15
|
+
After the scan, dotscope:
|
|
16
|
+
- Installs git hooks so it stays up to date on every commit
|
|
17
|
+
- Registers an AST-aware merge driver for scoped files
|
|
18
|
+
- Connects to your AI tool (Claude Desktop, Claude Code, or Cursor) automatically
|
|
19
|
+
- Shows you what it would have caught in your last 50 commits
|
|
20
|
+
|
|
21
|
+
## What agents see
|
|
22
|
+
|
|
23
|
+
When an agent starts working on your code, it asks dotscope: "What do I need to know about this part of the project?"
|
|
24
|
+
|
|
25
|
+
dotscope responds with:
|
|
26
|
+
- **The right files** — not the whole repo, just the ones that matter for this task
|
|
27
|
+
- **The rules** — which files are connected, what patterns to follow, what imports are off-limits
|
|
28
|
+
- **The style** — how the existing code is written, so new code matches
|
|
29
|
+
- **The locks** — which files other agents are working on right now
|
|
30
|
+
|
|
31
|
+
The agent gets all of this before writing a single line. It writes code that fits in on the first try.
|
|
32
|
+
|
|
33
|
+
## What happens when something goes wrong
|
|
34
|
+
|
|
35
|
+
Before every commit, dotscope checks the agent's work:
|
|
36
|
+
|
|
37
|
+
- **Holds** (blocking) — The agent modified a backend endpoint without updating the frontend consumer. Or it wrote to a file locked by another agent. Or it violated a frozen module. The commit is stopped. The agent fixes it or acknowledges the override with an audit trail.
|
|
38
|
+
- **Notes** (informational) — A low-confidence link was flagged, or a file could live in a better directory. Worth knowing, not worth blocking.
|
|
39
|
+
|
|
40
|
+
Most of the time, nothing fires. The routing is good enough that agents follow the rules without needing to be corrected.
|
|
41
|
+
|
|
42
|
+
## It sees across languages
|
|
43
|
+
|
|
44
|
+
Your Python backend and your TypeScript frontend share an invisible contract: the HTTP API. dotscope sees both sides.
|
|
45
|
+
|
|
46
|
+
When an agent modifies a Django ViewSet that serves `/api/documents/`, dotscope knows that `document-list.component.ts` calls that endpoint. If the agent changes the backend without updating the frontend, the commit is blocked.
|
|
47
|
+
|
|
48
|
+
This works for FastAPI, Flask, Django REST Framework (including class-based ViewSets), Angular `HttpClient`, React, and any fetch/axios call. dotscope extracts routes and HTTP calls from the AST and links them with confidence scoring:
|
|
49
|
+
|
|
50
|
+
- **1.0** — exact regex match (decorator path matches fetch URL)
|
|
51
|
+
- **0.8** — suffix-aligned match (handles base URL differences)
|
|
52
|
+
- **0.5** — semantic root match (`DocumentViewSet` linked to `/api/document-types/`)
|
|
53
|
+
|
|
54
|
+
High-confidence matches (>= 0.8) block the commit. Low-confidence matches (0.5) surface as informational notes.
|
|
55
|
+
|
|
56
|
+
## It knows where files go
|
|
57
|
+
|
|
58
|
+
Agents dump utility functions in `src/utils/` and helpers in `src/helpers/`. Six months later, nobody can find anything.
|
|
59
|
+
|
|
60
|
+
dotscope prevents this with two rules derived from the dependency graph:
|
|
61
|
+
|
|
62
|
+
- **Orphan Rule** — If a file is only imported by one other file, it should live in the same directory as its parent.
|
|
63
|
+
- **Shared Rule** — If a file is imported from multiple directories, it should live at their lowest common ancestor.
|
|
64
|
+
|
|
65
|
+
Before an agent creates a file, it can ask:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
dotscope_route_file("Stripe webhook retry task", imports=["domains.billing.models"])
|
|
69
|
+
→ domains/billing/tasks/
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
If an agent ignores the suggestion, the commit gets a note with a ready-to-apply `git mv` + AST-safe import rewrites across all dependent files.
|
|
73
|
+
|
|
74
|
+
On new projects, dotscope scaffolds a clean domain-driven structure from the first commit.
|
|
75
|
+
|
|
76
|
+
## It coordinates multiple agents
|
|
77
|
+
|
|
78
|
+
When two agents work on the same codebase at the same time, they will eventually touch the same file. dotscope prevents this with the Swarm Lock — a semantic mutex built on the dependency graph.
|
|
79
|
+
|
|
80
|
+
When Agent A claims a scope, dotscope computes the **blast radius** — not just the files Agent A asked for, but everything connected to them:
|
|
81
|
+
|
|
82
|
+
- **Depth 1** (direct dependents, network consumers, high-confidence co-change partners) — exclusively locked. Other agents cannot modify these.
|
|
83
|
+
- **Depth 2** (two-hop dependents) — shared lock with warnings. Other agents can read but get a warning before writing.
|
|
84
|
+
- **Depth 3+** — no lock. If two agents happen to modify the same function, the AST merge driver handles it.
|
|
85
|
+
|
|
86
|
+
Locks expire after 30 minutes. Agents can renew them. If a lock-related conflict fails to resolve after 2 attempts, dotscope escalates to a human operator with the full conflict state.
|
|
87
|
+
|
|
88
|
+
## It merges code semantically
|
|
89
|
+
|
|
90
|
+
When two agents legitimately modify the same file — say Agent A edits `get_user()` and Agent B adds `delete_user()` — Git's line-level merger often breaks. dotscope replaces it with an AST-aware merge driver.
|
|
91
|
+
|
|
92
|
+
The merge driver:
|
|
93
|
+
1. Extracts named mutations from each agent's diff (function edits, class changes, import additions)
|
|
94
|
+
2. Checks for conflicts (same function modified by both → halt)
|
|
95
|
+
3. Merges imports using set logic: `(Ancestor - Removed_A - Removed_B) ∪ Added_A ∪ Added_B`
|
|
96
|
+
4. Reconstructs the source in two passes: reverse-order replacements (no offset drift), then fresh insertion targets for additions
|
|
97
|
+
5. Runs contract verification on the merged result before accepting
|
|
98
|
+
|
|
99
|
+
The driver is registered via `.gitattributes` — only files in active scopes use it. Everything else falls through to Git's default merger.
|
|
100
|
+
|
|
101
|
+
## It gets smarter over time
|
|
102
|
+
|
|
103
|
+
Every commit teaches dotscope something. Did the agent need a file that wasn't included? Next time, it will be. Did a convention hold up across 50 commits? Its enforcement gets stronger. Did a rule get overridden three times in a month? It gets quieter.
|
|
104
|
+
|
|
105
|
+
You don't need to configure any of this. It happens automatically through the git hooks installed during `dotscope init`.
|
|
106
|
+
|
|
107
|
+
## What you can customize
|
|
108
|
+
|
|
109
|
+
dotscope works out of the box, but you can tune it:
|
|
110
|
+
|
|
111
|
+
**Freeze a module.** If you have stable code that agents shouldn't touch:
|
|
112
|
+
```
|
|
113
|
+
dotscope intent add freeze core/
|
|
114
|
+
```
|
|
115
|
+
Any change to `core/` will be blocked until acknowledged.
|
|
116
|
+
|
|
117
|
+
**Deprecate a file.** If you're migrating away from old code:
|
|
118
|
+
```
|
|
119
|
+
dotscope intent add deprecate utils/legacy.py --replacement utils/helpers.py
|
|
120
|
+
```
|
|
121
|
+
Agents that try to import from the old file get redirected.
|
|
122
|
+
|
|
123
|
+
**Edit conventions.** dotscope discovers conventions automatically, but you can add your own or adjust the ones it found. They live in `intent.yaml` at the root of your project.
|
|
124
|
+
|
|
125
|
+
## What gets created
|
|
126
|
+
|
|
127
|
+
dotscope creates two kinds of files:
|
|
128
|
+
|
|
129
|
+
**`.scope` files** (one per folder) — These describe what an agent needs to know about that part of your code. Commit them. They're your project's memory.
|
|
130
|
+
|
|
131
|
+
**`.dotscope/` folder** — Machine state: utility scores, swarm locks, cached graphs, network edges. Gitignored. Rebuilds automatically if deleted.
|
|
132
|
+
|
|
133
|
+
Both are plain text. You can read them, edit them, or ignore them entirely.
|
|
134
|
+
|
|
135
|
+
## Languages supported
|
|
136
|
+
|
|
137
|
+
Python, JavaScript, TypeScript, and Go get full analysis — every function, every class, every import relationship mapped. Python and JS/TS also get cross-language network contract detection (backend routes linked to frontend API calls) and AST-aware merging.
|
|
138
|
+
|
|
139
|
+
Other languages get basic import detection (enough for the dependency graph and git history analysis, but no convention or style discovery).
|
|
140
|
+
|
|
141
|
+
## Further reading
|
|
142
|
+
|
|
143
|
+
- [The .scope File](scope-file.md) — what's inside a scope file and how to edit it
|
|
144
|
+
- [MCP Server Setup](mcp-setup.md) — manual setup for AI tools (usually not needed after `dotscope init`)
|
|
145
|
+
- [CLI Reference](cli-reference.md) — every command dotscope offers
|
|
146
|
+
- [Architecture](architecture.md) — how dotscope itself is built (for contributors)
|
|
@@ -218,6 +218,22 @@ conventions:
|
|
|
218
218
|
- `prohibited_imports` — imports that violate the convention
|
|
219
219
|
- `required_methods` — methods all matching classes must implement
|
|
220
220
|
- `must_have_matching` — pattern for a companion file (e.g., a test file)
|
|
221
|
+
- `allowed_paths` — regex patterns for where matching files should live (spatial routing)
|
|
222
|
+
|
|
223
|
+
```yaml
|
|
224
|
+
conventions:
|
|
225
|
+
- name: "REST Controller"
|
|
226
|
+
source: discovered
|
|
227
|
+
match:
|
|
228
|
+
any_of:
|
|
229
|
+
- has_decorator: "router"
|
|
230
|
+
rules:
|
|
231
|
+
prohibited_imports: [sqlalchemy]
|
|
232
|
+
allowed_paths: ["domains/[^/]+/api/.*\\.py"]
|
|
233
|
+
compliance: 0.92
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
The `allowed_paths` rule is discovered automatically during ingest — if 80%+ of files matching a convention share a directory structure, that structure becomes the allowed path. Agents that create files in the wrong directory get a note with a `git mv` fix.
|
|
221
237
|
|
|
222
238
|
**Compliance** tracks what percentage of matching files follow the rules. Conventions with >=80% compliance are enforced as HOLDs, 50-79% as NOTEs, and below 50% are retired.
|
|
223
239
|
|
|
@@ -249,9 +265,21 @@ voice:
|
|
|
249
265
|
|
|
250
266
|
See [How It Works](how-it-works.md) for voice discovery and enforcement.
|
|
251
267
|
|
|
268
|
+
## Multi-Agent State
|
|
269
|
+
|
|
270
|
+
When multiple agents work concurrently, dotscope maintains additional state in `.dotscope/cache/`:
|
|
271
|
+
|
|
272
|
+
- **`swarm_state.json`** — active locks, blast radii, and conflict descriptors
|
|
273
|
+
- **`network_edges.json`** — cross-language API contract links (provider → consumer)
|
|
274
|
+
- **`network_confidence.json`** — match confidence scores per link (1.0/0.8/0.5)
|
|
275
|
+
- **`graph_hubs.json`** — dependency graph hub data for fast lookups
|
|
276
|
+
|
|
277
|
+
This state is ephemeral (gitignored) and rebuilds from `dotscope ingest`. The `.gitattributes` file (which registers the AST merge driver for scoped files) should be committed.
|
|
278
|
+
|
|
252
279
|
## What to Commit
|
|
253
280
|
|
|
254
281
|
- **`.scope` files** — commit them. They're institutional memory.
|
|
255
282
|
- **`.scopes` index** — commit it. Project metadata.
|
|
256
283
|
- **`intent.yaml`** — commit it. Team's architectural direction.
|
|
284
|
+
- **`.gitattributes`** — commit it. Merge driver registration for scoped files.
|
|
257
285
|
- **`.dotscope/`** — gitignored. Machine state. Rebuilds automatically.
|
|
@@ -10,6 +10,21 @@ includes:
|
|
|
10
10
|
- dotscope/discovery.py
|
|
11
11
|
- dotscope/parser.py
|
|
12
12
|
- dotscope/visibility.py
|
|
13
|
+
- dotscope/hooks.py
|
|
14
|
+
- dotscope/budget.py
|
|
15
|
+
- dotscope/models.py
|
|
16
|
+
- dotscope/assertions.py
|
|
17
|
+
- dotscope/health.py
|
|
18
|
+
- dotscope/utility.py
|
|
19
|
+
- dotscope/sessions.py
|
|
20
|
+
- dotscope/virtual.py
|
|
21
|
+
- dotscope/lessons.py
|
|
22
|
+
- dotscope/graph.py
|
|
23
|
+
- dotscope/textio.py
|
|
24
|
+
- dotscope/tokens.py
|
|
25
|
+
- dotscope/matcher.py
|
|
26
|
+
- dotscope/ast_analyzer.py
|
|
27
|
+
- .scopes
|
|
13
28
|
excludes:
|
|
14
29
|
- dotscope/__pycache__/
|
|
15
30
|
- dotscope/models/
|
|
@@ -56,6 +71,10 @@ related:
|
|
|
56
71
|
- dotscope/models/.scope
|
|
57
72
|
- dotscope/passes/.scope
|
|
58
73
|
- dotscope/storage/.scope
|
|
74
|
+
- dotscope/search/.scope
|
|
75
|
+
- dotscope/generate/.scope
|
|
76
|
+
- dotscope/merge/.scope
|
|
77
|
+
- dotscope/eval/.scope
|
|
59
78
|
tags:
|
|
60
79
|
- cli
|
|
61
80
|
- mcp
|
|
@@ -10,6 +10,7 @@ Defined in intent.yaml (project-wide) or .scope files (per-scope).
|
|
|
10
10
|
from typing import Dict, List, Optional
|
|
11
11
|
|
|
12
12
|
from .models.intent import Assertion, ContextExhaustionError # noqa: F401
|
|
13
|
+
from .textio import read_repo_text
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
def load_assertions(repo_root: str, scope_name: str = "") -> List[Assertion]:
|
|
@@ -26,8 +27,7 @@ def load_assertions(repo_root: str, scope_name: str = "") -> List[Assertion]:
|
|
|
26
27
|
intent_path = os.path.join(repo_root, "intent.yaml")
|
|
27
28
|
if os.path.exists(intent_path):
|
|
28
29
|
from .parser import _parse_yaml
|
|
29
|
-
|
|
30
|
-
data = _parse_yaml(f.read())
|
|
30
|
+
data = _parse_yaml(read_repo_text(intent_path).text)
|
|
31
31
|
for item in _to_list_of_dicts(data.get("assertions", [])):
|
|
32
32
|
assertions.append(_parse_assertion(item))
|
|
33
33
|
|
|
@@ -38,8 +38,7 @@ def load_assertions(repo_root: str, scope_name: str = "") -> List[Assertion]:
|
|
|
38
38
|
if scope_path:
|
|
39
39
|
try:
|
|
40
40
|
from .parser import _parse_yaml
|
|
41
|
-
|
|
42
|
-
data = _parse_yaml(f.read())
|
|
41
|
+
data = _parse_yaml(read_repo_text(scope_path).text)
|
|
43
42
|
raw = data.get("assertions", {})
|
|
44
43
|
if isinstance(raw, dict):
|
|
45
44
|
a = Assertion(scope=scope_name)
|