Trace item movement through time.
ItemGraph is a server-side Minecraft moderation and forensic analysis mod for NeoForge and Fabric 1.21.1. It answers the question ordinary grief loggers cannot: given the recorded evidence, how did this item plausibly move from one place to another?
Players do not need the mod on their clients. ItemGraph records native server evidence into its own database — plausible item-type and stack-quantity movement across players, supported vanilla containers, and ground/entity observations over time, plus a native audit ledger for non-item events — and builds an explainable temporal item-flow graph from it.
New here? Start with the admin quick start — it maps common incident questions to the exact command that answers each one.
ItemGraph keeps four kinds of results strictly separate, on every line of output and in every stored row:
| Label | Meaning |
|---|---|
OBSERVED |
A specific event or inventory delta was directly recorded. |
INFERRED |
ItemGraph linked observations under deterministic temporal, quantity, metadata, endpoint, and candidate rules. An explanation, not a direct observation. |
AMBIGUOUS |
Multiple targets or candidate flows fit. The candidates are shown; nothing is silently picked. |
UNRESOLVED |
The event is known, but its cause, destination, or relationship cannot be safely claimed. |
Two rules follow from this:
- ItemGraph reconstructs item type / metadata / quantity flow. It does not assign a permanent UUID to every physical item, and a matching fingerprint never proves two stacks are the same physical item.
- Unless creation, destruction, or transformation evidence exists, inferred
flow must conserve quantity. Every inferred edge links back to the exact
evidence IDs and deterministic scoring factors behind it — ask
/ig explain <edgeId>.
An empty query result means no matching stored row exists. It does not prove nothing happened; the coverage limits list event families that are not yet captured.
Releases ship exactly two files. Pick the one matching the server's loader — NeoForge is the primary loader and Fabric is also supported.
itemgraph-<version>-neoforge.jaritemgraph-<version>-fabric.jar
Place the jar in the server's mods/ folder and restart. ItemGraph targets
Minecraft 1.21.1 on dedicated servers.
ItemGraph replaces GriefLogger — the two mods must not be installed
together, and each loader declares the conflict in its metadata (NeoForge
incompatible, Fabric breaks). Both jars embed a SQLite driver in a way the
module system cannot deduplicate, so coexistence was never a stable state. The
0.4.0-beta.1 release published two -grieflogger-compatible jars as the
final coexistence artifacts; they are deprecated and no later release ships
them.
ItemGraph runs independently of GriefLogger. Native capture, storage, reconstruction, and native queries require neither the GriefLogger jar nor its database. Fabric and NeoForge use loader-specific event adapters over the same ItemGraph ledger. Native replacement coverage is tracked in GriefLogger replacement parity.
A separate read-only migration bridge can import legacy evidence when
explicitly enabled. It is disabled by default and never probes database.db
on its own.
- Stop the server.
- Remove the GriefLogger mod jar. Keep its
database.dbfile. - Install the standard ItemGraph jar for the loader.
- Enable the bridge: set NeoForge
general.grieflogger_integration_enabled=trueor Fabricgrieflogger_integration_enabled=true, and setgrieflogger_database_pathto the retained GriefLogger database. - Restart, then run
/ig ingest historyto queue the import. The source database stays read-only; ItemGraph writes imported rows and reports only to its own database.
Only the GriefLogger 1.2.10-1.21.1 schema is a tested import source; other
versions are rejected cleanly rather than mis-imported. Queries over imported
legacy rows require a completed source sync/import. Full procedure:
GriefLogger integration.
ItemGraph-owned storage defaults to SQLite — most servers need no database configuration at all. The full key, default, range, and restart matrix is in the configuration reference; the essentials:
| Goal | Setting |
|---|---|
| MySQL/MariaDB instead of SQLite | database_backend=mysql_mariadb plus database_host, database_port, database_name, database_username, database_password, database_ssl_mode, database_connection_timeout_ms |
| TLS to MySQL/MariaDB | database_ssl_mode=verify-full for production (use verify-ca with an explicitly trusted CA); verify-full/verify-ca are required for MySQL caching_sha2_password. disable is intended for a server authentication method that does not require RSA key retrieval, keeps database traffic plaintext, and warns when used with a non-loopback host |
| Optional non-unique lookup indexes | Enabled by default. Set NeoForge storage.use_indexes=false or Fabric use_indexes=false and restart to drop them; set true and restart to recreate. Required unique indexes stay for deduplication; MySQL/MariaDB also retain an index when it alone supports a foreign key |
| Query page size | Output defaults to ten rows, capped by query.max_page_size/max_page_size (range 1–100) |
NeoForge's database connection keys are under general; the index setting is
under storage in its server TOML. Raw evidence retention is fixed at
indefinite; ItemGraph does not purge raw evidence. Legacy V3–V5 topology
resets preserve old observation rows and their raw payloads in
ig_legacy_observation_evidence; those superseded rows remain available for
forensic review and are excluded from current graph queries.
/ig status
/ig audit
/ig status starts with an ACTION line — a safe next step when a
database/capture stop is reported, or a warning that no stop was reported
(capture coverage is still unproven). captureState=ACTIVE confirms the
capture path is open; it does not prove every event type is supported.
/ig audit checks stored-data invariants off-thread. Before trusting an empty
search, confirm capture was active and the event type is supported — the
admin quick start has the full status-field table.
Native ItemGraph event capture starts automatically when enabled in config.
/itemgraph and /ig are the same root. Every command requires
itemgraph.command plus its exact leaf nodes where listed. Unset named
permissions fall back to vanilla permission level 2; permission providers can
delegate each sensitive surface by exact node, nodes do not inherit through
dotted names, and an explicit permission-provider denial overrides operator
status.
Run /ig help permissions for the exact access nodes; the full contract is in
Security and permissions.
/ig help [topic]
/ig help permissions
/ig status
/ig audit
/ig ingest now
/ig ingest history
/ig event <observationId>
/ig explain <edgeId>
/ig lookup <eventType> [limit] [sinceMinutes]
/ig lookup near <dimension> <x> <y> <z> <radius> <eventType> [limit] [sinceMinutes]
/ig lookup player <playerName> <eventType> [limit] [sinceMinutes]
/ig lookup page <page> <eventType> [limit] [sinceMinutes]
/ig lookup action.<value> [user.<value>] [include.<value>] [exclude.<value>] [time.<value>] radius.<value>
/ig lookup provenance <sourceSha256> <table> <sourceKey> [limit]
/ig page <page> [session]
/ig trace item <query> [limit] [sinceMinutes]
/ig trace player <playerName> [limit] [sinceMinutes]
/ig trace container <x> <y> <z> [limit] [sinceMinutes]
/ig gui item <query> [sinceMinutes]
/ig gui player <playerName> [sinceMinutes]
/ig gui container <dimension> <x> <y> <z> [sinceMinutes]
/ig inspect [on|off|status]
What each one is for:
/ig help: bare/itemgraphor/igshows a short task-first overview./ig help commandsis a compact task hub that points to detailed topics;/ig help <topic>provides exact routes, syntax, and examples where applicable. Unknown topics suggest the closest matches and point to/ig help commands./ig audit: performs off-thread verification of database invariants (conservation, positivity, relational graph integrity, and allocation state consistency)./ig trace item: accepts numeric fingerprint IDs, item registry names, or custom item names. Quote namespaced IDs or names containing spaces (for example,/ig gui item "minecraft:netherite_boots"); use/ig gui item "id:123"to force an exact fingerprint ID when a bare numeric query is ambiguous. Shows supported chronological lineage, including anvil transformations. Craft/smelt outputs with unobserved inputs remain unresolved audit events and do not create trace edges./ig trace player: shows all movements involving a player across inventories, ground drops/pickups, containers, and armor stands./ig trace container: reconstructs item ingress and egress for a container at coordinates(x, y, z)./ig event,/ig explain, and/ig trace: preserve their stable visible text and provide bounded hover fields for evidence class, safe item identity, canonical fingerprint hash, event kind, UTC time, and recorded endpoints. Recorded spatial endpoints include a player-only, one-use[Go to ...]link; it rechecks the originating query permissions when clicked and works only while that dimension is loaded./ig gui: opens item/player/container timelines in a vanilla six-row chest menu. Each page has at most nine entries. A numbered chat companion identifies each row by evidence class, safe item identity, event kind, and UTC time when available; row numbers match menu slots. Hover text and icons add detail. In a selected detail page, hover each paper icon to read its field; use the page controls and Back button to navigate. Ambiguous targets require candidate selection; missing identities have an explicit fallback. The command and every menu action requireitemgraph.command,itemgraph.gui, anditemgraph.audit; see Security and permissions. The menu uses no custom client screen or packet and rejects inventory-movement actions./ig inspect: toggles per-player inspection mode. Left-clicking a block shows that block's paginated audit history in chat. Right-clicking a block entity that implementsContaineropens the read-only flow browser instead of the normal container GUI. Double chests clicked on either half resolve to the same canonical anchor used when their contents are recorded. Other right-clicks show paginated block history; ordinary blocks select the block on the clicked face. A click is consumed when its read-only request is accepted and when the request is denied for a missing grant — denied inspection clicks must not break or toggle blocks — while transient rejections and rejected container right-clicks preserve vanilla interaction.on,off, andstatusare deterministic forms. The command and each inspection click requireitemgraph.command.inspect; an inspection click on a container also requiresitemgraph.gui. Permission loss disables inspection mode, tells the player why, and consumes the click that detected it. Consumption covers the click's whole packet set — the block use, the off-handuseItemOn, the item-use twin packet, entity right-clicks (interact/interactAt, denied and recorded asINTERACT_ENTITY_DENIEDevidence), and entity left-clicks (attacks, denied and recorded asATTACK_ENTITY_DENIEDevidence) — so held or off-hand items, armor stands, shears, milk buckets, and name tags are never used on the inspected scene and no predicted hit can damage it, even on the revocation-detecting click; inspection does not record an inspection click as a transfer./ig lookup: a level-1 lookup-only moderator needs bothitemgraph.commandanditemgraph.command.lookup. Additemgraph.command.pagefor/ig pageand clickable page controls. Provider denies override operator level 2; unset nodes use the level-2 fallback. Use/ig help permissionsfor the other nodes./ig lookupand/ig lookup filtersreturn native or unified evidence, depending on the syntax. Historical reads are asynchronous and read-only. Native event capture runs automatically when enabled in config./ig ingest nowoptionally syncs from a configured GriefLogger source;/ig ingest historyis a separate read-only import from that source. Full argument table and output format: Query model.
Every result line is labeled with its evidence class — never once at the top, so a paste of the output cannot silently upgrade inference to observation:
[OBSERVED] CONTAINER 10,64,10 -> AlphaA : 1x at 2026-09-16 14:31:08 UTC (observation#8812 REMOVE_ITEM)
[OBSERVED] AlphaA -> GROUND 20,64,20 : 1x at 2026-09-16 14:31:18 UTC (observation#8813 DROP_ITEM)
[INFERRED conf=0.9990] AlphaA -> BetaB : 1x at 2026-09-16 14:31:18 UTC (edge#9931 inferred transfer spanning 1m0s)
[OBSERVED] GROUND 20,64,20 -> BetaB : 1x at 2026-09-16 14:32:18 UTC (observation#8814 PICKUP_ITEM)
A confidence value is a deterministic score computed from documented evidence
factors — not a calibrated probability that the history is true. /ig explain
shows the factors and candidate counts behind a link.
ItemGraph models item history as a directed temporal multigraph.
- Nodes represent inventories or locations capable of holding items.
- Observed events record direct evidence.
- Inferred edges connect compatible observations into plausible item flow.
- Time is a first-class constraint: later evidence cannot explain an earlier event.
- Quantity is conserved unless creation, destruction, or transformation evidence exists.
- Confidence is explicit and explainable.
Chest A --14:31, 1x named helmet--> Alice
Alice --14:52, 1x named helmet--> Ground
Ground --14:52, 1x named helmet--> Bob
Bob --15:08, 1x named helmet--> Chest B
Minecraft / Mod hooks / (optional) GriefLogger source
|
v
Raw observations
|
v
Evidence storage
|
v
Correlation / inference engine
|
v
Item Flow Graph
|
v
Query + explanation UI
When the optional migration bridge is enabled, confirmed cross-source copies
preserve both raw rows but contribute one quantity capacity; uncertain matches
remain ambiguous. Container GUI observations are session net deltas with
explicit time bounds, not click history, and generic IItemHandler rows keep
caller/cause identity UNKNOWN.
Existing grief and audit loggers answer who removed items from this chest or what was broken here. ItemGraph adds the reconstruction layer: given all available evidence, how did this named armor piece plausibly move from one inventory to another over the last two days?
The first useful vertical slice (the MVP contract) should:
- Read relevant GriefLogger evidence without mutating it.
- Record only missing high-value inventory events where necessary.
- Canonicalize an item fingerprint.
- Represent inventories as graph nodes.
- Represent raw observations separately from inferred movement.
- Reconstruct a simple item path through time.
- Trace a distinctive named item.
- Trace ordinary stack quantity flow.
- Explain why an inferred edge exists.
- Persist across restarts.
- Demonstrate the feature safely on staging.
Server messages can use en_us, nl_nl, or zh_tw through NeoForge
general.language or Fabric language. Text is rendered server-side for
vanilla clients; missing keys fall back to English. Help entry text and
navigation labels have translated entries; 174 authored source phrases
currently use the explicit English fallback inventory, including detailed help
topics. The exact GriefLogger 1.2.10-1.21.1 locale inventory is unknown;
supported ItemGraph locales are based on pinned 26.2 source config research
only.
Trusted server mods can use com.itemgraph.api PREVIEW_1 to register their own source
identity, submit bounded raw observations, and run asynchronous item/player/container
queries. The API is shipped in this JAR, uses a service-issued SourceHandle, and returns
immutable DTOs plus opaque evidence URIs—not JDBC, schema IDs, mutable Minecraft state, or
caller-provided inference. A compiling NeoForge fixture lives in examples/api-consumer.
The complete boundary and authorization rules are in Preview integration API.
- Name: ItemGraph
- Mod ID:
itemgraph - Primary command:
/itemgraph - Alias:
/ig - Platforms: Fabric, NeoForge
- Target Minecraft version: 1.21.1
- Primary deployment model: dedicated server
- Preview integration API:
com.itemgraph.apiPREVIEW_1in the main JAR - Changelog:
CHANGELOG.md - Tagline: Trace item movement through time.
For server admins and moderators:
- Admin quick start — incident question → exact command
- Query model — full command and filter reference
- Security and permissions — exact permission nodes
- Configuration reference — every config key
- GriefLogger integration — read-only history import
- ItemGraph event taxonomy — captured event types
For integrators and contributors:
- Preview integration API
- Architecture
- Evidence model
- Test plan
- Implementation plan
- Documentation writing contract
Records and project state:
- Business and intended value
- Decision log
- Milestones
- Complete GriefLogger and ItemGraph feature comparison
- GriefLogger schema versions
- GriefLogger source audit
- GriefLogger replacement parity
- UX audit
- Branding
- Collaboration policy
- Open-source policy
- Contributing
- Security policy
- Code of conduct
- MIT license
ItemGraph is developed in the open under the MIT License. External contributions use forks and pull requests. The configured non-publishing CI workflow runs on pull requests and pushes to main; release publishing remains a maintainer-only tag operation and never exposes release credentials to fork contributors.
Read CONTRIBUTING.md before opening a pull request. Report security issues privately using SECURITY.md.
Production must never be used as the development environment.
All discovery, schema inspection, testing, database exploration, and early implementation must happen on staging.
Evidence first. Inference second. Confidence explicit. Every conclusion traceable.