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, 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 module dependencies โ€” flags project(":foo") declarations whose target module's packages the consumer's source never imports.
  • ๐Ÿ’ฅ 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

# 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 four 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 Modules to audit for visibility Pre-selects all modules in the innermost layer; multi-select to customise.
4 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

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. No third-party Gradle plugin in the consumer's project either: every feature works against a vanilla Gradle build.


๐Ÿงฉ 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. cross-check declared project deps against source imports    โ”‚
   โ”‚      โ†’ unused module dependencies                              โ”‚
   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
   โ”‚ 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/
โ”‚   โ”‚   โ”œโ”€โ”€ unused_module_deps.py  cross-checks declared project deps against source imports
โ”‚   โ”‚   โ””โ”€โ”€ 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.

๐ŸŽฏ Scope

modulith-android focuses on modularity: graph shape, layer rules, visibility, and unused inter-module dependencies. It does NOT audit external Maven dependencies or Gradle configuration hygiene (api vs implementation, scope choices). For that, plugins like the Dependency Analysis Gradle Plugin are excellent companions and orthogonal to what this tool does.


๐Ÿ“„ 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.1.tar.gz (50.5 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.1-py3-none-any.whl (44.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: modulith_android-0.1.1.tar.gz
  • Upload date:
  • Size: 50.5 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.1.tar.gz
Algorithm Hash digest
SHA256 3d07f76cfc76ca643c7b6f76a5892217f634902cd8687ab490fdc6d1691c5db2
MD5 fbff62cbf8584ec341bae80ae613afc8
BLAKE2b-256 49672c19e2fc68b0972791555775ce528bfba630b05b37142224be3c96378f29

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for modulith_android-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a63f1a833329bcfc313395a8ba25b23070cf0ff1e12dbc6c8cb38e2b9516a2c2
MD5 a918de50d76a765236f8c634476f4467
BLAKE2b-256 7d7eed64be74a779f0dc0e94a0052c772bf6b6a36a0753923c529ce1e3c39e78

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