Skip to main content

Deterministic codebase intelligence for Python — dead code, duplication, circular dependencies, complexity, architecture, dependency hygiene, type health, and security as evidence, not guesses.

Project description

Mollify

Deterministic codebase intelligence for Python.

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

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. The core analysis phases are implemented, tested (100+ tests), and dogfooded; CI is 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.

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:931a82e6)
  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, 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:931a82e6", "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", "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.

There are no known correctness limitations; remaining roadmap items are 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

Project details


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.0.tar.gz (164.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.0-py3-none-win_amd64.whl (3.4 MB view details)

Uploaded Python 3Windows x86-64

mollify-0.1.0-py3-none-musllinux_1_2_x86_64.whl (3.6 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

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

Uploaded Python 3musllinux: musl 1.2+ ARM64

mollify-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.5 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

mollify-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.3 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

mollify-0.1.0-py3-none-macosx_11_0_arm64.whl (3.2 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

mollify-0.1.0-py3-none-macosx_10_12_x86_64.whl (3.4 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

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

File metadata

  • Download URL: mollify-0.1.0.tar.gz
  • Upload date:
  • Size: 164.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.14.1

File hashes

Hashes for mollify-0.1.0.tar.gz
Algorithm Hash digest
SHA256 31209e28e093a6e4534abec9090f24cbb589c0a9dac3e52cd911bbd8ec8d89cc
MD5 65d635e9cd8ae68458e2463d62f14068
BLAKE2b-256 4bd475065cafb6d8ca1933108f6e43b2a4fdc81f5b9ec3134d48b06047e4bec8

See more details on using hashes here.

File details

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

File metadata

  • Download URL: mollify-0.1.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 3.4 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.14.1

File hashes

Hashes for mollify-0.1.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 5ffed9a0040276552f81743f6a4b1a6265661aff75c553c747aa11c1df0dd44f
MD5 d874e92519fafde5ab90d8fa9e5cfff1
BLAKE2b-256 2a4c2f4b25540eb100e1bb57dd3704a1b9f26c2a74eac86ba89403f2449c049c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for mollify-0.1.0-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 4d66ea391c719806ced90fbb83f65882692925e5def3195b6584a1c214836c24
MD5 b86b5eacb3bdab584bebbd3e89aee7cc
BLAKE2b-256 7c1fceb1b59984fcb0969f2723bf7ad5eaf9b82b596582f9ecb5dcc2b74e4a5d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for mollify-0.1.0-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 6eaaf66376ca89f85bafd383b7c78a532578428b128539914d4b66e656e1323e
MD5 c2994777abf24de85e6d39d19b2049ce
BLAKE2b-256 18e73a81d5f948344b68228a7cb8c8ea472176decc852702b4c82d2d84e38a8d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for mollify-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5a828ebf9d57bdfc73afdf6a4851bbdc4a1c28f7aa531ea895c2cd3c56a58ad5
MD5 8ed475e344907d33f44175086a6983ed
BLAKE2b-256 5b286a3ae4e3cde9e82f8a4cb929a05a26cfad0bb6d0d759d4bdbd0591216b74

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for mollify-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 1b9710ba4e4ff575ed4a77acb463914af68be33ad538a4444b32d7aaea19d1b2
MD5 34891e433979941fdc6a65d3db88b71f
BLAKE2b-256 d63fc83535098bfcd415c8d8e406dbc848b9426ad30aa31ba3b30956d8f271b2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for mollify-0.1.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 fb5ba6c08e15d73028c052f3f3afa6b8c6b3a2103ed9ec71638dc8912fb8923f
MD5 c90558ac3fa9888c58bf6d6ed234fede
BLAKE2b-256 45728a2fa393b93f2cf1d9b8ca3684e16c079d972470dedc3cbc8c92ab474de2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for mollify-0.1.0-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 25d09275923ed9a1a42f9800cb4d807fa6f7452a87a67630a9e558d7947912fa
MD5 86c02b6e7c35d8aa8fd149af90292cd0
BLAKE2b-256 aa2a158194b19a027a3b1e0b17eec23aa259bb271552c14e63d934b556d946b0

See more details on using hashes here.

Supported by

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