mollify 0.1.0__py3-none-win_amd64.whl

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.
Binary file
@@ -0,0 +1,337 @@
1
+ Metadata-Version: 2.4
2
+ Name: mollify
3
+ Version: 0.1.0
4
+ Classifier: Development Status :: 4 - Beta
5
+ Classifier: Intended Audience :: Developers
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Programming Language :: Python
8
+ Classifier: Programming Language :: Rust
9
+ Classifier: Topic :: Software Development :: Quality Assurance
10
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
11
+ License-File: LICENSE
12
+ Summary: Deterministic codebase intelligence for Python — dead code, duplication, circular dependencies, complexity, architecture, dependency hygiene, type health, and security as evidence, not guesses.
13
+ Keywords: python,static-analysis,dead-code,code-quality,complexity,architecture,circular-dependencies,duplication,dependency-hygiene,security,mcp,lsp,agent-skills
14
+ Author-email: Favio Vázquez <favio.vazquezp@gmail.com>
15
+ License: MIT
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
18
+ Project-URL: Changelog, https://github.com/FavioVazquez/mollify/blob/main/CHANGELOG.md
19
+ Project-URL: Homepage, https://github.com/FavioVazquez/mollify
20
+ Project-URL: Issues, https://github.com/FavioVazquez/mollify/issues
21
+ Project-URL: Repository, https://github.com/FavioVazquez/mollify
22
+
23
+ <div align="center">
24
+
25
+ <img src="assets/logo/tangle_harper.png" alt="Mollify" width="250">
26
+
27
+ **Deterministic codebase intelligence for Python.**
28
+
29
+ *Dead code · duplication · circular dependencies · complexity & hotspots · architecture · dependency hygiene · type health · security — as evidence, not guesses.*
30
+
31
+ [Usage](docs/usage.md) · [Cookbook](cookbook/) · [Configuration](docs/configuration.md) · [Architecture](docs/architecture.md) · [CI integration](docs/ci-integration.md) · [Agent integrations](#agent-integrations)
32
+
33
+ </div>
34
+
35
+ ---
36
+
37
+ Mollify is a Rust-native engine that gives humans **and AI agents** a structured,
38
+ inspectable map of a Python codebase. It's [fallow](https://github.com/fallow-rs/fallow)'s
39
+ model — one fast binary that unifies the whole "what's unused / risky / duplicated /
40
+ tangled" question — ported to Python and extended with Python-specific signals
41
+ (type health, notebooks, framework awareness) that fallow doesn't have.
42
+
43
+ Its one rule: **no AI invents findings.** Every result is a piece of deterministic
44
+ evidence with a stable fingerprint, a confidence tier, and a human-readable reason.
45
+ Mollify *produces candidates*; you (or your agent) decide what to do with them.
46
+
47
+ > **Project status:** early but real. The core analysis phases are implemented,
48
+ > tested (100+ tests), and dogfooded; CI is green. See [`docs/adr/`](docs/adr)
49
+ > for design decisions and *Engineering notes* below for how it works.
50
+
51
+ ## Why Mollify
52
+
53
+ <p align="center">
54
+ <img src="assets/finals/why-mollify.png" alt="Why Mollify" width="700">
55
+ </p>
56
+
57
+ - **One tool, eight signals.** Most Python shops bolt together vulture + ruff +
58
+ deptry + tach + radon + jscpd + bandit. Mollify runs the equivalent set in a
59
+ single deterministic pass with one config and one output contract.
60
+ - **Built for coding agents.** A first-class MCP server plus shipped integrations
61
+ for **Devin/Cascade, Claude Code, Codex, Cursor, and Gemini CLI** — so the
62
+ agent reads repo *truth* instead of reconstructing it from `grep`.
63
+ - **Honest about uncertainty.** Python dead-code detection is undecidable in
64
+ general, so every verdict is tiered `certain / likely / uncertain` and only
65
+ `certain` findings are ever auto-fixed. Framework decorators (routes, tasks,
66
+ fixtures, CLI commands, validators) are understood, killing the #1 false positive.
67
+ - **Deterministic & CI-ready.** Identical input → byte-identical output. SARIF,
68
+ JSON, exit codes, and a PR-scoped `--gate new-only`.
69
+
70
+ ## What it detects
71
+
72
+ <p align="center">
73
+ <img src="assets/finals/what-it-detects.png" alt="What it detects" width="700">
74
+ </p>
75
+
76
+ | Area | Command | Rules |
77
+ |---|---|---|
78
+ | **Dead code** | `mollify dead-code` | `unused-file`, `unused-export`, `unused-import`, `unused-variable`, `unused-parameter`, `unused-method`, `unused-attribute`, `unused-enum-member`, `unreachable-code`, `duplicate-export`, `commented-code` |
79
+ | **Dependency hygiene** | `mollify deps` | `unused-dependency`, `missing-dependency`, `transitive-dependency`, `misplaced-dev-dependency`, `unresolved-import` (pyproject + requirements/uv/pdm; venv-aware) |
80
+ | **Architecture** | `mollify arch` | `circular-dependency`, `layer-violation`, `forbidden-import`, `independence-violation`, `private-import`, custom policies |
81
+ | **Complexity & cohesion** | `mollify complexity` | `high-complexity`, `hotspot` (churn × complexity), `low-cohesion` (LCOM*) |
82
+ | **Duplication** | `mollify dupes` | `duplication` (clone families) |
83
+ | **Type health** | `mollify types` | `untyped-function`, `private-type-leak` |
84
+ | **Security** | `mollify security` | eval/exec, shell, `sql-injection`, weak hash/cipher, insecure-random, unsafe deserialization, TLS, secrets, missing-timeout, Flask debug, Jinja2 autoescape, broad `except: pass` — each with a CWE id |
85
+ | **Cold paths** | `mollify coverage --coverage-file` | `cold-code` (reachable but never executed) |
86
+ | **Supply chain** | `mollify supply-chain` | `vulnerable-dependency` (live OSV; offline DB fallback) |
87
+ | **Metrics** | `mollify metrics` | Maintainability Index, Halstead, raw LOC, per-file complexity |
88
+ | **Everything + score** | `mollify audit` | all of the above + a 0–100 quality score |
89
+
90
+ Plus `mollify graph [--mermaid]` (import-graph export), `mollify lsp` (editor
91
+ diagnostics), and `--format github|junit` for CI.
92
+
93
+ Also: **Jupyter notebooks (`.ipynb`)** are discovered and analyzed cell-by-cell;
94
+ **framework awareness** (Flask/FastAPI/Django/Celery/pytest/click/Pydantic/…);
95
+ **architecture presets** (`layered`/`hexagonal`/`feature-sliced`/`bulletproof`) and
96
+ **declarative rule packs** (ban imports/calls per path); `mollify fix` to safely
97
+ remove `certain` unused symbols; `mollify explain <rule>` for rule semantics; and
98
+ `mollify trace <module>` for a module's import neighborhood; `mollify inspect
99
+ <file>` for a per-file evidence bundle; `mollify list` for project topology; and
100
+ **regression baselines** (`--save-baseline` / `--baseline --fail-on-regression`)
101
+ to gate CI on *new* issues without git.
102
+
103
+ ## Install
104
+
105
+ <p align="center">
106
+ <img src="assets/finals/install.png" alt="Install" width="700">
107
+ </p>
108
+
109
+ **Python users (recommended) — via [uv](https://docs.astral.sh/uv/):**
110
+
111
+ ```bash
112
+ uvx mollify audit # one-off, isolated (no install)
113
+ uv tool install mollify # persistent, puts `mollify` on your PATH
114
+ uvx mollify@latest audit # pin/refresh to a specific version
115
+ ```
116
+
117
+ **Or pip / cargo:**
118
+
119
+ ```bash
120
+ pip install mollify
121
+ cargo install mollify-cli # builds from crates.io (binary: mollify)
122
+ ```
123
+
124
+ **From source (Rust):**
125
+
126
+ ```bash
127
+ git clone https://github.com/FavioVazquez/mollify
128
+ cd mollify
129
+ cargo build --release # binary at ./target/release/mollify
130
+ ```
131
+
132
+ Every channel ships the **same self-contained binary** with the agent
133
+ integrations embedded: the PyPI wheel bundles the compiled binary (built with
134
+ [maturin](https://www.maturin.rs/)); the crates.io build embeds the artifacts
135
+ from the in-crate `assets/`. Interactive
136
+ human runs print a one-line upgrade hint when a newer version is published;
137
+ machine formats, pipes, CI, and non-TTY agent paths never do. Set
138
+ `MOLLIFY_UPDATE_CHECK=off` (or `DO_NOT_TRACK=1`) to disable it.
139
+
140
+ ### Install agent integrations
141
+
142
+ Scaffold the version-matched skills, rules, hooks, slash-commands, and
143
+ workflows for your agent straight into a repo (works however mollify was
144
+ installed):
145
+
146
+ ```bash
147
+ mollify init --agent claude # or: cursor / gemini / codex / cascade
148
+ mollify init --all # every supported agent
149
+ mollify init --all --force # overwrite existing files
150
+ ```
151
+
152
+ ## Quick start
153
+
154
+ <p align="center">
155
+ <img src="assets/finals/quick-start.png" alt="Quick start" width="700">
156
+ </p>
157
+
158
+ ```bash
159
+ mollify audit --path /your/python/project
160
+ ```
161
+
162
+ ```text
163
+ Mollify audit — /your/project
164
+ Quality score: 84/100
165
+ 12 finding(s) across 47 file(s) — 0 error, 12 warn
166
+ src/app.py:6 [warn/certain] unused-export — function `_legacy` has no reachable references (unused-export:931a82e6)
167
+ src/api.py:88 [warn/likely] high-complexity — function `handle` is complex (cyclomatic 14, cognitive 19) (high-complexity:1aa9…)
168
+ src/db.py:1 [warn/certain] circular-dependency — import cycle: db → models → db (circular-dependency:7c…)
169
+ pyproject.toml:1 [warn/likely] unused-dependency — declared dependency `rich` is never imported (unused-dependency:93…)
170
+ ```
171
+
172
+ Machine-readable + CI:
173
+
174
+ ```bash
175
+ mollify audit --format json # kind-discriminated contract
176
+ mollify audit --format sarif > mollify.sarif # GitHub/GitLab code scanning
177
+ mollify audit --gate new-only --base origin/main # only fail on regressions
178
+ mollify fix # preview safe removals (--apply to write)
179
+ ```
180
+
181
+ Supply-chain (live OSV by default, offline fallback):
182
+
183
+ ```bash
184
+ mollify supply-chain # query OSV.dev live for pinned versions
185
+ mollify supply-chain --refresh # …and cache results to .mollify/advisories.json
186
+ mollify supply-chain --offline # deterministic: local advisory DB only
187
+ # `mollify audit` stays offline — it folds in supply-chain from .mollify/advisories.json when present
188
+ python3 scripts/fetch-advisories.py .mollify/advisories.json # seed/refresh the DB out-of-band
189
+ ```
190
+
191
+ ## Confidence tiers
192
+
193
+ | Tier | Meaning | Auto-fixable |
194
+ |---|---|---|
195
+ | `certain` | Provable (e.g. a private unused symbol, no dynamic dispatch in scope) | ✅ |
196
+ | `likely` | Strong static signal, small residual dynamic risk | — |
197
+ | `uncertain` | Public surface, or near `getattr`/`eval`/`importlib` | — |
198
+
199
+ ## The JSON contract
200
+
201
+ Every command emits a `kind`-discriminated envelope (`schema_version` pinned by
202
+ agent skills). Clients switch on `kind` and iterate `findings[]`:
203
+
204
+ ```json
205
+ {
206
+ "kind": "audit", "schema_version": "0.1", "quality_score": 84,
207
+ "summary": { "total": 12, "errors": 0, "warnings": 12, "files_analyzed": 47 },
208
+ "findings": [{
209
+ "fingerprint": "unused-export:931a82e6", "rule": "unused-export",
210
+ "category": "dead-code", "severity": "warn", "confidence": "certain",
211
+ "reason": "function `_legacy` has no reachable references in the project",
212
+ "location": { "path": "src/app.py", "line": 6, "end_line": 7 },
213
+ "actions": [{ "type": "remove-symbol", "auto_fixable": true,
214
+ "suppression_comment": "# mollify: ignore[unused-export]" }]
215
+ }]
216
+ }
217
+ ```
218
+
219
+ ## Configuration — `.mollifyrc.json`
220
+
221
+ ```json
222
+ {
223
+ "severity": { "dead-code": "error", "duplication": "warn", "unused-dependency": "off" },
224
+ "ignore": ["tests/", "migrations/"],
225
+ "max_cyclomatic": 10,
226
+ "max_cognitive": 15,
227
+ "architecture": { "layers": ["api", "service", "domain", "infra"] },
228
+ "policies": [
229
+ { "id": "no-requests-in-domain", "forbid_import": "requests", "in_paths": ["domain/"], "severity": "error" }
230
+ ]
231
+ }
232
+ ```
233
+
234
+ Raise rules/categories to `error` to make CI (and agent hooks) **block**. Full
235
+ reference: [docs/configuration.md](docs/configuration.md).
236
+
237
+ ## Agent integrations
238
+
239
+ <p align="center">
240
+ <img src="assets/finals/agent-integrations.png" alt="Agent integrations" width="700">
241
+ </p>
242
+
243
+ One MCP server (`mollify mcp`), many front-ends. Shipped, ready-to-commit artifacts:
244
+
245
+ | Agent | Artifacts |
246
+ |---|---|
247
+ | **Devin Desktop / Cascade** | `.devin/skills/mollify/`, `.devin/rules/mollify.md`, `.devin/hooks.v1.json` + `.windsurf/hooks.json`, `.windsurf/workflows/mollify-*.md` |
248
+ | **Claude Code** | `.mcp.json`, `.claude/skills/mollify/`, `.claude/commands/`, `.claude/settings.json` hooks |
249
+ | **Codex** | `AGENTS.md`, `.codex/config.toml`, `.agents/skills/mollify/` (portable) |
250
+ | **Cursor** | `.cursor/rules/mollify.mdc`, `.cursor/mcp.json`, `.cursor/commands/` |
251
+ | **Gemini CLI** | `GEMINI.md`, `.gemini/settings.json`, `.gemini/commands/mollify/` |
252
+
253
+ Scaffold any of these into a repo with `mollify init --agent <name>` (or `--all`) — see [Install agent integrations](#install-agent-integrations) above.
254
+
255
+ ## Architecture
256
+
257
+ <p align="center">
258
+ <img src="assets/finals/architecture.png" alt="Architecture" width="700">
259
+ </p>
260
+
261
+ A Cargo workspace; data flows parse → graph → engines → report:
262
+
263
+ `mollify-types` (JSON contract) · `mollify-parse` (Python parsing, ruff AST) ·
264
+ `mollify-graph` (module/symbol graph + reachability + cycles) · `mollify-core`
265
+ (the engines) · `mollify-cli` (`mollify`) · `mollify-mcp` (MCP server) ·
266
+ `mollify-lsp` (Language Server).
267
+
268
+ See [docs/architecture.md](docs/architecture.md).
269
+
270
+ ## How it compares
271
+
272
+ <p align="center">
273
+ <img src="assets/finals/how-it-compares.png" alt="How it compares" width="700">
274
+ </p>
275
+
276
+ | | vulture | ruff | deptry | tach | radon | jscpd | bandit | **Mollify** |
277
+ |---|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
278
+ | Whole-project dead code | ✅ | – | – | – | – | – | – | ✅ (reachability + tiers) |
279
+ | Unused class members / enum members | ✅ | – | – | – | – | – | – | ✅ |
280
+ | Unreachable code | ✅ | ~ | – | – | – | – | – | ✅ |
281
+ | Dependency hygiene (unused/missing/transitive) | – | – | ✅ | – | – | – | – | ✅ |
282
+ | Misplaced dev dependency | – | – | ✅ | – | – | – | – | ✅ |
283
+ | Unresolved / broken imports | – | ~ | – | – | – | – | – | ✅ |
284
+ | Circular deps | – | – | – | ✅ | – | – | – | ✅ |
285
+ | Boundaries / interface (private-import) | – | – | – | ✅ | – | – | – | ✅ |
286
+ | Complexity | – | ~ | – | – | ✅ | – | – | ✅ |
287
+ | Churn × complexity | – | – | – | – | – | – | – | ✅ |
288
+ | Duplication | – | – | – | – | – | ✅ | – | ✅ |
289
+ | Type health + private-type leaks | – | ~ | – | – | – | – | – | ✅ |
290
+ | Security candidates (+CWE) | – | ~ | – | – | – | – | ✅ | ✅ |
291
+ | One deterministic pass + agent/MCP contract | – | – | – | – | – | – | – | ✅ |
292
+
293
+ `~` = partial. Mollify's wedge is the **unified deterministic pass** with one
294
+ contract — individual tools each already do a piece well; Mollify unifies them
295
+ into a single evidence stream.
296
+
297
+ ## Engineering notes
298
+
299
+ <div align="center">
300
+ <img src="assets/finals/banner.png" alt="Mollify banner" width="100%">
301
+ </div>
302
+
303
+ Mollify is built to be precise and dependency-light:
304
+
305
+ - **Full-fidelity parsing.** Built on Astral's `ruff_python_parser` / `ruff_python_ast`
306
+ — the same parser behind `ruff` — pinned to a crates.io release, so every
307
+ distribution channel builds the identical binary ([ADR-0001](docs/adr/0001-parser-tree-sitter.md)).
308
+ - **Real scope/binding resolution.** Reachability resolves each name *load* to its
309
+ binding (LEGB), so shadowing function-locals and attribute accesses never mask a
310
+ dead top-level symbol.
311
+ - **Exact duplication.** A linear-time **SA-IS suffix array + LCP** finds exact
312
+ maximal token clones — no hash-collision guessing, scales to large repos.
313
+ - **Supply-chain.** Matches pinned/locked versions precisely; for declared
314
+ **ranges** it resolves the concrete installed version when a virtualenv is
315
+ present, otherwise flags (at `uncertain` confidence) when the range *permits* a
316
+ vulnerable version. `supply-chain` queries OSV live by default (offline DB
317
+ fallback); `mollify audit` stays fully offline and deterministic.
318
+ - **Candidate-producer model.** Security findings are syntactic *candidates*
319
+ (never claimed as proven vulnerabilities), surfaced with a confidence tier — by
320
+ design, not a gap.
321
+
322
+ There are no known correctness limitations; remaining roadmap items are
323
+ performance optimizations (e.g. Salsa keystroke-incremental reparse for the LSP).
324
+
325
+ ## Contributing
326
+
327
+ <p align="center">
328
+ <img src="assets/finals/contributing.png" alt="Contributing" width="700">
329
+ </p>
330
+
331
+ See [CONTRIBUTING.md](CONTRIBUTING.md). The bar: every change compiles, is tested,
332
+ and is documented; the tree stays `fmt` + `clippy -D warnings` clean.
333
+
334
+ ## License
335
+
336
+ [MIT](LICENSE) © 2026 Favio Vázquez
337
+
@@ -0,0 +1,6 @@
1
+ mollify-0.1.0.data/scripts/mollify.exe,sha256=sNqVp-wmdpFYx58r7x3Xe37gSmcxTHH5rzU4yWolgr4,7579648
2
+ mollify-0.1.0.dist-info/METADATA,sha256=xkYF8doYTTOBywMYIGN7bmm9qpt6TlMU3--b2TPfyjc,16314
3
+ mollify-0.1.0.dist-info/WHEEL,sha256=2zDlIYIdD4m4N3p5DVEG3iJhGLdhsBQgdH-FqVkAur8,94
4
+ mollify-0.1.0.dist-info/licenses/LICENSE,sha256=8FMi1sHzUJhg-8oCj-YrousSPWLuxMbci6ijBxYulzQ,1092
5
+ mollify-0.1.0.dist-info/sboms/mollify-cli.cyclonedx.json,sha256=Px69eoP_xSGZI_ykZ9z3EMAiUeg_4xtGOWgYqOat5X4,189905
6
+ mollify-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.14.1)
3
+ Root-Is-Purelib: false
4
+ Tag: py3-none-win_amd64
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Favio Vázquez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
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:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.