Skip to content

kairowan/KInspector

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

KInspector

English | 简体中文

KInspector is a Kotlin-first inspection tool for Kotlin / Android multi-module projects that turns dependency drift, Gradle inconsistency, architecture leaks, and coroutine anti-patterns into actionable terminal, JSON, HTML, Markdown, and SARIF reports.

Why KInspector

Large Kotlin and Android codebases usually fail in the same places:

  • module dependencies start drifting without a clear owner
  • circular dependencies appear after a few rushed integrations
  • Gradle configuration stops being consistent across modules
  • architecture boundaries become documentation-only
  • coroutine mistakes stay invisible until runtime symptoms appear

KInspector focuses on those engineering-governance problems instead of trying to be a generic lint wrapper.

Features

  • Scans Gradle multi-module structure from settings.gradle(.kts) and module build files
  • Parses Android module metadata such as namespace, compileSdk, minSdk, targetSdk, and Compose enablement
  • Resolves version catalog plugin aliases, library aliases, and bundles from libs.versions.toml
  • Detects includeBuild(...) setups and precompiled script plugins from build-logic projects
  • Flags convention plugins separately from standard Kotlin/Android/Java plugins
  • Builds a project dependency graph for module-level analysis
  • Detects circular module dependencies
  • Flags architecture boundary violations using default layer heuristics or an ownership + allowlist policy
  • Generates owner coverage reports so unresolved modules are visible in one place
  • Tracks owner drift separately from issue drift so baseline comparisons show ownership regressions and resolutions
  • Checks Gradle drift such as missing build files, missing plugin declarations, and inconsistent JVM toolchains
  • Detects a first set of coroutine anti-patterns such as GlobalScope and runBlocking in production code
  • Supports baseline/diff mode for CI, including NEW, UNCHANGED, and FIXED issue tracking
  • Supports owner drift gates, either as the default actionable set or as status-specific gates such as only BECAME_UNOWNED
  • Emits GitHub Actions step summaries, PR comment Markdown, workflow annotations, and SARIF for code scanning
  • Generates terminal, JSON, standalone HTML, Markdown, and SARIF reports
  • Supports both CLI execution and Gradle task integration
  • Designed around small interfaces so new rules and new report formats stay isolated

Project Structure

KInspector
├── core            # Shared models and contracts
├── scanner         # Project structure scanning
├── rules           # Rule engine and default rules
├── reporter-json   # JSON renderer
├── reporter-html   # HTML renderer
├── reporter-markdown # GitHub PR summary Markdown renderer
├── reporter-sarif  # SARIF renderer for code scanning
├── reporter-github # GitHub workflow annotations
├── cli             # Command-line entrypoint
└── gradle-plugin   # Gradle task integration

More design details:

Quick Start

1. Run with the CLI

./gradlew :cli:run --args="--project ."

This prints a terminal report and also writes:

  • build/reports/kinspector/kinspector-report.json
  • build/reports/kinspector/kinspector-report.html
  • build/reports/kinspector/kinspector-report.md when requested
  • build/reports/kinspector/kinspector-report.sarif when requested

To capture a baseline for CI:

./gradlew :cli:run --args="--project . --formats json --write-baseline kinspector-baseline.json"

To compare against a baseline and fail only on new errors:

./gradlew :cli:run --args="--project . --baseline kinspector-baseline.json --fail-on-new-error"

To emit only the baseline delta for review:

./gradlew :cli:run --args="--project . --baseline kinspector-baseline.json --diff-only --formats terminal,html,markdown,sarif"

To emit a PR comment body and GitHub workflow annotations in CI:

./gradlew :cli:run --args="--project . --baseline kinspector-baseline.json --diff-only --formats markdown,sarif --pr-comment-file build/reports/kinspector/kinspector-pr-comment.md --pr-comment-mode compact --pr-comment-max-items 10 --pr-comment-overflow collapse --pr-comment-sort severity --write-github-step-summary --emit-github-annotations --sarif-category architecture-health"

To switch terminal, Markdown, HTML, and SARIF message text to Chinese output:

./gradlew :cli:run --args="--project . --formats terminal,html,markdown,sarif --report-locale zh-cn"

To emit SARIF under a stable GitHub code scanning category:

./gradlew :cli:run --args="--project . --formats sarif --sarif-category architecture-health"

To write a GitHub PR summary directly into the current Actions job:

./gradlew :cli:run --args="--project . --formats markdown --write-github-step-summary"

2. Build the distributable CLI

./gradlew :cli:installDist
./cli/build/install/kinspector/bin/kinspector --project .

3. Use through the Gradle plugin

plugins {
    id("io.github.kariowan.kinspector")
}

kInspector {
    formats.set(listOf("terminal", "html", "json", "markdown", "sarif"))
    failOnError.set(true)
    failOnNewError.set(true)
    failOnUnownedModule.set(true)
    failOnOwnerDriftStatuses.set(listOf("BECAME_UNOWNED"))
    baselineFile.set(layout.projectDirectory.file("kinspector-baseline.json"))
    reportLocale.set("zh-cn")
    sarifCategory.set("architecture-health")
    prCommentFile.set(layout.buildDirectory.file("reports/kinspector/kinspector-pr-comment.md"))
    prCommentMode.set("compact")
    prCommentMaxItems.set(10)
    prCommentOverflowStrategy.set("collapse")
    prCommentIssueSortStrategy.set("severity")
    writeGitHubStepSummary.set(true)
    emitGitHubAnnotations.set(true)
    diffOnly.set(true)
}
./gradlew kInspect

Use writeBaselineFile on the first run to create the baseline file. Add baselineFile when you want diff mode against an existing baseline. diffOnly requires baselineFile and filters reports down to NEW current issues plus FIXED issues in the human-readable diff sections. failOnUnownedModule requires ownership mode to be configured, otherwise KInspector fails fast because there is no owner coverage model to enforce. failOnOwnerDrift and failOnOwnerDriftStatuses require both a baseline and owner coverage data on the baseline/current runs.

4. Optional configuration

KInspector supports both JSON and YAML config files. They are validated against the schema at core/src/main/resources/schema/kinspector-config.schema.json.

Use a config file to disable rules, change severity, or define architecture policy:

{
  "rules": {
    "gradle.missing-plugin": {
      "enabled": false
    },
    "architecture.boundary": {
      "severity": "ERROR"
    }
  },
  "architecture": {
    "moduleOwners": {
      ":app": "shell"
    },
    "packageOwners": {
      "com.example.feature": "feature-team",
      "com.example.core": "platform"
    },
    "ownerAllowlist": {
      "shell": ["feature-team"],
      "feature-team": ["platform"]
    },
    "dependencyRules": [
      {
        "name": "feature-boundary",
        "from": {
          "modules": [":feature:*"]
        },
        "allow": {
          "layers": ["domain", "core"]
        }
      }
    ],
    "moduleAllowlist": {
      ":app": [":feature:feed"]
    }
  }
}

An example file is available at examples/kinspector.json.

YAML is also supported:

rules:
  architecture.boundary:
    severity: error
  gradle.missing-plugin:
    enabled: false
architecture:
  moduleOwners:
    :app: shell
  packageOwners:
    com.example.feature: feature-team
    com.example.core: platform
  ownerAllowlist:
    shell:
      - feature-team
    feature-team:
      - platform
  dependencyRules:
    - name: feature-boundary
      from:
        modules:
          - :feature:*
      allow:
        layers:
          - domain
          - core
  moduleAllowlist:
    :app:
      - :feature:feed

See examples/kinspector.yaml.

Example Output

Terminal

KInspector :: SampleApp
Root      :: /workspace/sample
Generated :: 2026-03-06T10:14:28+08:00

Summary   :: modules=18, projectDeps=42, issues=5, errors=1, warnings=3, info=1

Modules
  - :app [layer=app, toolchain=17] deps=[:feature:feed, :core:designsystem]
  - :feature:feed [layer=feature, toolchain=17] deps=[:domain:feed, :core:common]

Issues
  [ERROR] dependency.circular :: Circular dependency detected
  Detected module cycle: :feature:feed -> :data:feed -> :feature:feed.
  suggestion: Break the cycle by extracting shared contracts into a lower-level module.

JSON

{
  "toolName": "KInspector",
  "projectName": "SampleApp",
  "summary": {
    "moduleCount": 18,
    "issueCount": 5,
    "errorCount": 1,
    "warningCount": 3,
    "infoCount": 1
  },
  "issues": [
    {
      "ruleId": "dependency.circular",
      "title": "Circular dependency detected",
      "severity": "ERROR"
    }
  ]
}

HTML

The HTML report is standalone and CI-friendly. It includes:

  • summary cards for module and issue counts
  • baseline diff summary when a baseline is provided
  • a sortable-at-a-glance issues table
  • module dependency metadata for quick review
  • owner coverage sections with grouped owners and unresolved modules
  • version catalog and included build sections for build-logic visibility

Markdown

The Markdown renderer is intended for PR checks and step summaries. It focuses on:

  • top-level module and issue counts
  • owner coverage and unresolved modules
  • owner drift versus the baseline, including owner changes and newly unowned modules
  • NEW issues when baseline diff mode is active
  • FIXED issues when baseline diff mode is active

Use --pr-comment-file <path> or kInspector.prCommentFile when you want that Markdown body to be upserted into a PR comment by a workflow step.

Use --pr-comment-mode compact or kInspector.prCommentMode = "compact" when you want the comment to keep only:

  • summary metrics
  • owner drift summary
  • NEW issues
  • FIXED issues

Use --pr-comment-max-items <n> and --pr-comment-overflow collapse|truncate to control how many rows each compact section keeps before either:

  • collapsing the remainder into a <details> block
  • truncating the remainder with an omission note

Use --pr-comment-sort severity or reporting.prComment.issueSortStrategy: severity when the compact comment should show higher severity issues first before lower priority rows are pushed into the overflow section.

If you want to gate only specific ownership regressions, use --fail-on-owner-drift-statuses or kInspector.failOnOwnerDriftStatuses:

./gradlew :cli:run --args="--project . --baseline kinspector-baseline.json --fail-on-owner-drift-statuses BECAME_UNOWNED"
kInspector {
    failOnOwnerDriftStatuses.set(listOf("BECAME_UNOWNED"))
}

The same behavior can live in kinspector.yaml / kinspector.json:

gates:
  failOnOwnerDriftStatuses:
    - became_unowned
reporting:
  locale: zh-cn
  prComment:
    mode: compact
    maxItems: 10
    overflowStrategy: collapse
    issueSortStrategy: severity

Distribution

KInspector is prepared for two release channels:

  • JitPack for the publishable JVM modules such as core, scanner, and rules
  • Gradle Plugin Portal for the Gradle plugin id io.github.kariowan.kinspector

After pushing a release tag such as v0.1.0, JitPack consumers can use:

repositories {
    maven("https://jitpack.io")
}

dependencies {
    implementation("com.github.kariowan.kinspector:core:v0.1.0")
    implementation("com.github.kariowan.kinspector:rules:v0.1.0")
}

The Gradle plugin is configured for publication with:

  • plugin id: io.github.kariowan.kinspector
  • website: https://github.com/kariowan/kinspector
  • VCS URL: https://github.com/kariowan/kinspector.git

Until the plugin is published to the Gradle Plugin Portal, local and composite-build usage remain the reliable integration path inside this repository.

SARIF

Use the SARIF renderer when you want GitHub code scanning ingestion:

./gradlew :cli:run --args="--project . --baseline kinspector-baseline.json --diff-only --formats markdown,sarif --write-github-step-summary --sarif-category architecture-health"

The renderer emits:

  • ruleId and severity level per issue
  • repo-relative artifact paths
  • partialFingerprints.primaryLocationLineHash for stable alert matching
  • baseline state markers for current findings
  • optional SARIF category via --sarif-category <name>

GitHub Actions annotations

Use --emit-github-annotations or kInspector.emitGitHubAnnotations to print workflow commands for:

  • current issues in the visible report
  • current unowned modules when ownership mode is active
  • owner drift entries such as OWNER_CHANGED, BECAME_UNOWNED, NEWLY_UNOWNED, and STILL_UNOWNED

Example GitHub Actions step:

- name: Run KInspector
  run: ./gradlew :cli:run --args="--project . --baseline kinspector-baseline.json --diff-only --formats markdown,sarif --pr-comment-file build/reports/kinspector/kinspector-pr-comment.md --pr-comment-mode compact --pr-comment-max-items 10 --pr-comment-overflow collapse --pr-comment-sort severity --write-github-step-summary --emit-github-annotations --sarif-category architecture-health --fail-on-owner-drift-statuses BECAME_UNOWNED"

- name: Upload SARIF
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: build/reports/kinspector/kinspector-report.sarif

A complete workflow template is available at examples/github-actions/kinspector-code-scanning.yml.

MVP Scope

KInspector MVP is intentionally narrow:

  • Kotlin / Android multi-module project scanning
  • module dependency analysis
  • Gradle consistency checks
  • architecture boundary checks
  • HTML and JSON reports

What it does not do in MVP:

  • automatic fixes
  • deep AST-based Kotlin semantic analysis
  • full detekt integration
  • interactive UI

The detailed MVP breakdown lives in docs/mvp.md.

Roadmap

  • Add richer Gradle scanning for Android variants and plugin management edge cases
  • Add ownership-aware package and module visualizations in reports
  • Add SARIF quality gates and GitHub Action templates
  • Add detekt bridge support for deeper Kotlin and coroutine analysis
  • Add configuration file generated docs and migration guides
  • Publish tagged releases to JitPack, the Gradle Plugin Portal, and standalone binaries

Contributing

Contributions should keep the same constraints as the codebase:

  • keep scanning, rules, and rendering decoupled
  • prefer small interfaces and data classes over framework-heavy abstractions
  • add new checks as isolated rules instead of embedding logic into reporters or entrypoints
  • favor high-signal rules with low false-positive rates

Start here:

License

KInspector is available under the MIT License.

About

Engineering health checks for Kotlin and Android multi-module projects.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors