# Your first architecture definition







If you are not yet convinced that you need katachi, read [Motivation](/katachi/get-started/motivation/) first.

## Add katachi to your project

<Tabs>
  <TabItem label="Let an AI agent do it">
    <Steps>

    1. Start the AI agent you use and **give it this prompt**.

        ```md
        Set up katachi in this project.

        - Follow https://tbsten.github.io/katachi/install/en/index.md to do it.
        ```

        - Putting the project under git first is recommended.
        - The page the AI agent reads tells it to set katachi up **together with you**.

        <details>
        <summary>Additional options</summary>
        - **If your architecture documentation lives outside the codebase** (in Notion, for example), include a link to it in the prompt.
        - By default the AI agent creates an `architecture-test` module and writes the architecture definition there.
          - **To use a different module**, add a prompt such as `Create the test in <module>`.
        - As a matter of context hygiene, **start a fresh session dedicated to setting up katachi**.
            - For Claude Code or Codex CLI: clear the session with `/clear`, then enter the prompt.
        </details>

    2. **Review** the changes the AI agent made to your project and adjust them as needed.

        What to look at:
        - `architecture-test/src/test/kotlin/<package>/ProjectArchitecture.kt` is the entry point.
        - The AI agent splits the architecture definition into one file per group and per Role, and puts them in packages under `ProjectArchitecture.kt`. Review those files too.
        - If you work in a team, have your teammates (especially whoever leads it) review this closely as well.

    3. **Run the architecture test** and confirm that it is all green.

        ```shell
        ./gradlew :architecture-test:test
        ```

        That completes the setup.

    </Steps>
  </TabItem>
  <TabItem label="Install manually">
    <Steps>

    1. **Create the `:architecture-test` module**

        This module belongs to no layer of the app. It holds nothing but the architecture definition and the test that checks it.

        ```kotlin title="settings.gradle.kts"
        pluginManagement {
            repositories {
                gradlePluginPortal()
                mavenCentral()
            }
        }

        include(":architecture-test")
        ```

        katachi's Gradle plugin is published to Maven Central, not to the Gradle Plugin Portal. Without `mavenCentral()` in `pluginManagement { }`, the plugin cannot be resolved.

    2. **Declare the dependencies**

        Whether your project is Android or KMP, **make this a plain `kotlin("jvm")` module**, because katachi itself is a JVM library.

        ```kotlin title="architecture-test/build.gradle.kts"
        import org.gradle.api.tasks.testing.logging.TestExceptionFormat

        plugins {
            kotlin("jvm") version "<Kotlin version>"
            id("me.tbsten.katachi") version "<katachi version>"
        }

        kotlin {
            jvmToolchain(17)
        }

        tasks.test {
            useJUnitPlatform()
            // The files being checked are not inputs of the Test task, so run it every time (and keep its result out of the build cache)
            outputs.upToDateWhen { false }
            outputs.cacheIf { false }
            // Print the list of violations to the console
            testLogging { exceptionFormat = TestExceptionFormat.FULL }
        }

        dependencies {
            testImplementation("me.tbsten.katachi:katachi:<katachi version>")
            testImplementation("me.tbsten.katachi:katachi-konsist:<katachi version>")
            testImplementation(platform("org.junit:junit-bom:5.14.4"))
            testImplementation("org.junit.jupiter:junit-jupiter")
            testRuntimeOnly("org.junit.platform:junit-platform-launcher")
        }

        katachi {
            architecture = "com.example.projectArchitecture"
        }
        ```

        - **`outputs.upToDateWhen { false }` / `outputs.cacheIf { false }`**: katachi checks the files of the whole repository, but Gradle only sees the test classpath as the Test task's input. Without this line, `:architecture-test:test` is skipped as `UP-TO-DATE` even after you add or change files, and stays green even when there are violations. `cacheIf` keeps a previous result from being reused when the build cache is enabled.
        - **`testLogging { exceptionFormat = TestExceptionFormat.FULL }`**: without it, a failing test prints only a single line with the exception's class name to the console, and you have to open the test report to read the list of violations.
        - **`katachi { architecture = ... }`**: tells document generation and templates where to find the definition. Set it to the fully qualified name of the definition you write in step 3 (`package` + variable name).

        <Aside type="caution" title="For Android projects">
        Write `kotlin("jvm") version "..." apply false` in the root `build.gradle.kts`, and in the module write just `kotlin("jvm")`, **without a version**.
        </Aside>

        <details>
        <summary>Kotlin version (2.2 or later; below 2.4 a compiler option is needed)</summary>

        Use Kotlin **2.2 or later**. Earlier Kotlin versions cannot read the metadata of katachi's libraries.

        `ktFile()`, `konsist { }` and others are declared with context parameters. **Below Kotlin 2.4** they cannot be called without the following option (do not add it on 2.4 or later; it causes a warning).

        ```kotlin title="architecture-test/build.gradle.kts"
        kotlin {
            compilerOptions.freeCompilerArgs.add("-Xcontext-parameters")
        }
        ```

        </details>

    3. **Define the architecture.**

        `architecture-test/src/test/kotlin/<package>/ProjectArchitecture.kt` is the entry point.

        ```kotlin
        // Example
        @file:OptIn(ExperimentalKatachiApi::class)

        package com.example

        import me.tbsten.katachi.ExperimentalKatachiApi
        import me.tbsten.katachi.dsl.architecture
        import me.tbsten.katachi.dsl.gradle.gradle
        import me.tbsten.katachi.dsl.kotlin.ktFile

        val projectArchitecture = architecture {
            gradle() // Gradle's files: the wrapper, settings, build scripts and so on
            "domain".group {
                "UseCase" {
                    summary = "A single app-specific behavior that occurs on a screen"
                    layout {
                        "domain/src/main/kotlin/usecase" / "*UseCase".ktFile()
                    }
                }
            }
        }
        ```

    4. **Write the one test that checks it**

        ```kotlin title="architecture-test/src/test/kotlin/<package>/ProjectArchitectureTest.kt"
        @file:OptIn(ExperimentalKatachiApi::class)

        package com.example

        import me.tbsten.katachi.ExperimentalKatachiApi
        import me.tbsten.katachi.check.assert
        import org.junit.jupiter.api.Test

        class ProjectArchitectureTest {
            @Test
            fun `the project structure matches the definition`() {
                projectArchitecture.assert()
            }
        }
        ```

        **This is the only test your project writes.** Every violation in the repository lands in a single failure message, so there is no point in splitting the test up per rule.

        If your definition has `konsist { }`, call `assert(FileConstraintCheck())` instead of `assert()`. With `assert()` alone the constraints are not evaluated and the test fails. See [Konsist integration](/katachi/guides/konsist-integration/) for details.

    5. **Run it**

        ```shell
        ./gradlew :architecture-test:test
        ```

        At first **the files and directories you have not declared come out as violations.** katachi is an allow-list, so this is the normal starting point. Go through the reported paths and decide, one by one, whether to add them to the definition or delete them.

        Gradle's files (the wrapper, `settings.gradle.kts`, build scripts, `gradle.properties` and the version catalog) are declared by the single `gradle()` line in step 3. If you have `buildSrc` or convention plugins, see the [Gradle recipe](/katachi/recipes/gradle/).

        If there are too many existing violations to clear up right away, the experimental baseline feature lets you tolerate the existing violations for now and fail only on new ones. See [Baseline](/katachi/guides/baseline/) for details.

    </Steps>
  </TabItem>
</Tabs>

## Confirm that the setup works

<Tabs>
    <TabItem label="Let an AI agent verify it">
        Hand the AI agent a real task and see that it no longer produces files that break the architecture rules.

        <details>
        <summary>If you have implementation tasks coming up</summary>

        If you have tasks that are actually coming up, running one of them as a trial is the best way to measure whether katachi does its job.
        Hand the task to the AI agent and let it run.

        If the task is tracked in JIRA, Notion, or similar, passing those along works well too.

        </details>

        <details>
        <summary>If you have nothing in particular</summary>

        Have the AI agent invent a hypothetical task and check whether katachi works as a guardrail.

        ```md
        Come up with a few hypothetical tasks that are likely to come up in this project.
        ```

        </details>

    </TabItem>

    <TabItem label="Verify manually">
        1. Think of a piece of code that breaks an architecture rule and actually create that source file.
        2. Run `./gradlew :architecture-test:test` and confirm that the architecture test fails.
    </TabItem>
</Tabs>

## <Badge text="Optional" size="small" /> <br/> Wire it into CI

To keep the quality up, run the katachi architecture test regularly by wiring it into CI.

<Tabs>
    <TabItem label="Github Actions">
        Add a workflow file like this one.

        ```yaml title=".github/workflows/architecture.yml"
        name: Architecture

        on:
          push:
            branches: [main]
          pull_request:

        permissions:
          contents: read

        jobs:
          architecture:
            runs-on: ubuntu-latest
            steps:
              - uses: actions/checkout@v7

              - uses: actions/setup-java@v6
                with:
                  distribution: temurin
                  java-version: '17'

              - uses: gradle/actions/setup-gradle@v6

              - run: ./gradlew :architecture-test:test
        ```

    </TabItem>

    <TabItem label="Other CI systems">
        Describe a workflow like the following, in whatever form your CI system expects.

        1. Set up Java.
        2. Run `./gradlew :architecture-test:test`.
        3. Report the result of step 2.
    </TabItem>
</Tabs>

## Next steps

- Read the guides to deepen your understanding of katachi and refine your architecture definition.
    - [Basic API](/katachi/guides/basic-api/)
    - [Role](/katachi/guides/role/)
    - [Layout](/katachi/guides/layout/)
    - [Konsist integration](/katachi/guides/konsist-integration/)
    - [Document generation](/katachi/guides/document-generation/)
    - [Generate code from template](/katachi/guides/generate-code-from-template/)
    - [Baseline](/katachi/guides/baseline/)