compose-doctor

agent
Security Audit
Warn
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Warn
  • process.env — Environment variable access in .github/workflows/compose-doctor.yml
  • fs module — File system access in .github/workflows/compose-doctor.yml
  • process.env — Environment variable access in action.yml
  • fs module — File system access in action.yml
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Deterministic 0-100 health score and agent fix-loop for Android Jetpack Compose. Wraps detekt + compose-rules

README.md

compose-doctor

Gradle Plugin Portal
Claude Code Plugin
Gemini CLI Extension
ci
License: MIT
Website

A deterministic health check for Android Jetpack Compose — the React Doctor idea, for Compose.

Your agent writes Compose; this scores it. compose-doctor runs detekt +
compose-rules under the hood, then turns the findings
into a single 0–100 health score, a structured report an agent can fix against, and a CI/PR gate.

✅ Published. The plugin is live on the Gradle Plugin Portal
as dev.composedoctor — apply it with plugins { id("dev.composedoctor") version "0.1.0" }
(see Use it in your project).

Why

The pieces exist in the Compose world but are unbundled — compose-rules/compose-lints for the
rules, scattered agent guides, and no shared score. compose-doctor's value isn't the rules (those
are battle-tested upstream); it's the bundle: one score, an agent fix-loop, and a CI gate.

The score

score = 100 − (uniqueErrorRules × 1.5) − (uniqueWarningRules × 0.75)      // clamped to [0, 100]

Translated directly from React Doctor: the unit is unique rule IDs triggered, not instance
count and not normalized by code size. Fixing 49 of 50 violations of a rule does not move the
score; clearing the last one removes that rule's penalty. That makes the score deterministic
without calibration — and makes the agent loop ("clear one rule at a time") effective.

Labels: 75+ Great · 50–74 Needs work · <50 Critical.

Findings are grouped into display dimensions (State/Correctness, Performance, Architecture,
Security, Accessibility) for the report — dimensions do not weight the overall score.

compose-doctor applies a curated policy on top of detekt + compose-rules — Compose health plus
genuine bugs, with a two-tier severity (errors −1.5, warnings −0.75) and style noise disabled. See
docs/RULES.md.

Try it

The repo ships a deliberately-flawed playground/ feed app, wired to the plugin from
source via a composite build. With JDK 21:

git clone [email protected]:rotemmiz/compose-doctor.git && cd compose-doctor
./gradlew -p playground composeDoctor

📖 docs/TRY-IT-PLAYGROUND.md is a guided walkthrough — run it, read
the report, fix a rule, and watch the score move.

compose-doctor — health score: 72/100  [NEEDS_WORK]
  unique error rules:   9
  unique warning rules: 19
  total findings:       34

  by dimension:
    ARCHITECTURE       82/100
    STATE_CORRECTNESS  94/100
    ...

Outputs:

  • build/reports/compose-doctor/score.json — machine-readable score + findings (for agents/CI). Excerpt:

    {
      "schemaVersion": 1, "status": "ok", "score": 72, "label": "NEEDS_WORK",
      "uniqueErrorRules": 9, "uniqueWarningRules": 19, "totalFindings": 34,
      "dimensions": { "ARCHITECTURE": 82, "PERFORMANCE": 96, "STATE_CORRECTNESS": 94 },
      "byRule": [
        { "ruleId": "CompositionLocalAllowlist", "severity": "ERROR", "count": 1,
          "scoreImpactIfCleared": 1.5, "fixHint": "Avoid this CompositionLocal or add it to the allowlist." }
      ]
    }
    
  • build/reports/detekt/detekt.sarif — findings in SARIF, with precise locations.

Use it in your project

The plugin is on the Gradle Plugin Portal —
apply it by id and pin the version (pinning keeps scores comparable across runs):

// build.gradle.kts of a module with Compose source
plugins {
    id("dev.composedoctor") version "0.1.0"
}

composeDoctor {
    failBelow.set(75)          // fail the build below this score (optional)
    // per-engine strictness — see docs/RULES.md (needs: import dev.composedoctor.plugin.EngineLevel)
    // detekt  = EngineLevel.ERRORS              // count only detekt's genuine bugs
    // compose = EngineLevel.ERRORS_AND_WARNINGS // count all Compose issues (default)
    // autoConfigureDetekt.set(false)            // if you already configure detekt yourself
}

Then ./gradlew composeDoctor. The plugin applies detekt, attaches the compose-rules ruleset
(config bundled), enables SARIF, and scores it. Existing detekt machinery — baseline.xml,
detekt.yml, @Suppress — applies as usual.

Repositories: your build needs gradlePluginPortal(), mavenCentral(), and google()
available — the plugin pulls detekt and the io.nlopez.compose.rules ruleset from them.

JDK: run Gradle on JDK 17–21. detekt (1.23.x) can't analyze under a JDK newer than 22, so
a daemon on JDK 22+ fails the :detekt task — pin Gradle's JVM (org.gradle.java.home) if your
default JDK is newer.

CI

A reusable workflow posts the score on every PR, uploads SARIF for code-scanning annotations, and
gates on a threshold:

# .github/workflows/health.yml
jobs:
  health:
    uses: rotemmiz/compose-doctor/.github/workflows/compose-doctor.yml@main
    with:
      gradle-args: composeDoctor
      fail-below: 75

It posts a sticky score comment on the PR — a health badge, the headline score, the top outstanding
findings (with file:line and a fix hint), and a per-dimension breakdown:

compose-doctor's sticky PR score comment

Repo Health Badge

Showcase your project's Compose health score in your README:

[![Compose Doctor](https://img.shields.io/badge/Compose%20Doctor-75%2B%20Great-10b981?logo=android)](https://github.com/rotemmiz/compose-doctor)

Agent skill

skills/compose-doctor/SKILL.md teaches a coding agent to run the
task, read the SARIF, and fix the highest-value rule iteratively — plus Compose best-practices to
avoid the findings up front. It's the single source of truth; the per-agent packaging below wraps it.

Claude Code — install as a plugin (bundles the skill + a /compose-doctor command):

/plugin marketplace add rotemmiz/compose-doctor
/plugin install compose-doctor@compose-doctor

Codex · OpenCode · Google Antigravity · Cursor — zero install: all auto-read the root
AGENTS.md, the neutral mirror of the skill. OpenCode also ships the /compose-doctor
command in-repo at .opencode/commands/.

Gemini CLI — install as an extension (bundles the command + AGENTS.md context):

gemini extensions install https://github.com/rotemmiz/compose-doctor

See skills/README.md for all install paths. The skill is self-bootstrapping:
if a module has no composeDoctor task yet, it runs the bundled
init/compose-doctor.init.gradle.kts to apply the plugin
without editing any build file.

The full agent loop, the score.json contract, and the memory/integrity model are specified in
docs/AGENT-HARNESS.md.

How it works

A single self-contained Gradle plugin orchestrates the engines and aggregates their SARIF — it does
not embed detekt-core or reimplement rules. Internally: the scoring package is a pure,
deterministic function; rulemap maps rule IDs to dimensions; the plugin does the wiring, scoring,
and reporting.

Roadmap

  • Publish to the Gradle Plugin Portal. ✅ live as dev.composedoctor.
  • Wire android-lint to populate the Security/Accessibility dimensions.
  • composeDoctorBaseline task to seed detekt's baseline.xml.

License

MIT © 2026 Rotem Meidan

Reviews (0)

No results found