Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

AI: goals and brains

Verified against Minecraft 26.3 · Part VI · A villager’s day — wake, claim a job site, work until the schedule turns, walk home to bed — and the same tick under a zombie that has none of it.

It is dawn in a village. One villager climbs out of bed, walks to its composter and works there until the afternoon. Ten blocks away a zombie catches fire, sees the villager, and comes for it. Both are Mobs, both are driven by the same Mob.serverAiStep on the Server thread, and neither is running a script: each is being re-asked, every tick or every other tick, what it would like to be doing now. They are asked in two completely different ways, and the villager’s is the surprising one. Its day looks like a timetable held on the villager, and it is not one. A Brain holds an EnvironmentAttribute of Activity — a pointer into the world rather than a table on the mob — and Brain.updateActivityFromSchedule asks the EnvironmentAttributeSystem what that attribute’s value is at this position, at this time. The villager goes to bed because it asked the world what hour it is where it is standing. The answer comes out of a data-pack Timeline, Timelines.VILLAGER_SCHEDULE: a 24000-tick loop whose adult track names the tick each activity starts — idle at 10, work at 2000, meet at 9000, idle again at 11000, rest at 12000 — beside a baby track that swaps play in. Because the lookup takes a position, the day can in principle differ by location. That system is environment attributes and timelines; this page only asks it a question.

The cast

classwhat it decidesthread
GoalSelectorwhich goals run, by holding a four-entry table of Goal.Flag to the goal that owns itserver, from Mob.serverAiStep
Goalwhether it wants to run, whether it may be interrupted, and which flags it needsas above
WrappedGoalthe arbitration — WrappedGoal.canBeReplacedBy — plus the priority and the running bitas above
Brainwhich activity is active, what the memories hold, and which behaviours may start at allserver, from Mob.customServerAiStep
MemoryModuleTypethe vocabulary a brain thinks in: 115 constants, of which the 52 with a codec are the mob’s entire saved minddeclared, never ticked
Sensorwhen to look at the world, on its own scan rate, and which memories to writeserver, from Brain.tick
ActivityDataone activity’s prioritised behaviour list, its memory requirements, and the memories erased when it stopsbuilt per body by Brain.ActivitySupplier
Sensingwhether this mob can see that entity, memoised for exactly one tick — and both systems go through itserver, cleared at the top of Mob.serverAiStep

Seven things they do differently

the goal selectorthe brain
what holds the stateGoalSelector.availableGoals, an insertion-ordered set of WrappedGoal, beside a lock table and a set of disabled flagsa memory map, a sensor map, and Brain.availableBehaviorsByPriority — priority to activity to behaviour set
what fills itMob.registerGoals, once, from the constructor, and only when the level is a ServerLevelBrain.Provider.makeBrain, from an activity list built per body — and, for a villager, built again when its body changes
what decidesGoal.canUse, re-asked on every other tickBehavior.hasRequiredMemories then Behavior.checkExtraStartConditions, asked once a tick
what arbitratesthe flag table. Lower priority number wins a contested flag, and a non-interruptable incumbent wins outrightthe active activity. A behaviour whose activity is not active is not started at all
what persists across a savenothing. Not the running set, not the flags52 of the 115 memories, through Brain.Packed
what the world can push inMob.updateControlFlags every five ticks, and the leash, both on one selector onlythe schedule attribute, POI claims, hostiles seen by sensors, Attributes.FOLLOW_RANGE
which mobs use itevery Mob ticks one, and almost every mob without a brain fills it. 58 goal classes and 10 targeting ones20 classes override LivingEntity.makeBrain — but only Villager sets a schedule

Where both of them sit in one mob tick

The profiler section names, because they are what a profile shows:

LivingEntity.tick
  LivingEntity.aiStep
    "ai"               the guard: server side, and Mob.isEffectiveAi
      "newAi"          Mob.serverAiStep
        "sensing"        Sensing.tick — the line-of-sight memo is cleared
        "targetSelector" ┐ GoalSelector.tick on the full pass,
        "goalSelector"   ┘ tickRunningGoals(false) on the off tick
        "navigation"     PathNavigation.tick — see pathfinding
        "mob tick"       Mob.customServerAiStep → "villagerBrain" → Brain.tick
        "controls"       "move" / "look" / "jump"
    "jump"             LivingEntity's own jump handling — outside the guard
    "travel"           LivingEntity.travel — where the body actually moves
  "headTurn"           Mob.tickHeadTurn — no side check, so both sides

Note the scope of that guard. LivingEntity.aiStep runs on the client too; what it wraps in server side and effective AI is the one call to Mob.serverAiStep, not the jump and travel sections beneath it. Mob.isEffectiveAi is the more interesting half of the condition, and what it is — one of five predicates that decide which copy of an entity may do anything — belongs to authority. What belongs here is the guard’s scope. On the client neither selector nor brain is ticked at all — only the jump, travel and head-turn sections beneath the gate, and the debug renderers.

Each of the seven rows of that table is a section below, in the table’s own order.

What holds the state

GoalSelector holds three things and none of them is a plan: a set of WrappedGoal, a map from Goal.Flag to the goal currently holding it, and a set of flags that have been switched off. There is no state machine and no sequence. The only persistent state a goal system has is which goals are running and which flags are held, and a Mob keeps two independent copies of it, Mob.goalSelector and Mob.targetSelector.

A Brain holds a great deal more, and the piece to keep hold of is Brain.availableBehaviorsByPriority: a sorted map from priority, to activity, to a set of BehaviorControl. Priority is the outer key, so the whole brain is walked in priority order regardless of which activity a behaviour belongs to. Beside it sit the memory map, the sensor map, the per-activity requirements, the per-activity erase lists, the core activities, the active set and a default of Activity.IDLE.

Two things about ownership surprise people. Brain is declared on LivingEntity, not on Mob — every living entity has one, the player included, and the base implementation hands back an empty one that reports itself Brain.isBrainDead. And the activity list is not static: a Brain.Provider is what builds a brain, and it asks its Brain.ActivitySupplier for that list per body, which is how a villager’s profession selects its work package.

What fills it

Goals go in once, for almost every mob. The Mob constructor calls Mob.registerGoals only when the level it is being built into is a ServerLevel, so a client-side mob’s selectors stay all but empty for its whole life (a few mobs add a goal from the constructor or from loaded data, which nothing on the client ever ticks). After that the set is fixed, but for the few mobs that add or remove a goal on a state change.

Memories are filled continuously, by sensors and by behaviours alike. A Sensor looks at the world and writes what it saw: the default scan rate is 20 ticks (Sensor.DEFAULT_SCAN_RATE), GolemSensor uses 200 and SecondaryPoiSensor 40, and Sensor.randomlyDelayStart offsets each one at construction so a village does not scan in lockstep. What registers a memory slot is declaring it — every memory a sensor lists in Sensor.requires and every memory a behaviour names in its entry condition is registered when the brain is built. Reading one that was never registered throws Unregistered memory fetched: a behaviour has been installed on a mob that has no idea what it is talking about.

The two systems share one piece of machinery here, and it is easy to file under the wrong heading. Sensing is the per-mob line-of-sight memo, cleared once per tick at the top of Mob.serverAiStep, and it is not the goal system’s alone: TargetingConditions.test routes every line-of-sight check through Mob.getSensing, and the shared conditions the brain’s sensors use have that check on by default.

Those shared conditions deserve a second look. Sensor holds six static TargetingConditions objects, used by every brain mob in the world, and re-ranges all six from this body’s Attributes.FOLLOW_RANGE immediately before every scan. That is correct only because AI is strictly single-threaded — there is not a future, an executor or a thread anywhere in the AI packages — and it is about as clear a demonstration of the fact as the codebase offers.

What decides

A goal is asked Goal.canUse every other tick, staggered across mobs by tickCount + id, with an exception for a mob’s first tick, where the full pass runs whatever the parity. On the off tick GoalSelector.tickRunningGoals is called with false, so only goals that answer Goal.requiresUpdateEveryTick are ticked at all — and, more importantly, no goal is stopped, because the Goal.canContinueToUse sweep lives in the full pass. A goal that lost its reason to run on an off tick keeps running until the next even one.

The full pass, GoalSelector.tick, is three phases, and they are the next level down in a profile. goalCleanup stops every running goal that either holds a now-disabled flag or fails Goal.canContinueToUse, then drops every lock whose holder is no longer running. goalUpdate walks the set again and starts anything that is not running, holds no disabled flag, can take all its flags, and answers Goal.canUse. goalTick — reached through GoalSelector.tickRunningGoals with true — ticks the survivors.

A behaviour is asked once per tick, and the first question is not about the behaviour at all. Brain.tick runs four fixed phases in order: Brain.forgetOutdatedMemories, where every MemorySlot counts down and an expired one clears itself; Brain.tickSensors, where each Sensor counts its own scan rate down before it looks at anything; and then the two that walk the behaviours, Brain.startEachNonRunningBehavior over Brain.availableBehaviorsByPriority lowest number first, and Brain.tickEachRunningBehavior over everything now RUNNING. Both of those are complete sweeps, so what happens to one behaviour is two questions asked in two different phases of the same tick:

flowchart TD
    A["one behaviour, in one Brain.tick"]
    E{"is its activity active?"}
    F["never started"]
    G["Behavior.tryStart — its memories, then its extra conditions"]
    X["stays STOPPED until a later tick"]
    H["RUNNING, to a rolled end timestamp"]
    S["phase three ends, phase four begins"]
    J{"timed out, or Behavior.canStillUse false?"}
    K["Behavior.doStop, in the Brain.tick that started it"]
    L["Behavior.tick"]
    A -- "STOPPED" --> E
    A -- "already RUNNING" --> S
    E -- "no" --> F
    E -- "yes, and it is STOPPED" --> G
    G -- "either test fails" --> X
    G -- "both pass" --> H
    H --> S
    S --> J
    J -- "yes" --> K
    J -- "no" --> L

One behaviour through one Brain.tick. The two diamonds are the whole of this page: the first is asked in phase three and the second in phase four, and a one-shot, or a behaviour that keeps the default Behavior.canStillUse, ends at the second in the very tick it started.

The branch marked never started is what this page turns on. An activity is a filter, not a mode, and it filters starting: a behaviour already running when its activity leaves is still ticked, which is why SleepInBed checks the rest activity itself. The brain’s active set is always the core activities plus exactly one other, so Activity.CORE behaviours run at every hour of the day and switching activity only swaps the second half. (Core activities is plural in the API and singular in practice: nothing in 26.3 calls Brain.setCoreActivities with anything but Activity.CORE alone.)

The canStillUse branch is sharper than “a behaviour runs for one tick”. Behavior.canStillUse defaults to false, and phases 3 and 4 are both inside the same Brain.tick — so for a Behavior subclass that does not override it, Behavior.tick is not called once. Everything it does, it does in Behavior.start (a one-shot does its work in its trigger). The duration rolled at start between the behaviour’s minimum and maximum (Behavior.DEFAULT_DURATION is 60) matters only for the ones that do override it, which is why the same behaviour class configured with different bounds behaves differently in two packages.

What arbitrates

On the goal side, the flag table is the arbiter, not the priority list. GoalSelector.availableGoals is insertion-ordered and never sorted; priority only settles a contested flag. Two goals with no flag in common run together whatever their numbers, and two that share one never do. WrappedGoal.canBeReplacedBy is the whole rule: the incumbent must answer Goal.isInterruptable, and the challenger’s number must be strictly lower.

There is a small piece of craft in how that is arranged. GoalSelector never puts a placeholder in its lock table; it reads the table with a default — a sentinel WrappedGoal of maximum priority that reports itself not running — so this flag is free and this flag is held by someone worse than me are the same WrappedGoal.canBeReplacedBy call on an entry that may not exist.

On the brain side the arbiter is the active set, and the fallback is silent. Brain.setActiveActivityIfPossible checks the target activity’s memory requirements and, if they do not hold, calls Brain.useDefaultActivity instead. A jobless villager at tick 2000 is not “off schedule”: the switch to Activity.WORK fails its MemoryModuleType.JOB_SITE requirement and the villager is idle by construction. Switching is also not free — the brain first erases, for every activity leaving the set, the memories that activity’s ActivityData names as memoriesToEraseWhenStopped. It is one of the few places the brain mutates state rather than reading it.

What persists across a save

A goal system saves nothing. Which goals were running, which flags were held, how far through an attack a mob was — all of it is rebuilt from scratch when the chunk reloads and the constructor calls Mob.registerGoals again.

A brain saves Brain.Packed, and Brain.pack walks the memories keeping only those whose MemoryModuleType can serialise: 52 of 115, the remaining 63 transient by construction. Time-to-live travels with them, so a memory can expire across a reload as easily as within a tick — MemorySlot counts down in phase 1 of every Brain.tick and clears itself at zero.

The reason Brain.Packed exists as a first-class shape is that a brain is built more than once in a mob’s life. Villager.refreshBrain stops every running behaviour, packs the current memories, and runs the provider again from the packed state with a fresh activity list. Changing profession does that; so does growing up, which is how a baby swaps EnvironmentAttributes.BABY_VILLAGER_ACTIVITY for EnvironmentAttributes.VILLAGER_ACTIVITY.

What the world can push in

Into a goal selector, two things, and both of them work by switching a flag off rather than by asking for anything. The first is Mob.updateControlFlags, called from Mob.tick on the server every five ticks. It sets Goal.Flag.MOVE and Goal.Flag.LOOK from one question — is a Mob steering me — and Goal.Flag.JUMP from that and am I in an AbstractBoat. So a mob a mob is riding loses all three, and a mob sitting in a boat by itself loses only the jump.

The second is the lead in your hand. Leashable.tickLeash runs from Entity.baseTick (entity anatomy puts it among the capability interfaces), and when the mob is pulled past the distance a lead can hold, Mob.leashTooFarBehaviour breaks the lead and disables Goal.Flag.MOVE outright — so a mob that has just snapped its lead is not choosing to stand still, it has had the flag its movement goals need taken away — until Mob.updateControlFlags puts it back within five ticks. Both levers touch Mob.goalSelector only; Mob.targetSelector is never disabled. GoalSelector.tick then stops any running goal holding a disabled flag and refuses to start another.

Into a brain, rather more: the schedule attribute, whose value comes from the world; hostiles, players, items, beds and golems, all written by sensors that query the level; and POI claims, which go through the shared PoiManager (points of interest). And one attribute change reaches into the machinery itself: a new Attributes.FOLLOW_RANGE re-ranges the shared targeting conditions above and, through Mob.onAttributeUpdated, resizes how far the pathfinder may search (pathfinding).

Neither of them crosses the network

There is no AI packet. What a client sees are consequences — head rotations, motion, position deltas, pose changes, the occasional entity-event byte — plus a debug channel that costs nothing until someone subscribes: Mob.registerDebugValues registers DebugSubscriptions.ENTITY_PATHS and DebugSubscriptions.GOAL_SELECTORS for every mob, and DebugSubscriptions.BRAINS only for one that is not brain-dead.

And neither library is anything but more of the same

There are 103 classes at the top of world/entity/ai/behavior and 61 at the top of world/entity/ai/goal, and nearly all of them are one of the shapes above — a behaviour with its required memories and its start conditions, whether a Behavior subclass or a one-shot built with BehaviorBuilder, or a Goal with its flags and its Goal.canUse — beside a handful of the machinery that runs them and the value types they use. Reading a third is reading the first twice. The sensors are the same — 23 Sensor subclasses, each with a scan rate and a list of memories it writes, from TemptingSensor to PiglinSpecificSensor — and so are the eighteen *Ai classes, which hold the lists and, for the busier mobs, the helpers the lists call.

Nor is either of them data-driven. The villager’s day is data (Timelines.VILLAGER_SCHEDULE in Registries.TIMELINE) — but VillagerProfession is not — a BuiltInRegistries entry bootstrapped from code, with no directory under the built-in data pack, and neither is the PoiType it names (points of interest). And behaviours and goals are code too, plain Java lists in VillagerGoalPackages and the *Ai classes, not registered and not addressable from a data pack.

Which mobs use which

Every Mob has both fields, and almost every mob uses exactly one. Twenty classes override LivingEntity.makeBrain — Villager, Piglin, Warden, Hoglin, Frog, Allay, Axolotl, Goat and twelve more — and each keeps its behaviour lists in a class named for the mob: PiglinAi, WardenAi, FrogAi. There are eighteen such classes for twenty mobs, and the two exceptions are worth naming. Zoglin keeps its lists inline, in the mob itself. And Villager’s live in VillagerGoalPackages — genuinely the 26.3 name, and not a typo: it is the last survivor of the old convention, on a mob that has no goals at all. Nor do most of the other nineteen: a brain mob typically registers none.

One brain mob has a schedule: Brain.setSchedule has exactly two call sites and both are in Villager, picking the adult attribute or the baby one. The other nineteen never consult a clock: they call Brain.setActiveActivityToFirstValid, which walks a priority list and takes the first activity whose memory requirements hold. That is how PiglinAi picks fight over idle and FrogAi picks tongue over swim, with no time of day involved anywhere.

The brain’s trace: a villager’s day

Put the two phases together over one villager and the priorities become a clock. Four behaviours, in the order phase three reaches them:

sequenceDiagram
    participant Brain as Brain
    participant MTS as MoveToTargetSink
    participant AP as AcquirePoi
    participant UAFS as UpdateActivity<br/>FromSchedule
    participant EAS as Environment<br/>AttributeSystem
    participant SIB as SleepInBed

    rect rgba(0, 0, 0, 0.04)
    Note over Brain,SIB: one Brain.tick, phase three, ascending priority
    Brain->>MTS: priority 1, core
    Note over MTS: a wanted position leaves here for the pathfinder
    Brain->>AP: priority 6, core, which runs only while JOB_SITE is empty
    Brain->>UAFS: priority 99, last in the package
    UAFS->>Brain: updateActivityFromSchedule
    Brain->>EAS: getValue, VILLAGER_ACTIVITY at this position
    EAS-->>Brain: WORK, from tick 2000
    Brain->>Brain: setActiveActivity<br/>IfPossible
    end
    Note over Brain,SIB: with a job site held, the next Brain.tick is the first to run the work package
    rect rgba(0, 0, 0, 0.04)
    Note over Brain,SIB: after tick 12000, REST, which has no requirement
    Brain->>SIB: rest package, priority 3, once the walk home reaches the bed
    Brain->>SIB: tickOrStop, and again every tick until dawn
    end

A villager’s day as four behaviours in priority order; the two shaded bands are two ticks about ten thousand apart. The one to watch is the schedule behaviour at 99: it runs last, so the activity it asks for is the next tick’s — and Brain.setActiveActivityIfPossible takes it only if that activity’s requirements are met, and falls back to the default without saying so.

Read the priorities in that diagram as the ordering claims they are. The schedule behaviour is UpdateActivityFromSchedule, and it sits at 99, the last slot in every package that has one, so the activity a villager switches to is never the one the rest of this tick runs: the switch lands and the next tick acts on it. And it is only consulted when a behaviour asks — Brain.updateActivityFromSchedule refuses unless more than twenty ticks have passed since the last one. Five of the ten packages carry no such behaviour: core, panic and hide have nothing at 99 at all, and pre-raid and raid have ResetRaidStatus there instead. Core is never the activity a villager is stuck in, because it is always active alongside one other; the omission is how the other four pin the villager, and each carries its own way out rather than leaving it to the clock: VillagerCalmDown sits at priority 0 in the panic package and calls Brain.updateActivityFromSchedule itself once the fear memories clear, SetHiddenState does the same for hide, and ResetRaidStatus for the two raid packages. Nothing is asking the clock on a schedule; each escape hatch asks on its own terms, and the brain’s twenty-tick throttle meters them all.

The rest of the day hangs off that. Claiming a job site is AcquirePoi from the core package, and the claim itself — the scan, the best five, the one pathfind that decides which of them is reachable — belongs to points of interest, told there against a bed. A bell across a ravine is invisible to a villager. What is this page’s is what the memory then means: AcquirePoi writes MemoryModuleType.POTENTIAL_JOB_SITE, not the job site itself; AssignProfessionFromJobSite waits until the villager is within two blocks of that position, then erases the memory, writes MemoryModuleType.JOB_SITE and sets the profession if it has none — which is why walking to the workstation is a required step and not decoration, and why a villager that seems to be ignoring a perfectly good workstation is usually in one of three states rather than broken: it claimed the block and has not arrived yet, so the memory still says potential; the pathfind inside AcquirePoi failed and the site was skipped as unreachable; or it did not arrive within 1,200 ticks and GoToPotentialJobSite let the claim go. Three more behaviours can take a claim away afterwards — PoiCompetitorScan hands a contested one to the more experienced villager, YieldJobSite has a villager with no profession hand its claim to a neighbour whose profession works there, and ValidateNearbyPoi erases it when the block is gone.

Work is a weighted RunOne — one of the GateBehavior composites, which are behaviours whose children are behaviours — over six: WorkAtPoi (or WorkAtComposter), StrollAroundPoi, StrollToPoi, StrollToPoiList, HarvestFarmland and UseBonemeal; WorkAtPoi wants 300 ticks since the last check and 1.73 blocks or less to the workstation. Walking anywhere is MoveToTargetSink, entered on walk target present, path absent: it turns a MemoryModuleType.WALK_TARGET into a path, hands it to the navigation, and records a failure as MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE. Below that hand-off is pathfinding and then movement and collision. Bed is SleepInBed, whose entry conditions belong to the night shift. What matters here is that it is this page’s counter-example: it overrides Behavior.canStillUse, so, like MoveToTargetSink and unlike a one-shot, it is still running on the tick after the one that started it, and it overrides Behavior.timedOut to answer no, so it never times out. It ends when Brain.isActive for Activity.REST goes false at dawn.

The goal selector’s trace: the zombie

A Zombie has a Brain, because every LivingEntity does, but it is the base one — no memories, no sensors, no behaviours, Brain.isBrainDead true. Almost everything it will ever do comes out of Mob.registerGoals, run once in the constructor: seven goals in Mob.goalSelector — a turtle-egg attack goal, a SpearUseGoal, a ZombieAttackGoal, a MoveThroughVillageGoal, a WaterAvoidingRandomStrollGoal, a LookAtPlayerGoal and a RandomLookAroundGoal — and five in Mob.targetSelector, one HurtByTargetGoal and four NearestAttackableTargetGoals. Almost, because a zombie is one of the few mobs that adds a goal later: Zombie.setCanBreakDoors, rolled against local difficulty at spawn, inserts a thirteenth — a BreakDoorGoal at priority 1, above everything the constructor registered — and takes it out again when the flag is cleared.

Every other tick each of the twelve is re-asked, and the flag table settles it. The target goals hold Goal.Flag.TARGET and write Mob.setTarget. The attack goals hold Goal.Flag.MOVE and Goal.Flag.LOOK and drive the navigation, with SpearUseGoal at priority 2 sitting above ZombieAttackGoal at 3 — though it wants a spear in the main hand, so for most zombies the attack goal is the one holding them. LookAtPlayerGoal wants Goal.Flag.LOOK alone and RandomLookAroundGoal wants Goal.Flag.MOVE as well, and both lose to whoever already has them. No activity, no schedule, nothing persisted but a door-breaking flag, nothing the world can push in but the control flags and a neighbour’s alert: the zombie’s entire mind is a handful of running bits and one target field. Even that field is not read directly — Mob.getTarget filters through Mob.asValidTarget on every call, so a target that turned creative or spectator is gone the moment it is asked for, and nine of the brain mobs source theirs from Mob.getTargetFromBrain instead.

For a 1.21-era reader. There is no Schedule class in 26.3 and no schedule registry, so the file a villager’s timetable used to live in is gone. What replaced it is a Timeline in Registries.TIMELINE, read through an EnvironmentAttribute rather than off the mob: Timelines.VILLAGER_SCHEDULE is the data, Brain.setSchedule takes an attribute rather than a schedule, and the lookup now takes a position. Activity, MemoryModuleType, Sensor and the behaviour classes keep their shapes, and world/entity/schedule is a package that still exists and holds one class, Activity.

Where to look

The two systems have one entry point each and they are short: GoalSelector.tick, whose three phases are the whole arbiter, and Brain.tick, whose four are. Read WrappedGoal.canBeReplacedBy beside the first — it is the entire priority rule in one method — and Behavior.tryStart and Behavior.canStillUse beside the second, with OneShot, because between them they explain which behaviours see a second tick. Mob.registerGoals on any mob shows a goal list; VillagerGoalPackages shows what a brain’s lists look like instead, and Villager.refreshBrain is how one is rebuilt mid-life. Brain.updateActivityFromSchedule is the method the opening is about. Two doors: BehaviorBuilder, the DSL the one-shot behaviours, over half of them, are declared with, and Sensing, the one-tick memo both systems share.


Rules: names, never code · how the system works, not how the code reads · newest version only · every backticked name passes tools/verify_names.py.