Add new example project
diff --git a/examples/hello-world/README.md b/examples/hello-world/README.md
new file mode 100644
index 0000000..7fb6b4f
--- /dev/null
+++ b/examples/hello-world/README.md
@@ -0,0 +1,62 @@
+# KSP Hello World Example
+
+This project is a minimal, self-contained KSP project.
+
+It configures KSP via its Gradle plugin as one would normally do,
+in the hopes of providing an example that a new user can read and learn from.
+
+The project has three subprojects:
+- `annotations`: This subproject defines the `Gen` annotation. By keeping annotations in a separate
+  module, we avoid leaking the processor's implementation or the KSP API to the app's runtime.
+- `processor`: This subproject defines a minimal processor that selects functions annotated with
+  `Gen` and generates a function that prints a message.
+- `app`: This subproject defines a single `main` that calls the generated function.
+  The `main` function is annotated with `Gen` to trigger the processor.
+
+## Key Concepts
+
+While this is a minimal example, it demonstrates several core KSP mechanisms that are essential to
+understand:
+
+### Selecting Functions to Process
+
+The processor's entry point is the `process` method, which receives a `Resolver`.
+The `Resolver` type is the primary tool for querying the KSP's view of the source code.
+
+In `HelloWorldProcessor.kt`, we use:
+- `resolver.getSymbolsWithAnnotation(...)`: To find all symbols annotated with our fully qualified
+  annotation name (`com.example.annotations.Gen`).
+- `.filterIsInstance<KSFunctionDeclaration>()`: Since our processor is designed to work on
+  functions, we filter the results to ensure we are only dealing with function declarations.
+
+Once filtered, we use the **Visitor Pattern** (`it.accept(HelloWorldVisitor(), Unit)`) to perform the actual code generation. This is the recommended way to traverse the KSP AST (Abstract Syntax Tree).
+
+Note the file in `processor/src/main/resources/META-INF/services/`.
+It contains the fully qualified name of the `SymbolProcessorProvider` implementation.
+Without this, KSP will not know your processor exists.
+
+### Generating Code
+
+Using the selected function in the `HelloWorldVisitor`, we can create a new file and write directly
+to it like any other output stream.
+
+### Dependency Management
+
+In `app/build.gradle.kts`, notice how the dependencies are split:
+- `implementation(project(":annotations"))`: Gives the app access to the `Gen` annotation
+  definition.
+- `ksp(project(":processor"))`: Tells the KSP plugin to run the processor during compilation.
+
+The separation ensures the processor's code only exists during the build phase and isn't bundled
+into your final application.
+Note in `processor/build.gradle.kts` that the processor also depends on the annotations project with
+`implementation(project(":annotations"))`.
+
+### Inspecting Generated Code
+
+You can find the source code generated by this processor in the build directory of the app:
+`app/build/generated/ksp/main/kotlin/GeneratedHelloWorld.kt`
+
+## Further Reading
+
+Visit the [KSP documentation](https://kotlinlang.org/docs/ksp-overview.html) for more information.
diff --git a/examples/hello-world/annotations/build.gradle.kts b/examples/hello-world/annotations/build.gradle.kts
new file mode 100644
index 0000000..fb0d35a
--- /dev/null
+++ b/examples/hello-world/annotations/build.gradle.kts
@@ -0,0 +1,7 @@
+plugins {
+    kotlin("jvm")
+}
+
+repositories {
+    mavenCentral()
+}
diff --git a/examples/hello-world/annotations/src/main/kotlin/com/example/annotations/Gen.kt b/examples/hello-world/annotations/src/main/kotlin/com/example/annotations/Gen.kt
new file mode 100644
index 0000000..d329d1d
--- /dev/null
+++ b/examples/hello-world/annotations/src/main/kotlin/com/example/annotations/Gen.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2026 Google LLC
+ * Copyright 2010-2026 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.annotations
+
+/**
+ * The Gen annotation.
+ *
+ * Annotating a function with this will trigger the processor, thus generating a `helloWorld` function.
+ */
+annotation class Gen
diff --git a/examples/hello-world/app/build.gradle.kts b/examples/hello-world/app/build.gradle.kts
new file mode 100644
index 0000000..db43f69
--- /dev/null
+++ b/examples/hello-world/app/build.gradle.kts
@@ -0,0 +1,18 @@
+plugins {
+    kotlin("jvm")
+    application
+    id("com.google.devtools.ksp") version "2.3.5"
+}
+
+application {
+    mainClass.set("MainKt")
+}
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    implementation(project(":annotations"))
+    ksp(project(":processor"))
+}
diff --git a/examples/hello-world/app/src/main/kotlin/Main.kt b/examples/hello-world/app/src/main/kotlin/Main.kt
new file mode 100644
index 0000000..4c936e1
--- /dev/null
+++ b/examples/hello-world/app/src/main/kotlin/Main.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2026 Google LLC
+ * Copyright 2010-2026 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.example.annotations.Gen
+
+/**
+ * The main entrypoint.
+ *
+ * Annotated with `Gen` to trigger the processor which generates `helloWorld`.
+ */
+@Gen
+fun main() {
+    helloWorld()
+}
diff --git a/examples/hello-world/build.gradle.kts b/examples/hello-world/build.gradle.kts
new file mode 100644
index 0000000..72c43d1
--- /dev/null
+++ b/examples/hello-world/build.gradle.kts
@@ -0,0 +1,16 @@
+plugins {
+    kotlin("jvm") version "2.3.0" apply false
+}
+
+buildscript {
+    dependencies {
+        classpath(kotlin("gradle-plugin", version = "2.3.0"))
+    }
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+tasks.register<GradleBuild>("run") {
+    tasks.add(":app:run")
+}
diff --git a/examples/hello-world/processor/build.gradle.kts b/examples/hello-world/processor/build.gradle.kts
new file mode 100644
index 0000000..9d020a4
--- /dev/null
+++ b/examples/hello-world/processor/build.gradle.kts
@@ -0,0 +1,12 @@
+plugins {
+    kotlin("jvm")
+}
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    implementation(project(":annotations"))
+    implementation("com.google.devtools.ksp:symbol-processing-api:2.3.5")
+}
diff --git a/examples/hello-world/processor/src/main/kotlin/HelloWorldProcessor.kt b/examples/hello-world/processor/src/main/kotlin/HelloWorldProcessor.kt
new file mode 100644
index 0000000..e39813c
--- /dev/null
+++ b/examples/hello-world/processor/src/main/kotlin/HelloWorldProcessor.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2026 Google LLC
+ * Copyright 2010-2026 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.google.devtools.ksp.processing.CodeGenerator
+import com.google.devtools.ksp.processing.Dependencies
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSVisitorVoid
+import com.google.devtools.ksp.validate
+import java.io.OutputStream
+
+/**
+ * A code generator, called a processor, that uses KSP.
+ * It implements the [SymbolProcessor] interface that comes from KSP.
+ */
+class HelloWorldProcessor(val codeGenerator: CodeGenerator) : SymbolProcessor {
+
+    /**
+     * Selects functions annotated with `Gen` generates `helloWorld`.
+     * Always returns an empty list since it either generates the `helloWorld` function or not.
+     */
+    override fun process(resolver: Resolver): List<KSAnnotated> {
+        resolver
+            .getSymbolsWithAnnotation("com.example.annotations.Gen")
+            .filter { it.validate() }
+            .filterIsInstance<KSFunctionDeclaration>()
+            .forEach { it.accept(HelloWorldVisitor(), Unit) }
+
+        return emptyList()
+    }
+
+    /**
+     * Local visitor for the KSP AST.
+     * It extends the [KSVisitorVoid] which knows how to traverse the AST, but
+     * only overrides the `visitFunctionDeclaration` method, since it is only ever passed
+     * the handle to the `main` function.
+     */
+    inner class HelloWorldVisitor : KSVisitorVoid() {
+
+        /**
+         * Generates the `helloWorld` function.
+         */
+        override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+            createNewFileFrom(function).use { file ->
+                file.write(
+                    """
+                        fun helloWorld(): Unit {
+                            println("Hello world from function generated by KSP")
+                        }
+                    """.trimIndent()
+                )
+            }
+        }
+    }
+
+    /**
+     * Creates a new file for `function`.
+     */
+    private fun createNewFileFrom(function: KSFunctionDeclaration): OutputStream {
+        return codeGenerator.createNewFile(
+            dependencies = createDependencyOn(function),
+            packageName = "",
+            fileName = "GeneratedHelloWorld"
+        )
+    }
+
+    /**
+     * Creates a dependency for the file containing `function`.
+     */
+    private fun createDependencyOn(function: KSFunctionDeclaration): Dependencies {
+        return Dependencies(aggregating = false, function.containingFile!!)
+    }
+
+}
diff --git a/examples/hello-world/processor/src/main/kotlin/HelloWorldProcessorProvider.kt b/examples/hello-world/processor/src/main/kotlin/HelloWorldProcessorProvider.kt
new file mode 100644
index 0000000..24d4a1a
--- /dev/null
+++ b/examples/hello-world/processor/src/main/kotlin/HelloWorldProcessorProvider.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2026 Google LLC
+ * Copyright 2010-2026 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.processing.SymbolProcessorProvider
+
+/**
+ * Provides an instance of a [HelloWorldProcessor] (defined in this project).
+ * The KSP framework calls this class to construct our processor.
+ * KSP knows about this class because we defined it in the META-INF directory.
+ */
+class HelloWorldProcessorProvider : SymbolProcessorProvider {
+    override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
+        return HelloWorldProcessor(environment.codeGenerator)
+    }
+}
diff --git a/examples/hello-world/processor/src/main/kotlin/Util.kt b/examples/hello-world/processor/src/main/kotlin/Util.kt
new file mode 100644
index 0000000..ff6fc1c
--- /dev/null
+++ b/examples/hello-world/processor/src/main/kotlin/Util.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2026 Google LLC
+ * Copyright 2010-2026 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.OutputStream
+
+fun OutputStream.write(string: String): Unit {
+    this.write(string.toByteArray())
+}
diff --git a/examples/hello-world/processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/examples/hello-world/processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 0000000..58dfa70
--- /dev/null
+++ b/examples/hello-world/processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+HelloWorldProcessorProvider
\ No newline at end of file
diff --git a/examples/hello-world/settings.gradle.kts b/examples/hello-world/settings.gradle.kts
new file mode 100644
index 0000000..f0cb5ec
--- /dev/null
+++ b/examples/hello-world/settings.gradle.kts
@@ -0,0 +1,11 @@
+pluginManagement {
+    repositories {
+        gradlePluginPortal()
+    }
+}
+
+rootProject.name = "ksp-hello-world"
+
+include(":annotations")
+include(":app")
+include(":processor")