{"id":35699012,"url":"https://github.com/kotlin/kotlinx-schema","last_synced_at":"2026-01-16T08:01:26.723Z","repository":{"id":326428166,"uuid":"1058134588","full_name":"Kotlin/kotlinx-schema","owner":"Kotlin","description":"Kotlin Multiplatform library that generates JSON Schemas from your methods and classes at compile time and at runtime via reflection using Kotlin Symbol Processing (KSP)","archived":false,"fork":false,"pushed_at":"2026-01-12T10:28:26.000Z","size":533,"stargazers_count":65,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-01-12T18:51:01.455Z","etag":null,"topics":["code-generation","json-schema","kotlin","kotlin-symbol-processing","kotlin-symbol-processor"],"latest_commit_sha":null,"homepage":"https://kotlin.github.io/kotlinx-schema/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Kotlin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-09-16T17:04:45.000Z","updated_at":"2026-01-12T10:28:46.000Z","dependencies_parsed_at":"2026-01-12T13:02:04.414Z","dependency_job_id":null,"html_url":"https://github.com/Kotlin/kotlinx-schema","commit_stats":null,"previous_names":["kotlin/kotlinx-schema"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/Kotlin/kotlinx-schema","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kotlin%2Fkotlinx-schema","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kotlin%2Fkotlinx-schema/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kotlin%2Fkotlinx-schema/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kotlin%2Fkotlinx-schema/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Kotlin","download_url":"https://codeload.github.com/Kotlin/kotlinx-schema/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kotlin%2Fkotlinx-schema/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28478047,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T06:30:42.265Z","status":"ssl_error","status_checked_at":"2026-01-16T06:30:16.248Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-generation","json-schema","kotlin","kotlin-symbol-processing","kotlin-symbol-processor"],"created_at":"2026-01-06T01:09:15.577Z","updated_at":"2026-01-16T08:01:26.363Z","avatar_url":"https://github.com/Kotlin.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![JetBrains incubator project](https://jb.gg/badges/incubator.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)\n[![JetBrains Experimental](https://kotl.in/badges/experimental.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)\n\n[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/kotlinx-schema-ksp.svg?label=Maven%20Central)](https://central.sonatype.com/search?q=org.jetbrains.kotlinx%2Fkotlinx-schema-*)\n[![Build with Gradle](https://github.com/Kotlin/kotlinx-schema/actions/workflows/build.yml/badge.svg)](https://github.com/Kotlin/kotlinx-schema/actions/workflows/build.yml)\n[![CodeQL](https://github.com/Kotlin/kotlinx-schema/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/Kotlin/kotlinx-schema/actions/workflows/github-code-scanning/codeql)\n[![Docs](https://img.shields.io/badge/Docs-Live-blue?logo=kotlin)](https://kotlin.github.io/kotlinx-schema/)\n[![Examples](https://img.shields.io/badge/Examples-blue?logo=github)](examples)\n\n[![Kotlin](https://img.shields.io/badge/kotlin-2.2+-blueviolet.svg?logo=kotlin)](http://kotlinlang.org)\n[![Kotlin Multiplatform](https://img.shields.io/badge/Platforms-%20JVM%20%7C%20Wasm%2FJS%20%7C%20Native%20-blueviolet?logo=kotlin)](https://kotlinlang.org/docs/multiplatform.html)\n[![JVM](https://img.shields.io/badge/JVM-17+-red.svg?logo=jvm)](http://java.com)\n[![License](https://img.shields.io/badge/License-Apache_2.0-yellow.svg)](LICENSE)\n\n\n# kotlinx-schema\n\n**Generate JSON schemas and LLM function calling schemas from Kotlin code — including classes you don't own.**\n\n\u003e [!IMPORTANT]\n\u003e This library is **experimental**. \n\u003e Some parts might eventually be part of [kotlinx-serialization](https://github.com/Kotlin/kotlinx.serialization).\n\n## Key Features\n\n**Dual Generation Modes:**\n- **Compile-time (KSP)**: Zero runtime overhead, multiplatform, for your annotated classes\n- **Runtime (Reflection)**: JVM-only, for any class including third-party libraries\n\n**LLM Integration:**\n- First-class support for OpenAI/Anthropic function calling format\n- Automatic strict mode and parameter validation\n- Function name and description extraction\n\n**Flexible Annotation Support:**\n- Recognizes `@Description`, `@LLMDescription`, `@JsonPropertyDescription`, `@P`, and more\n- Recognizes KDoc\n- Works with annotations from Jackson, LangChain4j, Koog without code changes\n\n**Comprehensive Type Support:**\n- Enums, collections, maps, nested objects, nullability, generics (with star-projection)\n- Sealed class hierarchies with automatic `oneOf`/discriminator generation\n- Proper union types for nullable parameters (`[\"string\", \"null\"]`)\n- Type constraints (min/max, patterns, formats)\n- **Default values** (compile-time: tracked but not extracted; runtime: fully extracted)\n\n**Developer Experience:**\n- Gradle plugin for one-line setup\n- Type-safe Kotlin DSL for programmatic schema construction\n- Works everywhere: JVM, JS, iOS, macOS, Wasm\n\n## Why kotlinx-schema?\n\nThis library solves three key challenges:\n\n1. **🤖 LLM Function Calling Integration**: Generate OpenAI/Anthropic-compatible function schemas directly from Kotlin functions with proper type definitions and descriptions\n2. **📦 Third-Party Class Support**: Create schemas for library classes without modifying their source code (Spring entities, Ktor models, etc.)\n3. **🔄 Multi-Framework Compatibility**: Works with existing annotations from Jackson, LangChain4j, Koog, and more — no code changes needed\n\n### When to Use\n\n* 🤖 Building LLM-powered applications with structured function calling (OpenAI, Anthropic, Claude, MCP)\n* 👽 Need schemas for third-party library classes you cannot modify\n* ✅ Already using `@Description`-like annotations from other frameworks\n* 👌 Want zero runtime overhead with compile-time generation (multiplatform support)\n* ☕️ Need dynamic schema generation at runtime via reflection (JVM)\n\n## Quick Start\n\nRecommended: use the Gradle plugin.\nIt applies KSP for you, wires generated sources, and sets up task dependencies.\n\nRefer to the example projects [here](./examples).\n\n### Annotate Your Models\n\n```kotlin\n/**\n * A postal address for deliveries and billing.\n */\n@Schema\ndata class Address(\n    @Description(\"Street address, including house number\") val street: String,\n    @Description(\"City or town name\") val city: String,\n    @Description(\"Postal or ZIP code\") val zipCode: String,\n    @Description(\"Two-letter ISO country code; defaults to US\") val country: String = \"US\",\n)\n```\n\n\u003e **Note:** KDoc comments on classes can also be used as descriptions.\n\n### Configuration\n\n### Using Standard KSP Plugin\n\nYou can configure KSP processor manually using the standard Google KSP plugin.\n\n#### Multiplatform (metadata processing)\n\n```kotlin\nplugins {\n    kotlin(\"multiplatform\")\n    id(\"com.google.devtools.ksp\") version \"2.3.4\" // check https://github.com/google/ksp/releases\n}\n\ndependencies {\n    // Add KSP processor for metadata (common code)\n    add(\"kspCommonMainMetadata\", \"org.jetbrains.kotlinx:kotlinx-schema-ksp:\u003cversion\u003e\")\n\n    // Runtime dependencies\n    implementation(\"org.jetbrains.kotlinx:kotlinx-schema-annotations:\u003cversion\u003e\")\n    implementation(\"org.jetbrains.kotlinx:kotlinx-serialization-json:\u003cversion\u003e\")\n}\n\nkotlin {\n    sourceSets.commonMain {\n        // Make generated sources visible to metadata compilation\n        kotlin.srcDir(\"build/generated/ksp/metadata/commonMain/kotlin\")\n    }\n}\n\ntasks.withType\u003corg.jetbrains.kotlin.gradle.dsl.KotlinCompile\u003c*\u003e\u003e().all {\n    if (name != \"kspCommonMainKotlinMetadata\") {\n        dependsOn(\"kspCommonMainKotlinMetadata\")\n    }\n}\n```\n\n#### JVM Only\n\n```kotlin\nplugins {\n    kotlin(\"jvm\")\n    id(\"com.google.devtools.ksp\") version \"2.3.4\" // check https://github.com/google/ksp/releases\n}\n\ndependencies {\n    // Add KSP processor for main source set\n    ksp(\"org.jetbrains.kotlinx:kotlinx-schema-ksp:\u003cversion\u003e\")\n\n    // Runtime dependencies\n    implementation(\"org.jetbrains.kotlinx:kotlinx-schema-annotations:\u003cversion\u003e\")\n    implementation(\"org.jetbrains.kotlinx:kotlinx-serialization-json:\u003cversion\u003e\")\n}\n\n// Make generated sources visible to compilation\nsourceSets.main {\n    kotlin.srcDir(\"build/generated/ksp/main/kotlin\")\n}\n```\n\n\u003e **Note:** The KSP plugin version should match your Kotlin version. See the [KSP release table](https://github.com/google/ksp/releases) for compatibility.\n\n### Use the Generated Extensions\n\n```kotlin\nval schemaString: String = Address::class.jsonSchemaString\nval schemaObject: kotlinx.serialization.json.JsonObject = Address::class.jsonSchema\n```\n\n### Using the Gradle Plugin (WIP)\n\u003cdetails\u003e\n\u003csummary\u003eThis is \"work in progress\" yet\u003c/summary\u003e\n\n_Gradle plugin \"org.jetbrains.kotlinx.schema.ksp\" isn't yet available on Gradle Plugins portal._\n\n**Kotlin Multiplatform:**\n\n```kotlin\nplugins {\n    kotlin(\"multiplatform\")\n    id(\"org.jetbrains.kotlinx.schema.ksp\") // version \"\u003cx.y.z\u003e\" if used outside this repository\n}\n\n// Configuration (all options are optional)\nkotlinxSchema {\n    // Enable or disable schema generation (optional, default: true)\n    enabled.set(true)\n\n    // Process only classes in this package and subpackages (optional, speeds up builds)\n    // Omit to process all packages\n    rootPackage.set(\"com.example.models\")\n\n    // Generate jsonSchema: JsonObject property in addition to jsonSchemaString (optional, default: false)\n    // Can also be set per-class via @Schema(withSchemaObject = true)\n    // Global setting here overrides per-class annotations\n    withSchemaObject.set(true)\n}\n\nkotlin {\n    compilerOptions {\n        // Recommended: Apply annotations to both constructor params and properties\n        freeCompilerArgs.add(\"-Xannotation-default-target=param-property\")\n    }\n\n    // Configure your targets\n    jvm()\n    js { nodejs() }\n    wasmJs { browser() }\n    iosArm64()\n    iosSimulatorArm64()\n\n    sourceSets {\n        commonMain {\n            dependencies {\n                // Required: Annotations for your code\n                implementation(\"org.jetbrains.kotlinx:kotlinx-schema-annotations:\u003cversion\u003e\")\n                // Required: For JsonObject in runtime APIs\n                implementation(\"org.jetbrains.kotlinx:kotlinx-serialization-json:\u003cversion\u003e\")\n            }\n        }\n    }\n}\n```\n\n**Single-target JVM:**\n\n```kotlin\nplugins {\n    kotlin(\"jvm\")\n    id(\"org.jetbrains.kotlinx.schema.ksp\") // version \"\u003cx.y.z\u003e\" if used outside this repository\n}\n\n// Configuration (all options are optional)\nkotlinxSchema {\n    enabled.set(true)              // Optional, default: true\n    rootPackage.set(\"com.example\") // Optional, speeds up builds\n    withSchemaObject.set(false)    // Optional, default: false\n}\n\ndependencies {\n    implementation(\"org.jetbrains.kotlinx:kotlinx-schema-annotations:\u003cversion\u003e\")\n    implementation(\"org.jetbrains.kotlinx:kotlinx-serialization-json:\u003cversion\u003e\")\n}\n```\n\n**Notes:**\n- You do NOT need to apply the KSP plugin yourself — the Gradle plugin does it.\n- You do NOT need to add generated source directories — the plugin does it.\n- For an example project, see [gradle-plugin-integration-tests](./gradle-plugin-integration-tests).\n\u003c/details\u003e\n\n### Configuration Options\n\n##### `enabled`\nEnable or disable schema generation.\n- **Type:** `Boolean`\n- **Default:** `true`\n- **Example:** `enabled.set(false)`\n\n##### `rootPackage`\nProcess only classes in the specified package and its subpackages. Improves build performance in large projects.\n- **Type:** `String`\n- **Default:** All packages\n- **Example:** `rootPackage.set(\"com.example.models\")`\n\n##### `withSchemaObject`\nGenerate `jsonSchema: JsonObject` property in addition to `jsonSchemaString: String`.\n\n- **Type:** `Boolean`\n- **Default:** `false`\n- **Precedence:**\n  1. **Global option** (if set): Overrides all per-class annotations\n  2. **Per-class annotation** (fallback): `@Schema(withSchemaObject = true)`\n\n**Example with global setting:**\n```kotlin\nkotlinxSchema {\n    withSchemaObject.set(true)  // Applies to ALL classes\n}\n\n@Schema(withSchemaObject = false)  // IGNORED - global setting takes precedence\ndata class User(val name: String)  // ✅ Generates both jsonSchemaString and jsonSchema\n\n@Schema  // IGNORED - global setting takes precedence\ndata class Product(val id: Long)  // ✅ Generates both (due to global setting)\n```\n\n**Example with per-class annotations (no global setting):**\n```kotlin\n@Schema(withSchemaObject = true)   // ✅ Generates both extensions\ndata class User(val name: String)\n\n@Schema(withSchemaObject = false)  // ✅ Only generates jsonSchemaString\ndata class Address(val street: String)\n\n@Schema  // ✅ Only generates jsonSchemaString (annotation default)\ndata class Product(val id: Long)\n```\n\n## Runtime schema generation\n\nFor scenarios where compile-time generation isn't possible, use\n[`ReflectionClassJsonSchemaGenerator`](kotlinx-schema-generator-json/src/main/kotlin/kotlinx/schema/generator/json/ReflectionClassJsonSchemaGenerator.kt)\nand [`ReflectionFunctionCallingSchemaGenerator`](kotlinx-schema-generator-json/src/main/kotlin/kotlinx/schema/generator/json/ReflectionFunctionCallingSchemaGenerator.kt)\nwith Kotlin reflection (JVM only).\n\n### Why Runtime Generation?\n\n**Primary use case: Third-party library classes**\n\nThe compile-time (KSP) approach requires you to annotate classes with `@Schema`, which isn't possible for:\n- Library classes (Spring entities, Ktor models, database classes)\n- Framework-provided models\n- Classes from dependencies you don't control\n\nRuntime generation solves this by using reflection to analyze any class at runtime.\n\n\u003e [!IMPORTANT]\n\u003e **Limitations:**\n\u003e - KDoc annotations are not available at runtime\n\u003e - Function parameter defaults (e.g., `fun foo(x: Int = 5)`) cannot be extracted via reflection\n\u003e - Data class property defaults (e.g., `data class Config(val port: Int = 8080)`) ARE supported\n\n### Usage\n\n```kotlin\n// Works with ANY class, even from third-party libraries\nimport com.thirdparty.library.User  // Not your code!\n\nval generator = kotlinx.schema.generator.json.ReflectionClassJsonSchemaGenerator.Default\nval schema: JsonObject = generator.generateSchema(User::class)\nval schemaString: String = generator.generateSchemaString(User::class)\n```\n\n**Add dependency**: `org.jetbrains.kotlinx:kotlinx-schema-generator-json:\u003cversion\u003e`\n\n### Choosing Your Approach\n\n| Approach                 | Best For                               | Pros                                                               | Cons                                                        |\n|--------------------------|----------------------------------------|--------------------------------------------------------------------|-------------------------------------------------------------|\n| **Compile-time (KSP)**   | Your own annotated classes             | Zero runtime cost, multiplatform                                   | Only works for classes you own, no default value extraction |\n| **Runtime (Reflection)** | Third-party classes, dynamic scenarios | Works with any class, extracts default values, foreign annotations | JVM only, small reflection overhead, no KDoc support        |\n\n**Decision guide**:\n- ✅ Use **KSP** for your domain models in multiplatform projects\n- ✅ Use **Reflection** for third-party library classes or when you need dynamic generation\n\n\n## What Gets Generated\n\nSchemas follow a `$id/$defs/$ref` layout. Example (pretty-printed):\n\n```json\n{\n    \"$id\": \"com.example.Address\",\n    \"$defs\": {\n        \"com.example.Address\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"street\": {\n                    \"type\": \"string\",\n                    \"description\": \"Street address, including house number\"\n                },\n                \"city\": {\n                    \"type\": \"string\",\n                    \"description\": \"City or town name\"\n                },\n                \"zipCode\": {\n                    \"type\": \"string\",\n                    \"description\": \"Postal or ZIP code\"\n                },\n                \"country\": {\n                    \"type\": \"string\",\n                    \"description\": \"Two-letter ISO country code; defaults to US\",\n                    \"default\": \"US\"\n                }\n            },\n            \"required\": [\n                \"street\",\n                \"city\",\n                \"zipCode\"\n            ],\n            \"additionalProperties\": false,\n            \"description\": \"A postal address for deliveries and billing.\"\n        }\n    },\n    \"$ref\": \"#/$defs/com.example.Address\"\n}\n```\n\n- Enums are `type: string` with `enum: [...]` and carry `@Description` as `description`.\n- Object properties include their inferred type schema and, when present, property-level `@Description` as `description`.\n- **Default values** are automatically extracted and included in the schema when using **runtime reflection** (e.g., `val country: String = \"US\"` → `\"default\": \"US\"`). Note: KSP (compile-time) tracks which properties have defaults but cannot extract the actual values.\n- Nullable properties are emitted as a union including `null`.\n- Collections: `List\u003cT\u003e`/`Set\u003cT\u003e` → `{ \"type\":\"array\", \"items\": T }`; `Map\u003cString, V\u003e` →\n  `{ \"type\":\"object\", \"additionalProperties\": V }`.\n- Unknown/generic type parameters resolve to `kotlin.Any` with a minimal definition in `$defs`.\n\n## Examples\n\n### Basic data classes\n\nHere's a practical example of a product model with various property types:\n\n```kotlin\n@Description(\"A purchasable product with pricing and inventory info.\")\n@Schema\ndata class Product(\n    @Description(\"Unique identifier for the product\")\n    val id: Long,\n    @Description(\"Human-readable product name\")\n    val name: String,\n    @Description(\"Optional detailed description of the product\")\n    val description: String?,\n    @Description(\"Unit price expressed as a decimal number\")\n    val price: Double,\n    @Description(\"Whether the product is currently in stock\")\n    val inStock: Boolean = true,\n    @Description(\"List of tags for categorization and search\")\n    val tags: List\u003cString\u003e = emptyList(),\n)\n```\n\nUse the generated extensions:\n\n```kotlin\nval schema = Product::class.jsonSchemaString\nval schemaObject = Product::class.jsonSchema\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eGenerated JSON schema\u003c/summary\u003e\n\n```json\n{\n    \"$id\": \"com.example.Product\",\n    \"$defs\": {\n        \"com.example.Product\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"id\": {\n                    \"type\": \"integer\",\n                    \"description\": \"Unique identifier for the product\"\n                },\n                \"name\": {\n                    \"type\": \"string\",\n                    \"description\": \"Human-readable product name\"\n                },\n                \"description\": {\n                    \"type\": [\n                        \"string\",\n                        \"null\"\n                    ],\n                    \"description\": \"Optional detailed description of the product\"\n                },\n                \"price\": {\n                    \"type\": \"number\",\n                    \"description\": \"Unit price expressed as a decimal number\"\n                },\n                \"inStock\": {\n                    \"type\": \"boolean\",\n                    \"description\": \"Whether the product is currently in stock\",\n                    \"default\": true\n                },\n                \"tags\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                        \"type\": \"string\"\n                    },\n                    \"description\": \"List of tags for categorization and search\",\n                    \"default\": []\n                }\n            },\n            \"required\": [\n                \"id\",\n                \"name\",\n                \"description\",\n                \"price\"\n            ],\n            \"additionalProperties\": false,\n            \"description\": \"A purchasable product with pricing and inventory info.\"\n        }\n    },\n    \"$ref\": \"#/$defs/com.example.Product\"\n}\n```\n\n\u003c/details\u003e\n\n### Enums with descriptions\n\nEnums are supported with descriptions on both the enum class and individual values:\n\n```kotlin\n@Description(\"Current lifecycle status of an entity.\")\n@Schema\nenum class Status {\n    @Description(\"Entity is active and usable\")\n    ACTIVE,\n\n    @Description(\"Entity is inactive or disabled\")\n    INACTIVE,\n\n    @Description(\"Entity is pending activation or approval\")\n    PENDING,\n}\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eGenerated JSON schema\u003c/summary\u003e\n\n```json\n{\n    \"$id\": \"com.example.Status\",\n    \"$defs\": {\n        \"com.example.Status\": {\n            \"type\": \"string\",\n            \"enum\": [\n                \"ACTIVE\",\n                \"INACTIVE\",\n                \"PENDING\"\n            ],\n            \"description\": \"Current lifecycle status of an entity.\"\n        }\n    },\n    \"$ref\": \"#/$defs/com.example.Status\"\n}\n```\n\n\u003c/details\u003e\n\n### Nested objects\n\nYou can compose schemas by nesting annotated classes:\n\n```kotlin\n@Description(\"A person with a first and last name and age.\")\n@Schema\ndata class Person(\n    @Description(\"Given name of the person\")\n    val firstName: String,\n    @Description(\"Family name of the person\")\n    val lastName: String,\n    @Description(\"Age of the person in years\")\n    val age: Int,\n)\n\n@Description(\"An order placed by a customer containing multiple items.\")\n@Schema\ndata class Order(\n    @Description(\"Unique order identifier\")\n    val id: String,\n    @Description(\"The customer who placed the order\")\n    val customer: Person,\n    @Description(\"Destination address for shipment\")\n    val shippingAddress: Address,\n    @Description(\"List of items included in the order\")\n    val items: List\u003cProduct\u003e,\n    @Description(\"Current status of the order\")\n    val status: Status,\n)\n```\n\nThe generated schema for `Order` will automatically include definitions for all nested types (`Person`, `Address`,\n`Product`, `Status`) in the `$defs` section, with appropriate `$ref` pointers to link them together. This makes it easy\nto build complex, composable data models.\n\n### Generic types\n\nGeneric classes are supported, with type parameters resolved at usage sites:\n\n```kotlin\n@Description(\"A generic container that wraps content with optional metadata.\")\n@Schema\ndata class Container\u003cT\u003e(\n    @Description(\"The wrapped content value\")\n    val content: T,\n    @Description(\"Arbitrary metadata key-value pairs\")\n    val metadata: Map\u003cString, Any\u003e = emptyMap(),\n)\n```\n\nGeneric type parameters are resolved at the usage site. When generating a schema for a generic class, unbound type\nparameters (like `T`) are treated as `kotlin.Any` with a minimal definition in the `$defs` section. For more specific\ntyping, instantiate the generic class with concrete types when you need them.\n\n### Sealed class polymorphism\n\nThe library automatically generates JSON schemas for Kotlin sealed class hierarchies using `oneOf` with discriminator support:\n\n```kotlin\n@Description(\"Represents an animal\")\nsealed class Animal {\n    @Description(\"Animal's name\")\n    abstract val name: String\n\n    @Description(\"Represents a dog\")\n    data class Dog(\n        override val name: String,\n        @Description(\"Dog's breed\")\n        val breed: String,\n        @Description(\"Trained or not\")\n        val isTrained: Boolean = false,\n    ) : Animal()\n\n    @Description(\"Represents a cat\")\n    data class Cat(\n        override val name: String,\n        @Description(\"Cat's color\")\n        val color: String,\n        @Description(\"Lives left\")\n        val lives: Int = 9,\n    ) : Animal()\n}\n\nval generator = ReflectionClassJsonSchemaGenerator.Default\nval schema = generator.generateSchema(Animal::class)\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eGenerated JSON schema\u003c/summary\u003e\n\n```json\n{\n    \"name\": \"com.example.Animal\",\n    \"strict\": false,\n    \"schema\": {\n        \"type\": \"object\",\n        \"additionalProperties\": false,\n        \"description\": \"Represents an animal\",\n        \"oneOf\": [\n            {\n                \"$ref\": \"#/$defs/Cat\"\n            },\n            {\n                \"$ref\": \"#/$defs/Dog\"\n            }\n        ],\n        \"discriminator\": {\n            \"propertyName\": \"type\",\n            \"mapping\": {\n                \"Cat\": \"#/$defs/Cat\",\n                \"Dog\": \"#/$defs/Dog\"\n            }\n        },\n        \"$defs\": {\n            \"Cat\": {\n                \"type\": \"object\",\n                \"description\": \"Represents a cat\",\n                \"properties\": {\n                    \"name\": {\n                        \"type\": \"string\",\n                        \"description\": \"Animal's name\"\n                    },\n                    \"color\": {\n                        \"type\": \"string\",\n                        \"description\": \"Cat's color\"\n                    },\n                    \"lives\": {\n                        \"type\": \"integer\",\n                        \"description\": \"Lives left\",\n                        \"default\": 9\n                    }\n                },\n                \"required\": [\"name\", \"color\"],\n                \"additionalProperties\": false\n            },\n            \"Dog\": {\n                \"type\": \"object\",\n                \"description\": \"Represents a dog\",\n                \"properties\": {\n                    \"name\": {\n                        \"type\": \"string\",\n                        \"description\": \"Animal's name\"\n                    },\n                    \"breed\": {\n                        \"type\": \"string\",\n                        \"description\": \"Dog's breed\"\n                    },\n                    \"isTrained\": {\n                        \"type\": \"boolean\",\n                        \"description\": \"Trained or not\",\n                        \"default\": false\n                    }\n                },\n                \"required\": [\"name\", \"breed\"],\n                \"additionalProperties\": false\n            }\n        }\n    }\n}\n```\n\u003c/details\u003e\n\n**Key features:**\n- **`oneOf` with `$ref`**: Each sealed subclass is referenced from a `$defs` section\n- **Discriminator**: Automatically generated with `type` property mapping\n- **Property inheritance**: Base class properties included in each subtype\n- **Type safety**: Each subtype gets its own schema definition\n- **Default values**: Subtype properties with defaults (like `lives: Int = 9`) are included\n\n## Using @Schema and @Description annotations\n\n### @Schema annotation\n\nMark classes with `@Schema` to generate extension properties for them:\n\n```kotlin\n@Schema  // Uses default schema type \"json\"\ndata class Address(val street: String, val city: String)\n\n@Schema(\"json\")  // Explicitly specify schema type\ndata class Person(val name: String, val age: Int)\n```\n\n**@Schema parameters:**\n- `value = \"json\"`: Schema type (only JSON currently supported)\n- `withSchemaObject = false`: Generate `jsonSchema: JsonObject` property (see [Advanced Configuration](#advanced-configuration))\n\n**Note**: `jsonSchemaString` is always generated. `jsonSchema` requires `withSchemaObject = true`.\n\n### @Description annotation\n\nUse `@Description` on classes and properties to add human-readable documentation to your schemas:\n\n```kotlin\n@Description(\"A purchasable product with pricing info\")\n@Schema\ndata class Product(\n    @Description(\"Unique identifier for the product\") val id: Long,\n    @Description(\"Human-readable product name\") val name: String,\n    @Description(\"Optional detailed description of the product\") val description: String?,\n    @Description(\"Unit price expressed as a decimal number\") val price: Double,\n)\n```\n\n**Tip**: With the recommended compiler flag `-Xannotation-default-target=param-property`, a bare `@Description` on a\nprimary constructor parameter also applies to the property. If you do not enable the flag, use `@param:Description` for\nconstructor-declared properties.\n\n## Function calling schema generation for LLMs\n\nModern LLMs (OpenAI GPT-4, Anthropic Claude, etc.) use structured function calling to interact with your code. \nThey require a specific JSON schema format that describes available functions, their parameters, and types.\n\n### Why This Format?\n\nLLM APIs need to know:\n- What functions are available and what they do\n- Parameter names, types, and descriptions\n- Which parameters are required\n- Type constraints (enums, formats, ranges)\n\nThis library automatically generates schemas that comply with the [OpenAI function calling specification](https://platform.openai.com/docs/guides/function-calling), making it easy to expose Kotlin functions to LLMs.\n\n### Basic Usage\n\n```kotlin\n@Description(\"Get current weather for a location\")\nfun getWeather(\n    @Description(\"City and country, e.g. 'London, UK'\")\n    location: String,\n\n    @Description(\"Temperature unit\")\n    unit: String = \"celsius\"\n): WeatherInfo {\n    // Implementation...\n}\n\nval generator = ReflectionFunctionCallingSchemaGenerator.Default\nval schema = generator.generateSchema(::getWeather)\n```\n\n### Generated Schema\n\nThe generated schema follows the LLM function calling format:\n\n```json\n{\n  \"type\": \"function\",\n  \"name\": \"getWeather\",\n  \"description\": \"Get current weather for a location\",\n  \"strict\": true,\n  \"parameters\": {\n    \"type\": \"object\",\n    \"properties\": {\n      \"location\": {\n        \"type\": \"string\",\n        \"description\": \"City and country, e.g. 'London, UK'\"\n      },\n      \"unit\": {\n        \"type\": \"string\",\n        \"description\": \"Temperature unit\"\n      }\n    },\n    \"required\": [\"location\", \"unit\"],\n    \"additionalProperties\": false\n  }\n}\n```\n\n### Key Features\n\n- **Automatic extraction**: Function name and descriptions from `@Description` annotations\n- **Default values**: Property defaults in nested data classes are automatically extracted (e.g., `data class Config(val port: Int = 8080)`)\n- **Strict mode**: `strict: true` enables OpenAI's [strict mode](https://platform.openai.com/docs/guides/function-calling#strict-mode) for reliable parsing\n- **Union types**: Nullable parameters use `[\"string\", \"null\"]` instead of `nullable: true`\n- **Required by default**: All parameters marked as required (OpenAI structured outputs requirement)\n- **Type safety**: Proper JSON Schema types from Kotlin types (Int → integer, String → string, etc.)\n\n\u003e **Note:** Function parameter defaults (e.g., `unit: String = \"celsius\"`) cannot be extracted via reflection, but nested data class property defaults are fully supported.\n\n### Working with Multiple Functions\n\n```kotlin\n// Define your functions\n@Description(\"Search the knowledge base\")\nfun searchKnowledge(\n    @Description(\"Search query\") query: String,\n    @Description(\"Max results\") limit: Int = 10\n): String = TODO()\n\n@Description(\"Calculate order total with tax\")\nfun calculateTotal(\n    @Description(\"Item prices\") prices: List\u003cDouble\u003e,\n    @Description(\"Tax rate as decimal\") taxRate: Double = 0.0\n): Double = TODO()\n\n// Generate schemas\nval generator = ReflectionFunctionCallingSchemaGenerator.Default\nval schemas = listOf(::searchKnowledge, ::calculateTotal)\n    .map { generator.generateSchema(it) }\n\n// Serialize to JSON\nval jsonSchemas = schemas.map { Json.encodeToString(it) }\n\n// Or get as JsonObject\nval schemaObjects = schemas.map { it.encodeToJsonObject() }\n```\n\nThe generated schemas can be sent to any LLM API that supports function calling (OpenAI, Anthropic, etc.). \nIntegration with specific LLM providers requires their respective client libraries.\n\n### Nullable Parameters\n\nNullable parameters are represented as union types:\n\n```kotlin\n@Description(\"Update user profile\")\nfun updateProfile(\n    @Description(\"User ID\") userId: String,\n    @Description(\"New name, if changing\") name: String? = null,\n    @Description(\"New email, if changing\") email: String? = null\n): User = TODO(\"does not matter\")// ...\n```\n\nGenerates:\n\n```json\n{\n    \"properties\": {\n        \"userId\": {\n            \"type\": \"string\",\n            \"description\": \"User ID\"\n        },\n        \"name\": {\n            \"type\": [\n                \"string\",\n                \"null\"\n            ],\n            \"description\": \"New name, if changing\"\n        },\n        \"email\": {\n            \"type\": [\n                \"string\",\n                \"null\"\n            ],\n            \"description\": \"New email, if changing\"\n        }\n    },\n    \"required\": [\n        \"userId\",\n        \"name\",\n        \"email\"\n    ]\n}\n```\n\n**Note**: Even nullable parameters are in `required` array. The `null` type in the union indicates optionality.\n\nFor more details on function calling schemas and OpenAI compatibility, see [kotlinx-schema-json/README.md](kotlinx-schema-json/README.md#function-calling-schema-for-llm-apis).\n\n### Compile-time Function Schema Generation (KSP)\n\nGenerate function schemas at compile time with zero runtime overhead. KSP generates type-safe extensions for all your annotated functions, with APIs that reflect where functions actually live in your code.\n\n#### Top-Level Functions\n\nAnnotate package-level functions to generate top-level schema accessors:\n\n```kotlin\n@Schema\n@Description(\"Sends a greeting message to a person\")\nfun greetPerson(\n    @Description(\"Name of the person to greet\")\n    name: String,\n    @Description(\"Optional greeting prefix (e.g., 'Hello', 'Hi')\")\n    greeting: String = \"Hello\",\n): String = \"$greeting, $name!\"\n\n// Generated: top-level functions\nval schema = greetPersonJsonSchemaString()\n```\n\n#### Instance/Member Functions\n\nAnnotate class methods to generate `KClass` extensions on the containing class:\n\n```kotlin\nclass UserService {\n    @Schema\n    @Description(\"Registers a new user in the system\")\n    fun registerUser(\n        @Description(\"Username for the new account\")\n        username: String,\n        @Description(\"Email address\")\n        email: String,\n    ): String = \"User registered\"\n}\n\n// Generated: KClass extension on UserService\nval schema = UserService::class.registerUserJsonSchemaString()\n```\n\n#### Companion Object Functions\n\nAnnotate companion methods to generate `KClass` extensions on the companion object itself:\n\n```kotlin\nclass DatabaseConnection {\n    companion object {\n        @Schema\n        @Description(\"Creates a new database connection\")\n        fun create(\n            @Description(\"Database host\")\n            host: String,\n            @Description(\"Database port\")\n            port: Int = 5432,\n        ): DatabaseConnection = TODO()\n    }\n}\n\n// Generated: KClass extension on companion object\nval schema = DatabaseConnection.Companion::class.createJsonSchemaString()\n```\n\nThis API correctly reflects that companion functions belong to the companion object, not the parent class.\n\n#### Singleton Object Functions\n\nAnnotate object methods to generate `KClass` extensions on the object type:\n\n```kotlin\nobject ConfigurationManager {\n    @Schema\n    @Description(\"Loads configuration from a file\")\n    fun loadConfig(\n        @Description(\"Configuration file path\")\n        filePath: String,\n        @Description(\"Whether to create file if it doesn't exist\")\n        createIfMissing: Boolean = false,\n    ): Map\u003cString, String\u003e = TODO()\n}\n\n// Generated: KClass extension on object\nval schema = ConfigurationManager::class.loadConfigJsonSchemaString()\n```\n\n#### What Gets Generated\n\nKSP generates schema accessor functions that match where your functions live:\n\n| Function Type | Annotate         | Generated API                | Example                                                        |\n|---------------|------------------|------------------------------|----------------------------------------------------------------|\n| **Top-level** | Package function | Top-level accessor           | `greetPersonJsonSchemaString()`                                |\n| **Instance**  | Class method     | `KClass` extension           | `UserService::class.registerUserJsonSchemaString()`            |\n| **Companion** | Companion method | `Companion::class` extension | `DatabaseConnection.Companion::class.createJsonSchemaString()` |\n| **Object**    | Object method    | `Object::class` extension    | `ConfigurationManager::class.loadConfigJsonSchemaString()`     |\n\nFor each annotated function, you get:\n- **Always**: `{functionName}JsonSchemaString(): String` — returns the schema as a JSON string\n- **Optional**: `{functionName}JsonSchema(): FunctionCallingSchema` — returns the schema object (requires `withSchemaObject = true`)\n\n#### Schema Format\n\nGenerated schemas follow the [OpenAI function calling format](https://platform.openai.com/docs/guides/function-calling):\n\n```json\n{\n  \"type\": \"function\",\n  \"name\": \"greetPerson\",\n  \"description\": \"Sends a greeting message to a person\",\n  \"strict\": true,\n  \"parameters\": {\n    \"type\": \"object\",\n    \"properties\": {\n      \"name\": {\"type\": \"string\", \"description\": \"Name of the person to greet\"},\n      \"greeting\": {\"type\": \"string\", \"description\": \"Optional greeting prefix\"}\n    },\n    \"required\": [\"name\", \"greeting\"],\n    \"additionalProperties\": false\n  }\n}\n```\n\n**OpenAI Strict Mode**: All parameters are marked as required by default, even those with default values. This ensures compatibility with [OpenAI Structured Outputs](https://platform.openai.com/docs/guides/function-calling#strict-mode).\n\n#### KSP vs Runtime Reflection\n\n| Feature            | KSP (Compile-time)                                                                      | Reflection (Runtime)                     |\n|--------------------|-----------------------------------------------------------------------------------------|------------------------------------------|\n| **Performance**    | Zero runtime cost                                                                       | Small reflection overhead                |\n| **Platforms**      | Multiplatform                                                                           | JVM only                                 |\n| **Default values** | Tracked but not extracted ([KSP limitation](https://github.com/google/ksp/issues/1868)) | Fully extracted from data classes        |\n| **When to use**    | Your annotated functions                                                                | Third-party functions, dynamic scenarios |\n\n#### Suspend Functions\n\nSuspend functions work identically to regular functions. The generated schemas don't expose the suspend modifier—they describe parameter types only:\n\n```kotlin\n@Schema\n@Description(\"Fetches user data asynchronously\")\nsuspend fun fetchUserData(\n    @Description(\"User ID to fetch\") userId: Long,\n): UserData = TODO()\n\n// Generated API works the same way\nval schema = fetchUserDataJsonSchemaString()\n```\n\n## Multi-Framework Annotation Support\n\n**You don't need to change your existing code!**\n\nkotlinx-schema recognizes description annotations from multiple frameworks by their **simple name**, allowing you to generate schemas from code that uses annotations from other libraries.\n\n### Supported Annotations\n\nThe library automatically recognizes these description annotations by default:\n\n| Annotation                                                 | Simple Name               | Library/Framework | Example                               |\n|------------------------------------------------------------|---------------------------|-------------------|---------------------------------------|\n| `kotlinx.schema.Description`                               | `Description`             | kotlinx-schema    | `@Description(\"User name\")`           |\n| `ai.koog.agents.core.tools.annotations.LLMDescription`     | `LLMDescription`          | Koog AI agents    | `@LLMDescription(\"Query text\")`       |\n| `com.fasterxml.jackson.annotation.JsonPropertyDescription` | `JsonPropertyDescription` | Jackson           | `@JsonPropertyDescription(\"Email\")`   |\n| `com.fasterxml.jackson.annotation.JsonClassDescription`    | `JsonClassDescription`    | Jackson           | `@JsonClassDescription(\"User model\")` |\n| `dev.langchain4j.model.output.structured.P`                | `P`                       | LangChain4j       | `@P(\"Search query\")`                  |\n\n### How It Works\n\nThe introspector matches annotations by their **simple name only**, not the fully qualified name. This means:\n- ✅ No code changes needed to generate schemas from existing annotated classes\n- ✅ Can migrate between annotation libraries without modifying code\n- ✅ Generate schemas for third-party code that uses different annotations\n- ✅ Use your preferred annotation library while still getting schema generation\n\n### Customizing Annotation Detection\n\nAnnotation detection is configurable via `kotlinx-schema.properties` loaded from the classpath.\nThe configuration file is **optional** — if not provided or fails to load, the library uses sensible defaults.\n\n#### Default Configuration\n\nBy default, the library recognizes:\n\n**Annotation names**: Description, LLMDescription, JsonPropertyDescription, JsonClassDescription, P\n**Attribute names**: value, description\n\n#### Adding Custom Annotations\n\nTo customize, place `kotlinx-schema.properties` in your project's resources:\n\n```properties\n# Add your custom annotations to the defaults\nintrospector.annotations.description.names=Description,MyCustomAnnotation,DocString\nintrospector.annotations.description.attributes=value,description,text\n```\n\n**Note**: The library falls back to built-in defaults if the configuration file is missing or cannot be loaded.\n\n#### Example: Adding Support for a Custom Framework\n\n```kotlin\n// Your custom annotation\npackage com.mycompany.annotations\n\nannotation class ApiDoc(val text: String)\n\n// Usage in your models\n@ApiDoc(text = \"Customer profile information\")\ndata class Customer(\n    @ApiDoc(text = \"Unique customer identifier\")\n    val id: Long,\n    val name: String\n)\n```\n\nUpdate `kotlinx-schema.properties`:\n```properties\nintrospector.annotations.description.names=Description,ApiDoc\nintrospector.annotations.description.attributes=value,description,text\n```\n\nNow the schema generator will recognize `@ApiDoc` and extract descriptions from its `text` parameter.\n\n### Example: Reusing Jackson Annotations\n\nIf your project already uses Jackson for JSON serialization, you can generate schemas from existing Jackson-annotated classes without any modifications. This is particularly useful for REST APIs and Spring Boot applications where Jackson annotations are already present.\n\n```kotlin\n// Existing code with Jackson annotations - NO CHANGES NEEDED!\n@JsonClassDescription(\"Customer profile data\")\ndata class Customer(\n    @JsonPropertyDescription(\"Unique customer ID\")\n    val id: Long,\n\n    @JsonPropertyDescription(\"Full name\")\n    val name: String,\n\n    @JsonPropertyDescription(\"Contact email\")\n    val email: String\n)\n\n// Generate JSON schema without modifying the code\nval generator = ReflectionJsonSchemaGenerator.Default\nval schema = generator.generateSchema(Customer::class)\n\n// Schema includes all Jackson descriptions!\n```\n\n### Example: LangChain4j Integration\n\nLangChain4j uses the `@P` annotation for parameter descriptions in AI function calling. The library recognizes these annotations automatically, enabling seamless integration with existing LangChain4j codebases.\n\n```kotlin\n// Code using LangChain4j annotations\ndata class SearchQuery(\n    @P(\"Search terms\")\n    val query: String,\n\n    @P(\"Maximum results to return\")\n    val limit: Int = 10\n)\n\n// Generate schema for LLM function calling\nval schema = ReflectionFunctionCallingSchemaGenerator.Default\n    .generateSchema(SearchQuery::class)\n```\n\n### Example: Koog AI Agents\n\nKoog AI framework uses `@LLMDescription` for documenting agent tools and parameters. The library supports both the verbose `description =` syntax and the shorthand form, making migration from Koog straightforward.\n\n```kotlin\n@LLMDescription(description = \"Product with pricing information\")\n@Schema\ndata class Product(\n    @LLMDescription(description = \"Product identifier\")\n    val id: Long,\n\n    @LLMDescription(\"Product name\")\n    val name: String,\n\n    @LLMDescription(\"Unit price\")\n    val price: Double,\n)\n```\n\n### Precedence Rules\n\nIf multiple description annotations are present on the same element, the library uses this precedence order:\n1. `@Description` (kotlinx-schema's own annotation)\n2. Other annotations in alphabetical order by simple name\n\n**Tip**: For best compatibility, prefer `@Description` from kotlinx-schema when writing new code, but existing annotations from other libraries work seamlessly.\n\n## JSON Schema DSL\n\nFor manual schema construction, use the [**kotlinx-schema-json**](kotlinx-schema-json) module.\nIt provides type-safe Kotlin models and a DSL for building JSON Schema definitions programmatically,\nwith full kotlinx-serialization support.\n\n```kotlin\ndependencies {\n    implementation(\"org.jetbrains.kotlinx:kotlinx-schema-json:\u003cversion\u003e\")\n}\n```\n\n**Quick Example:**\n\n```kotlin\nval schema = jsonSchema {\n    name = \"User\"\n    schema {\n        property(\"id\") {\n            required = true\n            string { format = \"uuid\" }\n        }\n        property(\"email\") {\n            required = true\n            string { format = \"email\" }\n        }\n        // Polymorphic types with discriminators\n        property(\"role\") {\n            oneOf {\n                discriminator(propertyName = \"type\") {\n                    \"admin\" mappedTo \"#/definitions/AdminRole\"\n                    \"user\" mappedTo {\n                        property(\"type\") { string { constValue = \"user\" } }\n                        property(\"permissions\") { array { ofString() } }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n**Features:**\n- ✅ Type-safe property definitions (string, number, integer, boolean, array, object, reference)\n- ✅ **Polymorphism**: oneOf, anyOf, allOf with elegant discriminator support\n- ✅ Constraints: required, nullable, enum, const, min/max, format validation\n- ✅ Nested schemas and arrays of complex types\n- ✅ Full kotlinx-serialization integration\n- ✅ Kotlin Multiplatform support\n\n**📖 See [kotlinx-schema-json/README.md](kotlinx-schema-json/README.md) for comprehensive documentation** including:\n- Complete DSL reference and API overview\n- Polymorphism patterns (oneOf, anyOf, allOf)\n- Discriminator usage with references and inline schemas\n- Working with nested objects and arrays\n- Serialization/deserialization examples\n- Function calling schema for LLM APIs\n\n## Project architecture\n\n```mermaid\nC4Context\n    title kotlinx-schema\n\n    Boundary(lib, \"kotlinx-schema\") {\n\n        System(kxsGenCore, \"kotlinx-schema-generator-core\")\n        System(kxsAnnotations, \"kotlinx-schema-annotations\")\n        System(kxsGenJson, \"kotlinx-schema-generator-json\")\n        System(kxsJsn, \"kotlinx-schema-json\")\n        System(kxsKsp, \"kotlinx-schema-ksp\")\n\n        System(kxsGradle, \"kotlinx-schema-gradle-plugin\")\n    }\n\n    Rel(kxsGenJson, kxsGenCore, \"uses\")\n    Rel(kxsGenJson, kxsJsn, \"uses\")\n    Rel(kxsGenCore, kxsAnnotations, \"knows\")\n    Rel(kxsKsp, kxsGenJson, \"uses\")\n    \n    Rel(kxsGradle, kxsKsp, \"uses\")\n\n    Boundary(userCode, \"User's Application Code\") {\n        System_Ext(userModels, \"User Domain Models\")\n        System_Ext(userModelsExt, \"User Models Extensions\")\n        Rel(userModelsExt, userModels, \"uses\")\n    }\n\n    Rel(userModels, kxsAnnotations, \"uses\")\n    Rel(kxsKsp, userModelsExt, \"generates\")\n    \n```\n\nTop-level modules you might interact with:\n\n- **kotlinx-schema-annotations** — runtime annotations: @Schema and @Description\n- **kotlinx-schema-json** — type-safe models and DSL for building JSON Schema definitions programmatically\n- **kotlinx-schema-generator-core** — internal representation (IR) for schema descriptions, introspection utils, generator interfaces\n- **kotlinx-schema-generator-json** — JSON Schema transformer from the IR\n- **kotlinx-schema-ksp** — KSP processor that scans your code and generates the extension properties:\n    - `KClass\u003cT\u003e.jsonSchema: JsonObject`\n    - `KClass\u003cT\u003e.jsonSchemaString: String`\n- **kotlinx-schema-gradle-plugin** — Gradle plugin (id: \"org.jetbrains.kotlinx.schema.ksp\") that:\n    - Applies KSP automatically\n    - Adds the KSP processor dependency\n    - Wires generated sources into your source sets\n    - Sets up multiplatform task dependencies\n- **gradle-plugin-integration-tests** — Independent build that includes the main project; demonstrates real MPP usage and integration testing\n- **ksp-integration-tests** — KSP end‑to‑end tests for generation without the Gradle plugin\n\n### Workflow\n\n```mermaid\nsequenceDiagram\n    actor C as Client\n    participant S as SchemaGeneratorService\n    participant G as SchemaGenerator\n    participant I as SchemaIntrospector\n    participant T as TypeGraphTransformer\n    \n    C-\u003e\u003eS: getGenerator(T::class, R::class)\n    S--\u003e\u003eG: find\n    activate G\n    S--\u003e\u003eC: SchemaGenerator\n    C-\u003e\u003eG: generate(T) : R?\n\n    G-\u003e\u003eI: introspect(T)\n    I--\u003e\u003eG: TypeGraph\n\n    G-\u003e\u003eT: transform(graph = TypeGraph, rootName)\n    T--\u003e\u003eG: schema (R)\n    G--\u003e\u003eC: schema (R)\n    deactivate G\n```\n1. _Client_ (KSP Processor or Java class) calls _SchemaGeneratorService_ to lookup _SchemaGenerator_ \n   by target type T and expected schema class. _SchemaGeneratorService_ returns _SchemaGenerator_, if any.\n2. _Client_ (KSP Processor or Java class) calls _SchemaGenerator_ to generate a Schema string representation, \nand, optionally, object a Schema string representation.\n3. SchemaGenerator invokes SchemaIntrospector to convert an object into _TypeGraph_\n4. _TypeGraphTransformer_ converts a _TypeGraph_ to a target representation (e.g., JSON Schema)\n   and returns it to SchemaGenerator\n\n## Building and Contributing\n\nFor build instructions, development setup, and contribution guidelines, see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Requirements\n\n- Kotlin 2.2+\n- KSP 2 (applied automatically when using the Gradle plugin)\n- _kotlinx-serialization-json_ for JsonObject support\n\nTip: If you use `@Description` on primary constructor parameters, enable\n`-Xannotation-default-target=param-property` in Kotlin compiler options so the description applies to the backing\nproperty.\n\n## Code of Conduct\n\nThis project and the corresponding community are governed by\nthe [JetBrains Open Source and Community Code of Conduct](https://github.com/jetbrains#code-of-conduct). Please make\nsure you read and adhere to it.\n\n## License\n\nThis project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkotlin%2Fkotlinx-schema","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkotlin%2Fkotlinx-schema","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkotlin%2Fkotlinx-schema/lists"}