Skip to content

Docs guide (KmpToolkit)

What this file is

KmpToolkit-specific extensions on top of the canonical blueprint in DEVELOPMENT-TEMPLATE.mdread that first.

This file is owned by this repo. Unlike DEVELOPMENT-TEMPLATE.md (which is sync'd from mbl-library-template-kmp), this one is hand-authored and captures KmpToolkit's distinctive shape:

  • A third published surface (Dokka API reference bundled inside -javadoc.jar)
  • Three content types (narrative, per-module pages, cookbook recipes)
  • Cookbook recipe enforcement (CI-checked format constraints)
  • Legacy directory migration (14 excluded docs/<module>/ subdirs)

The three surfaces

KmpToolkit publishes documentation across three surfaces, each with its own pipeline.

Source: docs/**, mkdocs.yml

Lands at: https://mobilebytelabs.github.io/KmpToolkit/

The primary product. Everything in this guide is about authoring for this surface.

Source: Kotlin /// KDoc in source files

Lands at: Bundled inside each module's -javadoc.jar on Maven Central

Built per-module via the convention plugin at build-logic/convention/src/main/kotlin/DokkaConventionPlugin.kt. Each cmp-*/build.gradle.kts applies it (id("io.github.mobilebytelabs.kmptoolkit.dokka")) and wires the output into vanniktech.mavenPublish via JavadocJar.Dokka("dokkaGeneratePublicationHtml"). Users open the HTML from the Maven Central UI.

Source: docs/** mirrored

Lands at: https://github.com/MobileByteLabs/KmpToolkit/wiki/<basename>

Passive mirror for users who prefer GitHub's UI. Generic conventions in DEVELOPMENT-TEMPLATE.md cover this.


The three content types

1. Narrative docs

docs/index.md, docs/getting-started.md — top-of-funnel pages. Authored prose, full freedom on structure. Same conventions as the generic guide describes for any library.

2. Per-module pages

One page per published module under docs/modules/cmp-*.md. Two flavors, both registered in mkdocs.ymlnav: Modules::

Used by: 10 modules today (those with cmp-*/README.md)

Pattern: the per-module page uses the mkdocs-include-markdown-plugin Liquid-style directive to embed the module's source-tree README. See docs/modules/cmp-network-monitor.md for live syntax.

Don't duplicate the README content

Let the include do its job. The per-module page should be a thin wrapper that pulls in the source-tree README at build time.

Used by: 11 modules today (those without cmp-*/README.md yet)

Pattern: a minimal page noting "shipped; full docs coming" + GitHub source link + a one-line API reference note pointing at the -javadoc.jar on Maven Central.

Promote to README-embedded when the README lands

When a module gains a cmp-*/README.md, convert its docs/modules/cmp-*.md placeholder to the embedded form in the same PR. Reduces the gap between source-tree docs and site docs.

Always include the Maven Central API reference note

Both flavors must mention that the API reference is inside the -javadoc.jar on Maven Central. This is the only place users discover that pattern.

3. Cookbook recipes

docs/cookbook/{topic}/{recipe}.md — the bulk of user-facing how-to docs. Strict format, CI-enforced. Use the template at _partials/cookbook-recipe-template.md as the starting point.

Hard constraints (CI-checked)

  • ≤ 80 lines total (wc -l)
  • ≥ 1 ```kotlin code block (grep)
  • Frontmatter has reviewed_by.date (YYYY-MM) + reviewed_by.version
  • "How do I {task}?" title — phrased as a user question

Soft conventions

  • Quick start is ≤ 15 lines of copy-paste-runnable code
  • Caveats prefer per-platform bullets over prose
  • Related links: module page + sample + (optional) ADR

A new cookbook topic gets its own subdir + an index.md topic index listing recipes + relevant modules. See docs/cookbook/network-monitor/index.md for the shape.


Excluded legacy docs/<module>/ subdirs

These per-module docs subdirs predate the mkdocs site and use relative links that resolve only in the GitHub UI. They live in docs/ for backward compat but are excluded from the mkdocs build via mkdocs.ymlexclude_docs:.

Full list (14 directories + 5 root files)
docs/app-intents/
docs/bubble/
docs/clipboard/
docs/firebase-analytics/
docs/in-app-update/
docs/intent-launcher/
docs/inter-app-comms/
docs/network-monitor/
docs/open-url/
docs/pdf-generator/
docs/remote-config/
docs/share/
docs/toast/
docs/user-tickets/

docs/BUBBLE.md
docs/CLIPBOARD_MONITOR.md
docs/FEATURE_REQUEST.md
docs/REMOTE_CONFIG.md
docs/REMOTE_CONFIG_SAMPLES.md

Don't add new content to those directories

Lift content into one of the three current surfaces:

  • Module-level reference → write cmp-*/README.md (becomes source for docs/modules/cmp-*.md via include-markdown)
  • How-to → cookbook recipe under docs/cookbook/{topic}/
  • Narrative → top-level docs/<slug>.md

When a legacy directory's content gets migrated, drop its line from exclude_docs: in the same PR.


Agent quick reference

Generic recipes (add a page, add an asset, override brand colors, test, deploy) live in DEVELOPMENT-TEMPLATE.md. Below are operations specific to KmpToolkit's three-content-type structure.

Want to… Recipe
Add a cookbook recipe (1) cp docs/_partials/cookbook-recipe-template.md docs/cookbook/<topic>/<slug>.md (2) Fill in YAML frontmatter (title, reviewed_by.date, reviewed_by.version) (3) Author body — Quick start (≤15 lines kotlin) + Caveats + Related links (4) Append entry to docs/cookbook/<topic>/index.md recipe list. Don't add to mkdocs.yml nav.
Add a cookbook topic (1) mkdir docs/cookbook/<topic> (2) Author docs/cookbook/<topic>/index.md listing recipes + relevant modules (3) Add - <Title>: cookbook/<topic>/index.md under Cookbook in mkdocs.ymlnav:
New module shipped — README-embedded page (1) Write cmp-<name>/README.md (2) Create docs/modules/cmp-<name>.md with the include-markdown directive (see existing modules for syntax) (3) Add alphabetically into mkdocs.ymlnav: Modules: (4) Apply Dokka plugin in cmp-<name>/build.gradle.kts (id("io.github.mobilebytelabs.kmptoolkit.dokka")) + wire JavadocJar.Dokka("dokkaGeneratePublicationHtml") in vanniktech.mavenPublish config
New module shipped — placeholder page Same as above, but step (2) uses the standard placeholder block ("Full docs coming soon, see GitHub source") + Maven Central + API ref note instead of include-markdown
Migrate placeholder → README-embedded (1) Write cmp-<name>/README.md (2) Replace the page body in docs/modules/cmp-<name>.md with the include-markdown directive (3) Same PR
Migrate a legacy docs/<module>/ subdir (1) Move usable content into cmp-<module>/README.md or into cookbook recipes (2) Delete the legacy subdir (3) Remove its line from mkdocs.ymlexclude_docs:

Invariants

Generic invariants (Home.mdindex.md sync, new page → nav, etc.) live in DEVELOPMENT-TEMPLATE.md. Below are KmpToolkit-specific cross-file edit obligations.

If you change… Also update… Why
New cmp-<name>/ Gradle module (1) docs/modules/cmp-<name>.md (2) mkdocs.ymlnav: Modules: (3) cmp-<name>/build.gradle.kts Dokka plugin + JavadocJar config (4) cmp-<name>/CHANGELOG.md (5) root CHANGELOG.md entry Module ships without docs, API ref, or release notes otherwise
New cookbook recipe The matching docs/cookbook/<topic>/index.md (add to recipe list) Recipe is invisible unless the topic index links to it
Recipe verified against new release Bump reviewed_by.date + reviewed_by.version in frontmatter Without bump, recipe-freshness audit treats it as stale
Module's cmp-<name>/README.md content Nothing — docs/modules/cmp-<name>.md re-includes via plugin on every build This is the point of the include-markdown pattern
Module renamed (cmp-oldcmp-new) (1) Rename docs/modules/cmp-old.mdcmp-new.md (2) Update mkdocs.yml nav entry (3) Grep for inbound [link](cmp-old.md) references in cookbook recipes + fix Build fails on dangling links
Migrated legacy docs/<module>/ subdir Remove its line from mkdocs.ymlexclude_docs: Migration is incomplete otherwise; future authors see it excluded and may duplicate work

Scaling rubric

Generic scaling rubric (single-module → multi-module shape) lives in DEVELOPMENT-TEMPLATE.md. KmpToolkit is sized for ≥ 15 modules with heavy how-to content. Below: what to add as it scales further.

Current state What to add next
21 modules, 12 recipes today (now) Migrate one legacy docs/<module>/ subdir per release until exclude_docs: is empty. Each migration: lift content into cmp-<module>/README.md (replaces docs/modules/ placeholder) and/or split into 1-3 cookbook recipes.
25+ modules Group modules in nav by capability cluster (Inter-app comms, Network, Storage, etc.) instead of flat alphabetical. Edit mkdocs.ymlnav: Modules: to add subsections.
30+ cookbook recipes Introduce sub-topics within a cookbook section (e.g. cookbook/network-monitor/{detection,reaction,testing}/...). Each sub-topic gets its own index.md.
Recipe-freshness automation needed Add a CI gate that fails when ≥ N recipes have reviewed_by.version more than one minor behind current. (Not built today — manual audit per release.)
Cookbook page count > 100 Add a search-tag index page that groups recipes by tag (Android-only, requires-permission, async-flow, etc.). Tags live in recipe frontmatter; render via a custom mkdocs macro.
Multi-version docs needed (v3 + v4 coexisting) Add mike plugin for versioned docs. Significant ceremony; adopt only when users genuinely need v3 docs after v4 ships.

Anti-patterns

  • Don't create a new cookbook topic for a single recipe — wait for ≥ 3.
  • Don't add per-module pages for modules without cmp-*/README.md AND without a clear "ships standalone" story — placeholder pages pile up.
  • Don't link cookbook recipes from mkdocs.yml nav directly. Keep nav at topic-index level. Currently 12 recipes; direct nav would mean 12 entries instead of 4.

Validation commands

Generic validation (strict build, link audit, site liveness probe) lives in DEVELOPMENT-TEMPLATE.md. Below: audits specific to KmpToolkit's cookbook + multi-module structure.

Full KmpToolkit-specific audit suite
# Count cookbook recipes
find docs/cookbook -name "*.md" -not -name "index.md" | wc -l

# Audit: every cookbook recipe ≤ 80 lines (constraint AC12)
for f in docs/cookbook/**/*.md; do
  [ "$(basename "$f")" = "index.md" ] && continue
  lines=$(wc -l < "$f")
  [ "$lines" -gt 80 ] && echo "OVERLONG ($lines lines): $f"
done

# Audit: every cookbook recipe has ≥ 1 kotlin block (constraint AC13)
for f in docs/cookbook/**/*.md; do
  [ "$(basename "$f")" = "index.md" ] && continue
  grep -q '```kotlin' "$f" || echo "MISSING kotlin block: $f"
done

# Audit: cookbook recipes with stale reviewed_by.version (not current 3.5.x)
grep -L "version: 3.5" docs/cookbook/**/*.md 2>/dev/null | grep -v "index.md"

# Cross-check: every cmp-* Gradle module has a docs/modules/cmp-*.md
diff <(ls -1d cmp-*/ 2>/dev/null | sed 's|/||') \
     <(ls -1 docs/modules/cmp-*.md | xargs -n1 basename | sed 's|\.md||') \
  | head -20

# Cross-check: every cmp-* module applies the Dokka convention plugin
for d in cmp-*/; do
  grep -q "io.github.mobilebytelabs.kmptoolkit.dokka" "$d/build.gradle.kts" \
    || echo "MISSING Dokka plugin: $d"
done

# Verify the convention plugin sources the Dokka v2 task name
grep -r "dokkaGeneratePublicationHtml" cmp-*/build.gradle.kts | wc -l
# Expect: 21 (one per cmp-* module)

Run all audits before opening a release PR

Catches drift before users see it. The cookbook line/kotlin/version audits are particularly important — CI's recipe-shape constraints exist because the format is what makes the cookbook scannable.