Skip to main content
Mollify

Deterministic codebase intelligence for Python.

Dead code · duplication · circular dependencies · complexity & hotspots · architecture · dependency hygiene · type health · security — as evidence, not guesses.

PyPI crates.io Python CI CodeQL License: MIT

Usage · Cookbook · Configuration · Architecture · CI integration · Agent integrations


Mollify is a Rust-native engine that gives humans and AI agents a structured, inspectable map of a Python codebase. It's fallow's model — one fast binary that unifies the whole "what's unused / risky / duplicated / tangled" question — ported to Python and extended with Python-specific signals (type health, notebooks, framework awareness) that fallow doesn't have.

Its one rule: no AI invents findings. Every result is a piece of deterministic evidence with a stable fingerprint, a confidence tier, and a human-readable reason. Mollify produces candidates; you (or your agent) decide what to do with them.

Project status: early but real — published on PyPI and crates.io (see the badges above for the current version). The core analysis phases are implemented, tested (210+ tests), and dogfooded; CI + CodeQL are green. See docs/adr/ for design decisions and Engineering notes below for how it works.

Why Mollify

Why Mollify

  • One tool, eight signals. Most Python shops bolt together vulture + ruff + deptry + tach + radon + jscpd + bandit. Mollify runs the equivalent set in a single deterministic pass with one config and one output contract.
  • Built for coding agents. A first-class MCP server plus shipped integrations for Devin/Cascade, Claude Code, Codex, Cursor, and Gemini CLI — so the agent reads repo truth instead of reconstructing it from grep.
  • Honest about uncertainty. Python dead-code detection is undecidable in general, so every verdict is tiered certain / likely / uncertain and only certain findings are ever auto-fixed. Framework decorators (routes, tasks, fixtures, CLI commands, validators) are understood, killing the #1 false positive.
  • Deterministic & CI-ready. Identical input → byte-identical output. SARIF, JSON, exit codes, and a PR-scoped --gate new-only.

What it detects

What it detects

Area Command Rules
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
Dependency hygiene mollify deps unused-dependency, missing-dependency, transitive-dependency, misplaced-dev-dependency, unresolved-import (pyproject + requirements/uv/pdm; venv-aware)
Architecture mollify arch circular-dependency, layer-violation, forbidden-import, independence-violation, private-import, custom policies
Complexity & cohesion mollify complexity high-complexity, hotspot (churn × complexity), low-cohesion (LCOM*)
Duplication mollify dupes duplication (clone families)
Type health mollify types untyped-function, private-type-leak
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
Cold paths mollify coverage --coverage-file cold-code (reachable but never executed)
Supply chain mollify supply-chain vulnerable-dependency (live OSV; offline DB fallback)
Metrics mollify metrics Maintainability Index, Halstead, raw LOC, per-file complexity
Everything + score mollify audit all of the above + a 0–100 quality score

Plus mollify graph [--mermaid] (import-graph export), mollify lsp (editor diagnostics), and --format github|junit for CI.

Also: Jupyter notebooks (.ipynb) are discovered and analyzed cell-by-cell; framework awareness (Flask/FastAPI/Django/Celery/pytest/click/Pydantic/…); architecture presets (layered/hexagonal/feature-sliced/bulletproof) and declarative rule packs (ban imports/calls per path); mollify fix to safely remove certain unused symbols; mollify explain <rule> for rule semantics; and mollify trace <module> for a module's import neighborhood; mollify inspect <file> for a per-file evidence bundle; mollify list for project topology; and regression baselines (--save-baseline / --baseline --fail-on-regression) to gate CI on new issues without git; and --include <dir> (repeatable) to scan a directory normally pruned by the builtin denylist, exclude_dirs, or .gitignore.

Install

Install

Python users (recommended) — via uv:

uvx mollify audit              # one-off, isolated (no install)
uv tool install mollify        # persistent, puts `mollify` on your PATH
uvx mollify@latest audit       # pin/refresh to a specific version

Or pip / cargo:

pip install mollify
cargo install mollify-cli        # builds from crates.io (binary: mollify)

From source (Rust):

git clone https://github.com/FavioVazquez/mollify
cd mollify
cargo build --release          # binary at ./target/release/mollify

Every channel ships the same self-contained binary with the agent integrations embedded: the PyPI wheel bundles the compiled binary (built with maturin); the crates.io build embeds the artifacts from the in-crate assets/. Interactive human runs print a one-line upgrade hint when a newer version is published; machine formats, pipes, CI, and non-TTY agent paths never do. Set MOLLIFY_UPDATE_CHECK=off (or DO_NOT_TRACK=1) to disable it.

Install agent integrations

Scaffold the version-matched skills, rules, hooks, slash-commands, and workflows for your agent straight into a repo (works however mollify was installed):

mollify init --agent claude    # or: cursor / gemini / codex / cascade
mollify init --all             # every supported agent
mollify init --all --force     # overwrite existing files

Quick start

Quick start

mollify audit --path /your/python/project
Mollify audit — /your/project
Quality score: 84/100
12 finding(s) across 47 file(s) — 0 error, 12 warn
  src/app.py:6   [warn/certain]  unused-export — function `_legacy` has no reachable references  (unused-export:931a82e6d41f07c3)
  src/api.py:88  [warn/likely]   high-complexity — function `handle` is complex (cyclomatic 14, cognitive 19)  (high-complexity:1aa9…)
  src/db.py:1    [warn/certain]  circular-dependency — import cycle: db → models → db  (circular-dependency:7c…)
  pyproject.toml:1 [warn/likely] unused-dependency — declared dependency `rich` is never imported  (unused-dependency:93…)

Machine-readable + CI:

mollify audit --format json                       # kind-discriminated contract
mollify audit --format sarif > mollify.sarif      # GitHub/GitLab code scanning
mollify audit --gate new-only --base origin/main  # only fail on regressions
mollify fix                                        # preview safe removals (--apply to write)

Supply-chain (live OSV by default, offline fallback):

mollify supply-chain                 # query OSV.dev live for pinned versions
mollify supply-chain --refresh       # …and cache results to .mollify/advisories.json
mollify supply-chain --offline       # deterministic: local advisory DB only
# `mollify audit` stays offline — it folds in supply-chain from .mollify/advisories.json when present
python3 scripts/fetch-advisories.py .mollify/advisories.json   # seed/refresh the DB out-of-band

Confidence tiers

Tier Meaning Auto-fixable
certain Provable (e.g. a private unused symbol in reachable, non-fixture code; no dynamic dispatch in scope)
likely Strong static signal, small residual dynamic risk
uncertain Public surface, or near getattr/eval/importlib

The JSON contract

Every command emits a kind-discriminated envelope (schema_version pinned by agent skills). Clients switch on kind and iterate findings[]:

{
  "kind": "audit", "schema_version": "0.1", "quality_score": 84,
  "summary": { "total": 12, "errors": 0, "warnings": 12, "files_analyzed": 47 },
  "findings": [{
    "fingerprint": "unused-export:931a82e6d41f07c3", "rule": "unused-export",
    "category": "dead-code", "severity": "warn", "confidence": "certain",
    "reason": "function `_legacy` has no reachable references in the project",
    "location": { "path": "src/app.py", "line": 6, "end_line": 7 },
    "actions": [{ "type": "remove-symbol",
                  "description": "Delete unused function `_legacy`",
                  "auto_fixable": true,
                  "suppression_comment": "# mollify: ignore[unused-export]" }]
  }]
}

Configuration — .mollifyrc.json

{
  "severity": { "dead-code": "error", "duplication": "warn", "unused-dependency": "off" },
  "ignore": ["tests/", "migrations/"],
  "max_cyclomatic": 10,
  "max_cognitive": 15,
  "architecture": { "layers": ["api", "service", "domain", "infra"] },
  "policies": [
    { "id": "no-requests-in-domain", "forbid_import": "requests", "in_paths": ["domain/"], "severity": "error" }
  ]
}

Raise rules/categories to error to make CI (and agent hooks) block. Full reference: docs/configuration.md.

Agent integrations

Agent integrations

One MCP server (mollify mcp), many front-ends. Shipped, ready-to-commit artifacts:

Agent Artifacts
Devin Desktop / Cascade .devin/skills/mollify/, .devin/rules/mollify.md, .devin/hooks.v1.json + .windsurf/hooks.json, .windsurf/workflows/mollify-*.md
Claude Code .mcp.json, .claude/skills/mollify/, .claude/commands/, .claude/settings.json hooks
Codex AGENTS.md, .codex/config.toml, .agents/skills/mollify/ (portable)
Cursor .cursor/rules/mollify.mdc, .cursor/mcp.json, .cursor/commands/
Gemini CLI GEMINI.md, .gemini/settings.json, .gemini/commands/mollify/

Scaffold any of these into a repo with mollify init --agent <name> (or --all) — see Install agent integrations above.

Architecture

Architecture

A Cargo workspace; data flows parse → graph → engines → report:

mollify-types (JSON contract) · mollify-parse (Python parsing, ruff AST) · mollify-graph (module/symbol graph + reachability + cycles) · mollify-core (the engines) · mollify-cli (mollify) · mollify-mcp (MCP server) · mollify-lsp (Language Server).

See docs/architecture.md.

How it compares

How it compares

vulture ruff deptry tach radon jscpd bandit Mollify
Whole-project dead code ✅ (reachability + tiers)
Unused class members / enum members
Unreachable code ~
Dependency hygiene (unused/missing/transitive)
Misplaced dev dependency
Unresolved / broken imports ~
Circular deps
Boundaries / interface (private-import)
Complexity ~
Churn × complexity
Duplication
Type health + private-type leaks ~
Security candidates (+CWE) ~
One deterministic pass + agent/MCP contract

~ = partial. Mollify's wedge is the unified deterministic pass with one contract — individual tools each already do a piece well; Mollify unifies them into a single evidence stream.

Engineering notes

Mollify banner

Mollify is built to be precise and dependency-light:

  • Full-fidelity parsing. Built on Astral's ruff_python_parser / ruff_python_ast — the same parser behind ruff — pinned to a crates.io release, so every distribution channel builds the identical binary (ADR-0001).
  • Real scope/binding resolution. Reachability resolves each name load to its binding (LEGB), so shadowing function-locals and attribute accesses never mask a dead top-level symbol.
  • Exact duplication. A linear-time SA-IS suffix array + LCP finds exact maximal token clones — no hash-collision guessing, scales to large repos.
  • Supply-chain. Matches pinned/locked versions precisely; for declared ranges it resolves the concrete installed version when a virtualenv is present, otherwise flags (at uncertain confidence) when the range permits a vulnerable version. supply-chain queries OSV live by default (offline DB fallback); mollify audit stays fully offline and deterministic.
  • Candidate-producer model. Security findings are syntactic candidates (never claimed as proven vulnerabilities), surfaced with a confidence tier — by design, not a gap.

Precision is the priority, built on real scope/binding resolution and package-aware import resolution; the deliberate precision tradeoffs (e.g. how lazy imports feed reachability but not architecture) are documented in docs/adr/. Remaining roadmap items are mostly performance optimizations (e.g. Salsa keystroke-incremental reparse for the LSP).

Contributing

Contributing

See CONTRIBUTING.md. The bar: every change compiles, is tested, and is documented; the tree stays fmt + clippy -D warnings clean.

License

MIT © 2026 Favio Vázquez

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mollify-0.1.5.tar.gz (216.3 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

mollify-0.1.5-py3-none-win_amd64.whl (3.5 MB view details)

Uploaded Python 3Windows x86-64

mollify-0.1.5-py3-none-musllinux_1_2_x86_64.whl (3.7 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

mollify-0.1.5-py3-none-musllinux_1_2_aarch64.whl (3.4 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

mollify-0.1.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

mollify-0.1.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.4 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

mollify-0.1.5-py3-none-macosx_11_0_arm64.whl (3.3 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

mollify-0.1.5-py3-none-macosx_10_12_x86_64.whl (3.5 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file mollify-0.1.5.tar.gz.

File metadata

  • Download URL: mollify-0.1.5.tar.gz
  • Upload date:
  • Size: 216.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mollify-0.1.5.tar.gz
Algorithm Hash digest
SHA256 d52f3bc41ec348e296ef9b17c909f1019bda84108397fed9ba42e1e105d06c9a
MD5 646d4b76a902c8c6736b06e8788a5112
BLAKE2b-256 682bbe06ec16a12bece252dcf20742f2668f0fcd3179faafecc0f6413fc2f11b

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.5.tar.gz:

Publisher: release.yml on FavioVazquez/mollify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mollify-0.1.5-py3-none-win_amd64.whl.

File metadata

  • Download URL: mollify-0.1.5-py3-none-win_amd64.whl
  • Upload date:
  • Size: 3.5 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mollify-0.1.5-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 1046fd4137154d64445633c9befb72349536705bcfc3403970901ef8489206b9
MD5 1b4f67c95780fc8588d6c549d5ed60a9
BLAKE2b-256 5dcff79dd5d06c107c799de3652d06f050d5769ce7460ba279813b776ee99949

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.5-py3-none-win_amd64.whl:

Publisher: release.yml on FavioVazquez/mollify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mollify-0.1.5-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for mollify-0.1.5-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 d0762bba23660dd6bb1b39b1f74dbf1ee23367acab30037f4f8ed30c7e528ec0
MD5 38931c02491ede01ccc4e97295f882b0
BLAKE2b-256 3e71cab4b964f7a9eba3406af72d413c97222f1aa7042424d58edbbb468ae14a

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.5-py3-none-musllinux_1_2_x86_64.whl:

Publisher: release.yml on FavioVazquez/mollify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mollify-0.1.5-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for mollify-0.1.5-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 3edcab10b2613cd5d7420f89a0f1d491aeb62cf2b42f54b3a05a975b15874469
MD5 b0ed3917a85c80bcd0d0fd16c91a0669
BLAKE2b-256 2dc775c9574533d842c9fea75fb56d75539e9f0c7a950f21be23a433d5d5ac78

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.5-py3-none-musllinux_1_2_aarch64.whl:

Publisher: release.yml on FavioVazquez/mollify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mollify-0.1.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for mollify-0.1.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 8c4c2473dd9cebc829c7266a3f8e0723801dadb3b7b6d4131a6f38deb524a2b3
MD5 68912241f21c0ab2d9cdb5247ac9a3f7
BLAKE2b-256 9de5890b608b4c279ac538b83f94943b95003f82c3cb82da2228a8b33eef6cec

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on FavioVazquez/mollify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mollify-0.1.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for mollify-0.1.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 6efea5f74d22c89e460b42a591ab70cd31d3c30c247c8e0e53036a0f16afd8be
MD5 aa3040c34b8ecbb1535e1c70c3475c80
BLAKE2b-256 f17815c9672d7b2ce77898c51c6fb210c6989c1e730c710c118680c80517ea22

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on FavioVazquez/mollify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mollify-0.1.5-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for mollify-0.1.5-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 65056807c8448214c1aa813cf5d57d501b47e289f4b3d883d86a6575ca840967
MD5 d378e7618bc6ef993ee5d987515d8d2a
BLAKE2b-256 22143b1de8f84c93d0783f0cd64b1ab9bef6d768e53d999224955f6c5251fec5

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.5-py3-none-macosx_11_0_arm64.whl:

Publisher: release.yml on FavioVazquez/mollify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mollify-0.1.5-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for mollify-0.1.5-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 5673bac0cadf509ff2b0e1f88c92d6f19a6e6fc534d604c28cd44d38a4593874
MD5 bcd9c6fb997c8d0ce5d49957b7923d0f
BLAKE2b-256 baf542f73d85b02b053cc5f081ef1348e0396d14d4644ec6cbe703fdf822b19a

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.5-py3-none-macosx_10_12_x86_64.whl:

Publisher: release.yml on FavioVazquez/mollify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.1.6

8 files

This release

0.1.5 This release

8 files

0.1.4

8 files

0.1.3

8 files

0.1.2

8 files

0.1.1

7 files

0.1.0

8 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page