Handles & capabilities
Handles & capabilities
The entity, world, and nav handles goal callbacks receive — and the capability each op requires
Goal callbacks declared with declare_mob receive three handles as
positional arguments:
A handle is a thin, id-carrying value — it never holds a live entity pointer. Every access
re-resolves the entity on the owning region’s store on the tick goroutine, so reading a mob that
has since despawned returns a clean Starlark error (entity 42 no longer exists), never a stale
reference. Handles are built fresh per callback call; stashing one across calls is safe but it
still re-resolves on each access.
Every operation checks the owning plugin’s manifest capabilities at the operation boundary. A denied call raises a visible error:
The entity handle
The mob the goal is running for. str(entity) is <entity 42>; type(entity) is "entity".
Reads — require entities.read
Read methods
Mutations
Per-mob RNG and goal state — no capability required
The RNG methods draw from the mob’s own deterministic per-entity stream. Sulfur’s vanilla-mob plugins rely on this to stay in RNG lockstep with the ported Java code — a plugin-driven pig and a Go-native pig draw byte-identical streams.
The world handle
type(world) is "world".
The nav handle
The mob’s navigation. type(nav) is "nav".
path_to also accepts an advanced 31-float form (10 raw stroll candidates plus a land-mode flag)
used by the vanilla stroll-goal ports to hand candidate selection to the host. For custom mobs,
the 3-argument form is what you want.
Design rules the handles enforce
- Goals set targets; Go moves mobs. There is no raw position write. Movement always flows through navigation → physics → collision, so a plugin mob obeys the same movement rules as a vanilla one.
- Single-owner tick. Callbacks run on the owning region’s goroutine; handles resolve against that region’s entity store. A callback can only see its own region’s entities (matching the Folia-style region-ownership discipline).
- Reads return copies. Scalars and tuples only — no live references ever cross into Starlark.

