User report 2026-05-25: launched 'npm run bot' fresh, MC server kicked
every login with "Игрок с данным никнеймом уже играет на сервере" and
the bot fell into a perpetual reconnect-then-kicked loop. Root cause:
a smoke-test supervisor from an earlier shell was still running in the
background, holding the pepa_bot session open. Two supervisors racing
on the same nickname is undefined behaviour from the server's side and
results in this exact failure mode.
Changes:
runtime/supervisor.js — acquires state/<host>/supervisor.pid before
spawning the child. If another supervisor is alive (kill -0 check), the
new one exits with a clear message telling the operator how to recover.
On SIGINT/SIGTERM/exit the lock is released; stale pidfiles are detected
when the recorded PID is no longer alive.
scripts/stop.sh — emergency cleanup helper:
- kills any supervisor or bot.js processes matching this repo
- removes pidfile + bot.sock
- reminds the operator to wait ~30s for the MC server to drop the old
session before re-launching
package.json — new `npm run stop` script.
Smoke-tested:
- first 'node runtime/supervisor.js' acquires lock, writes pid
- second call refuses with diagnostic message
- first SIGTERM ⇒ pidfile removed automatically
Co-authored-by: Yuriy Mayatnikov <mayatnikov@me.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the self-improvement loop end-to-end:
reflex fails 3× → proposal file → operator approves in TUI →
`npm run propose:apply <file>` spawns Pi on a feature branch →
Pi commits the patch → supervisor watches runtime/*.js and
restarts the child on change.
runtime/state-store.js — atomic current-task.json writes, daily diary
append, proposals/ + proposals/approved/ helpers.
runtime/bot.js:
- ctx.dispatch writes current-task.json on start and updates it on
completion / failure / throw.
- failure tracker: 3 consecutive same-label failures → writeProposal()
with the snapshot, labels, and a suggested-next-step section.
30-min cooldown prevents proposal spam.
- on startup, surfaces resume info (previous task + pending proposal
count); on death, clears current-task.json + writes diary line.
- new IPC commands: PROPOSAL_LATEST returns the newest pending
proposal body; PROPOSAL_APPROVE moves it to proposals/approved/.
tui/tui.tsx — status bar shows `[proposals N, press y]` badge when
bot.pendingProposals > 0. Hotkey 'y' opens the proposal panel; 'y'
approves, 'n'/Esc closes.
scripts/propose-apply.js — given an approved proposal filename, creates
a `feat/proposal-<slug>` branch and spawns `pi -p` with the proposal
+ repo-conventions prompt. Refuses on dirty tree. No auto-push, no
auto-merge — operator reviews the diff and decides.
runtime/supervisor.js — forks bot.js as a child, watches runtime/*.js,
restarts on file change or on child exit code 42. Rate-limited at 5
restarts/minute. SIGINT/SIGTERM forward cleanly. `npm run bot` now
goes through the supervisor; `npm run bot:bare` skips it.
Smoke-tested: supervisor spawned, bot connected to MC, spawned at
expected coords, diary line written, state cleanup on SIGTERM correct.
Co-authored-by: Yuriy Mayatnikov <mayatnikov@me.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(mindcraft-skills): hard timeout on every skill call
mc_avoid_enemies (and 7 other tools) wrapped only in safeCall without a
withTimeout. When mindcraft's underlying pathfinder/pvp goal couldn't be
satisfied, the call never resolved — the Pi tick loop blocked forever.
Observed live: mc_avoid_enemies pending >10 minutes after one mc_observe.
safeCall now takes timeoutMs (default 30s) and wraps withTimeout itself,
so every tool gets a hard ceiling. Per-tool overrides:
- goToPosition / goToNearestBlock: 120s / 90s (unchanged from before)
- defendSelf / avoidEnemies: 45s
- stay: secs*1000 + 10s
- craft / consume / pickup / place: 30s
- equip: 15s
collectBlock still uses its bespoke per-iter 75s loop.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(runtime): script-driven reflex daemon + Ink TUI dashboard
Pure-Pi runtime had three failure modes in practice:
- slow: 20-60s per decision because LLM was in the hot path
- expensive: every tick (defend, eat, idle) paid for a reasoning pass
- invisible: required tmux capture-pane to know what the bot was doing
New runtime/ layer is a long-running Node daemon that owns the MC
connection, ticks a priority-ordered reflex chain (defend > eat > sleep
> idle) with NO LLM in the hot path, and exposes status + commands over
a Unix-socket IPC. tui/ is an Ink dashboard that attaches over IPC and
can detach freely — multiple TUI clients can connect at once.
Pi/Codex are still available, but as on-demand escalation: TUI hotkey
'a' spawns `pi -p "<prompt>"` as a subprocess and streams stdout into
the dashboard. The self-improvement loop (proposals → operator approval
→ Pi-driven patch → hot reload) is documented in docs/runtime.md but
not yet wired.
Reflex bodies are stubs today — they log decisions but don't drive
Mineflayer actions yet. The priority chain, IPC contract, and TUI are
fully working; subsequent commits will fill in defend/eat/sleep bodies
and wire automatic escalation.
Run with `npm run bot` + `npm run tui`. Pi-only fallback stays at
`npm run agent`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Yuriy Mayatnikov <mayatnikov@me.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The bot was acting blind: it knew its own coordinates but nothing about
what was around it. mc_goto's over-strict safety guards refused every
real path. mc_dig was too low-level to drive a coherent farming loop.
The result: 4+ hours of "trying" with zero physical achievement.
This commit reframes the bridge around a perceive→decide→act loop using
proven primitives from Mindcraft (github.com/kolbytn/mindcraft, MIT —
LICENSE-MINDCRAFT vendored beside the library files).
Changes:
- extensions/lib/ (new, vendored from Mindcraft with attribution)
- world.js (431 LoC) — 21 perception functions: getNearbyBlockTypes,
getNearbyEntities, getInventoryCounts, getNearestBlock, getPosition,
getBiomeName, etc.
- skills.js (2093 LoC) — 30+ action primitives: collectBlock, placeBlock,
goToPosition, goToNearestBlock, craftRecipe, equip, consume,
defendSelf, avoidEnemies, pickupNearbyItems, stay, etc.
- mcdata.js (~600 LoC) — Mindcraft's mc-data adapter. Imports patched
to local paths; mineflayer-auto-eat removed (our installed 5.x has
a divergent API; skills.consume() falls back to bot.consume()).
Added attachPluginsAndInit(bot) export so mineflayer-bridge.ts can
wire plugins onto its externally-created bot.
- settings.js — minimal stub with farmer-bot defaults.
- extensions/mindcraft-skills.ts (new, 406 LoC) — Pi extension registering
15 high-level tools on top of the vendored library:
- Perception: mc_observe, mc_inventory, mc_nearby_blocks, mc_nearby_entities
- Action: mc_collect_block, mc_place_block, mc_go_to, mc_go_to_block,
mc_craft, mc_equip, mc_consume, mc_defend_self, mc_avoid_enemies,
mc_stay, mc_pickup_nearby
ES modules from extensions/lib/ are loaded via dynamic import() at
extension init so the cross-extension require()-race resolves cleanly.
- extensions/mineflayer-bridge.ts
- Expose the live Mineflayer bot on globalThis.__pepaPiBot so the
mindcraft-skills extension can use it (set on connect, cleared on
error/end/manual disconnect).
- Call attachPluginsAndInit(nextBot) right after createBot to load
pathfinder, pvp, collectblock, armorManager and prime
minecraft-data once login completes.
- package.json — new runtime deps: minecraft-data, vec3,
mineflayer-pvp, prismarine-item.
- AGENTS.md — new "Perception → decision → action" section before
"Your tools right now" with full tool catalog and a deprecation
note for the broken mc_goto / mc_build_pyramid_5x5 / low-level
mc_dig from the old bridge.
Smoke test (medium thinking): bot called mc_observe and received a
real JSON snapshot — nearbyBlocks listed coal_ore, oak_log, water,
sand; nearbyEntityTypes listed creeper, zombie, pillager, skeleton.
The bot can finally see what it could not see this morning.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Initial seed for an autonomous, self-extending Minecraft player powered by
Pi (pi.dev) and Mineflayer.
Includes README, AGENTS.md mandate, .env.example, MIT LICENSE, package.json
with mineflayer + dotenv, and empty skills/ extensions/ prompts/ dirs for
the agent to grow into.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>