evolution-engine 0.2.2__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/LICENSE +1 -0
  2. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/LICENSE-MIT +15 -11
  3. {evolution_engine-0.2.2/evolution_engine.egg-info → evolution_engine-0.3.1}/PKG-INFO +56 -30
  4. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/README.md +41 -18
  5. evolution_engine-0.3.1/evolution/__init__.py +1 -0
  6. evolution_engine-0.3.1/evolution/adapters/error_tracking/__init__.py +0 -0
  7. evolution_engine-0.3.1/evolution/adapters/error_tracking/sentry_adapter.py +243 -0
  8. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/agents/base.py +18 -1
  9. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/cli.py +315 -56
  10. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/config.py +12 -1
  11. evolution_engine-0.3.1/evolution/constants.py +80 -0
  12. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/format_comment.py +8 -0
  13. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/friendly.py +88 -0
  14. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/history.py +2 -2
  15. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/init.py +5 -0
  16. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/investigator.py +40 -0
  17. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/kb_sync.py +114 -2
  18. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/knowledge_store.py +3 -3
  19. evolution_engine-0.3.1/evolution/license.py +609 -0
  20. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/orchestrator.py +226 -18
  21. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/phase1_engine.py +2 -2
  22. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/phase3_engine.py +3 -16
  23. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/phase4_engine.py +9 -20
  24. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/phase5_engine.py +204 -88
  25. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/pr_comment.py +73 -17
  26. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/report_generator.py +990 -327
  27. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/report_server.py +24 -3
  28. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/setup_ui.py +32 -8
  29. evolution_engine-0.3.1/evolution/telemetry.py +324 -0
  30. {evolution_engine-0.2.2 → evolution_engine-0.3.1/evolution_engine.egg-info}/PKG-INFO +56 -30
  31. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution_engine.egg-info/SOURCES.txt +3 -0
  32. evolution_engine-0.3.1/evolution_engine.egg-info/requires.txt +17 -0
  33. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/pyproject.toml +18 -14
  34. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/setup.py +2 -2
  35. evolution_engine-0.2.2/evolution/__init__.py +0 -1
  36. evolution_engine-0.2.2/evolution/license.py +0 -298
  37. evolution_engine-0.2.2/evolution/telemetry.py +0 -141
  38. evolution_engine-0.2.2/evolution_engine.egg-info/requires.txt +0 -13
  39. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/MANIFEST.in +0 -0
  40. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/accepted.py +0 -0
  41. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapter_scaffold.py +0 -0
  42. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapter_security.py +0 -0
  43. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapter_validator.py +0 -0
  44. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapter_versions.py +0 -0
  45. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/__init__.py +0 -0
  46. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/ci/__init__.py +0 -0
  47. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/ci/circleci_adapter.py +0 -0
  48. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/ci/github_actions_adapter.py +0 -0
  49. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/ci/gitlab_pipelines_adapter.py +0 -0
  50. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/config/__init__.py +0 -0
  51. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/config/terraform_adapter.py +0 -0
  52. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/dependency/__init__.py +0 -0
  53. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/dependency/pip_adapter.py +0 -0
  54. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/deployment/__init__.py +0 -0
  55. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/deployment/github_releases_adapter.py +0 -0
  56. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/deployment/gitlab_releases_adapter.py +0 -0
  57. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/git/__init__.py +0 -0
  58. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/git/git_adapter.py +0 -0
  59. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/git/git_history_walker.py +0 -0
  60. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/github_client.py +0 -0
  61. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/gitlab_client.py +0 -0
  62. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/schema/__init__.py +0 -0
  63. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/schema/openapi_adapter.py +0 -0
  64. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/security/__init__.py +0 -0
  65. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/security/github_security_adapter.py +0 -0
  66. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/security/trivy_adapter.py +0 -0
  67. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/testing/__init__.py +0 -0
  68. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/testing/coverage_adapter.py +0 -0
  69. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/adapters/testing/junit_adapter.py +0 -0
  70. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/agents/__init__.py +0 -0
  71. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/agents/anthropic_agent.py +0 -0
  72. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/agents/cli_agent.py +0 -0
  73. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/data/adapter_blocklist.json +0 -0
  74. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/data/adapter_catalog.json +0 -0
  75. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/data/pattern_blocklist.json +0 -0
  76. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/data/pattern_index.json +0 -0
  77. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/data/sdk_fingerprints.json +0 -0
  78. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/data/universal_patterns.json +0 -0
  79. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/data/verified_adapters.json +0 -0
  80. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/fixer.py +0 -0
  81. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/fp_validation.py +0 -0
  82. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/hooks.py +0 -0
  83. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/inline_suggestions.py +0 -0
  84. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/kb_export.py +0 -0
  85. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/kb_security.py +0 -0
  86. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/llm_anthropic.py +0 -0
  87. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/llm_openrouter.py +0 -0
  88. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/notifications.py +0 -0
  89. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/pattern_registry.py +0 -0
  90. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/pattern_scaffold.py +0 -0
  91. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/pattern_validator.py +0 -0
  92. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/phase2_engine.py +0 -0
  93. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/phase3_1_renderer.py +0 -0
  94. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/prescan.py +0 -0
  95. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/registry.py +0 -0
  96. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/validation_gate.py +0 -0
  97. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution/watcher.py +0 -0
  98. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution_engine.egg-info/dependency_links.txt +0 -0
  99. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution_engine.egg-info/entry_points.txt +0 -0
  100. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/evolution_engine.egg-info/top_level.txt +0 -0
  101. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/setup.cfg +0 -0
  102. {evolution_engine-0.2.2 → evolution_engine-0.3.1}/tests/test_git_history_walker.py +0 -0
@@ -5,6 +5,7 @@ Parameters
5
5
  Licensor: CodeQual LLC
6
6
 
7
7
  Licensed Work: Evolution Engine Core Analysis Engine v0.2.0 (and all subsequent versions)
8
+ The Licensed Work is (c) 2025-2026 CodeQual LLC.
8
9
 
9
10
  Additional Use Grant: You may use the Licensed Work in non-production environments for internal testing and development without a commercial license. Production use requires a valid Pro subscription.
10
11
 
@@ -2,18 +2,12 @@ MIT License
2
2
 
3
3
  Copyright (c) 2025-2026 CodeQual LLC
4
4
 
5
- This license applies to the following components of Evolution Engine:
6
- - Command-line interface wrapper (evolution/cli.py)
7
- - Adapter framework (evolution/adapters/)
8
- - Plugin interfaces
9
- - GitHub Action wrapper (action/)
10
-
11
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
12
- of the above-listed components and associated documentation files (the
13
- "Software"), to deal in the Software without restriction, including without
14
- limitation the rights to use, copy, modify, merge, publish, distribute,
15
- sublicense, and/or sell copies of the Software, and to permit persons to whom
16
- the Software is furnished to do so, subject to the following conditions:
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
17
11
 
18
12
  The above copyright notice and this permission notice shall be included in all
19
13
  copies or substantial portions of the Software.
@@ -25,3 +19,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
21
  SOFTWARE.
22
+
23
+ ---
24
+
25
+ This MIT license applies to the following components of Evolution Engine:
26
+ - Command-line interface (evolution/cli.py)
27
+ - Adapter framework (evolution/adapters/)
28
+ - Plugin interfaces
29
+ - GitHub Action (action/)
30
+
31
+ The core analysis engine (Phases 2-5) is licensed under BSL 1.1. See LICENSE.
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: evolution-engine
3
- Version: 0.2.2
3
+ Version: 0.3.1
4
4
  Summary: Git-native codebase evolution indexer
5
5
  Author: Slava
6
6
  License: BSL-1.1
7
7
  Project-URL: Homepage, https://codequal.dev
8
- Project-URL: Repository, https://github.com/alpsla/evolution_monitor
9
- Project-URL: Bug Tracker, https://github.com/alpsla/evolution_monitor/issues
8
+ Project-URL: Repository, https://github.com/alpsla/evolution-engine
9
+ Project-URL: Bug Tracker, https://github.com/alpsla/evolution-engine/issues
10
10
  Keywords: git,devops,ci-cd,code-quality,evolution,drift-detection,codebase-analysis
11
11
  Classifier: Development Status :: 3 - Alpha
12
12
  Classifier: Environment :: Console
@@ -23,24 +23,36 @@ Requires-Python: >=3.10
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
25
  License-File: LICENSE-MIT
26
- Requires-Dist: GitPython>=3.1
27
- Requires-Dist: click>=8.0
28
- Requires-Dist: requests>=2.25
29
- Requires-Dist: jinja2>=3.0
26
+ Requires-Dist: GitPython<4,>=3.1
27
+ Requires-Dist: click<9,>=8.0
28
+ Requires-Dist: requests<3,>=2.25
29
+ Requires-Dist: jinja2<4,>=3.0
30
30
  Provides-Extra: llm
31
- Requires-Dist: requests>=2.25; extra == "llm"
31
+ Requires-Dist: requests<3,>=2.25; extra == "llm"
32
+ Provides-Extra: demo
33
+ Requires-Dist: playwright<3,>=1.40; extra == "demo"
32
34
  Provides-Extra: dev
33
- Requires-Dist: pytest>=7.0; extra == "dev"
34
- Requires-Dist: pytest-cov>=4.0; extra == "dev"
35
- Requires-Dist: python-dotenv>=0.19; extra == "dev"
36
- Requires-Dist: stripe>=7.0; extra == "dev"
35
+ Requires-Dist: pytest<9,>=7.0; extra == "dev"
36
+ Requires-Dist: pytest-cov<6,>=4.0; extra == "dev"
37
+ Requires-Dist: python-dotenv<2,>=0.19; extra == "dev"
38
+ Requires-Dist: stripe<12,>=7.0; extra == "dev"
39
+ Requires-Dist: build<2,>=1.0; extra == "dev"
37
40
  Dynamic: license-file
38
41
 
39
42
  # Evolution Engine
40
43
 
44
+ [![PyPI version](https://img.shields.io/pypi/v/evolution-engine)](https://pypi.org/project/evolution-engine/)
45
+ [![Python 3.10+](https://img.shields.io/pypi/pyversions/evolution-engine)](https://pypi.org/project/evolution-engine/)
46
+ [![License: BSL 1.1](https://img.shields.io/badge/license-BSL%201.1-blue)](LICENSE)
47
+ [![Tests](https://img.shields.io/badge/tests-1770%20passing-brightgreen)]()
48
+
41
49
  **AI coding tools write correct code that silently breaks your architecture. Evolution Engine detects the drift, shows you the exact commit, and lets your AI fix it — with evidence.**
42
50
 
43
- Calibrated on 90+ open-source repos. 6.18M signals analyzed. Your code never leaves your machine.
51
+ Calibrated on 200+ open-source repos. 6.18M signals analyzed. Your code never leaves your machine.
52
+
53
+ **[codequal.dev](https://codequal.dev)** | [Quickstart](QUICKSTART.md) | [PyPI](https://pypi.org/project/evolution-engine/)
54
+
55
+ ![Evolution Engine CLI Demo](docs/images/demo.gif)
44
56
 
45
57
  ---
46
58
 
@@ -53,18 +65,35 @@ Evolution Engine is a **drift detector for AI-assisted development**. It learns
53
65
  ### The Loop: Detect → Evidence → Fix → Verify
54
66
 
55
67
  ```
56
- evo analyze . What changed? Is it unusual for THIS repo?
68
+ evo analyze . What changed? Is it unusual for THIS repo?
57
69
  |
58
- evo investigate . AI identifies the root cause commit + drift pattern
70
+ evo analyze . --show-prompt Copy the investigation prompt with evidence
59
71
  |
60
- evo fix . AI proposes a fix based on evidence, not guesswork
72
+ You + your AI tool Paste into Claude Code / Cursor / Copilot to fix
61
73
  |
62
- evo verify . Did the fix resolve the drift? Or did it make it worse?
74
+ evo analyze . --verify Did the fix resolve the drift? Or make it worse?
63
75
  |
64
- evo accept . 1 2 Expected change? Accept it. Move on.
76
+ evo accept . 1 2 Expected change? Accept it. Move on.
65
77
  ```
66
78
 
67
- This is the full cycle no other tool offers: detect drift, provide evidence, let AI fix it, verify the fix worked, and let humans decide what's intentional.
79
+ EE generates the evidence and the prompt you bring your own AI tool to investigate and fix. Then EE verifies whether the drift resolved. No other tool closes this loop.
80
+
81
+ ### Sample Reports
82
+
83
+ <table>
84
+ <tr>
85
+ <td width="50%"><strong>Analyze Report</strong></td>
86
+ <td width="50%"><strong>Verification Report</strong></td>
87
+ </tr>
88
+ <tr>
89
+ <td><a href="docs/images/report-analyze.png"><img src="docs/images/report-analyze.png" alt="Analyze Report" width="400"></a></td>
90
+ <td><a href="docs/images/report-verify.png"><img src="docs/images/report-verify.png" alt="Verification Report" width="400"></a></td>
91
+ </tr>
92
+ <tr>
93
+ <td><em>Findings, patterns, and investigation prompt</em></td>
94
+ <td><em>Verification banner shows what resolved</em></td>
95
+ </tr>
96
+ </table>
68
97
 
69
98
  ### How It Works (5-Phase Pipeline)
70
99
 
@@ -83,7 +112,7 @@ Your Repo → Phase 1 (Record events) → Phase 2 (Detect deviation from YOUR ba
83
112
  | **Phase 1** | Records immutable events — commits, builds, deps, releases |
84
113
  | **Phase 2** | Computes per-repo baselines, flags statistical deviation (MAD/IQR) |
85
114
  | **Phase 3** | Explains signals in human language — PM-friendly, evidence-backed |
86
- | **Phase 4** | Matches against 44 validated patterns from 90+ repos |
115
+ | **Phase 4** | Matches against 44 validated patterns from 200+ repos |
87
116
  | **Phase 5** | Prioritized advisory with severity, evidence, and action items |
88
117
 
89
118
  ---
@@ -124,10 +153,6 @@ evo init . --path all
124
153
 
125
154
  Free tier covers Path 1 (CLI). Pro unlocks Path 2 (hooks) and Path 3 (CI integration), plus AI investigation, AI fix loop, and inline PR review comments.
126
155
 
127
- ### Founding Member Program
128
-
129
- We're looking for 50 developers who use AI coding tools daily. In exchange for monthly feedback, you get founding member pricing: **$9.50/month for 3 months** (regular: $19/month). Use code `FOUNDING50` at checkout.
130
-
131
156
  ### Environment Variables
132
157
 
133
158
  ```bash
@@ -135,7 +160,7 @@ We're looking for 50 developers who use AI coding tools daily. In exchange for m
135
160
  GITHUB_TOKEN=ghp_xxx # Unlocks CI, deployment, security adapters
136
161
  GITLAB_TOKEN=glpat-xxx # Unlocks GitLab CI, releases adapters
137
162
  EVO_LICENSE_KEY=xxx # Pro features (free tier works without)
138
- ANTHROPIC_API_KEY=sk-ant-xxx # For evo investigate / evo fix (Pro)
163
+ ANTHROPIC_API_KEY=sk-ant-xxx # For evo fix automated loop (Pro)
139
164
  ```
140
165
 
141
166
  ---
@@ -188,9 +213,10 @@ evo analyze [path] # Detect adapters, run full pipeline
188
213
  evo analyze . --families git,ci # Override auto-detection
189
214
  evo report [path] # Generate HTML report from last run
190
215
  evo status # Show detected adapters and event counts
191
- evo investigate [path] # AI root cause analysis (Pro)
192
- evo fix [path] # AI fix-verify loop (Pro)
193
- evo fix [path] --residual # Iteration-aware prompt (current vs previous)
216
+ evo analyze . --show-prompt # Copy investigation prompt for your AI tool
217
+ evo fix [path] --dry-run # Generate evidence-backed fix prompt (Pro)
218
+ evo fix [path] --dry-run --residual # Iteration-aware prompt (what's fixed vs still broken)
219
+ evo fix [path] # Automated fix-verify loop with CLI agent (Pro, advanced)
194
220
  evo verify <advisory> # Compare current state to a previous advisory
195
221
 
196
222
  # Setup & Integration
@@ -343,7 +369,7 @@ evolution-engine/
343
369
  │ ├── pattern_validator.py # Pattern package validation
344
370
  │ ├── pattern_scaffold.py # Pattern package scaffolding
345
371
  │ ├── report_generator.py # Standalone HTML report generator
346
- │ ├── investigator.py # AI investigation (evo investigate, Pro)
372
+ │ ├── investigator.py # AI investigation engine (Pro)
347
373
  │ ├── fixer.py # AI fix-verify loop (evo fix, Pro)
348
374
  │ ├── adapter_validator.py # 13-check adapter certification
349
375
  │ ├── adapter_scaffold.py # Package scaffolding + AI prompt gen
@@ -397,7 +423,7 @@ evolution-engine/
397
423
 
398
424
  AI coding tools are generating more code than ever. Teams ship faster — but structural quality is invisible until something breaks. EE provides the missing feedback loop: a guardrail that tells you (and your AI) when development patterns drift from what's normal for your project.
399
425
 
400
- Calibrated on **90+ open-source repos**, **6.18 million SDLC signals**, and **2.1 million commits**. 44 validated cross-signal patterns. 1.6% false positive rate.
426
+ Calibrated on **200+ open-source repos**, **6.18 million SDLC signals**, and **2.1 million commits**. 44 validated cross-signal patterns. 1.6% false positive rate.
401
427
 
402
428
  ## Open-Core Model
403
429
 
@@ -1,8 +1,17 @@
1
1
  # Evolution Engine
2
2
 
3
+ [![PyPI version](https://img.shields.io/pypi/v/evolution-engine)](https://pypi.org/project/evolution-engine/)
4
+ [![Python 3.10+](https://img.shields.io/pypi/pyversions/evolution-engine)](https://pypi.org/project/evolution-engine/)
5
+ [![License: BSL 1.1](https://img.shields.io/badge/license-BSL%201.1-blue)](LICENSE)
6
+ [![Tests](https://img.shields.io/badge/tests-1770%20passing-brightgreen)]()
7
+
3
8
  **AI coding tools write correct code that silently breaks your architecture. Evolution Engine detects the drift, shows you the exact commit, and lets your AI fix it — with evidence.**
4
9
 
5
- Calibrated on 90+ open-source repos. 6.18M signals analyzed. Your code never leaves your machine.
10
+ Calibrated on 200+ open-source repos. 6.18M signals analyzed. Your code never leaves your machine.
11
+
12
+ **[codequal.dev](https://codequal.dev)** | [Quickstart](QUICKSTART.md) | [PyPI](https://pypi.org/project/evolution-engine/)
13
+
14
+ ![Evolution Engine CLI Demo](docs/images/demo.gif)
6
15
 
7
16
  ---
8
17
 
@@ -15,18 +24,35 @@ Evolution Engine is a **drift detector for AI-assisted development**. It learns
15
24
  ### The Loop: Detect → Evidence → Fix → Verify
16
25
 
17
26
  ```
18
- evo analyze . What changed? Is it unusual for THIS repo?
27
+ evo analyze . What changed? Is it unusual for THIS repo?
19
28
  |
20
- evo investigate . AI identifies the root cause commit + drift pattern
29
+ evo analyze . --show-prompt Copy the investigation prompt with evidence
21
30
  |
22
- evo fix . AI proposes a fix based on evidence, not guesswork
31
+ You + your AI tool Paste into Claude Code / Cursor / Copilot to fix
23
32
  |
24
- evo verify . Did the fix resolve the drift? Or did it make it worse?
33
+ evo analyze . --verify Did the fix resolve the drift? Or make it worse?
25
34
  |
26
- evo accept . 1 2 Expected change? Accept it. Move on.
35
+ evo accept . 1 2 Expected change? Accept it. Move on.
27
36
  ```
28
37
 
29
- This is the full cycle no other tool offers: detect drift, provide evidence, let AI fix it, verify the fix worked, and let humans decide what's intentional.
38
+ EE generates the evidence and the prompt you bring your own AI tool to investigate and fix. Then EE verifies whether the drift resolved. No other tool closes this loop.
39
+
40
+ ### Sample Reports
41
+
42
+ <table>
43
+ <tr>
44
+ <td width="50%"><strong>Analyze Report</strong></td>
45
+ <td width="50%"><strong>Verification Report</strong></td>
46
+ </tr>
47
+ <tr>
48
+ <td><a href="docs/images/report-analyze.png"><img src="docs/images/report-analyze.png" alt="Analyze Report" width="400"></a></td>
49
+ <td><a href="docs/images/report-verify.png"><img src="docs/images/report-verify.png" alt="Verification Report" width="400"></a></td>
50
+ </tr>
51
+ <tr>
52
+ <td><em>Findings, patterns, and investigation prompt</em></td>
53
+ <td><em>Verification banner shows what resolved</em></td>
54
+ </tr>
55
+ </table>
30
56
 
31
57
  ### How It Works (5-Phase Pipeline)
32
58
 
@@ -45,7 +71,7 @@ Your Repo → Phase 1 (Record events) → Phase 2 (Detect deviation from YOUR ba
45
71
  | **Phase 1** | Records immutable events — commits, builds, deps, releases |
46
72
  | **Phase 2** | Computes per-repo baselines, flags statistical deviation (MAD/IQR) |
47
73
  | **Phase 3** | Explains signals in human language — PM-friendly, evidence-backed |
48
- | **Phase 4** | Matches against 44 validated patterns from 90+ repos |
74
+ | **Phase 4** | Matches against 44 validated patterns from 200+ repos |
49
75
  | **Phase 5** | Prioritized advisory with severity, evidence, and action items |
50
76
 
51
77
  ---
@@ -86,10 +112,6 @@ evo init . --path all
86
112
 
87
113
  Free tier covers Path 1 (CLI). Pro unlocks Path 2 (hooks) and Path 3 (CI integration), plus AI investigation, AI fix loop, and inline PR review comments.
88
114
 
89
- ### Founding Member Program
90
-
91
- We're looking for 50 developers who use AI coding tools daily. In exchange for monthly feedback, you get founding member pricing: **$9.50/month for 3 months** (regular: $19/month). Use code `FOUNDING50` at checkout.
92
-
93
115
  ### Environment Variables
94
116
 
95
117
  ```bash
@@ -97,7 +119,7 @@ We're looking for 50 developers who use AI coding tools daily. In exchange for m
97
119
  GITHUB_TOKEN=ghp_xxx # Unlocks CI, deployment, security adapters
98
120
  GITLAB_TOKEN=glpat-xxx # Unlocks GitLab CI, releases adapters
99
121
  EVO_LICENSE_KEY=xxx # Pro features (free tier works without)
100
- ANTHROPIC_API_KEY=sk-ant-xxx # For evo investigate / evo fix (Pro)
122
+ ANTHROPIC_API_KEY=sk-ant-xxx # For evo fix automated loop (Pro)
101
123
  ```
102
124
 
103
125
  ---
@@ -150,9 +172,10 @@ evo analyze [path] # Detect adapters, run full pipeline
150
172
  evo analyze . --families git,ci # Override auto-detection
151
173
  evo report [path] # Generate HTML report from last run
152
174
  evo status # Show detected adapters and event counts
153
- evo investigate [path] # AI root cause analysis (Pro)
154
- evo fix [path] # AI fix-verify loop (Pro)
155
- evo fix [path] --residual # Iteration-aware prompt (current vs previous)
175
+ evo analyze . --show-prompt # Copy investigation prompt for your AI tool
176
+ evo fix [path] --dry-run # Generate evidence-backed fix prompt (Pro)
177
+ evo fix [path] --dry-run --residual # Iteration-aware prompt (what's fixed vs still broken)
178
+ evo fix [path] # Automated fix-verify loop with CLI agent (Pro, advanced)
156
179
  evo verify <advisory> # Compare current state to a previous advisory
157
180
 
158
181
  # Setup & Integration
@@ -305,7 +328,7 @@ evolution-engine/
305
328
  │ ├── pattern_validator.py # Pattern package validation
306
329
  │ ├── pattern_scaffold.py # Pattern package scaffolding
307
330
  │ ├── report_generator.py # Standalone HTML report generator
308
- │ ├── investigator.py # AI investigation (evo investigate, Pro)
331
+ │ ├── investigator.py # AI investigation engine (Pro)
309
332
  │ ├── fixer.py # AI fix-verify loop (evo fix, Pro)
310
333
  │ ├── adapter_validator.py # 13-check adapter certification
311
334
  │ ├── adapter_scaffold.py # Package scaffolding + AI prompt gen
@@ -359,7 +382,7 @@ evolution-engine/
359
382
 
360
383
  AI coding tools are generating more code than ever. Teams ship faster — but structural quality is invisible until something breaks. EE provides the missing feedback loop: a guardrail that tells you (and your AI) when development patterns drift from what's normal for your project.
361
384
 
362
- Calibrated on **90+ open-source repos**, **6.18 million SDLC signals**, and **2.1 million commits**. 44 validated cross-signal patterns. 1.6% false positive rate.
385
+ Calibrated on **200+ open-source repos**, **6.18 million SDLC signals**, and **2.1 million commits**. 44 validated cross-signal patterns. 1.6% false positive rate.
363
386
 
364
387
  ## Open-Core Model
365
388
 
@@ -0,0 +1 @@
1
+ __version__ = "0.3.0"
@@ -0,0 +1,243 @@
1
+ """
2
+ Sentry Source Adapter (Error Tracking)
3
+
4
+ Emits canonical SourceEvent payloads for Sentry issues.
5
+ Conforms to:
6
+ - docs/ADAPTER_CONTRACT.md (universal)
7
+
8
+ Supports:
9
+ - API mode: Fetches issues from Sentry API v0 (requires auth token)
10
+ - Fixture mode: Pre-parsed issue dicts (for testing)
11
+
12
+ Auth is via SENTRY_AUTH_TOKEN env var (Bearer token).
13
+ Supports self-hosted Sentry instances via base_url parameter.
14
+ """
15
+
16
+ import json
17
+ import os
18
+ import hashlib
19
+ from pathlib import Path
20
+ from typing import Optional
21
+
22
+ try:
23
+ import requests as _requests
24
+ except ImportError:
25
+ _requests = None
26
+
27
+
28
+ class SentryAdapter:
29
+ source_family = "error_tracking"
30
+ source_type = "sentry"
31
+ ordering_mode = "temporal"
32
+ attestation_tier = "medium"
33
+
34
+ API_BASE = "https://sentry.io/api/0"
35
+
36
+ def __init__(self, *, org: str = None, project: str = None,
37
+ token: str = None, issues: list = None,
38
+ source_id: str = None, max_issues: int = 500,
39
+ cache_dir: Path = None, base_url: str = None):
40
+ """
41
+ Args:
42
+ org: Sentry organization slug
43
+ project: Sentry project slug
44
+ token: Sentry auth token (or SENTRY_AUTH_TOKEN env)
45
+ issues: Pre-parsed list of issue dicts (fixture mode)
46
+ source_id: Unique identifier
47
+ max_issues: Maximum issues to fetch (default 500)
48
+ cache_dir: Directory for response caching (optional)
49
+ base_url: Base URL for self-hosted Sentry (e.g. "https://sentry.mycompany.com/api/0")
50
+ """
51
+ self._fixture_issues = issues
52
+ self._api_base = base_url or self.API_BASE
53
+ self.source_id = source_id or (
54
+ f"sentry:{org}/{project}" if org and project else "sentry:fixture"
55
+ )
56
+ self.max_issues = max_issues
57
+ self._org = org
58
+ self._project = project
59
+ self._token = token or os.getenv("SENTRY_AUTH_TOKEN")
60
+ self._cache_dir = cache_dir
61
+ self._requests_made = 0
62
+
63
+ if issues is None:
64
+ if _requests is None:
65
+ raise RuntimeError("requests library required. pip install requests")
66
+ if not org or not project:
67
+ raise RuntimeError(
68
+ "Provide org and project, or issues for fixture mode."
69
+ )
70
+ if not self._token:
71
+ raise RuntimeError(
72
+ "Sentry auth token required. Set SENTRY_AUTH_TOKEN env var or pass token=."
73
+ )
74
+
75
+ def _headers(self) -> dict:
76
+ return {
77
+ "Authorization": f"Bearer {self._token}",
78
+ "Accept": "application/json",
79
+ }
80
+
81
+ def _cache_key(self, url: str, params: dict = None) -> str:
82
+ raw = f"{url}:{json.dumps(params or {}, sort_keys=True)}"
83
+ return hashlib.sha256(raw.encode()).hexdigest()[:16]
84
+
85
+ def _get(self, url: str, params: dict = None) -> tuple:
86
+ """GET with caching. Returns (json_data, response_headers)."""
87
+ if self._cache_dir:
88
+ key = self._cache_key(url, params)
89
+ cache_file = self._cache_dir / f"{key}.json"
90
+ if cache_file.exists():
91
+ return json.loads(cache_file.read_text(encoding="utf-8")), {}
92
+
93
+ resp = _requests.get(url, headers=self._headers(),
94
+ params=params, timeout=30)
95
+ self._requests_made += 1
96
+ resp.raise_for_status()
97
+ data = resp.json()
98
+
99
+ if self._cache_dir:
100
+ self._cache_dir.mkdir(parents=True, exist_ok=True)
101
+ cache_file = self._cache_dir / f"{key}.json"
102
+ cache_file.write_text(json.dumps(data, indent=2), encoding="utf-8")
103
+
104
+ return data, resp.headers
105
+
106
+ def _normalize_level(self, level: str) -> str:
107
+ """Normalize Sentry issue level."""
108
+ level_map = {
109
+ "fatal": "fatal",
110
+ "error": "error",
111
+ "warning": "warning",
112
+ "info": "info",
113
+ "debug": "debug",
114
+ "sample": "info",
115
+ }
116
+ return level_map.get(level, "error") if level else "error"
117
+
118
+ def _normalize_status(self, status: str) -> str:
119
+ """Normalize Sentry issue status."""
120
+ status_map = {
121
+ "unresolved": "unresolved",
122
+ "resolved": "resolved",
123
+ "ignored": "ignored",
124
+ "muted": "ignored",
125
+ "resolvedInNextRelease": "resolved",
126
+ }
127
+ return status_map.get(status, "unresolved") if status else "unresolved"
128
+
129
+ def _fetch_issues(self) -> list:
130
+ """Fetch issues from Sentry API."""
131
+ url = f"{self._api_base}/projects/{self._org}/{self._project}/issues/"
132
+ all_issues = []
133
+ params = {
134
+ "query": "is:unresolved",
135
+ "statsPeriod": "90d",
136
+ "sort": "date",
137
+ }
138
+
139
+ while len(all_issues) < self.max_issues:
140
+ data, headers = self._get(url, params=params)
141
+
142
+ if not isinstance(data, list) or not data:
143
+ break
144
+
145
+ all_issues.extend(data)
146
+
147
+ # Cursor-based pagination via Link header
148
+ link = headers.get("Link", "")
149
+ next_url = self._parse_next_link(link)
150
+ if not next_url:
151
+ break
152
+ url = next_url
153
+ params = {} # URL already contains params
154
+
155
+ return all_issues[:self.max_issues]
156
+
157
+ def _parse_next_link(self, link_header: str) -> Optional[str]:
158
+ """Parse Sentry's Link header for the next page URL.
159
+
160
+ Validates that the next URL has the same scheme and host as
161
+ self._api_base to prevent open-redirect / SSRF attacks.
162
+ """
163
+ from urllib.parse import urlparse
164
+
165
+ if not link_header:
166
+ return None
167
+ for part in link_header.split(","):
168
+ part = part.strip()
169
+ if 'rel="next"' in part and 'results="true"' in part:
170
+ url = part.split(";")[0].strip().strip("<>")
171
+ # Validate scheme + host match self._api_base
172
+ parsed_base = urlparse(self._api_base)
173
+ parsed_next = urlparse(url)
174
+ if (parsed_next.scheme != parsed_base.scheme or
175
+ parsed_next.hostname != parsed_base.hostname):
176
+ return None
177
+ return url
178
+ return None
179
+
180
+ def iter_events(self):
181
+ if self._fixture_issues is not None:
182
+ issues = self._fixture_issues
183
+ else:
184
+ issues = self._fetch_issues()
185
+
186
+ # Sort by firstSeen for temporal ordering
187
+ issues.sort(key=lambda i: i.get("firstSeen", ""))
188
+
189
+ for issue in issues:
190
+ yield self._issue_to_event(issue)
191
+
192
+ def _issue_to_event(self, issue: dict) -> dict:
193
+ """Convert a Sentry issue dict to a SourceEvent."""
194
+ issue_id = str(issue.get("id", ""))
195
+ first_seen = issue.get("firstSeen", "")
196
+ last_seen = issue.get("lastSeen", "")
197
+ level = self._normalize_level(issue.get("level", "error"))
198
+ status = self._normalize_status(issue.get("status", "unresolved"))
199
+ is_unhandled = bool(issue.get("isUnhandled", False))
200
+ title = issue.get("title", "")
201
+ count = int(issue.get("count", 0))
202
+ user_count = int(issue.get("userCount", 0))
203
+
204
+ # Extract release from metadata if available
205
+ release = ""
206
+ metadata = issue.get("metadata", {})
207
+ if isinstance(metadata, dict):
208
+ release = metadata.get("release", "")
209
+
210
+ payload = {
211
+ "issue_id": issue_id,
212
+ "title": title,
213
+ "level": level,
214
+ "status": status,
215
+ "is_unhandled": is_unhandled,
216
+ "trigger": {
217
+ "type": "error",
218
+ "commit_sha": "",
219
+ "release": release,
220
+ },
221
+ "timing": {
222
+ "first_seen": first_seen,
223
+ "last_seen": last_seen,
224
+ },
225
+ "stats": {
226
+ "event_count": count,
227
+ "user_count": user_count,
228
+ },
229
+ }
230
+
231
+ return {
232
+ "source_family": self.source_family,
233
+ "source_type": self.source_type,
234
+ "source_id": self.source_id,
235
+ "ordering_mode": self.ordering_mode,
236
+ "attestation": {
237
+ "type": "error_issue",
238
+ "issue_id": issue_id,
239
+ "trust_tier": self.attestation_tier,
240
+ },
241
+ "predecessor_refs": None,
242
+ "payload": payload,
243
+ }
@@ -128,12 +128,29 @@ def get_agent(
128
128
  key = api_key or os.environ.get("ANTHROPIC_API_KEY", "")
129
129
  return AnthropicAgent(api_key=key, model=model)
130
130
  except ImportError:
131
- pass # anthropic package not installed
131
+ if prefer == "anthropic":
132
+ import sys
133
+ print(
134
+ "Warning: 'anthropic' package not installed. "
135
+ "Install it with: pip install anthropic\n"
136
+ "Falling back to prompt display mode.",
137
+ file=sys.stderr,
138
+ )
132
139
 
133
140
  if prefer == "cli" or (prefer is None and _has_cli(cli_command)):
134
141
  from evolution.agents.cli_agent import CliAgent
135
142
  return CliAgent(command=cli_command or "claude", model=model)
136
143
 
144
+ if prefer is None and _has_anthropic_key(api_key):
145
+ # API key is set but anthropic package is missing — warn the user
146
+ import sys
147
+ print(
148
+ "Note: ANTHROPIC_API_KEY is set but the 'anthropic' package is not installed.\n"
149
+ "Install it with: pip install anthropic\n"
150
+ "Using prompt display mode instead.",
151
+ file=sys.stderr,
152
+ )
153
+
137
154
  return ShowPromptAgent()
138
155
 
139
156