`craftPlanks`, `craftSticks`, `placeCraftingTable` (reuses existing table within 4 m), `craftWoodenAxe`, `craftWoodenPickaxe`, `craftWoodenSword`. All use `bot.recipesFor`+`bot.craft` with a 15 s timeout. Same `{ok, detail}` shape as the other actions.
Helpers `inv.{getItemCount, getAnyPlanksCount, getAnyLogCount}` exported for cheap inventory checks in reflexes.
2. Tech-tree reflex (`runtime/reflex.js`)
New `techTreeReflex` between sleep and autonomous. Pure script (no LLM), 5 s cooldown:
Step
Condition
Action
1
`logs ≥ 1 && planks < 4`
craft planks
2
`planks ≥ 2 && sticks < 4`
craft sticks
3
`planks ≥ 3 && sticks ≥ 2 && !hasAxe`
wooden_axe (places table)
4
`hasAxe && !hasPickaxe`
wooden_pickaxe
5
`hasAxe && hasPickaxe && !hasSword`
wooden_sword
3. LLM planner (`runtime/planner.js`)
Background `setInterval` every 15 min (+30 s warm-up). Reads `goal.md` + `plan.md` + slim snapshot, prompts Pi to output a fresh `plan.md`. Stripped of code fences, capped at 16 KB, written verbatim. Pi is told the format (numbered milestones, ✓ for done) and the constraints (overworld only, no OP, reach of current capabilities).
The reflex layer doesn't auto-execute the plan text yet — the plan is the long-horizon shape future reflexes (build house, plant farm) will read.
Progression now looks like
```
chop log (autonomous) →
craft planks → craft sticks → wooden_axe (tech-tree) →
chop faster (autonomous, has axe) →
wooden_pickaxe + wooden_sword (tech-tree) →
mine stone … (next PR: stone tools, farm site, house frame)
```
Test plan
All three modules import cleanly (sanity check passed)
## Scope
Closes "бот стоит, копит proposals" → "копит ресурсы, строит к глобальной цели" pivot.
Three pieces in one PR:
### 1. Crafting primitives (\`runtime/actions.js\`)
\`craftPlanks\`, \`craftSticks\`, \`placeCraftingTable\` (reuses existing table within 4 m), \`craftWoodenAxe\`, \`craftWoodenPickaxe\`, \`craftWoodenSword\`. All use \`bot.recipesFor\`+\`bot.craft\` with a 15 s timeout. Same \`{ok, detail}\` shape as the other actions.
Helpers \`inv.{getItemCount, getAnyPlanksCount, getAnyLogCount}\` exported for cheap inventory checks in reflexes.
### 2. Tech-tree reflex (\`runtime/reflex.js\`)
New \`techTreeReflex\` between sleep and autonomous. Pure script (no LLM), 5 s cooldown:
| Step | Condition | Action |
|---|---|---|
| 1 | \`logs ≥ 1 && planks < 4\` | craft planks |
| 2 | \`planks ≥ 2 && sticks < 4\` | craft sticks |
| 3 | \`planks ≥ 3 && sticks ≥ 2 && !hasAxe\` | wooden_axe (places table) |
| 4 | \`hasAxe && !hasPickaxe\` | wooden_pickaxe |
| 5 | \`hasAxe && hasPickaxe && !hasSword\` | wooden_sword |
### 3. LLM planner (\`runtime/planner.js\`)
Background \`setInterval\` every 15 min (+30 s warm-up). Reads \`goal.md\` + \`plan.md\` + slim snapshot, prompts Pi to output a fresh \`plan.md\`. Stripped of code fences, capped at 16 KB, written verbatim. Pi is told the format (numbered milestones, ✓ for done) and the constraints (overworld only, no OP, reach of current capabilities).
The reflex layer doesn't auto-execute the plan text yet — the plan is the long-horizon shape future reflexes (build house, plant farm) will read.
## Progression now looks like
\`\`\`
chop log (autonomous) →
craft planks → craft sticks → wooden_axe (tech-tree) →
chop faster (autonomous, has axe) →
wooden_pickaxe + wooden_sword (tech-tree) →
mine stone … (next PR: stone tools, farm site, house frame)
\`\`\`
## Test plan
- [x] All three modules import cleanly (sanity check passed)
- [ ] Live: bot collects 4 logs → auto-crafts planks → auto-crafts sticks → auto-crafts axe
- [ ] Live: after 30 s, \`state/<host>/plan.md\` appears, content reflects current goal
- [ ] Live: \`state/<host>/plan.md\` regenerates every 15 min
## Next PR (queued)
- Stone-tier progression: mine cobblestone with wooden pickaxe → stone tools
- Site selection: pick a flat spot near water + trees per goal.md
- Build primitives: place block grid (3×3 frame for first hut)
- Persistent \`locations.json\` for named places
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Scope
Closes "бот стоит, копит proposals" → "копит ресурсы, строит к глобальной цели" pivot.
Three pieces in one PR:
1. Crafting primitives (`runtime/actions.js`)
`craftPlanks`, `craftSticks`, `placeCraftingTable` (reuses existing table within 4 m), `craftWoodenAxe`, `craftWoodenPickaxe`, `craftWoodenSword`. All use `bot.recipesFor`+`bot.craft` with a 15 s timeout. Same `{ok, detail}` shape as the other actions.
Helpers `inv.{getItemCount, getAnyPlanksCount, getAnyLogCount}` exported for cheap inventory checks in reflexes.
2. Tech-tree reflex (`runtime/reflex.js`)
New `techTreeReflex` between sleep and autonomous. Pure script (no LLM), 5 s cooldown:
3. LLM planner (`runtime/planner.js`)
Background `setInterval` every 15 min (+30 s warm-up). Reads `goal.md` + `plan.md` + slim snapshot, prompts Pi to output a fresh `plan.md`. Stripped of code fences, capped at 16 KB, written verbatim. Pi is told the format (numbered milestones, ✓ for done) and the constraints (overworld only, no OP, reach of current capabilities).
The reflex layer doesn't auto-execute the plan text yet — the plan is the long-horizon shape future reflexes (build house, plant farm) will read.
Progression now looks like
```
chop log (autonomous) →
craft planks → craft sticks → wooden_axe (tech-tree) →
chop faster (autonomous, has axe) →
wooden_pickaxe + wooden_sword (tech-tree) →
mine stone … (next PR: stone tools, farm site, house frame)
```
Test plan
Next PR (queued)
🤖 Generated with Claude Code