ktlint
CLAUDE.md6.8k starsChanged 20 days agoMITView on GitHub
Build uses Gradle with Kotlin DSL. Convention plugins live in build-logic/. Dependencies are declared in gradle/libs.versions.toml. Kotlin API/language version is locked to 2.2; explicitApi() is enforced in all modules. All current rules extend RuleV2 from ktlint-rule-engine-core. Built-in standard rules extend StandardRule, which pre-fills ruleId with standard:<id> and sets About metadata: Custom rules may extend RuleV2 directly. The project itself only use rulesets with custom rules for testing purposes, as well as explaining how to build a custom ruleset. Rules implement…
We split this CLAUDE.md into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 51
All current rules extend RuleV2 from ktlint-rule-engine-core.
≈ “Common” is an estimate: at least 1 in 5 of the 25,680 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Build and Development Commands
# Build all modules and run ktlint self-check
./gradlew ktlintCheck build
# Run all tests
./gradlew test
# Run a single module's tests
./gradlew :ktlint-ruleset-standard:test
# Run a specific test class
./gradlew :ktlint-ruleset-standard:test --tests "io.github.ktlint.core.ruleset.standard.rules.FinalNewlineRuleTest"
# Format all Kotlin sources
./gradlew ktlintFormat
# Run tests on specific JDK versions (CI runs 17 and 21)
./gradlew testOnJdk17
./gradlew testOnJdk21
# Enable trace logging during tests
KTLINT_UNIT_TEST_TRACE=on ./gradlew :ktlint-ruleset-standard:testBuild uses Gradle with Kotlin DSL. Convention plugins live in build-logic/. Dependencies are declared in gradle/libs.versions.toml. Kotlin API/language version is locked to 2.2; explicitApi() is enforced in all modules.
Module Structure
| Module | Role |
ktlint-rule-engine-core | Public API types: RuleV2, RuleId, EditorConfigProperty, AutocorrectDecision |
ktlint-rule-engine | Core engine: KtLintRuleEngine, CodeFormatter, EditorConfigLoader |
ktlint-ruleset-standard | ~100 built-in lint rules |
ktlint-cli-ruleset-core | RuleSetV2Provider SPI base class (ServiceLoader entry point for custom rulesets) |
ktlint-cli | CLI entry point, shadow JAR, uses Clikt for argument parsing |
ktlint-test | Test utilities: KtLintAssertThat DSL, KtlintTestFileSystem |
ktlint-cli-reporter-* | Seven reporter modules (plain, json, html, checkstyle, sarif, baseline, etc.) |
ktlint-bom | Bill of Materials for consistent dependency versions |
ktlint-api-consumer | Example of embedding ktlint as a library |
Architecture
Rule Definition
All current rules extend RuleV2 from ktlint-rule-engine-core. Built-in standard rules extend StandardRule, which pre-fills ruleId with standard:<id> and sets About metadata:
class FinalNewlineRule : StandardRule(
id = "final-newline",
usesEditorConfigProperties = setOf(INSERT_FINAL_NEWLINE_PROPERTY),
)Custom rules may extend RuleV2 directly. The project itself only use rulesets with custom rules for testing purposes, as well as explaining how to build a custom ruleset.
class NoVarRule : RuleV2(
ruleId = RuleId("myruleset:no-var"),
about = About(maintainer = "...", repositoryUrl = "...", issueTrackerUrl = "..."),
)Rule Lifecycle Hooks
Rules implement up to four hooks called by the KtLintRuleEngine per file:
beforeFirstNode(editorConfig)— read.editorconfigproperties herebeforeVisitChildNodes(node, emit)— depth-first, before childrenafterVisitChildNodes(node, emit)— after childrenafterLastNode()— teardown
The emit lambda: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> AutocorrectDecision. Rules inspect the returned value and call .ifAutocorrectAllowed { } to decide whether to modify the AST. Call stopTraversalOfAST() to skip remaining nodes.
AST Traversal
The engine uses the Kotlin compiler's embedded IntelliJ PSI/AST (org.jetbrains.kotlin.com.intellij.lang.ASTNode). Element type constants are in ElementType (e.g. ElementType.VAR_KEYWORD). ASTNodeExtension.kt provides many helper extension functions.
EditorConfig Integration
Rules declare consumed properties in usesEditorConfigProperties. The engine resolves them from the .editorconfig hierarchy and passes them via beforeFirstNode(editorConfig). Rules read values with editorConfig[MY_PROPERTY].
Rule Discovery (Custom Rulesets)
Custom rulesets register via Java ServiceLoader. Create a file at:
META-INF/services/io.github.ktlint.core.cli.ruleset.core.api.RuleSetV2Providerlisting the fully-qualified RuleSetV2Provider subclass name.
Thread Safety
KtLintRuleEngine is thread-safe. RuleV2Provider (a () -> RuleV2 lambda) creates a fresh rule instance per file, so rule instances may hold mutable state safely.
Format Loop
CodeFormatter runs format passes in a loop until output stabilizes (up to maxFormatRunsPerFile), allowing fixes from one rule to trigger another rule's fix. However, it is not guaranteed that all problems are fixed after that, especially not on a code base which has never been formatted before. Ktlint CLI clearly indicates this in its console output.
Rule Opt-in Markers
RuleV2.Experimental— only runs when experimental rules are enabledRuleV2.OfficialCodeStyle— only runs withcode_style = ktlint_officialRuleV2.OnlyWhenEnabledInEditorconfig— opt-in rule, disabled by default@SinceKtlint("1.2", STABLE)— documents when a rule was added and its stability
Testing Patterns
Tests use JUnit 5, AssertJ, and the custom KtLintAssertThat DSL from ktlint-test. Each rule in ktlint-ruleset-standard has a corresponding *Test.kt. Tests are organized with @Nested inner class using backtick-quoted descriptive names.
private val myRuleAssertThat = assertThatRule { MyRule() }
@Test
fun `description of scenario`() {
val code = "val x = 1"
myRuleAssertThat(code)
.hasLintViolation(1, 1, "error message")
.isFormattedAs("val x = 1\n")
// or: .hasNoLintViolations()
// or: .hasLintViolationWithoutAutoCorrect(2, 5, "error message")
}Tests use an in-memory KtlintTestFileSystem (Jimfs) so the project's own .editorconfig does not affect test outcomes.
@KtlintDocumentationTest marks tests that also serve as documentation examples.
Trending
Quiet since June.about the whole repository
Who's talking about pinterest/ktlint
- ktlint/ktlint“Annotation wrapping before explicit constructor (ktlint_official)”GitHub · Jul 20, 2023 · 76 reactions
- ktlint/ktlint“Illegal reflective access operation with Kotlin 1.5.0”GitHub · May 7, 2021 · 25 reactions
- jeremymailen/kotlinter-gradle“Kotlin 2.1.0 failure”GitHub · Nov 28, 2024 · 22 reactions
- ktlint/ktlint“ktlint has become too opinionated”GitHub · Jun 17, 2024 · 20 reactions
- ktlint/ktlint“ktlint default settings disagree with IntelliJ IDEA Ultimate Edition on continuation indentation level (8 …”GitHub · Jun 29, 2020 · 17 reactions
The biggest 5 of 54 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 54
Talked about on GitHub and Stack Overflow (54 times).
On GitHub · 49
- Jul 20, 2023Annotation wrapping before explicit constructor (ktlint_official) — ktlint/ktlint76 reactions · 53 comments
- May 7, 2021Illegal reflective access operation with Kotlin 1.5.0 — ktlint/ktlint25 reactions · 8 comments
- Nov 28, 2024Kotlin 2.1.0 failure — jeremymailen/kotlinter-gradle22 reactions · 18 comments
- Jun 17, 2024ktlint has become too opinionated — ktlint/ktlint20 reactions · 38 comments
- Jun 29, 2020ktlint default settings disagree with IntelliJ IDEA Ultimate Edition on continuation indentation level (8 vs 12) — ktlint/ktlint17 reactions · 17 comments
44 more on GitHub
- Jun 18, 2020Kotlin support — super-linter/super-linter15 reactions · 1 comment
- Apr 6, 2021[Question] What is the reason to drop support for absolute paths in file patterns? — ktlint/ktlint11 reactions · 12 comments
- Mar 2, 2022java.lang.reflect.InaccessibleObjectException: Unable to make field private transient java.lang.Object java.lang.Throwable.backtrace accessible: module java.base does not "opens java.lang" to unnamed module @76628072 — ktlint/ktlint10 reactions · 29 comments
- Nov 7, 2021Internal error: `NoSuchElementException` in `TrailingCommaRule` when using `--experimental` — ktlint/ktlint9 reactions
- Mar 19, 2021Cannot choose between the following variants of com.pinterest:ktlint:0.41.0: — ktlint/ktlint9 reactions · 11 comments
- Dec 7, 2025IDE Internal Error 0.30.1 — nbadal/ktlint-intellij-plugin8 reactions · 1 comment
- Aug 22, 2022`ktlint` 0.47 displays plenty of warnings about the `--disabled_rules` argument usage — ktlint/ktlint8 reactions · 11 comments
- Jul 19, 2022Supporting flexible configurations of `TrailingCommaRule` — ktlint/ktlint8 reactions · 6 comments
- Jul 15, 2025NoSuchMethodError after upgrading from 1.6.0 to 1.7.0 — ktlint/ktlint7 reactions
- Aug 22, 2022Ant-style path pattern support broken when `ktlint` is invoked from the command line — ktlint/ktlint7 reactions · 4 comments
- Dec 22, 2021Cannot load extensions/core.xml with JDK 8 and maven-antrun-plugin — ktlint/ktlint7 reactions · 5 comments
- Jun 27, 2021Support .editorconfig file — autostyle/autostyle7 reactions
- Jun 24, 2020Another differences between AndroidStudio and Ktlint formatting — ktlint/ktlint7 reactions · 10 comments
- Jan 17, 2020Differences in formatting between ktlint and Android Studio — ktlint/ktlint7 reactions · 7 comments
- Sep 18, 2022Upgrade ktlint to 0.47.1 — detekt/detekt6 reactions · 2 comments
- Aug 22, 2022Traversing the directory hierarchy is broken on Windows as of version 0.47 — ktlint/ktlint6 reactions · 29 comments
- Sep 9, 2023Support Ktlint 1.0.0 — diffplug/spotless5 reactions · 5 comments
- Jan 18, 2022Add `ktlint` Kotlin linter — streetcomplete/StreetComplete5 reactions · 16 comments
- Apr 16, 20210.41.0 Performance decrease — ktlint/ktlint5 reactions · 14 comments
- Jun 3, 2022Bump Kotlin-related dependencies — TouK/sputnik4 reactions · 2 comments
- Mar 23, 2022chore(ktlint): bump ktlint to 0.45.1 / spacing changes w/new version — ankidroid/Anki-Android3 reactions · 1 comment
- Nov 3, 2021Bump KtLint to 0.43.2 and add TrailingComma rule — detekt/detekt3 reactions · 9 comments
- Apr 20, 2019Include annotations in parameter indentation checks. — ktlint/ktlint3 reactions
- Jan 9, 2024Bump ktlint from 1.1.0 to 1.1.1 — nbadal/ktlint-intellij-plugin2 reactions · 1 comment
- May 27, 2023Respect `RunAfterRule` constraint from ktlint — detekt/detekt2 reactions · 2 comments
- Jan 13, 2022Fix git hooks: do not run ktlint on all files of the current directory — ktlint/ktlint2 reactions · 1 comment
- Oct 6, 2020#436 Fix ktlints rules — http4k/http4k2 reactions · 5 comments
- Oct 5, 2020GH-534 Add ktlint for Kotlin and refactor codebase to utilize Kotlin idioms — panda-lang/hub2 reactions · 1 comment
- Aug 22, 2020IndentationRule: Do not enforce raw strings opening quote to be on a separate line — ktlint/ktlint2 reactions · 1 comment
- Jun 29, 2019Allow 'it' for variable and function names in multiline lambda rule — ktlint/ktlint2 reactions · 4 comments
- Jun 22, 2026(chore): Update GitHub repo URLs — ScoopInstaller/Main1 reaction · 4 comments
- Dec 1, 2025chore(deps): bump the minor group across 1 directory with 3 updates — loculus-project/loculus1 reaction · 2 comments
- Jul 15, 2025Make Ktlint code backwards compatible with lower Kotlin versions (down to 2.0) — ktlint/ktlint1 reaction
- Jul 15, 2025Bump ktlint from 1.0.1 to 1.7.0 — nbadal/ktlint-intellij-plugin1 reaction · 1 comment
- Dec 8, 2024Remove usages of getPsi() — ktlint/ktlint1 reaction · 22 comments
- May 29, 2024Fixed [{ }] notation for issue #2675 — ktlint/ktlint1 reaction · 1 comment
- Mar 25, 2024Bump com.pinterest.ktlint:ktlint-ruleset-standard from 0.50.0 to 1.2.1 — nbadal/ktlint-intellij-plugin1 reaction · 6 comments
- Mar 25, 2024Bump com.pinterest.ktlint:ktlint-logger from 0.50.0 to 1.2.1 — nbadal/ktlint-intellij-plugin1 reaction · 3 comments
- Mar 1, 2024Bump ktlint from 1.1.1 to 1.2.1 — nbadal/ktlint-intellij-plugin1 reaction · 1 comment
- Feb 29, 2024Bump ktlint from 1.1.1 to 1.2.0 — nbadal/ktlint-intellij-plugin1 reaction · 2 comments
- Feb 29, 2024Bump default Ktlint version to 1.2.1 — diffplug/spotless1 reaction
- Feb 25, 2024Correctly provide EditorConfig property types for Ktlint — diffplug/spotless1 reaction · 8 comments
- Feb 17, 2024Prevent conflict when curly closing brace is followed by range (until) operator — ktlint/ktlint1 reaction · 2 comments
- Dec 20, 2023Bump ktlint from 1.0.1 to 1.1.0 — nbadal/ktlint-intellij-plugin1 reaction · 1 comment
On Stack Overflow · 5
- Nov 29, 2020How do you tell ktlint in android to exclude specific paths in the project?16 votes · 3 answers
- Feb 2, 2020How do I add KtLint style to Android Studio using Gradle?3 votes · 1 answer
- Jan 10, 2022ktLintFormat fails with an error: Process 'command '/Library/Java/JavaVirtualMachines/jdk-17.0.1.jdk/Contents/Home/bin/java'' (macOS w/ Apple M1 chip)2 votes
- Nov 29, 2020Kotlin Linting RuleSetProvider 'trailing-comma'1 vote · 1 answer
- Oct 2, 2020How to install ktlint properly0 votes · 1 answer
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

