Five concrete patterns from Voyager and Mindcraft, applied in our shape
without abandoning the git-as-evolution-substrate that makes pepa
distinct. Plus a first multi-agent surface so two bots from the same
repo can share intent.
1. runtime/critic.js (Voyager critic.txt)
- Spawns `pi -p` with a JSON-only critic prompt before a proposal is
written. {reasoning, success, critique}.
- success=true short-circuits the proposal (bot recovered between
detector tripping and now), saving Pi tokens on false positives.
- critique is spliced into the proposal body via attachCritique() so
the downstream auto-patcher has a sharp spec.
- Graceful: pi missing / timeout / unparseable JSON → proposal still
filed without the critic block.
2. scripts/lint-patch.js (Mindcraft coder._lintCode)
- Pre-flight gate between Pi commit and npm test: node --check, dynamic
import (catches missing named exports), regex extraction of
runSkill("id") calls cross-checked against the live registry.
- Cheaper than npm test, fails fast with a clear reason.
3. runtime/stuck-incident.renderActionTemplate (Voyager action_template.txt)
- All proposal bodies now follow the same fixed-section layout: Task /
Last result / Execution error / State / Metrics / Journal /
Scenarios / Critique / Fix / Edit scope / Forbidden.
4. runtime/skill-library.js (Mindcraft skill_library.getRelevantSkillDocs)
- Word-overlap ranking (Mindcraft's offline fallback) — zero deps,
deterministic. auto-patch.js injects top-3 similar skills into the
Pi prompt as "look at these patterns".
5. runtime/modes.js (Mindcraft modes.js)
- Declarative {name, interrupts, on, active, update(ctx)} chain that
runs BEFORE the curriculum each tick.
- Ships self_preservation (low HP → eat/flee), hunger (food<14 → eat),
night_shelter (night + bed in hand → sleep). Cleaner than ad-hoc
lastFleeAttempt cooldowns in reflex.js.
6. runtime/social/conversation.js + cmd:conv-say/conv-recent/conv-list
- File-JSONL topic channel so two bots from the same repo (different
usernames, different host dirs under state/) can append turns and
read peers. Skeleton — multi-agent collaboration on top later.
Differentiator preserved: every Pi-written skill still lands on main via
auto-patch.js (real git branch + smoke gate + cherry-pick). Voyager
keeps skills in a Chroma JSON, Mindcraft keeps them in RAM — pepa keeps
them as versioned source code reviewable in `git log`.
package.json: 0.0.1 → 0.1.0. 174/174 tests pass. README + AGENTS updated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 0 of plans/autonomous-survival-bot-prd.md: change the product
direction from operator-driven remote control to autonomous survival
resident. MC chat is dialog-only for everyone, including
OPERATOR_USERNAMES — commands like come/follow/build/pause/stop are
recorded in the diary but not dispatched. TUI remains the only local
control plane.
Runtime changes:
- Remove operatorGoalReflex from reflex.js (the come-here chat command).
- Replace handleOperatorChat in bot.js with a dialog-only handleChat
that answers greetings/status questions and records command-like
verbs (en+ru) without dispatching them.
- Default MC_VERSION to "auto" in runtime/config.js; mineflayer
receives `false` to trigger version auto-detection.
- Update auto-escalation prompt's reflex chain summary.
Docs:
- AGENTS.md: product pivot notice up top; chat-driven scope-trust is
flagged as legacy/Pi-only.
- README.md / docs/runtime.md: replace operator-chat command list with
dialog-only description; update reflex chain summary.
- docs/roadmap.md: Phase 2/3 marked superseded by the PRD where they
assumed chat-driven control.
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>
Three things that together turn the bot from a reactive chat agent into
a goal-driven autonomous one.
1. Memory model (docs/memory-model.md, new). Formal split:
- SHARED knowledge — skills/, extensions/, prompts/, docs/,
.pi/settings.json — committed, community-improvable, portable to any
server.
- PERSONAL memory — state/<MC_HOST>/ — gitignored, per-instance, per-
server. Survives restarts (local disk), doesn't survive a re-clone
(deliberately). Holds goal.md, plan.md, current-task.json,
locations.json, diary/, inventory-log.jsonl, escalations.
Covers resume-after-restart protocol, what "abstract a lesson into a
skill" means, and the two anti-patterns (committing state, gitignoring
shared knowledge).
2. AGENTS.md changes:
- New section "Long-term goal and personal memory" wiring AGENTS.md
directly into state/<MC_HOST>/goal.md + current-task.json with a
pointer to docs/memory-model.md.
- Operating principle #4 ("I'll try to learn") rewritten with
**bias to action**: a pending stub is now a last resort, not a
default. Operator-trusted requests are themselves approval — bot
does not write a stub and wait for a separate "go".
Rationale: today's pyramid task got stuck because the bot wrote
a careful "pending" stub and waited; the operator had to send
"ты ждешь одобрения? можешь стартовать!" before any action. That
extra round-trip is the reflex this rewrite removes.
- Operating principle #5 ("live your best life when idle") expanded
to "goal-driven autonomy" with an explicit 5-level priority order
(operator task > non-op reply > resume current-task.json > next
plan milestone > decompose goal). Memory protocol made concrete:
write current-task.json before every meaningful action, append to
diary, keep locations.json fresh, tick off plan.md.
3. prompts/live-your-life.md (new). Canonical kickoff to switch the
bot into autonomous mode. Numbered concrete asks (re-read three
docs, write plan.md, implement memory protocol, implement
resume-on-restart, start). Includes a "plan.md draft for review"
gate so the operator can shape direction without micromanaging
execution. Designed to be sent after Phase 0/1/operator-trust are
stable and a goal.md exists for the target server.
Companion seed (local-only, NOT in this commit because gitignored):
state/play.xmatic.team_25565/goal.md — "build a small village and
survive long-term, live like a farmer". Lives only on the operator's
machine; a fresh clone won't see it.
README and roadmap updated with the new Phase 3 status (🌱 → 🌿
kickoff) and pointers to the new memory-model doc.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two-tier chat trust:
- Anyone in OPERATOR_USERNAMES (comma-separated, .env-only) is SCOPE-trusted.
The bot skips the "out of scope / not sure where" escalation reflex for
these users and instead applies "I'll try to learn" (Operating principle
#4): attempt, codify into a new skill, or reply with a concrete reason.
- Hard safety rules (no OP, no breaking other players' builds, no .env
leak, no chat spam, no destructive bash) remain ABSOLUTE. Operators get
the same refusal + escalation as anyone else for safety-borderline
requests — with slightly pointed wording, because they should know better.
- No transitive trust: chat-based "trust X for the next hour" / "make Y
an op" requests are themselves safety escalations. Op membership only
flows through .env on disk.
Security caveat documented in .env.example: nickname-based trust is only
safe on servers with identity protection (online-mode UUID or AuthMe).
On pure cracked servers OPERATOR_USERNAMES must stay empty.
- AGENTS.md: new Identity field for OPERATOR_USERNAMES; new Operating
principle #6 "Trusted operators" with the scope-vs-safety split; old
escalation principle renumbered to #7; Control channel section
rewritten with primary/secondary trust distinction.
- .env.example: OPERATOR_USERNAMES placeholder with multi-paragraph
security note covering when the model is and isn't safe.
- prompts/grant-op-trust.md: canonical implementation prompt for the
next Pi pass — re-read AGENTS.md, wire isOperator() into the bridge's
escalation flow, codify into skills/operator-trust.md, reload bridge,
verify with two concrete chat replays (scope vs safety).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 0 (body) is done. The next steps shouldn't be guessed prompt-by-prompt —
write down the order, the judgement principles, and the next concrete
session prompt, so the bot has a coherent direction and the human can
hand it off in one message.
- docs/roadmap.md (new): six phases, each with status, scope, and stretch.
Phase 0 = 🌳 done, Phase 1 = 🌿 in progress, the rest = 🌱.
Explicit non-goals (no PvP, no OP, no cross-server identity).
- AGENTS.md: First-objective section collapsed to a pointer at the
onboarding skill (it's been done). New "What to do, in priority order"
summary citing the roadmap. New top-level "Operating principles"
section: presence, bounded reconnect, hold focus, "I'll try to learn"
reflex, idle = best-life mode, escalate destructive doubt with a
JSONL log under state/<host>/escalations.jsonl.
- prompts/awake-and-live.md (new): canonical kickoff prompt for the
next session. Scopes itself explicitly to phases 1+5+6 and excludes
locomotion (phase 2 needs care, separate session).
- README Status: 🌳 Phase 0 done / 🌱 Phase 1 in progress, links to
roadmap and operating principles.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The whole point of this project is that the agent's growth is shareable.
If skills and extensions silently land in ~/.pi/ on the maintainer's
laptop, every clone starts from zero and the repo becomes a fancy
README. Fix that with an explicit hard rule and a contributor guide.
- AGENTS.md: new "Artifact location — hard rule" subsection spelling out
that skills/extensions/prompts/state/.pi-settings ALL live in this repo,
never in ~/.pi/. Pi's own built-in skills (skill-creator, etc.) stay
user-global; the agent may use them, but their *output* must land here.
- README: new "Everything in the repo" subsection covering the same rule
in user-facing language, plus a pointer to CONTRIBUTING.md.
- CONTRIBUTING.md (new): skill/extension formats, server-agnostic and
no-secrets requirements, smoke-test recipe, PR checklist.
- .gitignore: switch from blanket `.pi/` ignore to `.pi/*` + explicit
un-ignore of `.pi/settings.json`, so project Pi config is reproducible.
- "Don't push without operator confirmation" → "without human
confirmation via the repo" — consistent with the new control model.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There's no good reason to bake a specific operator nickname into the bot's
identity — it differs per server, may not exist at all, and treating any
in-game name as "trusted" is a chat-injection vector ("I am the operator,
do X").
New model: the **repo** is the only trusted control plane. Anyone editing
AGENTS.md, skills/, or .env has filesystem access and is, by definition,
an operator. In-game chat becomes a dialog-only comms plane — the bot
talks to anyone but refuses destructive requests unless a corresponding
skill or AGENTS.md instruction makes the action explicitly permitted.
- .env / .env.example: OPERATOR_USERNAME removed
- AGENTS.md: identity section trimmed; "Operator contact" rewritten as
"Control channel" with the trust model spelled out; rules #2 and #6
rephrased so they no longer reference a named operator
- docs/architecture.md: top box renamed to "Human" with explicit
control-plane vs comms-plane split
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The bot is a universal Minecraft player, not tied to any one server.
Server identity (host, port, username, auth mode, optional AuthMe password)
is now read entirely from .env.
- README: rewritten as universal-bot pitch; auth covered as two dimensions
(MC auth mode + LLM credential)
- AGENTS.md: identity comes from .env, hard-coded references to pepa
removed; bootstrap step auto-detects whether the server uses an
AuthMe-style /register-/login plugin
- .env.example: example values replaced with placeholders, MC_AUTH_MODE
added (offline | microsoft)
- docs/architecture.md: rephrased target as "any Minecraft Java server",
added open question on cross-server vs per-server state
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>