Imported from rfizzle/instinct (
AGENTS.md). Install upstream withnpx skills add rfizzle/instinct. Copyright stays with the author.
AGENTS.md
Guidance for AI coding agents (Claude Code, Google Jules, and any future tool)
working on this repository. CLAUDE.md is a symlink to this file — both names
point at the same content so each agent finds what it expects to read.
Project overview
Instinct is a Minecraft 1.21.1 Fabric mod — a husbandry overhaul: pets with a
survival instinct and veterancy, livestock bloodline genetics, herd flocking,
a feeding trough block, a command whistle, and downed-pet revival. Java 21,
Fabric Loader 0.16.10, Loom 1.9. The player-experience promise lives in
design/VISION.md; the full behavioral spec is
design/SPEC.md. Work is tracked in GitHub Issues — see the
Development lifecycle section below.
Suite standards (Concord)
This mod is a member of Concord, a modular collection of system overhauls. Suite-wide standards live in
the concord repo — checked out at ../concord/
in the local workspace. Normative for this repo:
- API-STANDARD.md — the
apipackage conventions - HUD-STANDARD.md — Instinct has no HUD slot, by design (
design/DESIGN.md§2) - DESIGN-SYSTEM.md — palette, typography, logo rules
- REPO-LAYOUT.md — where non-code files live
Build commands
./gradlew build # compile + test + jar
./gradlew test # JUnit tests only
./gradlew runGametest # Fabric gametests (headless server)
./gradlew runClient # launch dev client
./gradlew runServer # launch dev server
./gradlew genSources # decompile MC sources for IDE nav
A Makefile wraps these (make build, make test, make run-client, etc.)
and adds make release VERSION=X.Y.Z (tags vX.Y.Z and pushes it to trigger
the release).
Run a single JUnit test:
./gradlew test --tests "com.rfizzle.instinct.SomeTest"
Read .ai/skills/mc-gradle-builds/SKILL.md
before running any Gradle command — it covers how to avoid wasted reruns
from partial output capture.
Source layout
Loom's splitEnvironmentSourceSets() is enabled — three source sets:
| Source set | Root | Purpose |
|---|---|---|
main |
src/main/java |
Server + common logic. Entrypoint: Instinct.java |
client |
src/client/java |
Client-only code. Entrypoint: InstinctClient.java |
gametest |
src/gametest/java |
Fabric gametests (run with runGametest). Has main on its classpath but is NOT included in the jar. |
JUnit tests go in the standard src/test/java directory. The test classpath
includes fabric-loader-junit but excludes fabric-api — tests that need
Fabric APIs must use gametests instead.
Key conventions
- Mod ID:
instinct— useInstinct.id("path")to createResourceLocations. Never constructResourceLocationdirectly with the mod ID inlined. - Mappings: Official Mojang mappings (not Yarn). Use Mojang class/method
names everywhere (
CompoundTag, notNbtCompound;Level, notWorld). - Architectural stance (SPEC.md intro): augment, never replace — no
replacement entity types, no rewritten AI brains; injected goals,
pathfinding maluses, and persistent Fabric data attachments on vanilla
animals. Entity coverage resolves through the membership sets (config →
#instinct:*tags → heuristic) — see SPEC.md "Animal Coverage". - Asset philosophy: vanilla animals keep vanilla looks, always. Custom
pixel-art (glyph pipeline) only for what Instinct adds: the feeding trough
faces, the three item sprites, the paw glyph. Whistle/milestone cues are
custom
/sfxsynthesis; organic sounds stay vanilla. Masters live inart/with.glyphsources inart/glyphs/. - Mixin config:
instinct.mixins.jsoninsrc/main/resources, mixin packagecom.rfizzle.instinct.mixin— created with the first mixin. - Commits: Conventional Commits
with a topical scope naming the feature area:
feat(veterancy): …,fix(trough): …,refactor(genetics): …,ci(review): …,docs(readme): …. Allowed types:feat,fix,refactor,chore,docs,test,build,ci,perf,style. Subject line in imperative mood, no trailing period, ≤72 chars. Reference the issue in the body footer:Closes #42(orRefs #42for partial work).
Compat integrations
The mod plans optional integrations (all modCompileOnly — not bundled):
- Mod Menu — config screen entry
- Cloth Config — settings GUI builder
- Jade / WTHIT — animal/trough tooltip overlays
- Tribulation — veterancy accrual doubling at high difficulty tiers
Compat classes live under com.rfizzle.instinct.compat.<modid>.
Where things live
| Path | Purpose |
|---|---|
design/VISION.md |
The player-experience promise — the domain gate for incoming work. |
design/SPEC.md |
Full behavioral spec for the mod. |
design/DESIGN.md |
Brand, palette, asset specs — the pre-implementation "why & what". |
site/ |
Structured website content (source for instinct.rfizzle.com), rendered by the shared Concord template. |
| GitHub Issues | Active work — feature requests, bugs, in-flight specs. |
.ai/skills/ |
Domain skills — read these before working in their subject area. |
.github/workflows/ |
Thin trigger stubs — workflow logic, default CI prompts, and review criteria live in rfizzle/concord. |
Working with domain skills
The suite's mc-* domain skills live under .ai/skills/, vendored from concord
and refreshed with make sync. The full list — each skill's one-line
summary and the situation that should make you pull it in — is the generated
catalog at .ai/skills/CATALOG.md. It is always in step
with the skills actually vendored here, so consult it rather than a hand-kept
table.
Claude Code auto-loads these via the .claude/skills symlink; Google Jules,
OpenCode, and any other agent should read the relevant SKILL.md directly
before working in its subject area.
Pure core, thin Minecraft shell
Split gameplay logic into a pure core — decision and math logic with no
net.minecraft.* or net.fabricmc.* types — behind a thin shell that wires
the core to the game (the event handler, mixin body, command node, or renderer).
Extract pure logic whenever a seam allows it, for two reasons:
- Testability — the core is plain JUnit (fast, no Fabric bootstrap), which is what keeps real coverage on gameplay logic instead of pushing everything into slow gametests.
- Multi-version portability — mapping renames, Minecraft version bumps, and multi-version targeting touch only the shells; the core ports untouched.
The craft (which seams to extract, how to route tests across the three tiers) is
the mc-mod-testing skill; the merged unit + gametest coverage report that
measures the result is in mc-gradle-builds.
Custom art & audio
Custom, high-quality assets are encouraged across the suite — there are clean,
consistent pipelines for both (the mc-textures skill → /glyph, the mc-audio
skill → /sfx), so the bar is fitness and coherence, not vanilla purity. The
one hard cosmetic rule is the vanilla font (never a custom font in any
GUI/HUD/tooltip).
Decide whether to make a custom asset here, before reaching for a skill:
- Default to custom where it serves a valid purpose — identity, clarity, or a slot vanilla can't fill. This is not license for a blanket retexture or a wholesale soundscape overhaul; add assets where they earn their place, not for their own sake.
- Use a vanilla asset when it is genuinely already right — a trade UI literally showing an emerald, a literal bell on a bell block.
- Audio also stays vanilla when the sound is organic — a real horn, a physical bell, footsteps, foley — which pure synthesis renders obviously fake. Synthesis is for synthetic cues (alarms, UI blips, tech alerts, charge-ups, chiptune).
Once the decision is made, the mc-textures / mc-audio skills are the craft
reference for producing a good one. The normative spec is concord's
design/DESIGN-SYSTEM.md §8 (textures) and §9 (audio).
Development lifecycle
- Issue opened using the feature or bug template under
.github/ISSUE_TEMPLATE/. - Triage — human discussion in the issue.
needs-speclabel added →.github/workflows/claude-spec.ymlfires. Claude normalizes the issue title to a Conventional Commits form and writes a plain-language summary plus a structured implementation spec into the issue body, preserving the reporter's original text in between (prompt: concord's defaultspec-writer.md, unless a repo-local.ai/prompts/spec-writer.mdoverride exists). Once the spec lands theneeds-speclabel is removed and a status label is added:readywhen the spec has no open questions,open-questionswhen it does. A player-facing change (new feature, config option, command, or gameplay rule) carries a Docs impact section naming thesite/page(s) to update; internal-only work omits it.- Human review — spec edited or approved. For
open-questions, answer the questions inline in the issue (no spec re-run needed for the simple cases). juleslabel added → Jules picks up the issue and opens a draft PR. Apply it from eitherreadyoropen-questionsonce you're satisfied. For a locally supervised implementation instead, run the vendored/implement <issue#>command in Claude Code — the same lifecycle end to end (domain gate, plan, a green build + unit-test + gametest sweep, parallel reviews, PR) with human approval gates at plan, remediation, and ship.- PR opened →
claude-code-review.ymlposts a structured ✓/⚠/✗ review (categories from concord's defaultreview-criteria.yml, unless a repo-local.ai/review-criteria.ymloverride exists). For player-facing work it scores a Site docs category — a feature, config, command, or gameplay change that ships without the matchingsite/page update is flagged.ci.ymlruns the full build, unit tests + gametests, with JaCoCo coverage. - Human review + merge.
@claude <message> in any issue or PR comment also invokes Claude for ad-hoc
help via .github/workflows/claude.yml.
Pull requests & commits
When you open a pull request for an issue:
- Title — Conventional Commits with a topical scope, matching the issue's
normalized title (e.g.
feat(render): add glyph atlas cache). Imperative mood, lower-case, no trailing period. - Body — open with a short plain-language summary of what changed and why,
then link the source issue with
Closes #<n>so it auto-closes on merge and the code review can pull the issue's spec for context. UseRefs #<n>only when the PR deliberately leaves part of the issue for later. - Commits — Conventional Commits using the same scope vocabulary. Group the edits for one logical change together rather than scattering fixup commits.
- Run the project's build and tests before opening the PR, and open it only once the build is green.
No tooling or session metadata
Commits, PR titles and bodies, issue and review comments, and code comments are durable records for the humans reading this repo later — write them as if a human did. Never add agent or tooling provenance:
- No agent/cloud session or run links, and no session/task/run IDs. They point at ephemeral, often private surfaces and mean nothing to a reader.
- No "generated by" / "co-authored-by" lines naming a tool or agent, and no tool banners, badges, or sign-offs.
- No narrating which agent did the work; the change stands on its content, and git already records authorship.
If your tooling appends such a footer by default, strip it before committing or posting.
Version scheme
The pushed v* tag is the single source of version truth. Releasing is just
git tag vX.Y.Z && git push origin vX.Y.Z — the release workflow injects the tag
as the build version. mod_version=0.0.0 in gradle.properties is only the
local/dev base; local builds surface as 0.0.0+g<sha>. Never hand-edit a real
version into gradle.properties or open a "set version" PR.
Suite toolchain
The Minecraft target and build toolchain — minecraft_version,
loader_version, fabric_version, loom_version, java_version — are pinned
suite-wide in the concord-owned versions-common.properties, synced in by the
concord-sync PR and loaded in settings.gradle. Do not hand-edit those keys or
inline them in build.gradle; a suite bump lands as one commit in concord and
arrives as a sync PR. gradle.properties keeps only this repo's own values —
the mod_version dev base, maven_group/archives_base_name, per-mod
integration pins, and Gradle JVM/daemon tuning.
Release notes
Release notes are AI-written from the merged PRs by default. To publish curated
notes for a version instead — e.g. a 1.0.0 milestone — commit a
changelogs/<version>.md (no v prefix, e.g. changelogs/1.0.0.md) before
tagging. When that file exists it is published verbatim to GitHub, Modrinth, and
CurseForge and the model is not run; absent, notes are generated as usual.