Commands#
Every command lives under /vg. Two alias roots redirect to the same tree:
/co and /guardian. The /co alias exists so operators arriving from
CoreProtect do not have to relearn the prefix.
/vg <subcommand> [arguments]
/co <subcommand> [arguments]
/guardian <subcommand> [arguments]
Subcommands marked with a console badge may be run from the server console or RCON. Those marked with a player badge require a player — they need a position, an inventory, or an entity to act on.
Command index#
| Command | Aliases | Permission (default op) | |
|---|---|---|---|
/vg inspect |
i, inspector |
vonixguardian.inspect (2) |
player |
/vg lookup |
l, page |
vonixguardian.lookup (2) |
both |
/vg near |
— | vonixguardian.near (2) |
player |
/vg rollback |
rb, ro |
vonixguardian.rollback (3) |
both |
/vg apply |
— | rollback or restore |
both |
/vg cancel |
— | rollback or restore |
both |
/vg restore |
rs, re |
vonixguardian.restore (3) |
both |
/vg undo |
— | vonixguardian.undo (3) |
both |
/vg purge |
— | vonixguardian.purge (4) |
both |
/vg status |
stats, version |
vonixguardian.status (3) |
both |
/vg consumer |
— | vonixguardian.consumer (4) |
both |
/vg reload |
— | vonixguardian.reload (4) |
both |
/vg config |
— | vonixguardian.command.config (4) |
both |
/vg entitylog |
— | vonixguardian.command.config (4) |
both |
/vg teleport |
tp |
vonixguardian.command.teleport (3) |
player |
/vg give |
— | vonixguardian.command.give (4) |
player |
/vg migrate-db |
— | vonixguardian.migrate_db (4) |
console |
/vg help |
— | root: vonixguardian.base (2) |
both |
The op-level column is the vanilla fallback used when LuckPerms is absent. See Permissions for node resolution order and the per-node override map.
inspect#
/vg inspect
Toggles inspection mode for you. While it is on, left-clicking a block runs a position-anchored lookup on that block, and right-clicking a chest shows the container transactions recorded there.
/vg inspect ← enable
[VonixGuardian] Inspect mode ENABLED. Left-click a block to look it up.
/vg inspect ← disable
[VonixGuardian] Inspect mode disabled.
The inspector queries p:<x>,<y>,<z> r:2 t:30d r:#world_<key> — a 5×5×5 window
around the clicked block, 30 days back, scoped to that block's world so identical
coordinates in another dimension cannot leak in.
Player only
Console cannot inspect, because there is no block to click. Running it from
console returns Inspect mode must be run by a player.
lookup#
/vg lookup [<page>[:<perPage>]] [filters]
/vg l [<page>[:<perPage>]] [filters]
/vg page [<page>[:<perPage>]] [filters]
Searches the audit log. All filters are optional; with none, the query is unbounded in time and global in space.
Pagination. If the first whitespace-separated token is purely numeric, or
<n>:<m>, it is consumed as the page selector and removed from the filter:
/vg lookup 2 ← page 2, default page size
/vg lookup 2:20 u:Steve ← page 2, 20 rows per page
/vg lookup u:Steve ← page 1, default page size
Per-page is clamped to 1–50. The default comes from lookup.defaultPageSize
(7 as shipped), also clamped to 1–50.
Counting. #count returns a single total instead of rows:
/vg lookup #count r:50 t:24h
[VonixGuardian] Count: 3
No results. You get a hint rather than silence:
[VonixGuardian] No results found. Try a wider radius (r:20+) or longer time
(t:24h+), or check filter tokens.
Scan limit. A lookup whose permission-filtered page would have to scan more than 100,000 raw rows fails closed rather than paging through them:
[VonixGuardian] Lookup aborted: the permission-filtered page exceeded the
100000-row scan limit. Narrow the time, radius, or action filter and try again.
Full parameter reference: Filters & parameters.
near#
/vg near
A shortcut for lookup r:5 t:1h centred on you. It takes no arguments.
/vg near ≡ /vg lookup r:5 t:1h
Player only. Because it is a lookup, no default rollback radius is applied —
which changes nothing here, since r:5 is explicit.
rollback#
/vg rollback [filters]
/vg rb [filters]
/vg ro [filters]
Reverses the matching actions in the world. Each row's inverse is computed
(block_break → place the original state back, container_deposit → withdraw the
same stacks, and so on) and applied newest-first.
Default radius. If you supply no numeric radius and no world or WorldEdit
selector, rollback applies r:10 centred on you. This matches CoreProtect, and it
is the single most common surprise: a rollback you expected to be global was
scoped to 10 blocks. Use r:#global explicitly for a whole-world mutation.
/vg rollback u:Griefer t:24h ← 10-block radius around you
/vg rollback u:Griefer t:24h r:#global ← everything, everywhere
/vg rollback t:15m r:30 ← anyone, last 15 minutes, 30 blocks
Preview first. #preview renders the plan without touching the world:
/vg rollback u:Griefer t:24h r:#global #preview
Confirmation mode. If rollback.requireConfirm is true, every rollback stops
after planning and waits for /vg apply. The shipped default
is false, so rollbacks apply immediately.
Counting. #count plans without executing and reports the plan size:
/vg rollback u:Griefer t:24h #count
[VonixGuardian] Rollback count: planned=318 skipped=2
Progress. Long plans report every tenth page and at limit boundaries:
[VonixGuardian] Rollback planning: scanned=1200 planned=340 skipped=2
Result. Mutations report one authoritative summary line and, with #verbose,
a second line of id counts:
[VonixGuardian] Rollback SUCCESS affected=318 planned=320 skipped=2 failed=0
compensated=0 repairRequired=0 batchId=17 closed=true
| Status | Meaning |
|---|---|
SUCCESS |
Every planned step applied. |
PARTIAL |
Some steps applied; the rest were skipped. |
COMPENSATED |
A failure was rolled forward and the world was restored to its pre-mutation state. |
REPAIR_REQUIRED |
A step could not be applied or compensated. Rows are listed in vg_repair_required. |
FAILED |
Nothing was applied. |
A successful mutation that matched nothing extra says so, because the usual cause is a radius that does not cover explosion splash:
[VonixGuardian] Rollback found 0 matching actions. Explosions record their blast
CENTER — try r:20+ or move to the source of the damage.
#silent suppresses the result block entirely on success. It is suppressed for
success only — failures and previews still report.
Explosion centres
Explosion rows record the blast centre. A rollback with a tight radius can
miss splash damage whose centre sits outside the radius. Widen r: for
explosive damage, or use r:#global with a short t: window.
apply and cancel#
/vg apply
/vg cancel
apply executes the rollback or restore preview you most recently generated.
cancel discards it. Both act only on your pending preview — previews are
keyed per actor, and the console has its own key.
The preview is invalidated when you start a new rollback or restore, and the command re-checks your permission at apply time. If either changed, apply refuses and asks you to preview again:
[VonixGuardian] Pending rollback preview changed or expired; run preview again.
apply requires the rollback node for a rollback preview, or the restore node
for a restore preview.
/vg rollback u:Griefer t:1h #preview
/vg apply ← commit exactly that plan
restore#
/vg restore [filters]
/vg rs [filters]
/vg re [filters]
Reapplies actions that were previously rolled back — either by replaying the
forward inverse of a batch, or by re-applying actions matching a filter. Same
filter language, same default 10-block radius, same #preview and #count
behaviour as rollback.
Restore and rollback are two directions of the same engine; a restore is not a "history pop". Both mutate the world and both are recorded as batches.
undo#
/vg undo
Reverses your own last rollback or restore by executing its inverse against the exact rows that were affected. It is not a history-pop and it does not touch a newer mutation. With no prior batch:
[VonixGuardian] Nothing to undo.
Each actor has an independent undo stack entry, and the console has its own. If
the stored entry predates row-level id tracking, undo drops it and says so
rather than guessing:
[VonixGuardian] Undo: dropped 42 entries from history (legacy/empty entry —
world state not reverted).
purge#
/vg purge <t:duration> [other filters]
Permanently deletes rows older than the given time window. This is retention
semantics, not a query window: t:30d keeps the last 30 days and deletes the
rest.
/vg purge t:90d ← delete everything older than 90 days
/vg purge t:60d a:block ← only block rows
/vg purge t:30d r:#world_nether ← only the Nether
Age floors. A purge cannot delete recent data, and the floor depends on who runs it. Both are configurable.
| Source | Default floor | Config key | Minimum allowed |
|---|---|---|---|
| Console | 24 hours | purge.minAgeSecondsConsole |
60 seconds |
| In-game | 30 days | purge.minAgeSecondsInGame |
1 hour |
A purge that violates its floor is refused before anything is deleted:
[VonixGuardian] Purge refused: purge requires a time filter at least 2592000s old
(CP-1:1 safety floor; use a larger t: window)
Reclaiming disk. #optimize runs dialect-specific storage maintenance after a
successful purge: VACUUM on SQLite, OPTIMIZE TABLE on MySQL/MariaDB,
VACUUM ANALYZE on PostgreSQL.
/vg purge t:90d #optimize
The optimize step is capped at five minutes and failure is swallowed — a purge that deleted rows is still a successful purge if maintenance does not complete.
Purge is irreversible
Purged rows are gone. There is no rollback of a purge, and no #preview for
one. Take a database backup first if the range is large and the history
matters.
status#
/vg status
/vg stats
/vg version
The canonical diagnostic. All three spellings render the same report. It is read-only and on-demand — there is no always-on debug spam.
The report has these sections:
| Section | Contents |
|---|---|
| VonixGuardian | Version. |
| Storage | Backend type, schema version, DAO health (OK / UNHEALTHY). |
| Writer queue | Consumer state, maintenance write-block, depth/max, submitted, gated, dropped, sink drops, quarantined, recovered, quarantine overflow and write-failure counters. Per-type submitted and dropped histograms when non-empty. |
| Rollback recovery | Open rollback/restore batch ids with mode and affected count, plus vg_repair_required rows. |
| Coalescer | Window, max tracked, active entries, suppressed, passed, evictions, cap drops. Omitted when coalescing is disabled. |
| Mixin hot events | Kill-switch state, allocation rate, and per-type submit rates for the eight hot-tick mixin action types. |
| Event hooks | The registered hook chain in order, plus the internal hook count. |
| Per-world overrides | Count and list of worlds with a per-world config file. |
| Blacklist file | Rule count, when blacklist.txt is loaded. |
| Auto-purge | Enabled state and retention, or 0 = unbounded with the suggested 90-day horizon. |
| Permissions | Default op level and the number of per-node overrides. |
| Public API | API version. |
Reading the rollback recovery section
An open batch means a rollback or restore did not finish. Boot does not
replay it — by design, so a half-applied mutation is not applied a second
time. Inspect the listed ids with /vg lookup and #verbose before re-running
anything.
consumer#
/vg consumer ← report current state
/vg consumer pause
/vg consumer resume
/vg consumer toggle
Controls the async writer. Pausing stops rows reaching the database but does not stop events being queued:
[VonixGuardian] Consumer PAUSED — incoming events are buffered, not written.
Resuming drains the buffer:
[VonixGuardian] Consumer RESUMED — draining buffered events.
The bare form reports state and depth:
[VonixGuardian] Consumer is currently RUNNING (queue.depth=0)
Pausing is not free
A paused consumer keeps buffering until queue.maxSize (50,000 as shipped) is
reached, then events are dropped with a WARN. Pause for maintenance windows,
not indefinitely.
reload#
/vg reload
Re-reads config/vonixguardian/config.json from disk and hot-swaps the subsections
that are safe to change in-process. It also reloads blacklist.txt and the
per-world override files. The reload runs off the server thread.
Output names what took effect and what did not:
[VonixGuardian] Hot-swapped: 2 actions, purge
[VonixGuardian] Requires restart: 1 database
[VonixGuardian] Errors: 0 (none)
Keys reported as requires restart were detected on disk but are not applied;
the old in-memory value stays live. If validation fails, the whole reload aborts
and the live config is unchanged.
See Configuration for the complete hot-swap matrix.
config#
/vg config get <key>
/vg config set <key> <value>
Reads and writes individual keys without opening the file. set persists the
change to disk, then runs the same validated reload path as /vg reload, so the
value is live immediately — or reported as needing a restart.
/vg config get lookup.maxRadius
[VonixGuardian] lookup.maxRadius = 10000
/vg config set purge.autoPurgeSeconds 7776000
[VonixGuardian] Updated purge.autoPurgeSeconds = 7776000 (hot-swapped: purge)
Both operations are serialised under a config mutation lock, so two concurrent
config set calls cannot clobber each other's full-file write.
Settable keys. Only these are accepted; anything else reports
Unknown or read-only config key.
| Group | Keys |
|---|---|
| General | theme, language |
| Log file | logFile.enabled |
| Lookup | lookup.defaultPageSize, lookup.maxRadius, lookup.maxResultRows |
| Privacy | privacy.hashIps |
| Purge | purge.minAgeSecondsConsole, purge.minAgeSecondsInGame, purge.autoPurgeSeconds, purge.autoPurgeTime |
| Actions | actions.logBlocks, actions.logContainers, actions.logItems, actions.logEntities, actions.logExplosions, actions.logChat, actions.logCommands, actions.logSessions, actions.logSigns, actions.logInteractions, actions.logWorldEvents, actions.entityBlockChangeCoalesceWindowMs, actions.entityBlockChangeMaxTracked, actions.entityChangeLogAllEntities, actions.mixinHotEvents, actions.itemBlacklist, actions.entityBlacklist |
| Storage | storage.persistNbt |
| Rollback | rollback.explosionSupplementalReach |
List values (actions.itemBlacklist, actions.entityBlacklist) are set as a
comma- or whitespace-separated string. none or [] clears the list.
/vg config set actions.itemBlacklist none
/vg config set actions.entityBlacklist minecraft:zombie,create:contraption
Not settable by command
database.*, queue.*, permissions.*, lookup.maxConcurrent,
logFile.directory, logFile.gzipRotated, logFile.retentionDays,
logFile.forceSyncOnFlush, privacy.salt, rollback.mutationBatchSize and
rollback.requireConfirm are file-only. Edit config.json and reload or
restart.
entitylog#
/vg entitylog ← same as list
/vg entitylog list
/vg entitylog add <entity>
/vg entitylog remove <entity>
Manages the modded-entity griefing allowlist (actions.entityChangeAllowlist).
This is the command that turns on auditing for a modded mob that breaks blocks.
/vg entitylog add isleofberk:night_fury
/vg entitylog add isleofberk:*
/vg entitylog add isleofberk
/vg entitylog list
/vg entitylog remove isleofberk
Three entry shapes are accepted:
| Shape | Example | Matches |
|---|---|---|
| Exact registry key | isleofberk:night_fury |
That one entity type. |
| Namespace wildcard | isleofberk:* |
Every entity in that namespace. |
| Bare namespace | isleofberk |
Equivalent to isleofberk:*. |
Entries are lower-cased and stored verbatim, so list round-trips what you
typed. Invalid input is rejected before anything touches disk:
[VonixGuardian] Invalid entity entry: 'isleo berk'. Use ns:path, ns:*, or ns.
Why an allowlist, not a blocklist
On Forge and NeoForge, LivingDestroyBlockEvent is a prospective query
fired per mob tick — a flying dragon can fire it hundreds of thousands of
times per second without destroying anything. Recording all of them would
drown the write queue. The shipped policy is fail-closed: vanilla mobs known
to genuinely change blocks are recorded, and modded mobs must be opted in
here.
actions.entityChangeLogAllEntities=true bypasses the allowlist entirely and
records everything. That restores pre-1.1.5 behaviour and will flood a modded
pack. It is a diagnostic setting, not a production one.
teleport#
/vg teleport <world> <x> [y] <z>
/vg tp <world> <x> [y] <z>
Teleports you to a coordinate, typically one read from a lookup row.
/vg tp overworld 128 64 -342
/vg tp minecraft:the_nether -20 45 88
World accepts a full resource location, or the shorthands overworld, nether,
end (which expand to minecraft:overworld, minecraft:the_nether,
minecraft:the_end). Coordinates are plain numbers, 2 or 3 of them.
When you omit Y, your current Y is used, capped at 63 so you do not teleport into the void on a coordinate recorded underground:
/vg tp overworld 128 -342
Player only, and the target world must be loaded:
[VonixGuardian] Unknown world: the_moon
give#
/vg give <itemId> [amount]
Puts an item in your inventory, dropping it at your feet if the inventory is full.
amount clamps to a minimum of 1 and defaults to 1.
/vg give minecraft:diamond 64
/vg give create:andesite_alloy 32
/vg give diamond ← namespace defaults to minecraft:
Player only. Unknown ids are rejected:
[VonixGuardian] Unknown item: minecraft:not_a_thing
migrate-db#
/vg migrate-db <sqlite|mysql|postgresql> CONFIRM
Copies the audit catalog from the active backend to the backend described by
database.migrationTarget in config.json. Console only.
Without CONFIRM it prints what it would do and stops — this is the dry run:
[VonixGuardian] migrate-db: about to copy every audit row from 'sqlite' to 'mysql'.
[VonixGuardian] This is a one-way operation — the target must be at schema v9 and empty.
[VonixGuardian] To proceed, run: /vg migrate-db mysql CONFIRM
Preflight refusals, each with its own message:
- No
database.migrationTargetblock in config. - The command's target type does not match
migrationTarget.type. - Another maintenance write-block is already active.
- The async pipeline did not go idle within 30 seconds.
The command blocks new audit writes, waits for the ring buffer, the worker's local batch, and any in-flight sink transaction to idle, then copies in 1,000-row chunks. That is a best-effort snapshot barrier, not a global database freeze.
Full procedure: Backend migration.
help#
/vg help
Prints the command summary. Bare /vg prints a shorter hint list. Bare
/vg lookup, /vg rollback, /vg restore, and /vg purge print a three-line
usage block with examples rather than brigadier's Unknown or incomplete command.
help is gated only by the root vonixguardian.base node.
Behaviour shared by mutating commands#
rollback, restore, undo, apply, purge, and migrate-db all run
off-thread on a bounded worker pool, so they never stall a server tick. Two
consequences worth knowing:
Saturation is visible, not silent. If the command worker queue is full, the command is rejected instead of queuing unboundedly:
[VonixGuardian] Command worker is saturated; retry shortly or reduce concurrent
heavy commands.
Output follows you. Results are routed back to your player entity by UUID at delivery time. If you disconnect mid-operation, the result goes to the console channel instead of being lost.
Superseded output is suppressed. Starting a second heavy command invalidates the first one's chat generation, so a slow rollback's result cannot overwrite the newer command's output.