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

Every finding carries one of mollify's eight categories (dead-code, dependency-hygiene, circular-dependency, complexity, architecture, duplication, type-health, security); cold paths, supply chain, and metrics are additional command surfaces over those same categories.

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.6.tar.gz (224.1 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.6-py3-none-win_amd64.whl (3.6 MB view details)

Uploaded Python 3Windows x86-64

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

Uploaded Python 3musllinux: musl 1.2+ x86-64

mollify-0.1.6-py3-none-musllinux_1_2_aarch64.whl (3.5 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

mollify-0.1.6-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.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.4 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

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

Uploaded Python 3macOS 11.0+ ARM64

mollify-0.1.6-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.6.tar.gz.

File metadata

  • Download URL: mollify-0.1.6.tar.gz
  • Upload date:
  • Size: 224.1 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.6.tar.gz
Algorithm Hash digest
SHA256 40477e34a09239295a70bc288a42b3b4a60f698e874a226d9ecd486bec4ed43e
MD5 334c156e6f8c7e45eca126bb38f0eeca
BLAKE2b-256 4d94b8483dcc9decf13e6784605926b36521a9685f935d44efd43c191c54b5f8

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.6.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.6-py3-none-win_amd64.whl.

File metadata

  • Download URL: mollify-0.1.6-py3-none-win_amd64.whl
  • Upload date:
  • Size: 3.6 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.6-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 efab8ef931b84713fc78c66fea2faff82e2fd29b6d68d59e5fda0380d4a818f0
MD5 4c5e93d3f73d7fbbfc4c9f087a16e309
BLAKE2b-256 68ad514feb7e09ee5090a55b8cb5e6d7b4fe11790d5415593dd61f1af13fd7de

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.6-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.6-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for mollify-0.1.6-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 d8e09dcb8dc5c3e83064a99ccc339e2ec203c43942a4a81028692ed1884ff5fe
MD5 59d05d3586967b9bb1211827df4044b3
BLAKE2b-256 8e2ee68cbfb554a914a0509db34df02ecfe67f4c3297b73d6ce378750edafc7a

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.6-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.6-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for mollify-0.1.6-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 6182eb993fdd9ee30ce6a751a1bece836e683201f33210e6c608bfba435e9a55
MD5 86dcf7b0a3cb94eea39076e1e0507d3b
BLAKE2b-256 f0390f63853034cc8871feb1aded8d9b5aa8217b87a4a1242ac84e69b353b015

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.6-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.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for mollify-0.1.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c8a0b56b6af6578b61f980761bbe65e36157042a00a64731ffdbcd472d6d74ba
MD5 f3b4a34e6d134d80711abe080f5ae4e9
BLAKE2b-256 c5e4b8f85f4e57e0c409e12f8923479d6eec4d84a7dc74b561a7cdd4a00408ce

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.6-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.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for mollify-0.1.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 d77047f9b0027af54bb2b9eb43cfba91c7002b65aa1979d11ddd32e492091657
MD5 5f7a5fb2ca149bfd9d868ccfc871446d
BLAKE2b-256 90d5bf7866b4c10ed733551422f8e86eaec1dfa3db547067e4eac2a22706b0ef

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.6-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.6-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for mollify-0.1.6-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 47e3e144759a8a05d69a2c385bc39d7fae7cce10b83c19fccef7a0b5295b89f5
MD5 f85b26f5c498808960f32067e7a66a39
BLAKE2b-256 b83eb6acad43ed5311842cb6b1e89e5fd691d3c9f4b813a2f7e8fd5e8cc78578

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.6-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.6-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for mollify-0.1.6-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 ee28b53e7af6e91c45214b769f9a8f124f26853e2c515e2368d7ae5e7115879f
MD5 8deb2aeda98732fd9a0317512e482190
BLAKE2b-256 6bf8466c2a2bd17caa2a231d3e36a5e60d2837d9cc432062ee0e56097a9cbf65

See more details on using hashes here.

Provenance

The following attestation bundles were made for mollify-0.1.6-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.

Supported by

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