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.

Release history Release notifications | RSS feed

This release

0.1.6 This release

8 files

0.1.5

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