Mineflayer runner for starting several Minecraft accounts from local session JSON files. It can join a server, run configurable commands, move inside a small AFK area, log chat/status, and use a SOCKS proxy per bot.
This project is for personal use on servers where automation is allowed. Do not sell it, resell it, rebrand it, or upload private account/session files.
- Human movement system with random walk bursts, sprint, strafe, jump, sneak, smooth head turns, idle pauses, and radius limits.
- Movement before spawn commands, configurable in seconds.
- Per-bot config overrides.
- Per-bot SOCKS4/SOCKS5 proxy support.
- Per-bot chat log on/off.
- Configurable command mode: send all commands or pick one random command.
- Periodic status log with health, food, game mode, dimension, and position.
- Built-in tests with
npm test.
Install Node.js 22 or newer.
Check it:
node -vGood examples:
v22.x
v23.x
v24.xOpen this project folder, the folder that contains package.json.
Windows example:
cd "C:\Users\YourName\Downloads\donutsmp-session-runner"Install modules:
npm installWindows users can also double-click:
install.batFirst check that accounts load:
npm run dryStart the bots:
npm startWindows users can also double-click:
start.batMost users edit only these:
config.json
cookies/*.json
accounts.jsonNever upload these:
cookies/*.json
accounts.json
profiles/
logs/
.envOpen config.json.
{
"connection": {
"host": "donutsmp.net",
"port": 25565,
"version": "1.21.11",
"auth": "offline",
"physicsEnabled": true
}
}Meaning:
host: server IP or domain.port: server port, usually25565.version: Minecraft version accepted by the server.auth: fallback auth mode when an account file has no session.physicsEnabled: must staytruefor normal Mineflayer movement.
Put JSON files inside cookies/.
cookies/
bot1.json
bot2.jsonExample:
{
"profile": {
"name": "AccountName",
"id": "minecraft-java-profile-uuid-here"
},
"ygg": {
"token": "minecraft-java-access-token-here"
},
"refreshToken": "optional-microsoft-refresh-token-here"
}Create accounts.json:
{
"accounts": [
{
"profile": {
"name": "AccountName",
"id": "minecraft-java-profile-uuid-here"
},
"ygg": {
"token": "minecraft-java-access-token-here"
}
}
]
}Each account can override global config.
Example:
{
"profile": {
"name": "BotOne",
"id": "minecraft-java-profile-uuid-here"
},
"ygg": {
"token": "minecraft-java-access-token-here"
},
"proxy": "proxyOne",
"features": {
"chatLog": false,
"statusLog": true
},
"donut": {
"spawnCommands": ["/afk 30"],
"commandMode": "all",
"preCommandMovement": {
"enabled": true,
"seconds": 5
}
},
"humanMovement": {
"enabled": true,
"radiusBlocks": 5,
"sprintChance": 0.45
}
}Shortcut to disable chat log on one bot:
{
"name": "BotOne",
"disableChatLog": true
}The proxy is for the Minecraft server TCP connection.
In config.json:
{
"network": {
"proxy": null,
"proxies": {
"proxyOne": {
"protocol": "socks5",
"host": "127.0.0.1",
"port": 1080,
"username": "",
"password": ""
}
}
}
}Use it on one account:
{
"name": "BotOne",
"proxy": "proxyOne"
}Two bots can use the same proxy name. You can also put the proxy URL directly:
{
"name": "BotOne",
"proxy": "socks5://user:pass@127.0.0.1:1080"
}Supported:
socks4socks5- optional username/password
Spawn commands are in donut.spawnCommands.
Default:
{
"donut": {
"enabled": true,
"sendAfkCommand": true,
"spawnCommands": ["/afk 30"],
"commandMode": "all",
"commandDelayMs": 2500,
"commandJitterMs": 1500
}
}Meaning:
sendAfkCommand: iffalse, spawn commands are not sent.spawnCommands: commands sent after spawn.commandMode:allsends every command,randomOnepicks one command.commandDelayMs: base delay before command send.commandJitterMs: extra random delay.
Mineflayer sends commands with bot.chat("/command"). There is no real Minecraft
GUI chat window in Mineflayer, so the stable way is to send the command through
the normal chat API.
Before commands are sent, the bot can move for a few seconds.
{
"donut": {
"preCommandMovement": {
"enabled": true,
"seconds": 5
}
}
}Set enabled to false to disable it.
The movement system uses Mineflayer controls and physics. It does not write custom spoofed packets. Mineflayer and minecraft-protocol still handle movement packets normally.
{
"humanMovement": {
"enabled": true,
"look": true,
"move": true,
"sprint": true,
"jump": true,
"sneak": true,
"radiusBlocks": 4,
"intervalMs": 1200,
"jitterMs": 1200,
"burstMinMs": 2500,
"burstMaxMs": 8000,
"stepMinMs": 450,
"stepMaxMs": 1800,
"stepPauseMinMs": 120,
"stepPauseMaxMs": 700,
"idleChance": 0.14,
"sprintChance": 0.38,
"strafeChance": 0.42,
"jumpChance": 0.12,
"sneakChance": 0.06,
"turnMinRadians": 0.2,
"turnMaxRadians": 1.15,
"pitchJitterRadians": 0.16,
"maxPitch": 0.75
}
}Simple meanings:
radiusBlocks: how far the bot tries to stay from its spawn point.intervalMs: base delay between movement bursts.jitterMs: random extra delay.burstMinMs/burstMaxMs: how long one movement burst lasts.stepMinMs/stepMaxMs: how long one small movement step lasts.idleChance: chance to pause instead of moving.sprintChance: chance to sprint during a step.strafeChance: chance to move left/right while going forward.jumpChance: chance to jump.sneakChance: chance to sneak when not sprinting.turnMinRadians/turnMaxRadians: turn size.pitchJitterRadians: small up/down head movement.maxPitch: maximum up/down look angle.
Keep radiusBlocks small if the AFK zone is small.
The old simple anti-AFK feature still exists:
{
"antiAfk": {
"enabled": true,
"look": true,
"jump": true,
"sneak": true,
"walk": false,
"intervalMs": 18000,
"jitterMs": 9000
}
}Leave walk as false when humanMovement.enabled is true.
Status log writes a small status line per bot.
{
"features": {
"statusLog": true
},
"statusLog": {
"intervalMs": 60000
}
}It logs:
- health
- food
- game mode
- dimension
- position
{
"features": {
"chatLog": true,
"statusLog": true,
"autoEat": true,
"autoArmor": true,
"autoTool": true
}
}Meaning:
chatLog: write chat and whispers to logs.statusLog: write health/food/position status lines.autoEat: use food automatically when plugin is loaded.autoArmor: equip armor automatically when plugin is loaded.autoTool: load tool plugin.
npm install
npm run dry
npm start
npm test
npm run check
npm run pack:dryRun:
npm installMake sure you are in the folder with package.json.
No valid account was found.
Fix:
- put account JSON files in
cookies/, or - create
accounts.json
Then run:
npm run dryThe server or Minecraft Services rejected the token.
Common causes:
- expired access token
- token is not a Minecraft Java token
- UUID does not match the token
- account does not own Java Edition
- refresh token is missing or expired
Fix:
- Export a fresh Minecraft Java session.
- Add a refresh token if your exporter gives one.
- Run
npm run dry. - Run
npm start.
Check:
- proxy host and port are correct
- proxy supports SOCKS4 or SOCKS5
- username/password are correct
- the proxy allows TCP connections to the Minecraft server
Lower:
{
"humanMovement": {
"radiusBlocks": 2,
"burstMaxMs": 4000,
"sprintChance": 0.2
}
}Read LICENSE. This is a personal-use project.