Skip to main content

Architectural audit tool for multi-module Gradle Android projects.

Project description

๐Ÿงฑ modulith-android

Architectural audit for multi-module Gradle Android projects โ€” cycles, layer violations, visibility issues, unused dependencies, and impact cascades, all in a single self-contained HTML report.

Python 3.10+ License: MIT Platform Status


Point it at any Gradle Android repo. It parses your settings.gradle[.kts], walks every module's build file, optionally ingests the Dependency Analysis Gradle Plugin report, scans your Kotlin/Java sources for cross-module imports, and produces a single self-contained HTML file with:

  • ๐Ÿ•ธ๏ธ Module graph โ€” every :layer:name module and its dependency edges, colour-coded by layer.
  • ๐Ÿ” Cycle detection โ€” Tarjan-based strongly-connected components; any cyclic coupling between modules is flagged.
  • ๐Ÿšซ Layer violations โ€” edges that cross a forbidden layer pair (e.g. core โ†’ feature under Clean Architecture), with the offending Gradle dependency listed.
  • ๐Ÿ‘๏ธ Visibility audit โ€” for the modules you choose, every public symbol is classified as internalize_candidate, di_required, external_consumer, or star_import_uncertain so you know what's actually load-bearing.
  • ๐Ÿชฆ Unused dependencies โ€” surfaces the Dependency Analysis Gradle Plugin's findings inline next to each module.
  • ๐Ÿ’ฅ Impact cascades โ€” pick a module, see every module that transitively depends on it.
  • ๐Ÿ“Š Rankings โ€” modules sorted by fan-in, fan-out, instability, and abstractness.

Configuration-driven and project-agnostic. Every project-specific value (root package, layer names, forbidden layer pairs, audited modules) lives in a single modulith.toml at your repo root. Run modulith-android init and the wizard auto-detects sensible defaults in seconds โ€” confirm with Enter, edit otherwise. Drop it into any Gradle Android project and you're scanning in under a minute.

A report generator, not a CI gate. modulith-android never fails a build and never exits non-zero based on findings. It reads, computes, and writes โ€” interpretation and policy belong to whoever reads the report. By design.


๐Ÿšง Status

Pre-alpha. v0.1.0 in active development. The repository scaffold is in place; CLI, wizard, and analysis pipeline land progressively as the milestones in the roadmap ship. The quick start below describes the shipped behaviour at v0.1.0.


๐Ÿš€ Quick start

# 1. (optional) populate unused-dependency data
./gradlew buildHealth -q

# 2. one-shot, no install โ€” needs uv (https://docs.astral.sh/uv/)
uvx --from modulith-android modulith-android init   # wizard writes ./modulith.toml
uvx --from modulith-android modulith-android        # writes build/dependency-graph/index.html

Prefer an installed entry-point? Use pipx:

pipx install modulith-android
modulith-android init
modulith-android

The default run writes build/dependency-graph/index.html. Open it in any browser โ€” no static server, no JavaScript build, no external assets.


๐Ÿ› ๏ธ Commands

Command What it does Output
modulith-android init runs the interactive wizard with auto-detected defaults ./modulith.toml
modulith-android runs the full analysis using ./modulith.toml build/dependency-graph/index.html
modulith-android --repo PATH analyse a project in a different directory report in that project's build/
modulith-android --out PATH write the report somewhere else HTML at the supplied path
modulith-android --config PATH use a config file at a non-default location unchanged

Exit codes are 0 on success and 1 on configuration / I/O errors. Findings never change the exit code.


๐Ÿช„ The wizard

modulith-android init runs five short questions, each with an auto-detected default. Confirm with Enter; edit anything that looks off.

# Question Auto-detected from
1 Root package (e.g. com.example) Scans .kt/.java files, computes the longest common package prefix.
2 Layer names (e.g. core, data, feature, app) Reads settings.gradle[.kts], extracts the first segment of each module path.
3 DAGP report location Globs **/build/reports/dependency-analysis/build-health-report.json. Absence is non-fatal โ€” the Unused deps tab is just empty.
4 Modules to audit for visibility Pre-selects all modules in the innermost layer; multi-select to customise.
5 Forbidden layer pairs Offers presets (Clean Architecture, MVI/MVVM) or "Custom" for manual entry.

The wizard prints the generated modulith.toml for review and asks before writing.


โš™๏ธ Configuration

The full modulith.toml schema:

# Generated by `modulith-android init`. Hand-edit anything you like.

[scan]
# Root Java/Kotlin package. Used by the visibility analyzer to scope
# import-index scanning to symbols declared in this package tree.
root_package = "com.example"

[layers]
# Ordered list of layer names, derived from the first segment of each
# Gradle module path (e.g. ":core:logger" -> "core"). Modules whose
# first segment isn't listed are parsed for edges but excluded from
# violation checking.
names = ["core", "data", "feature", "app"]

[visibility]
# Gradle module paths whose public API will be enumerated and
# cross-checked for external references.
target_modules = [
    ":core:logger",
    ":core:network",
]

# Each [[violations]] entry forbids a directed edge between two layers.
# Multiple entries are independent โ€” they don't compose.
[[violations]]
from = "core"
to   = "data"

[[violations]]
from = "core"
to   = "feature"

[[violations]]
from = "data"
to   = "feature"

Missing sections are silently treated as "skip this analysis" โ€” e.g. an absent [visibility] skips the visibility audit, an empty [[violations]] table means no violation rules are active. A missing modulith.toml is a hard error with a "run modulith-android init" hint.


๐Ÿ“‹ Requirements

Tool Why Notes
Python 3.10+ runs the analyzer stdlib-only on 3.11+; one backport (tomli) on 3.10
uv or pipx (recommended) one-shot or isolated install pip install --user modulith-android works too
Gradle project the analysis target Groovy or Kotlin DSL settings.gradle โ€” both are supported
Dependency Analysis Gradle Plugin populates unused-dependency advice optional โ€” the Unused deps tab is empty without it

The analyzer itself has zero runtime dependencies on Python 3.11+ and exactly one (tomli) on Python 3.10. No HTML/JS framework, no JSON schema library, no graph library โ€” pure stdlib.


๐Ÿงฉ How it works

                       modulith-android
                              โ”‚
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚ 1. read modulith.toml โ€” every project-specific value           โ”‚
   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
   โ”‚ 2. parse settings.gradle[.kts]            โ†’ list of modules    โ”‚
   โ”‚    parse each module's build.gradle[.kts] โ†’ edges              โ”‚
   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
   โ”‚ 3. core graph algorithms (stdlib only):                        โ”‚
   โ”‚      Tarjan SCC          โ†’ cycles                              โ”‚
   โ”‚      layer-pair filter   โ†’ violations                          โ”‚
   โ”‚      reverse-BFS         โ†’ cascades                            โ”‚
   โ”‚      fan-in/out, etc.    โ†’ metrics                             โ”‚
   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
   โ”‚ 4. (optional) ingest build-health-report.json                  โ”‚
   โ”‚      โ†’ unused-dependency advice per module                     โ”‚
   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
   โ”‚ 5. scan public API of audited modules; classify each symbol    โ”‚
   โ”‚      by external-consumer count + Hilt/Koin DI markers         โ”‚
   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
   โ”‚ 6. render a single self-contained HTML file                    โ”‚
   โ”‚      โ†’ build/dependency-graph/index.html                       โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Every output is deterministic: given identical inputs the HTML is byte-for-byte the same, so regenerating after a code change produces a clean diff you can review.


๐Ÿ—‚๏ธ Project layout

modulith-android/
โ”œโ”€โ”€ src/modulith_android/
โ”‚   โ”œโ”€โ”€ cli.py                 entry-point; argparse dispatch
โ”‚   โ”œโ”€โ”€ config.py              ModulithConfig dataclass + TOML loader
โ”‚   โ”œโ”€โ”€ wizard.py              interactive `init` flow with auto-detect
โ”‚   โ”œโ”€โ”€ parsers/
โ”‚   โ”‚   โ””โ”€โ”€ gradle_modules.py  settings.gradle[.kts] + build.gradle[.kts] reader
โ”‚   โ”œโ”€โ”€ analyzers/
โ”‚   โ”‚   โ”œโ”€โ”€ dagp_ingest.py     Dependency Analysis Gradle Plugin report reader
โ”‚   โ”‚   โ””โ”€โ”€ visibility_audit.py  public-API scanner + DI-marker classifier
โ”‚   โ”œโ”€โ”€ core/
โ”‚   โ”‚   โ”œโ”€โ”€ model.py           Edge, Module, GraphSnapshot
โ”‚   โ”‚   โ”œโ”€โ”€ cycles.py          Tarjan SCC
โ”‚   โ”‚   โ”œโ”€โ”€ cascades.py        transitive impact computation
โ”‚   โ”‚   โ”œโ”€โ”€ metrics.py         fan-in, fan-out, instability, abstractness
โ”‚   โ”‚   โ””โ”€โ”€ violations.py      layer-rule checker
โ”‚   โ”œโ”€โ”€ reports/
โ”‚   โ”‚   โ”œโ”€โ”€ html.py            the self-contained HTML+CSS+JS report
โ”‚   โ”‚   โ””โ”€โ”€ json_export.py     machine-readable graph dump
โ”‚   โ”œโ”€โ”€ common/
โ”‚   โ”‚   โ””โ”€โ”€ paths.py           module-path utilities
โ”‚   โ””โ”€โ”€ flows/
โ”‚       โ””โ”€โ”€ analyze.py         orchestrates the full pipeline
โ”œโ”€โ”€ tests/                     stdlib-unittest suite, no pip deps
โ”œโ”€โ”€ pyproject.toml
โ”œโ”€โ”€ LICENSE
โ””โ”€โ”€ README.md

๐Ÿง‘โ€๐Ÿ’ป Direct CLI

uvx/pipx are the easy paths, but the package is a normal CLI. Once installed:

modulith-android [SUBCOMMAND] [OPTIONS]

Subcommands:
  init                run the wizard; writes ./modulith.toml

Options (default run):
  --repo PATH         repository root (default: cwd)
  --out PATH          output directory (default: <repo>/build/dependency-graph)
  --config PATH       config file (default: <repo>/modulith.toml)
  -h, --help          show this help and exit
  --version           show version and exit

Exit codes:
  0  success; HTML report written
  1  configuration or I/O error

๐Ÿงช Development

pip install -e ".[dev]"
python -m pytest tests/                          # full suite
python -m pytest tests/test_visibility_audit.py  # one module
ruff check src/ tests/                           # lint

Tests use stdlib unittest; pytest discovers them with no configuration. CI runs the suite on Python 3.10 and 3.12.


๐Ÿ—บ๏ธ Roadmap

  • v0.1.0 โ€” analyzer core, modulith.toml config, wizard with auto-detect, self-contained HTML report, PyPI publication.
  • v0.2.0 โ€” JSON export improvements; richer cascade visualisation; configurable Hilt/Koin marker sets.
  • v0.3.0 โ€” multi-DSL improvements (KTS multi-line includes, type-safe project accessors).
  • v1.0.0 โ€” API stability promise.

๐Ÿ“„ License

MIT โ€” see LICENSE.

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

modulith_android-0.1.0.tar.gz (47.3 kB view details)

Uploaded Source

Built Distribution

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

modulith_android-0.1.0-py3-none-any.whl (41.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: modulith_android-0.1.0.tar.gz
  • Upload date:
  • Size: 47.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for modulith_android-0.1.0.tar.gz
Algorithm Hash digest
SHA256 573227126658313d1df06173ae83a9b74ad1dbff56e5f688df2f53885de31f5d
MD5 dba142ecdacd2de7e76bccbc687d2026
BLAKE2b-256 a8dedb6e676b1e712de4aa223efc316978f5e789579fcc3e94076d1ffc5defbc

See more details on using hashes here.

File details

Details for the file modulith_android-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for modulith_android-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9ed8666470791fc3eddf1e3bd8b595d76deb2ddb3541558a3f22ed7d6fa1ed60
MD5 c28c758474c7053d26453687c908e3d2
BLAKE2b-256 89d4ac84b552eff43fe85258acbfd42e371afeff32bd6b2b9d2dc78841b59c0e

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