sample-scaffolder

Scaffolds new Fakt sample projects with correct structure, build scripts, and CI integration. Supports JVM, KMP, Android, multi-module, test-fixtures, and fake-publishing types. Use when creating a ne

SKILL.md

GitHub

Sample Project Scaffolder

Creates new sample projects under samples/ following confirmed patterns from existing samples.

Instructions

1. Determine Sample Type

Use AskUserQuestion to select type:

  • JVM single-module — simplest, src/main + src/test
  • KMP single-module — commonMain/commonTest, all targets
  • KMP multi-module — multiple submodules with -fakes collectors
  • Android single-module — Android library with Fakt
  • JVM test-fixtures — Gradle java-test-fixtures plugin
  • Fake publishing — publisher + consumer via Maven coordinates

Ask for: sample name (kebab-case), purpose/feature being demonstrated.

2. Create Directory Structure

JVM single-module:

samples/{name}/
├── build.gradle.kts
├── settings.gradle.kts
└── src/
    ├── main/kotlin/com/rsicarelli/fakt/samples/{camelName}/
    │   ├── models/
    │   └── scenarios/
    └── test/kotlin/com/rsicarelli/fakt/samples/{camelName}/

KMP single-module:

samples/{name}/
├── build.gradle.kts
├── settings.gradle.kts
└── src/
    ├── commonMain/kotlin/com/rsicarelli/fakt/samples/{camelName}/
    │   ├── models/
    │   └── scenarios/
    └── commonTest/kotlin/com/rsicarelli/fakt/samples/{camelName}/

KMP multi-module:

samples/{name}/
├── build.gradle.kts          (root: apply plugins false)
├── settings.gradle.kts       (include submodules)
├── core/{module}/
│   ├── build.gradle.kts
│   └── src/commonMain/...
└── core/{module}-fakes/
    ├── build.gradle.kts      (collectFakesFrom)
    └── src/commonMain/...

3. Generate settings.gradle.kts

All samples use this template (adjust relative paths for nesting depth):

rootProject.name = "{name}"

pluginManagement {
    includeBuild("../../build-logic")
    repositories {
        mavenLocal()
        gradlePluginPortal()
        mavenCentral()
        google()
        maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
    }
}

dependencyResolutionManagement {
    @Suppress("UnstableApiUsage")
    repositories {
        mavenLocal()
        mavenCentral()
        google()
        maven {
            name = "Central Portal Snapshots"
            url = uri("https://central.sonatype.com/repository/maven-snapshots/")
        }
    }
    versionCatalogs {
        create("libs") {
            from(files("../../gradle/libs.versions.toml"))
        }
    }
}

enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")

Rules:

  • mavenLocal() FIRST in both repository blocks
  • includeBuild points to build-logic (adjust depth: ../../ for top-level, ../../../ for nested)
  • Version catalog always references shared libs.versions.toml

Note: JVM samples may use a simpler repository setup without Central Portal Snapshots. Always check an existing sample of the same type for the exact template. rootProject.name placement (top vs bottom) and @Suppress("UnstableApiUsage") usage also vary between samples.

4. Generate build.gradle.kts

JVM single-module:

import com.rsicarelli.fakt.compiler.api.LogLevel

plugins {
    id("fakt-sample-jvm")
    alias(libs.plugins.fakt)
}

dependencies {
    implementation(libs.fakt.annotations)
    testImplementation(kotlin("test"))
    testImplementation(libs.coroutines.test)
}

fakt {
    logLevel.set(LogLevel.DEBUG)
}

KMP single-module:

import com.rsicarelli.fakt.compiler.api.LogLevel

plugins {
    id("fakt-sample-kmp")
    alias(libs.plugins.fakt)
}

kotlin {
    sourceSets {
        commonMain {
            dependencies {
                implementation(libs.fakt.annotations)
            }
        }
        commonTest {
            dependencies {
                implementation(kotlin("test"))
                implementation(libs.coroutines.test)
            }
        }
        jvmTest {
            dependencies {
                implementation(kotlin("test-junit5"))
            }
        }
    }
}

fakt {
    logLevel.set(LogLevel.DEBUG)
}

Android single-module: use fakt-sample-android convention plugin.

JVM test-fixtures: add java-test-fixtures plugin, fakt { useGradleTestFixtures.set(true) }.

KMP multi-module root: apply plugins false, submodules apply independently.

Collector module (multi-module -fakes):

plugins {
    id("fakt-sample-kmp")
    id("com.rsicarelli.fakt")
}

kotlin {
    sourceSets {
        commonMain {
            dependencies {
                api(projects.core.{module})
                implementation(libs.coroutines)
            }
        }
    }
}

fakt {
    logLevel.set(com.rsicarelli.fakt.compiler.api.LogLevel.DEBUG)
    @OptIn(com.rsicarelli.fakt.gradle.ExperimentalFaktMultiModule::class)
    collectFakesFrom(projects.core.{module})
}

5. Create Example Interface

// Copyright (C) 2025 Rodrigo Sicarelli
// SPDX-License-Identifier: Apache-2.0
package com.rsicarelli.fakt.samples.{camelName}.scenarios

import com.rsicarelli.fakt.Fake

@Fake
interface {ExampleInterface} {
    fun getData(): String
    suspend fun fetchItems(): List<String>
}

6. Add to CI

Edit .github/actions/test-samples/action.yml:

JVM/Android samples — add build step:

- name: "Test {name} sample"
  run: ./gradlew -p samples/{name} build

KMP samples — add allTests + check:

- name: "Test {name} sample"
  run: ./gradlew -p samples/{name} allTests --continue

- name: "Check {name} sample"
  run: ./gradlew -p samples/{name} check

7. Verify

make publish-local
./gradlew -p samples/{name} build  # or allTests for KMP

Convention plugins available: fakt-sample-jvm, fakt-sample-kmp, fakt-sample-android.

Related Skills

  • compilation — diagnose build failures in new samples
  • feature-option — new features often need a sample to demonstrate