Imported from YanIanZ/SourbyCraft (
AGENTS.md). Install upstream withnpx skills add YanIanZ/SourbyCraft. Copyright stays with the author.
AGENTS.md — SourbyCraft 26.2 Canvas
Region-threading Minecraft 26.2 server fork. Re-platformed onto CanvasMC via Canvas's own io.canvasmc.weaver.patcher toolchain (see build.gradle.kts:9-11, "Path B"). Custom sourbypatcher is unused on this branch — do not reintroduce it without checking PR #12 context in the root build script.
Toolchain
- JDK 25 required (Temurin). Set via Gradle toolchains +
org.gradle.toolchains.foojay-resolver-convention. CI usesactions/setup-java@v4+temurin+java-version: 25. - Gradle wrapper at
./gradlew. Configuration cache is on (org.gradle.configuration-cache=true). Do not introduce rawProcessBuildercalls indoLast; useproviders.exec. - Branching → version suffix (
gradle.propertiesreleaseVersion+sourbyBuild+ git branch):release/*→REL,feat/*/experimental/*→EXP, elseDEV. Stamped intoMETA-INF/sourbycraft-build.properties(viawriteBuildInfoinbuild.gradle.kts:246) and the jar manifestImplementation-Version(insourbycraft-server/build.gradle.kts.patch). These MUST stay in lockstep.
Build commands (root)
./gradlew applyAllPatches # materialize Paper → Canvas → SourbyCraft sources
./gradlew :sourbycraft-server:compileJava
./gradlew slimServerJar # → build/libs/SourbyCraft-slim.jar (~34 MiB; rest fetched on first boot)
Slim-jar task: slimServerJar strips 19 hard-coded artifact dirs from the paperclip jar (build.gradle.kts:90-110); sourbyclip re-downloads them by coordinate on first boot via META-INF/libraries manifest. If the strip count is 0, the task fails — update the prefix list when libraries move.
The CI workflow .github/workflows/build.yml does:
cd sourbypatcher && ./gradlew publishToMavenLocal— legacy step for the Folia patcher; on this branch sourbypatcher is unused but the step remains in CI. Do not delete without reworking the workflow.bash scripts/setup_metal.sh— Metal is vendored atMetal/, not a submodule (upstream LuminolMC/Metal went offline).setup_metal.shcallsMetal/gen_sources.sh.applyAllPatchesthencompileJava, thenslimServerJar -PsourbyBuild=N, copy torelease/SourbyCraft-26.2-REL.jar.boot-testjob: boots witheula=true,online-mode=false,level-type=minecraft:flat, waits 240s forDone (inserver.log, sendsstop, gives 60s to shut down, thenSIGTERM. Fails CI on timeout.
Module layout
:sourbyapi— branded API artifactdev.iyanz.sourbycraft:sourbyapi. Zero custom source; it republishespaper-api+canvas-apiunder the SourbyCraft group id (seesourbyapi/README.md). Materialized fromcanvas-api/build.gradle.ktsvia theupstreams.canvas { patchFile { ... } }block in rootbuild.gradle.kts.:sourbycraft-server— the server. Source-set merge inbuild.gradle.kts.patchaddspaper-server+canvas-serverto the main and test source sets, andsrc/log4jPlugins/java(own log4j2 pattern plugins, e.g.%scLogger).:Metal— vendored Minecraft library-decode codegen.src/empty untilsetup_metal.shruns.sourbypatcher/— own paperweight fork. Not used on this branch. Do not edit unless you are reviving the Folia line.sourbyclip/— Leavesclip fork (paperclip bootstrap). Replaces upstream paperclip; coordinatesdev.iyanz:sourbyclip:${clipVersion}are wired insourbycraft-server/build.gradle.kts.patch.test-harness/— NMS-compat smoke harness. Only used by.github/workflows/nms-compat.yml, which isworkflow_dispatchonly (predates 26.2 rebase, marked stale in the workflow header).test-plugin/,luminol-generator/— opt-in projects; activated by uncommentinginclude(":test-plugin")in their*.settings.gradle.kts.
Patch application
Three-stage fork via weaver's own ForkConfig: Paper → Canvas (own base/ git-format foundational patches + sources/ codechicken diffpatch + features/ git-format) → SourbyCraft (paper-patches/, canvas-patches/, folia-patches/, minecraft-patches/, plus log4jPlugins/). gitFilePatches = false project-wide — sources/ diffpatches go through java-diff-utils instead of git apply.
Critical gotcha in sourbycraft-server/build.gradle.kts.patch: mergeMinecraftATs MUST read Canvas's own .at, not paperweight.activeFork (activeFork is now sourbycraft, which has no canvas.at — silently breaks canvas-server minecraft-patches). Same patch adds an afterEvaluate { ... } to override importCanvasLibraryFiles.devImports to build-data/canvas-dev-imports.txt (upstream's list is empty; canvas.base/ uses ca.spottedleaf.concurrentutil.* classes that need explicit vendoring). And sortFoliaATs is made an explicit dependency of mergeMinecraftATs to avoid out-of-order execution under rebuildMinecraftFeaturePatches.
paper-patches/, canvas-patches/, folia-patches/, minecraft-patches/ under sourbycraft-server/ are the actual patch source of truth — edit patch files there, never the materialized sources under paper-server/, canvas-server/, paper-api/, canvas-api/ (those are git working copies, regenerated by applyAllPatches).
Configuration surfaces
Two independent configs (do not conflate):
- SourbyCraft utility layer →
sourbycraft_config/sourbycraft_global_config.toml(nightconfig). Messages,/maxppersistence, auto-updater, ViaVersion auto-provision. - Canvas engine →
config/canvas-server.yml+config/canvas-worlds.yml(region scheduler, tick rate, autosave). Defaultregion-scheduler.guard-severity: LOG(not Canvas's crash-proneTHROW). - Crash-prevention + packet-guard limits →
sourbycraft-security.yml(checked in; sampled atsourbycraft-security.yml).
Cherry mixin engine
Off by default. Enable with -Dcherry.enable.mixin=true. Plugin authors drop a cherry-plugin.json next to the plugin jar with optional mixin and access-transformers blocks. Server-side only — does not run full Fabric mods, only Fabric-format mixin/AT/access-widener declarations. Plugin-author guide lives at https://github.com/YanIanZ/Cherry (not vendored).
Boot-time network
First boot needs internet once:
SourbyLoader/SourbyClipfetches the externalized libraries into the paperclip cache.ViaVersion+ViaBackwardsjars auto-provisioned intoplugins/(SHA-256-verified, https-only) before the plugin manager scans. Toggle:[viaversion] auto-provisionin the global TOML (defaulttrue). Idempotent — never re-downloads verified jars, never overwrites user config.
If the boot host has no internet, SourbyLoader prints the exact URLs + target paths. Offline-immutable; subsequent boots run fully offline.
Docker
docker build --build-arg JAR=release/SourbyCraft-26.2-REL.jar -t sourbycraft:26.2 .
docker compose up -d --build
Image: eclipse-temurin:25-jre (NOT jdk), non-root user sourby, /data volume, LANG=C.UTF-8 (without this, stdout.encoding defaults to US-ASCII and garbles the branded box-drawing banner). mem_limit: 8g in compose with MEMORY: 6144 MiB heap.
Verifying a build locally
java -Xmx2G -XX:+UseG1GC -jar release/SourbyCraft-26.2-REL.jar --nogui
Wait for Done ( in console. /ver reports the channel + build Nc (e.g. build 41c).
Things agents commonly miss
- Bump
sourbyBuildingradle.propertiesper release; thecsuffix is appended bywriteBuildInfoand the serverbuild.gradle.kts.patchindependently — both must change together (they read the same property). releaseVersiondefaults to26.2.gradle.propertiescodenameis currentlycookies(per README build-id38cline is stale — currentsourbyBuild=41).- Do not commit
paper-server/,canvas-server/,paper-api/,canvas-api/working-copy edits — those are generated byapplyAllPatchesfrom thecanvasRefpin ingradle.properties(Canvasdf0f2ebb...). sourbypatcher/is unused but kept in tree and CI for the Folia line. Do not delete without coordinating.- The
slimServerJartask'sexternalizeArtifactDirslist is matched by path prefix against the paperclip layout — when Canvas/weaver bumps versions, jars may move and the task will fail loudly withstripped 0 libraries. That's the intended signal to update the list. applyAllPatchesis config-cache friendly butwriteBuildInfois opted out (notCompatibleWithConfigurationCache) because it reads git branch viaproviders.execat execution time.- The Dockerfile's LABEL still says "Paper 26.2" in the description — known minor copy lag, not your bug to fix unless touching the Dockerfile.