Contributing to kiban
August 27, 2026 · View on GitHub
Issues, discussion and pull requests are all welcome. This document is the practical part: what to run before you push, what the repository expects a change to carry with it, and which checks cannot run on every machine. The policy that decides what a change means for consumers — major, minor or patch, and what the binary compatibility guarantee covers — is VERSIONING.md; the mechanics of cutting a release are in RELEASING.md.
Reporting a security vulnerability is a separate path: do not open an issue, see SECURITY.md.
What you need
A JDK 17 or newer is the only prerequisite. Gradle comes from the wrapper — always invoke
./gradlew, never a locally installed gradle, so everyone runs the version the repository pins.
The Kotlin, Android and Kotlin/Native toolchains are downloaded by the build itself.
Two parts of the build need more than that, and neither is expected of a contributor:
- Apple targets (
ios*,macos*,tvos*,watchos*,assembleKibanDebugXCFrameworkandsamples/swift-console) need macOS with Xcode. They cannot be built on Linux or Windows at all. - Android-specific tasks (
:library:testAndroidHostTest,assembleAndroidMain, lint) need an Android SDK, i.e.ANDROID_HOMEpointing at an installation. Without one they fail with "SDK location not found", which is a missing SDK rather than anything wrong with the change.
CI runs the full target matrix — Linux, macOS and Windows runners, the Swift sample included — on
every pull request (.github/workflows/gradle.yml). That is what verifies the targets your machine
cannot build, so a green local run plus a green CI run is the complete picture.
Before you push
./gradlew jvmTest checkKotlinAbi ktfmtCheck
These three run everywhere, including on Linux and Windows without an Android SDK, and they catch most of what CI would reject:
jvmTestruns the common test suite on the JVM. The same sources run on every other target in CI, so a failure here is a failure everywhere.checkKotlinAbicompares the public API against the dumps committed underlibrary/api/(jvm/library.apiandlibrary.klib.api). A klib needs no Xcode, so the Apple targets are dumped from a Linux host like any other — you do not need a Mac to check the API.ktfmtCheckenforces formatting../gradlew ktfmtFormatapplies it; run that rather than hand-fixing the report.
Changing the public API
checkKotlinAbi fails on any change to the public API, including additions. That is deliberate: the dumps
are the reviewable record of what consumers can see, and VERSIONING.md defines the
public API as exactly what they contain.
When a change to the API is intended, regenerate and commit the dumps:
./gradlew updateKotlinAbi
Both dump files are expected in the same commit as the code that changes them. Note that a new
optional parameter on an already-published function is source-compatible but not binary
compatible — see the @IntroducedAt rule in VERSIONING.md before adding one.
Tests
Tests live in library/src/commonTest and run on every target. The suite uses
TestBalloon with assertk
assertions — a test file declares val SomethingTest by testSuite { … } holding test("…") { … }
blocks, rather than annotated methods; follow the shape of the neighbouring files. A table of inputs
loops around the test { … } declaration rather than inside a single test body, so a failure names
the case that failed instead of stopping at the first one.
New behaviour needs a test, and a bug fix needs one that fails without it.
IBAN registry data
CountryCodesData.kt and CountryTestData.kt are generated — do not hand-edit them. They come
from the SWIFT IBAN Registry TXT via scripts/generate_country_data.main.kts; the README's
"Updating the IBAN registry data" section has the
sequence, and the raw registry file is never committed because it is not redistributable. A weekly
workflow (.github/workflows/registry-sync.yml) opens the update pull request when the registry
changes, so this is rarely something to do by hand.
Both scripts under scripts/ carry their own offline test: --self-check on either one asserts
over its parsing helpers and exits. Changing how the generator reads the registry means extending
scripts/testdata/synthetic-registry.txt — there is no real registry file to test against.
Pull requests
- One topic per pull request. Keep unrelated cleanups out of a change that has to be reviewed on its merits.
- Reference the issue it addresses, if there is one.
- Say what you ran. List the Gradle commands you actually executed and name what you could not verify locally (Apple targets and Android tasks, typically). Do not describe an unrun check as passing — CI will run it, and an honest gap is more useful than a claim.
- Add a CHANGELOG entry under the top
## X.Y.Z (unreleased)section of CHANGELOG.md for anything a consumer would notice, in the appropriate group (breaking changes first). The existing entries show the expected level of detail: what changed and why it was the right call, not just what moved. - Let CI go green before asking for a merge. The matrix is the real verification.
- Every source file carries the Apache 2.0 licence header — copy it from a neighbouring file when adding one.
Automated agents
Coding agents work on this repository from cloud sandboxes. CLAUDE.md records which Gradle tasks do and do not run in such a container and what "verified" is allowed to mean there. It is a note to those agents, not contributor documentation — this file is the human one.