GITHUB • DOCUMENTATION • DISCORD
Plain text version
Everything above, as readable text. Expand whichever section you need.
Spoiler: Overview - what BileTools does
BileTools watches your plugins directory and drives runtime lifecycle changes, so a rebuild lands in the running server instead of a restart.
BileTools is a development tool. It deliberately manipulates plugin lifecycle state at runtime. That is exactly what makes the development loop fast, and exactly why it belongs on dev and test servers. Hot reload is not a substitute for a clean restart on a live server.
- Auto hot-reload. Recompile over an existing plugin jar and BileTools detects the content change automatically.
- Hot-drop. Drop a new jar into the plugins directory and it is queued for runtime loading without a full restart.
- Auto-unload. Delete a tracked jar and its plugin is unloaded.
- Lifecycle commands. Load, unload, reload, install and uninstall by hand from the /bile command tree.
- Dependency aware. Dependent plugins are unloaded and reloaded around a replacement instead of reloading one jar blindly.
- Local plugin library. Every jar BileTools sees is archived by version, and the same folder is what /bile install reads from. Backup and rollback are the same feature.
- Remote deploy. Push selected jar changes to other configured servers over an authenticated, size-limited, SHA-256 verified transfer.
BileTools is a development tool. It deliberately manipulates plugin lifecycle state at runtime. That is exactly what makes the development loop fast, and exactly why it belongs on dev and test servers. Hot reload is not a substitute for a clean restart on a live server.
Spoiler: Compatibility - runtimes and Java
One jar covers all six runtimes, Minecraft
1.20.1 through current 26.x.
Folia and Canvas: hot reload on regionized servers is inherently more fragile. A third-party plugin that does not declare folia-support may still fail when hot-loaded.
- Paper loads through the server's public PluginManager
- Purpur same Paper-family load and unload paths
- Leaf Paper-family fork, treated like Paper
- Folia regionized scheduling, BileTools declares folia-supported
- Canvas Folia fork, same regionized rules
- Spigot loads through plugin.yml; jars that ship only paper-plugin.yml are refused
Folia and Canvas: hot reload on regionized servers is inherently more fragile. A third-party plugin that does not declare folia-support may still fail when hot-loaded.
Spoiler: Commands and permissions
Root command is
/biletools. Aliases:
/bile,
/bi,
/b.
One permission covers the whole tree:
Manual commands always bypass the watcher filters. Tab completion suggests installed plugins, library plugins and stored versions. Running
/bile on its own opens a paginated hover-and-click help menu.
Optional arguments must be named. Passing them positionally fails with "unexpected argument":
Code (Text):
/bile load <plugin> Load a plugin jar from the plugins directory
/bile unload <plugin> Unload an installed plugin
/bile reload <plugin> Reload an installed plugin
/bile uninstall <plugin> Delete a plugin jar from the plugins directory
/bile install <plugin> [version=..] Install a plugin from the BileTools library
/bile library [plugin=..] List library plugins, or versions for one plugin
/bile unload <plugin> Unload an installed plugin
/bile reload <plugin> Reload an installed plugin
/bile uninstall <plugin> Delete a plugin jar from the plugins directory
/bile install <plugin> [version=..] Install a plugin from the BileTools library
/bile library [plugin=..] List library plugins, or versions for one plugin
Code (Text):
bile.use Gives access to BileTools default: op
Optional arguments must be named. Passing them positionally fails with "unexpected argument":
Code (Text):
/bile install MyPlugin works (defaults to version=latest)
/bile install MyPlugin version=1.4.2 works
/bile install MyPlugin version=latest works
/bile install MyPlugin 1.4.2 FAILS
/bile library works (lists everything)
/bile library plugin=MyPlugin works
/bile library MyPlugin FAILS
/bile install MyPlugin version=1.4.2 works
/bile install MyPlugin version=latest works
/bile install MyPlugin 1.4.2 FAILS
/bile library works (lists everything)
/bile library plugin=MyPlugin works
/bile library MyPlugin FAILS
Spoiler: Configuration - full default config.yml
What each option does
Code (Text):
remote-deploy:
slave:
slave-enabled: false
slave-port: 9876
slave-payload: pickapassword
master:
master-enabled: false
master-deploy-to:
- yourserver.com:9876:password
master-deploy-signatures:
- MyPlugin
- AnotherPlugin
socket-timeout-ms: 15000
max-transfer-bytes: 268435456
archive-plugins: true
watcher:
idle-poll-ticks: 20
active-poll-ticks: 5
fingerprint-debounce-ticks: 8
ignore:
- LuckPerms
- Vault
- ProtocolLib
- packetevents
- WorldGuard
- CoreProtect
- spark
only: []
coalesce-window-ticks: 10
observability:
log-timings: true
lifecycle:
health-check: true
slave:
slave-enabled: false
slave-port: 9876
slave-payload: pickapassword
master:
master-enabled: false
master-deploy-to:
- yourserver.com:9876:password
master-deploy-signatures:
- MyPlugin
- AnotherPlugin
socket-timeout-ms: 15000
max-transfer-bytes: 268435456
archive-plugins: true
watcher:
idle-poll-ticks: 20
active-poll-ticks: 5
fingerprint-debounce-ticks: 8
ignore:
- LuckPerms
- Vault
- ProtocolLib
- packetevents
- WorldGuard
- CoreProtect
- spark
only: []
coalesce-window-ticks: 10
observability:
log-timings: true
lifecycle:
health-check: true
- watcher.ignore Plugin names that automatic hot-drop, reload and unload will skip. The defaults are things that are usually dangerous or useless to auto-reload on a dev box.
- watcher.only When this list is not empty, only these plugins are auto-managed. Useful when you are actively developing one or two projects on a busy server.
- watcher.active-poll-ticks / idle-poll-ticks How often the watcher scans while changes are arriving, versus once the directory has settled.
- watcher.fingerprint-debounce-ticks How long a jar's fingerprint must hold steady before lifecycle work starts. This is what stops half-written jars from being loaded.
- watcher.coalesce-window-ticks Batches nearby jar writes into one dependency-ordered reload flush, so a multi-module build does not trigger five separate reloads.
- archive-plugins Archive each plugin jar into the library folder before it is replaced.
- lifecycle.health-check After a load or reload, verify the plugin is actually registered and enabled. A failed operation marks the plugin dirty and pauses automatic reloads for it.
- observability.log-timings Log per-phase timings (unload, dependents, load, health) for every operation.
Spoiler: Plugin library and rollback
With
archive-plugins on, every plugin jar BileTools sees is copied here before it gets replaced. That means the library doubles as a rollback history,
/bile library lists what you have, and
/bile install <plugin> version=<version> puts any of it back into the running server.
Code (Text):
plugins/BileTools/library/<PluginName>/<version>.jar
Spoiler: Remote deploy
Optional. Lets a master server push selected jar changes to one or more slave servers.
Transfers land in a temporary .part file and are only promoted after the password, filename, transfer size and SHA-256 all check out. Filenames are sanitized and any path that would escape the plugins folder is rejected. Defaults are a 256 MB cap and a 15 second socket timeout.
- On each receiving server: set remote-deploy.slave.slave-enabled: true, pick a port and set slave-payload to a shared password.
- On the sending server: set remote-deploy.master.master-enabled: true, list each target in master-deploy-to in the form below, and list which plugins to forward in master-deploy-signatures.
Code (Text):
master-deploy-to:
- host:port:password
- host:port:password
Spoiler: Languages - all 17 locale codes
English is selected by default. To switch, set
locale in
plugins/BileTools/language.yml:
You can also override individual lines without touching the bundles. Anything you add under a
messages: section in language.yml wins; everything you leave out falls back to the selected language, then to English. The file is hot loaded upon save.
Code (Text):
locale: en_US
Code (Text):
de_DE German (Germany)
es_ES Spanish (Spain)
fi_FI Finnish (Finland)
fr_FR French (France)
he_IL Hebrew (Israel)
it_IT Italian (Italy)
ja-JP Japanese (Japan)
ko_KR Korean (South Korea)
lt_LT Lithuanian (Lithuania)
nl_NL Dutch (Netherlands)
pl_PL Polish (Poland)
pt_PT Portuguese (Portugal)
ru_RU Russian (Russia)
tr_TR Turkish (Turkey)
vi_VI Vietnamese (Vietnam)
zh_CN Chinese (Simplified)
zh_TW Chinese (Traditional)
es_ES Spanish (Spain)
fi_FI Finnish (Finland)
fr_FR French (France)
he_IL Hebrew (Israel)
it_IT Italian (Italy)
ja-JP Japanese (Japan)
ko_KR Korean (South Korea)
lt_LT Lithuanian (Lithuania)
nl_NL Dutch (Netherlands)
pl_PL Polish (Poland)
pt_PT Portuguese (Portugal)
ru_RU Russian (Russia)
tr_TR Turkish (Turkey)
vi_VI Vietnamese (Vietnam)
zh_CN Chinese (Simplified)
zh_TW Chinese (Traditional)
Spoiler: How a reload actually runs
Every operation hot-drop, reload, install, uninstall, remote deploy: goes through one serialized queue with dedupe keys, on a dedicated plugin-operations thread. Lifecycle mutations themselves always run on the global or main thread.
Plugins that implement VolmLib's
ReloadAware contract get a HOT_RELOAD or HOT_UNLOAD callback
before their tasks are cancelled and listeners torn down, so they can drain in-flight work while their scheduler is still alive.
Unloading scrubs the plugin out of the live command graph, services, messaging channels and lookup tables before closing its classloader, which is why commands and tab-completion come back correct instead of half-wired.
Lifecycle waits carry an explicit timeout. A stuck operation surfaces as a failure and marks the plugin dirty rather than blocking the queue. Turn on observability.log-timings to see per-phase timings for every operation.
Code (Text):
detect -> stabilize -> fingerprint -> queue -> unload -> load -> dependents -> health check
Unloading scrubs the plugin out of the live command graph, services, messaging channels and lookup tables before closing its classloader, which is why commands and tab-completion come back correct instead of half-wired.
Lifecycle waits carry an explicit timeout. A stuck operation surfaces as a failure and marks the plugin dirty rather than blocking the queue. Turn on observability.log-timings to see per-phase timings for every operation.
Spoiler: Known limits of hot reload
Not every plugin can be hot-reloaded cleanly, and BileTools does not pretend otherwise. Things that generally do not survive a class reload:
- Static state fields held across a class reload
- Background threads work started outside the plugin scheduler
- Native resources anything bound outside the JVM
- External connections sockets and pools with their own lifetime
- Plugin-specific internals caches and registries other plugins own
Spoiler: Links
- Source Code: github.com/VolmitSoftware/BileTools
- Documentation: docs.volmitsoftware.com
- Discord: volmitsoftware.com/discord
VOLMITSOFTWARE
Quick facts
- Edition: Minecraft Java
- File type: .jar
- Minecraft versions listed: 1.20, 1.20.6, 1.21
- How to install: Install the matching mod loader (Forge, Fabric or NeoForge) for your Minecraft version. → Download the .jar. → Put it in the .minecraft/mods folder and launch that loader profile.
- Where to get it: Opens on Spigot — not every file is mirrored on our own servers.
Install steps are the general flow for this file type — How to install Minecraft Java mods & modpacks walks through it step by step.
BileTools - Test Plugins Faster is a free Minecraft Java mod. Compatible with Minecraft 1.20, 1.20.6, 1.21, 26.1 and newer. Downloaded 2,727 times (via Spigot). Download it and open it directly in the game.