Agents Guide
-
Purpose: short, actionable instructions for automated coding agents operating in this repo
-
Location: run all commands from repository root; use
./gradlew(wrapper) to ensure the correct Gradle/JDK/tooling -
Important: this repository is a multi-module Kotlin/Java Gradle project (Paper/Folia fork). The build uses Java toolchain 21; tests and run tasks expect JDK 21.
-
Quick commands
- Build everything:
./gradlew build(use--parallelfor faster builds where appropriate) - Run checks only:
./gradlew check - Run tests for a specific subproject:
./gradlew :plugins:plugin-islands:test - Skip tests while building:
./gradlew build -x test - Run a development server (Folia):
./gradlew :folia-server:runDevServer - Run an assembled server:
./gradlew :folia-server:runServer - List available tasks:
./gradlew tasks --all - Note:
:folia-server:runServerand:folia-server:runDevServerare configured to depend on plugin shadow JAR tasks (see rootbuild.gradle.ktsgradle.projectsEvaluatedblock). When run, generated plugin JARs are passed to the server via--add-pluginarguments.
- Build everything:
-
Running a single test (recommended way)
-
Run a single test class in a subproject (Gradle + JUnit 5):
./gradlew :plugins:plugin-islands:test --tests "net.azisaba.vanilife.islands.portal.HologramSpawnerTest" -
Run a single test method:
./gradlew :plugins:plugin-islands:test --tests "net.azisaba.vanilife.islands.portal.HologramSpawnerTest.testSpawnHologram" -
Notes:
- Use the fully qualified class name. Surround the
--testspattern with quotes to avoid shell expansion. - Gradle's
--testssupports patterns/wildcards (e.g.*Hologram*). - Some projects (notably
:folia-server) configureuseJUnitPlatform { excludeTags("Slow") }in theirtesttask. By default slow tests will be skipped there. - If a test task adds JVM agents (mockito agent for Java 21) or other
jvmArgumentProviders, the task configuration will inject them automatically — prefer the Gradle task above over running tests with rawjava. - For example,
:folia-serverand:folia-apiregister amockitoAgentconfiguration and use aMockitoAgentProvideradded totasks.test'sjvmArgumentProviders, so-javaagent:arguments are injected automatically (seefolia-server/build.gradle.ktsandfolia-api/build.gradle.kts).
- Use the fully qualified class name. Surround the
-
-
Debugging tests
- Run with stacktrace and verbose logging: add
--stacktrace --infoor--debugto your Gradle command. - IDE: use IntelliJ's Run gutter for quick single-test execution and debugging.
- Run with stacktrace and verbose logging: add
-
Lint & formatting
- There is no enforced ktlint/detekt/spotless configuration in repository root. The project uses Kotlin and Java; prefer the Kotlin official style and IntelliJ formatter.
- Note: there is no enforced ktlint/detekt/spotless Gradle configuration, but an IDE ktlint configuration file exists at
.idea/ktlint-plugin.xml(IDE-level only; not enforced by the build). - Recommended (not yet configured): add
ktlintanddetektand wire them into./gradlew check. - Import rules: avoid wildcard imports (
*), group and order imports sensibly (standard library -> third party -> project), and keep imports alphabetized inside groups.
-
Code Style Guidelines (applies to Kotlin & Java plugin code)
-
Language & tooling
- Kotlin is the primary language for plugin code under
plugins/. - Java code exists (server/upstream). Keep Java changes idiomatic to the surrounding code style.
- Use the Gradle wrapper
./gradlewand Java toolchain (Java 21) defined by the build scripts.
- Kotlin is the primary language for plugin code under
-
Formatting
- Use 4-space indentation.
- Opening brace on same line (Kotlin default style).
- Keep lines reasonably short (wrap at ~120 chars).
- Use the IDE formatter or a project ktlint configuration if added.
-
Imports
- No wildcard imports. Be explicit.
- Group imports with a blank line between standard library (kotlin/java), third-party (org/, com/, io/), and project-local packages (
net.azisaba.*). - Keep imports alphabetized within each group.
-
Naming
- Packages: lower case dot-separated (already
net.azisaba.vanilife.*). - Classes/objects: UpperCamelCase.
- Functions / properties: lowerCamelCase.
- Constants (public
const val): UPPER_SNAKE_CASE inside companion objects or top-level objects. - Test class names:
<Thing>Testfor unit tests and*TestSuitefor suites.
- Packages: lower case dot-separated (already
-
Types & nullability (Kotlin)
- Prefer
valovervar. Usevaronly when mutation is required. - Prefer explicit return types for public functions and members; internal/private functions may omit when obvious.
- Embrace Kotlin nullability: prefer
?.,?:,let, andrequireNotNullwhere appropriate; avoid unchecked platform-type assumptions when interacting with Java APIs.
- Prefer
-
Error handling & logging
- Do not use
e.printStackTrace()in plugin code. Instead, log contextual information and the exception.- Example (preferred):
plugin.logger.log(Level.SEVERE, "Failed to update hologram UUID in repository", e)
- Example (preferred):
- Catch the most specific exception possible. Avoid catching
Throwableunless you need to guard a boundary and explicitly document why. - Do not swallow exceptions silently. Log and either handle or rethrow.
- Avoid leaking secrets into logs.
- Do not use
-
Coroutines & concurrency
- This project uses coroutines and Folia region dispatchers in plugin code (see
plugin.launch(plugin.regionDispatcher(loc))). - When interacting with Folia/async server internals, schedule actions on the correct dispatcher (region/world thread) rather than running blocking logic on caller threads.
- Prefer structured concurrency: tie coroutine lifecycles to plugin lifecycle where appropriate and close resources explicitly.
- This project uses coroutines and Folia region dispatchers in plugin code (see
-
Dependency Injection
- Use Koin for DI as in plugin Main classes. Start/stop the
KoinApplicationinonEnable/onDisableand keep registrations minimal and explicit.
- Use Koin for DI as in plugin Main classes. Start/stop the
-
Public API & documentation
- Add KDoc to public API surface. Keep comments for non-obvious algorithms only.
- Avoid TODOs without ticket/issue references.
-
Tests
- Use JUnit 5 (junit-jupiter); tests are configured with
useJUnitPlatform()in server modules. - Tag slow/integration tests with
@Tag("Slow")and be mindful that:folia-server:testexcludes that tag by default. - Keep tests hermetic when possible (mock external services). The build already wires a Mockito javaagent for certain test tasks.
- Use JUnit 5 (junit-jupiter); tests are configured with
-
-
Git / commits
- Follow existing commit message style in the repo (conventional-ish:
fix(module): short description). - Do not rewrite or amend commits unless explicitly required and coordinated with repo owners.
- Follow existing commit message style in the repo (conventional-ish:
-
Files and locations that matter (quick map)
- Root build:
build.gradle.kts - Version catalog:
gradle/libs.versions.toml - Folia/server project:
:folia-server(tasks:runServer,runDevServer,test) - Plugins live under
plugins/(e.g.:plugins:plugin-islands,:plugins:plugin-npc)
- Root build:
-
Cursor/Copilot rules
- Cursor rules (.cursor/rules/ or .cursorrules): none found in repo.
- Copilot instructions (.github/copilot-instructions.md): none found in repo.
-
Troubleshooting hints
- If tests warn
SLF4J(W): Defaulting to no-operation (NOP) logger implementationadd a test logging binding (e.g.org.slf4j:slf4j-simple) to the test runtime or configure logger inside tests. - If Gradle fails with a JDK mismatch, ensure JDK 21 is used or rely on
./gradlewwhich uses the configured Java toolchain. - If a test hangs, run the test class directly from IntelliJ with debugger to inspect threads, or rerun Gradle test with
--debugand--stacktrace.
- If tests warn
-
If you change formatting or static analysis rules
- Add the tool (ktlint/detekt/spotless) to the Gradle build and wire into
check. - Update this
AGENTS.mdwith the exact commands for CI and local runs.
- Add the tool (ktlint/detekt/spotless) to the Gradle build and wire into
Appendix: Example single-test invocations (copy/paste)
- Class
./gradlew :plugins:plugin-islands:test --tests "net.azisaba.vanilife.islands.portal.HologramSpawnerTest" - Method
./gradlew :plugins:plugin-islands:test --tests "net.azisaba.vanilife.islands.portal.HologramSpawnerTest.testSpawnHologram"
If anything in this document is unclear or you need a change to tooling (add ktlint/detekt, configure CI linting, or add a recommended gradle task), update this file and add a short PR explaining why.