fix-issue
Skill766 starsChanged 34 days agoApache-2.0View on GitHub
Diagnose and fix an Endstone bug report - a server crash (crash report, access violation, abort), an event or API that behaves differently from vanilla BDS or from Bukkit/Paper, an event that never fires, fires when it should not, or leaves the client out of sync when cancelled, or a Python binding that raises or returns the wrong thing. Use when asked to "fix #N", "look at this crash report", "X doesn't work like vanilla", "event Y doesn't fire", "Z crashes the server", or to work through bugs from the GitHub issue tracker. Layout/vtable drift after a BDS bump is handed off to bump-bds and reconcile-headers.
- Installs packages
53 other projects use a version of this.
Adopted by
Most recently taken up by
- domengabrovsek/agent-configtheir own version, first seen Nov 8, 2026
- domengabrovsek/claudetheir own version, first seen Nov 8, 2026
- TidalPaladin/skillstheir own version, first seen Nov 8, 2026
- ThinkFlowLab/agentdescenttheir own version, first seen Nov 8, 2026
- getsentry/sentry-javascripttheir own version, first seen Nov 6, 2026
- encoreshao/encore-skillstheir own version, first seen Oct 29, 2026
Used with
Projects with it also use prepare-release, document and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
ShopifySkillprepare-release
Prepare the changeset-release/main branch for release by syncing version.ts files and running pnpm install
Also in 4 projects that use this
nicolasestremSkilldocument
Create focused documentation for specific components or features
Also in 4 projects that use this
GitHubSkillrefactor
Surgical code refactoring to improve maintainability without changing behavior. Covers extracting functions, renaming variables, breaking down god functions, improving type safety, eliminating code smells, and applying design patterns. Less drastic than repo-rebuilder; use for gradual improvements.
Also in 5 projects that use this
SentrySkillwrite-tests
Write tests following project conventions. Use when adding new tests or modifying existing ones.
Also in 3 projects that use this
AWSSkillship
Finalize dev work on an issue branch — update docs, push, and open a PR.
Also in 6 projects that use this
Microsoft AzureSkillbuild
Build the TypeSpec Rust emitter from source. Run this after cloning the repo, after pulling changes, or when TypeScript source files have been modified.
Also in 4 projects that use this
Other versions53 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 53
- pytorch/pytorch★ 105ksame name
- ZhuLinsen/daily_stock_analysis★ 68ksame name
- Dokploy/dokploy★ 38ksame name
- remix-run/remix★ 33ksame name
- PrefectHQ/fastmcp★ 28ksame name
- jlowin/fastmcp★ 28ksame name
- NVIDIA-NeMo/Speech★ 19ksame name
- NVIDIA-NeMo/NeMo★ 19ksame name
- getsentry/sentry-javascript★ 8.8ksame name
- datlechin/TablePro★ 6.4ksame name
43 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository8 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- add-conan-recipeSkill
- build-ida-dbSkill
- bump-bdsSkill
- locate-functionSkill
- reconcile-headersSkill
- releaseSkill
- update-signaturesSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
14 rules. 0 are common, 5 are distinctive, and 9 are very specific to this project.
0
Common
Most of the 51 edited versions we read keep these.
5
Distinctive
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 35
DO fix the root cause, not the symptom: Do not wrap a use-after-free in try/catch, null-guard a wrong offset, or add a delay to dodge an …
- Very specific: line 43
DO NOT invent: Never write a BDS function body you cannot see.
- Very specific: line 118
Paths a player drives need a client: Write the repro as an in-server test in the endstone_test plugin.
- Distinctive: line 122
If it does not reproduce, change no code: Ask the reporter for:
- Very specific: line 242
BDS inlined the hooked function: When the movement-correction system was inlined, PlayerMoveEvent moved to the PlayerAuthInputPacket …
- Distinctive: line 302
After any cancel fix, check in game that the client shows the server's state and that every follow-on effect is suppressed: knockback, …
- Distinctive: line 334
Key functions and vtable emission: If a class's only virtual is the one you hook, the hook becomes its key function and clang emits the …
- Distinctive: line 343
Prefer calling the virtual from an already-hooked non-virtual function.
- Very specific: line 363
Downcasts: Add new subclasses to polymorphic_type_hook (9fbb1974c).
- Very specific: line 392
When BDS already bounds the input itself, put the guard in the raknet recipe patch rather than in a hook.
- Very specific: line 394
Close connections with
NetworkSystem::setCloseConnection,: never closeConnection, which runs onConnectionClosed a second time over freed … - Very specific: line 408
Commit: Write a fix(<scope>): <what works now> subject.
- Very specific: line 412
CHANGELOG: Add one user-visible Fixed line ending in (#N).
- Distinctive: line 414
Record what you learned: When a fix teaches a new class or a new tell, add it to this skill.
“Common” is measured: kept by at least 6 in 10 of the 51 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Fix an Endstone bug
Almost every fix in this repository's history falls into one of the classes below, and the fix is always the same move: find out what BDS does (for game behaviour) or what Paper/CraftBukkit does (for API semantics), then make Endstone do exactly that. Classify the report, read the evidence, fix the root cause, then look for the same mistake elsewhere.
Each class cites commits as worked examples. Read them with git show <hash>. They
live on develop or the current release branch, so fetch both. Commit bodies explain
the mechanism in detail, so read the body as well as the diff.
Ground rules
- DO read the evidence before naming a cause. That means the crash report, the BDS function decompiled at the target version, and the Paper source fetched, not recalled. A theory about a crash that never opened the dump is a guess.
- DO confirm BDS behaviour by decompiling. A function's name, size, vtable slot or
neighbourhood does not establish what it does. The
locate-functionskill covers finding a function without symbols. Put the evidence in the commit body: BDS version, platform, address and the instruction or call that settles it (4be6a165f,c54592af5). - Know your sources. The Linux
bedrock_serverkeeps its symbol names and is the easy place to read a mechanism. Use the Windows build of the target version for offsets.build-ida-dbbuilds both databases.bedrock-headersis NDA-restricted. Without access to it, the binaries are the source of truth. - DO mirror Paper/CraftBukkit for API semantics, including call order, copy versus
live semantics and which subclasses an event covers. Endstone says
Actorwherever Bukkit saysEntity. - DO fix the root cause, not the symptom. Do not wrap a use-after-free in
try/catch, null-guard a wrong offset, or add a delay to dodge an ordering problem.
For example, resending boss bars after a dimension change on a delay never worked
(
6e953497c). Answering the client's own Query is what fixed it (bf772c28a). - DO sweep for siblings. One divergence in a file means you check every function
in it. The #539 crash fix found three more divergences in the same file
(
4be6a165f). A rule copied into four call sites was wrong in all four (78a7ea71e). - DO NOT invent. Never write a BDS function body you cannot see. Declare it and
resolve it by symbol instead. Never return a translation key no client resolves
(
440bb56a8raises instead). Never fill in a constant you cannot read (29bb533c1leaves it undefined so any use fails to link). - DO NOT add speculative hardening such as locks, retries or guards for callers that break the main-thread-only contract. If you spot an adjacent problem, report it and land it separately.
- DO NOT add public API on a released minor. A new virtual in
include/endstone/breaks every compiled C++ plugin. If the fix cannot be made without one, say so and leave the fix ondevelop.
1. Triage
Read a crash report
Crash reports are written to crash_reports/crash-<datetime>-server.txt in the
server folder.
- Turn addresses into RVAs. Frames show the preferred base plus the RVA, so for
bedrock_server.exe,RVA = addr - 0x140000000. Forendstone_runtime.dll, the base is0x180000000. The same crash gives the same addresses on every run. - Find the faulting frame. Filtered modules keep their indices, so frame numbers have gaps. The crash handler's own frames come first. The first frame after the gap is the faulting PC. Every address is the return address minus 1, so expect the call instruction one byte later.
Use the exception code to pick a class:
Code Means Go to 0xC0000005, right after a BDS bumpwrong offset §2 0xC0000005in a BDS frame, ticks after a disconnect, unload or reloadfreed object §3, §5, §11 0x40000015(STATUS_FATAL_APP_EXIT)uncaught C++ throw; frame #0 is the throw site §4 0xC0000409, or a fail-fast with no useful stacka call landed in the wrong virtual ( a6e36ac3b)§2 bad_variant_accessat shutdownevent variant drift bump-bds- Resolve
??frames against the PDB when that version ships one. Otherwise use the named Linux build or the.pdatafunction bounds.
Classify a behaviour report
| Report | Section |
| An event never fires, fires on only some paths, or fires when it should not | §6 |
| Cancelling did nothing visible, the item vanished, or a side effect still happened | §7 |
| An API returns garbage | §2 |
| An API returns a plausible but wrong value | §5, §8 |
| Data is lost after a read-modify-write | §8 |
| Works on Windows but not Linux, or the reverse | §9 |
| Fails only from Python | §10 |
Breaks only after /reload or a plugin disable | §11 |
| A client can crash or hang the server | §12 |
Reproduce
- Read the code at the reported release, not at
HEAD. The branch may already target a newer BDS, so compare offsets withgit show v<version>:src/bedrock/symbols/<platform>.h. - Test the symptom, not the cause the reporter suggests. Reports often blame "missing symbol bindings" or hooks without evidence.
Drive a headless server from its console before forming a theory. Copy the server folder to a scratch directory and give it:
- a fresh
level-type=FLATworld; online-mode=falseandallow-list=false;- unused ports.
Then pipe commands into
endstone -s <copy> -y --no-interactive:tickingarea addto load chunks;fillorsetblockto build the scene;summon, or a powered dispenser for projectiles;testforblock, ortestfor @e[...,x=,y=,z=,dx=,dy=,dz=], to read the result.
Pipe the same script into the bare
bedrock_serverfor a vanilla baseline.- a fresh
- Use a clean environment. A dev venv loads every plugin installed in it as an
entry point. For a clean run, and for Linux,
pip install endstone==<version>in apythoncontainer. Point it at the extracted BDS zip with a matchingversion.txtso it skips the download. - Paths a player drives need a client. Write the repro as an in-server test in the
endstone_testplugin; find it withgit ls-files '*endstone_test/__init__.py'. An opped player runs/test.ctestandpytestnever load BDS. You cannot join a server or issue/test, so ask the user. - If it does not reproduce, change no code. Ask the reporter for:
- their OS and container;
- the output of
/pluginsand any add-ons in the world; - the log around one occurrence;
- whether plain BDS behaves the same.
2. src/bedrock disagrees with the binary (layout, vtable, enum drift)
This is the largest class by count. A reconstruction compiles whether or not it matches BDS. A wrong offset reads a neighbouring field, and a missing virtual dispatches to the wrong function.
- Field offsets. A member dropped from LevelChunk made
Block::getBiomereturn an unrelated biome or crash (950af2d8a). - Enum values. A new game rule shifted
SHOW_DEATH_MESSAGES(e66d9065e).ChunkStatelost two states, so>= Loadednever passed andChunkLoadEventwent silent (4c673704c).BlockPropertywas renumbered (39bb2498a).Undeadlacked itsMobbit (5a4d5dc5e). Check every enumerator's value, not just the count. - Virtual count. A missing virtual sent
/statusinto the wrong function (9dcc3272b). - Objects Endstone builds and hands to BDS.
BlockChangeContextgained a bool, so BDS read past every Endstone-built instance (39bb2498a). - A hook bound to a function that no longer exists. 1.26.51 split
_loadMapDatainto_deserializeMapDataand_publishMapData. The bump kept the old name and cut a pattern that matched_deserializeMapData, which returns aunique_ptrthrough a hidden pointer. The hook took that pointer for the map, so it was never null and the map id came from the caller's stack. Every deferredMapInitializeEventtask then re-queued itself (#537,7ad256cc1). A hooked return value that is never null is the tell.
Detect drift with bump-bds and sweep it against headers with reconcile-headers.
Model members with their real types, never with manual padding, and pin sizes with
BEDROCK_STATIC_ASSERT_SIZE(T, win, linux). Derive the Linux size separately rather
than copying the Windows one, for two reasons:
- libc++'s
std::stringis 24 bytes against MSVC's 32. - Itanium packs a derived class into its base's tail padding (
4fe727f20,d46e8473b).
3. A wrapper outlives the BDS object (stale reference)
BDS frees and recreates objects on its own schedule, and a plugin, especially a Python one, may hold an Endstone wrapper forever. Any wrapper that caches a raw pointer or reference into BDS is a use-after-free waiting to happen.
- Block states cached
::BlockActorandBlockSource(ceb33198f). - Inventories cached
::Container(72d9d79c8). MapViewheld aMapItemSavedData&, which BDS erases and recreates per id (5a49f8bda).Effectstored anIdentifier, which is a pair ofstring_views pointing into the pybind11 caster's temporary buffer (e4b5cbe4f).
Fixes follow from that:
- DO store an identity (an id, a position plus dimension, or an entity handle)
and resolve it on every access. Throw
"Trying to access a <thing> that is no longer valid."when it is gone. Check the type when re-resolving, because a sign replaced by a chest must raise, not reinterpret the bytes (ceb33198f). - DO capture once, at construction, any value that must survive teardown (the
player address in
14da6800e). - DO own strings in public value types.
- DO NOT cache
BlockSource,Container,BlockActor,MapItemSavedDataorLevelChunkpointers in a wrapper.
4. An exception escapes into BDS
Nothing up a BDS call stack catches. A throw out of a hook, or out of core code that
BDS called, aborts the server with 0x40000015. Calls a plugin makes are already
wrapped, so this only bites core-initiated paths.
- Core fan-outs over plugin-held objects must tolerate a dead handle. A retained
Playercrashedbroadcast(d5ff6d115). NowsendMessagedoes nothing on a dead handle, andisOpfalls back to the last known value. Identity getters (getName,getUniqueId) still throw by design. - DO NOT
std::abort()or fall off the end of a non-void function (811e211ac). Throw where the plugin can catch it. - Report "not found" the way the return type allows, such as a null or an
invalid handle, and let the caller decide what absence means (
addd3f478). Refuse to construct a wrapper over a null handle (4ae5123bd). Never dereference a missed lookup (c4c683ed4).
5. A reimplementation in src/bedrock diverges from BDS
src/bedrock contains real bodies of BDS functions that run in-process: inlined
helpers, hashers, operators, and functions reimplemented so they can be hooked. They
drift silently.
removeFromObjectivenever erased the score, which left a freedIdentityDefinition*that the next save walked (#539,4be6a165f).std::hash<ActorUniqueID>masked 24 bits where BDS masks 32. Every lookup into a BDS-owned map missed, and a re-queuing task took 95% of the tick (c54592af5).Actor::hasTypecompared the whole value instead ofTypeMask, soPlayerPickupArrowEventnever fired (8824fae10).- An
operator==branched on the wrong type, and a constructor left half the key uninitialised (78a7ea71e). - Block lists copied from
LeavesBlock::randomTickfell behind, so poplar leaves decayed next to their trunk (43d537e60). - The NBT reader had five divergences, including swallowed load errors
(
bed530ed2).
Fix it by decompiling the BDS function at the target version and lining it up against ours. Check:
- the order of operations;
- masks and integer widths;
- which branch is taken;
- what is initialised;
- whether a key is copied to a local before a loop that frees its storage (an aliasing bug).
Then sweep the rest of the file. Where BDS exports the function, call it by symbol
instead of keeping a copy: the hand-cloned BlockActor::loadStatic had dropped two
steps (#503). Re-check lists and tables copied from BDS on every bump, because they
go stale without a compile error.
6. An event fires at the wrong time, or never
The hook point defines what the event means.
It never fires:
- BDS inlined the hooked function. When the movement-correction system was
inlined,
PlayerMoveEventmoved to thePlayerAuthInputPackethandler (83759305d). Check that the hook still resolves to a function that runs. - An enum or mask diverges (§2, §5).
- A subclass Bukkit covers is skipped.
ActorDeathEventignored players althoughPlayerDeathEventderives from it (2fad9f9eb). - The BDS event has no cancel channel. In that case, own the packet handler and
fire before the vanilla call (
0fbddfeec).
It covers only one path:
- DO hook the function every path funnels through, the one BDS itself calls, not
the client packet behind one of the paths.
PlayerBedLeaveEventfired from the leave button only. HookingPlayer::stopSleepInBedcovers morning, a broken bed and every other wake-up (52ed4043d).
It fires when it should not:
- Query calls.
InteractComponent::getInteractionalso runs withmNoCaptureset, just to fill in the interact text. Gate onshouldCapture()(cf3cb4113). - No-op inputs: the same slot (
e399567bc), an empty item (#528,a4965c076), or a book with no user data (dcae14bfd). - After an earlier event was cancelled. No
PlayerTeleportEventafter a cancelledPlayerMoveEvent(660113a22), and noActorRemoveEventafter a cancelledActorSpawnEvent(074281ec6). - Off the server thread. Synchronous events are rejected there.
BlockFormEventflooded the log during chunk instaticking until it was guarded on!isInstaticking()(3946f6420).
It reports the wrong payload:
- DO observe the value, never derive it.
PlayerLevelChangeEventcomputed the old level from the requested delta, which a clamp makes unrecoverable. Reading the level on either side ofPlayer::addLevelsfixed it (4cd803f16). - Read the field the server itself uses. The bed comes from
BED_POSITIONentity data, not from the respawn point (52ed4043d).
Mechanics:
- To re-enter BDS without re-firing your own event, call
ENDSTONE_HOOK_CALL_ORIGINALdirectly. - To pass one bit from core to a hook, tag the entity with an empty component from
flag_components.h. Do not add athread_localor a helper namespace. - On
develop, packet hooks areEndstonePacketHandlerspecializations inbedrock_hooks/packet.cpp. Callhandle()to forward to the vanilla handler, or return without calling it to drop the packet.
7. Cancelling leaves the client out of sync, or side effects still happen
The client predicts its own actions, and server-authoritative inventory has often committed the change before the event fires. Skipping the BDS call is not enough.
- Dropped items. The item stack request had already taken the stack, so a refused
drop left the item nowhere. Put it back in the slot (#375,
279558cb2). - Book edits. Re-setting an identical stack is a no-op, because
setPlayerContainerreturns early on a match. Clear the slot and then put the book back, which forces a resync. With text filtering on, BDS applies the edit later from a callback, so only patch the slot when it holds what you predicted (dcae14bfd). - Movement. A cancelled position-only move sends a correction packet. A cancelled
jump or rotation needs a teleport (
83759305d). - Damage. Knockback was still applied after the damage event was cancelled
(
7181ee3a7). Lowered damage bypassed invulnerability frames (ad4d3ed51). - Commands. A cancelled command was still logged (
0719ae587).
After any cancel fix, check in game that the client shows the server's state and that every follow-on effect is suppressed: knockback, logs, broadcasts and dependent events. Resync through a vanilla path such as a forced set or a correction packet, not raw bytes.
8. The right object, the wrong value
- Wrong overload.
Potion::getDescriptionId()returns a raw token, and thePotionTypeoverload builds the lang key (ee0304bea).BlockTypereturned the base id wherebuildDescriptionId()is what clients resolve (04cead1ab). - Semantics read backwards.
ChunkSource::LoadMode::Nonemeans "do not load" (66e2774e9). - Disjoint storage. BDS keeps players in a vector separate from
ActorManager::mEntities, sogetActors()never saw them (a55ff5803). - Transport assumptions. Downcasting to RakNet types on NetherNet read a member
that object does not have (
4b84239a5). Go through the base types both transports share. - Truthiness on a valid zero.
if (tag.getInt(k))is false forORIGINAL. Usecontains()(04cead1ab). - Lossy round-trips. Rebuilding a list from scratch dropped each book page's photo
and filtered text (
918e6ad72). It also dropped a map's marker flag (d93f56fcc) and server-list fields Endstone does not model (35e3c33a2). DO rewrite only the fields you model and pass everything else through. - Vanilla settings ignored:
SHOW_DEATH_MESSAGES(bfdc73067),SEND_COMMAND_FEEDBACK(064027b78), thedamage_sensorcomponent (da68c2947). - Bukkit semantics. Paper's metadata getters return copies (
dcae14bfd).isValid()meansisAlive() && valid, andgetHandle()still reaches a removed actor (7e8d31f8b). On quit the order is the event, then the disconnect, then the message (d5ff6d115).
9. Works on one platform only
- Key functions and vtable emission. If a class's only virtual is the one you
hook, the hook becomes its key function and clang emits the vtable in our object.
That drags in base destructors that are never defined, so define the base destructor
out of line (
75feefb7d) or declare a key function (9ea8c42bf). MSVC never emits that vtable, so Windows links fine and Linux does not. - Unqualified virtual calls inside a reimplementation. On Itanium such a call
dispatches through our vtable at the wrong slot. Qualify it (
260121626). - Virtuals introduced in a secondary base.
ENDSTONE_HOOK_CALL_ORIGINALmust name the declaring base's member pointer, and MSVC and Itanium adjustthisdifferently. Prefer calling the virtual from an already-hooked non-virtual function. - Type identity across shared objects. On Linux,
std::type_indexand typeinfo addresses differ betweenlibendstone_runtime.so, the Python extension and every plugin. Compare mangled names instead (c4c683ed4). Neverdynamic_castacross plugins. - Static initialisation order. A namespace-scope
std::thread::idwas re-zeroed after the library constructor recorded it. Use a function-local static (0c5fd2d64). - Includes. clang-cl does not pull standard headers in transitively, so include what you use.
10. Python binding bugs
- Wrong or missing bindings.
disable_pluginwas bound toenablePlugin(70969ca0d). Some APIs were documented but never bound (e8910bde2). An unterminated)doc"swallowed the next.def, which still compiled (27cc2e04d). - Bases and registration order. Register the C++ base, or
isinstancedisagrees with the C++ hierarchy (e8910bde2). Register a base before its subclasses. When two classes reference each other, declare bothpy::class_handles before adding any.def. - Downcasts. Add new subclasses to
polymorphic_type_hook(9fbb1974c). - Casters. A caster must throw for a right-typed but wrong-valued argument, and
return
falseonly for a type mismatch, so overload resolution still works. Never usePyErr_SetStringfollowed byreturn false(580153955). - Unregistered types. Cast through the bound type:
std::ref(*this)deduced the unboundEndstoneServer(dccb890f4). - Hashing.
__hash__must agree with__eq__. Types that compare equal to their id string hash that string (32c6d3fc5). - Reference cycles. A
std::functionholding a Python callable that captures the wrapper is never collected. Clear it on disconnect (52990325c). - Stubs. Regenerate them after any binding change, because CI fails on a stale
.pyi.
11. Plugin lifetime and /reload
- Release plugin-supplied code before its module is unloaded. Anything holding
code a plugin supplied (a
std::function, a service, a metrics chart, a task or an event handler) must be released first. Unregister these on disable (36da53f9b,492f3175c). Inreload(), clear them beforeclearPlugins(), because that call unloads every C++ plugin module. A late release jumps into unmapped code. - Destroy loaders in reverse load order (
9244bd1bb). - Never hold the scheduler lock and a task's lock at once. Collect the targets
under the lock, then act on them after releasing it (
62f8d63c8).
12. A client can crash or hang the server
- Untrusted input needs BDS's bounds. Input that reaches an Endstone
reimplementation must be bounded the way BDS bounds it: NBT nesting depth
(
9462d2e9c), certificate chain sizes (da9b2316c), ACK/NAK ranges (f6f095398). When BDS already bounds the input itself, put the guard in theraknetrecipe patch rather than in a hook. - Close connections with
NetworkSystem::setCloseConnection, nevercloseConnection, which runsonConnectionCloseda second time over freed objects (ccdef427f). - Never hand-write wire bytes. Reconstruct the packet and build it with
MinecraftPackets::createPacket.
13. Land the fix
- Branch. Fix on the line where users see the bug, then
cherry-pick -xto the other line. Before porting back, check that the commits the fix builds on exist there too. If the port needs an API or ABI change, leave the fix ondevelop. - Verify. Build both platforms when a layout changed, because the size asserts are
the Linux check. Run
ctestandpytest, run the in-server/test, and run the reporter's repro in game. Say what you verified and what you did not. - Commit. Write a
fix(<scope>): <what works now>subject. Write the body in prose: what was wrong and what users saw, the mechanism, the BDS evidence (version and address), and the change. End withFixes #NorCloses #N. Never add aCo-Authored-Byline for Claude. - CHANGELOG. Add one user-visible
Fixedline ending in(#N). Add nothing for internal-only fixes or for regressions that were never released. - Record what you learned. When a fix teaches a new class or a new tell, add it to this skill.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

