Single source of truth for the v0.2.0 iteration: - what shipped per rc (rc.1/rc.2/rc.3), with links to PRs/commits - live DB snapshot from 2026-05-27 ~15:30 - 7 known issues / followups ranked by impact (rc.4 candidates) - quick-start checklist for the next session Also: - docs/v0.2.0-self-learning.md: phase checklist updated to reflect shipped state and points at dev/v0.2.0/STATUS.md for live data - README status bullet refreshed with rc.1/2/3 summary Folder convention: dev/v<version>/ for per-version development notes. Anything still in flight or candidate for the next iteration lives here; design docs that pre-date the iteration stay in docs/. Co-authored-by: Yuriy Mayatnikov <mayatnikov@me.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
11 KiB
pepa v0.2.0 — status
Read this first if you're continuing the iteration in a new session. It's the single source of truth for "where we are, what shipped, what's next".
Live state snapshot lives in
state/<host>/(gitignored). Code lives onmain. Anything in this folder is shared knowledge for future contributors / sessions.
Last update: 2026-05-27, after rc.3 merged (PR #22).
Current code: 0.2.0-rc.3. Live bot running on this version since
2026-05-27 15:32 (supervisor PID 31432, child PID rotates on hot-restart).
What v0.2.0 is
Major iteration over v0.1.x. The bot acquires a self-learning substrate: structured knowledge in SQLite, post-mortem analysis of every death by Pi, Russian chat narration, retrieval-augmented dispatch (lessons override planned actions), and a 30-min self-reflection loop where Pi asks the bot "are you in a loop?".
It also tightens the self-improvement pipeline: auto-patch now opens a
PR for operator review instead of cherry-picking onto main (branch
protection enforces — only operator can merge).
See docs/v0.2.0-self-learning.md
for the original design doc.
Shipped (rc.1 → rc.3)
rc.1 — substrate ([PR #?]/9c2c56f)
runtime/knowledge/{schema.sql,store.js,seed.js,lessons.js,index.js}— SQLite knowledge base atstate/<host>/knowledge.db. 9 tables (recipes, mob_intel, block_intel, lessons, deaths, postmortems, poi, wiki_pages, chat_log, code_changes). Seeded fromdocs/minecraft-recipes.json+ inline starter intel: 38 recipes, 15 mobs (creeper/zombie/etc. withverdict_no_weapon), 30 blocks, 12 starter lessons (creeper rule, "first wood→pickaxe→sword", etc.).runtime/coach/postmortem.js—bot.on('death')captures context (last skill, hostile, nearby journal, scenarios tail) →deathstable. Periodic drain (5min, ≤3 Pi calls/h) batches up to 8 unanalysed deaths and asks Pi for generalised lessons. Pi reply parsed intopostmortems+lessonsrows.runtime/coach/advice.js+ reflex hooks —consultAdvice()runs before dispatch incurriculumReflexanddefendReflex. Lessons withconfidence ≥ 0.6and matchingavoid_skillswap the planned skill withprefer_skill(if it's inSAFE_OVERRIDES).runtime/persona/chatter.js— Russian narration in MC chat on skill transitions, threat spotted, day/night, respawn, milestone done. Rate-limited 8/h, min 75s gap, no-dup suppression.auto-patch.jsswitched to PR-open (no more direct cherry-pick to main).PEPA_AUTO_PATCH_MERGE=cherry-pickfallback for emergencies.- Branch protection on
main: 1 required approver,enforce_admins:false.
rc.2 — P0 hardening ([PR #21]/e84148d)
- PEPA_HEADLESS=1 —
pi -psubprocesses (banter/coach/planner) no longer open a second MC connection. extensions/mineflayer-bridge.ts:session_startskipsconnect("startup")when env is set; pi-bridge sets it on every spawn. - Test state isolation —
runtime/config.jsdetects node test runner /PEPA_STATE_DIRand redirectsstateDirto/tmp/pepa-test-state-<pid>/.npm testno longer pollutes livescenarios.jsonl/world-journal.jsonl/ daily log. - defendReflex outcome bug fix —
reportAdviceOutcomewas called withsucceeded:falsebefore the flee skill returned. Now wired throughdispatchDefendFleeonComplete. - Mode-name → skill-id translation in
coach/advice.js. Pi-coach prefer values like"night_shelter","self_preservation","hunger"now map tosurvive.sleep / survive.flee / survive.eat. - Self-reflection loop (
runtime/coach/reflect.js). Every 30 min Pi gets asked "are you making progress, or in a loop?". Verdict + summary + new lessons. Writes tostate/<host>/reflections/<ts>.md, lessons land in DB withsource="pi-reflect". Rate-limited 2/h.
rc.3 — escape mechanics ([PR #22]/865aae1)
survive.pillar-up— vertical escape skill. Places dirt/cobble/ planks under self, jumps onto it. Up to 8 steps per dispatch. NO pickaxe required.- Wedged-emergency reflex — at top of
curriculumReflex: if no hostile <6m AND position hasn't moved 16+ blocks in 60s AND placeable block in inv → force pillar-up. 2-min cooldown. - consult() in fallback path —
curriculumReflexwander/explore.far fallback now consults advice too. This closes the gap where Pi-coach lessons fired but the dispatcher's fallback bypassed them. - POI on death —
coach/postmortem.jscallsrecordPOI({kind:"danger"})on every death. 6h expiry. POI table now populates as bot plays. - SAFE_OVERRIDES extended: +
survive.pillar-up, +village.choose-base.
Current state (2026-05-27 ~15:30, ~1.5h after rc.3)
Live DB:
deaths 28
postmortems 22 (coach analyzed all but 6 — backlog draining at 5min/batch)
lessons 34 (12 starter + 22 Pi-extracted)
lessons_applied 1 ← still very low; advice consult fires but most matches fail
poi 22 (rc.3 fired recordPOI on every death since 14:17 deploy)
chat_log 0 (chatter narrates in MC chat but doesn't write to DB table yet)
reflections 2 (14:51, 15:22 — 30-min interval working)
The bot is alive but still struggling. Coach is producing high-quality
lessons (see state/<host>/reflections/2026-05-27T12-21-58-656Z.md:
"Я не продвинулся к цели… выбрать новое безопасное дневное место"), but:
- Pi-coach + Pi-reflect routinely invent
prefer_skillvalues that aren't registered skill ids (e.g.choose.safe.surface,relocate.daylight).normalisePreferSkillonly knows mode names, not these. So even the right advice can't dispatch the right action. - The bot's home terrain (~608, 90) is genuinely bad — stone walls, no pickaxe to break out, hostiles spawn nearby. pillar-up can help but it needs a placeable block AND open sky above. In a closed cave it places dirt and hits a ceiling.
gather.stonereturnsmissing_toolcorrectly (rc.0 was already fine here), but curriculum doesn't auto-route tocraft.wooden-pickaxe— it just backs off and tries the same thing.
Known issues / followups (rc.4 candidates)
Ranked roughly by impact.
1. Pi-suggested prefer_skill is often a hallucinated action name
Symptom: reflections produce prefer: choose.safe.surface,
prefer: relocate.daylight, prefer: defend.self — none are
registered skills. SAFE_OVERRIDES check fails, lesson falls back
to bare avoid (which dispatches nothing).
Fix options:
- (a) Include the full registered-skill list in the Pi prompt so it picks from valid IDs.
- (b) Add a fuzzy mapper: "choose|find|new + base|spot|place" →
village.choose-base. "relocate|move + safe|day" →explore.far. - (c) Both. (b) is a fallback safety net.
Where: runtime/coach/{postmortem.js, reflect.js} prompt builder +
runtime/coach/advice.js normalisePreferSkill.
2. Tool-progression auto-craft
Symptom: gather.stone returns missing_tool → curriculum backs
off → next tick tries gather.stone again → loop. Should auto-suggest
craft.wooden-pickaxe. Same pattern for axe-required gathering.
Fix: In curriculum or in a new "tool-need" reflex, when a gather
skill returns missing_tool, look up the tier requirement (already in
block_intel.required_tool) and route to the matching craft skill if
materials are available, else to the prerequisite gather skill.
Where: runtime/reflex.js or new runtime/coach/tool-progression.js.
3. village.choose-base should penalise danger POI
Symptom: bot may pick a new base that's adjacent to a danger POI
(a recent death site). rc.3 records the POIs but choose-base scoring
doesn't read them.
Fix: In runtime/base-site.js scoreCurrentPosition, query
poiNearby({kind:"danger", x, z, radius: 32}) and subtract a penalty
proportional to recent danger count.
4. Pillar-up perimeter sense
Symptom: in a closed cave, pillar-up places a block and hits the ceiling block above. Useless.
Fix: before starting pillar-up, scan a 3×3 above current head; if
solid blocks in the column path, abort and request recovery.tunnel-out
instead. Or walk to a column-clear cell within reach first.
5. chat_log table not populated
Symptom: 0 rows in chat_log despite bot narrating ~8 lines/hour.
Fix: runtime/persona/chatter.js sendChat() calls logChat()
from knowledge index. Also wire the inbound side in bot.js
bot.on("chat") handler.
6. Reflections don't write lessons to the DB until they parse
Symptom: confirmed working; just noting that the verdict + summary
themselves aren't queryable. Currently only lessons table benefits
from reflection.
Possible fix: add a reflections table mirroring the JSON output.
Or run lessons-from-reflection through the same advice path so they
get applied_count.
7. Re-narration spam
Symptom: persona narrated за дровами twice in 6 seconds after
hot-restart. Cooldown is per-process state, lost on restart.
Fix: persist _lastNarrationAt and _narrationTimes in a small
file in state/<host>/ so restarts inherit the cooldown.
Next session — quick start
- Read this file first.
- Check live DB for the latest counters:
sqlite3 state/play.xmatic.team_25565/knowledge.db \ "SELECT 'deaths', COUNT(*) FROM deaths UNION SELECT 'lessons', COUNT(*) FROM lessons UNION SELECT 'lessons_applied', COUNT(*) FROM lessons WHERE applied_count > 0 UNION SELECT 'poi', COUNT(*) FROM poi;" - Read the latest reflection for current Pi assessment:
ls -t state/play.xmatic.team_25565/reflections/ | head -1 - Check bot is alive:
ps aux | grep "runtime/(bot|supervisor)". - Pick a followup from §"Known issues" (1 and 2 are the highest impact: actually-applying-lessons + tool progression).
Workflow notes for next session
mainis protected — only the operator merges PRs. Auto-patch from the bot itself opens PRs viagh pr create.- Tests:
npm test(255+ green at last check). Tests run isolated under/tmp/pepa-test-state-<pid>/and don't pollute live state. - The bot supervisor watches
runtime/**/*.jsand hot-restarts on file change. After merging a PR,git pulllocally and the supervisor picks up the new code. - Stop bot:
bash scripts/stop.sh. Start:npm run bot(inside tmux is fine). - Memory in
state/<host>/is server-specific and gitignored. - Don't bypass branch protection — the auto-mode classifier will block it.