```
reflex fails 3× → proposal markdown file → operator approves in TUI →
npm run propose:apply → spawn Pi on a feature branch →
Pi commits the patch → supervisor restarts the child on file change
```
Operator is in the loop at the approval step and the diff-review step — Pi never pushes or merges on its own.
New IPC commands: `PROPOSAL_LATEST`, `PROPOSAL_APPROVE`.
`tui/tui.tsx` — status bar badge `[proposals N, press y]`. Hotkey `y` opens the latest proposal; `y` approves, `n`/Esc closes.
`scripts/propose-apply.js` — given an approved filename, creates `feat/proposal-` branch, spawns `pi -p` with proposal + repo-conventions prompt. Refuses on dirty tree.
`runtime/supervisor.js` — forks `bot.js` as a child, watches `runtime/*.js`, restarts on file change or exit code 42. Rate-limited 5 restarts/min. Clean SIGINT/SIGTERM. `npm run bot` goes through supervisor; `npm run bot:bare` is the unsupervised escape hatch.
Why supervisor instead of true ESM hot-reload
True module hot-reload in Node ESM means dealing with import-cache poisoning, the open mineflayer client, the IPC socket, the path-finder plugin's WeakMap. Restart-on-change is the same outcome with none of the gotchas — the bot loses a TCP connection it would reconnect after a kick anyway.
Smoke test
`npm run bot` brings up supervisor + child, child connects + AuthMe login + spawn at (623, 85, 95).
Diary line written: `13:18:46 spawned at 623,85,95`.
SIGTERM forwards cleanly, IPC socket removed, current-task.json reset to `{}`.
Test plan
Trigger a real proposal: park the bot in dark_forest, let `flee from zombie` fail 3×, verify a proposal markdown lands under `state//proposals/`.
Open TUI, see `[proposals 1, press y]` badge, press `y`, read the proposal, press `y` to approve.
Run `npm run propose:apply ` and verify Pi gets the prompt and a new feature branch.
Edit `runtime/reflex.js` while supervisor is up → supervisor logs restart → bot reconnects.
## Summary
Closes the self-improvement loop:
\`\`\`
reflex fails 3× → proposal markdown file → operator approves in TUI →
npm run propose:apply <file> → spawn Pi on a feature branch →
Pi commits the patch → supervisor restarts the child on file change
\`\`\`
Operator is in the loop at the approval step and the diff-review step — Pi never pushes or merges on its own.
## Pieces
- **\`runtime/state-store.js\`** — atomic write-rename for \`current-task.json\`, daily diary append, proposals/ + proposals/approved/ helpers.
- **\`runtime/bot.js\`**:
- \`ctx.dispatch\` writes \`current-task.json\` on start, updates on completion / failure / throw.
- Failure tracker: 3 consecutive same-label failures → \`writeProposal()\` with the snapshot, label history, and a "next-step" section. 30 min cooldown.
- Startup logs previous task + pending-proposal count.
- On death: clears current-task, writes diary line.
- New IPC commands: \`PROPOSAL_LATEST\`, \`PROPOSAL_APPROVE\`.
- **\`tui/tui.tsx\`** — status bar badge \`[proposals N, press y]\`. Hotkey \`y\` opens the latest proposal; \`y\` approves, \`n\`/Esc closes.
- **\`scripts/propose-apply.js\`** — given an approved filename, creates \`feat/proposal-<slug>\` branch, spawns \`pi -p\` with proposal + repo-conventions prompt. Refuses on dirty tree.
- **\`runtime/supervisor.js\`** — forks \`bot.js\` as a child, watches \`runtime/*.js\`, restarts on file change or exit code 42. Rate-limited 5 restarts/min. Clean SIGINT/SIGTERM. \`npm run bot\` goes through supervisor; \`npm run bot:bare\` is the unsupervised escape hatch.
## Why supervisor instead of true ESM hot-reload
True module hot-reload in Node ESM means dealing with import-cache poisoning, the open mineflayer client, the IPC socket, the path-finder plugin's WeakMap. Restart-on-change is the same outcome with none of the gotchas — the bot loses a TCP connection it would reconnect after a kick anyway.
## Smoke test
- \`npm run bot\` brings up supervisor + child, child connects + AuthMe login + spawn at (623, 85, 95).
- Diary line written: \`13:18:46 spawned at 623,85,95\`.
- SIGTERM forwards cleanly, IPC socket removed, current-task.json reset to \`{}\`.
## Test plan
- [ ] Trigger a real proposal: park the bot in dark_forest, let \`flee from zombie\` fail 3×, verify a proposal markdown lands under \`state/<host>/proposals/\`.
- [ ] Open TUI, see \`[proposals 1, press y]\` badge, press \`y\`, read the proposal, press \`y\` to approve.
- [ ] Run \`npm run propose:apply <filename>\` and verify Pi gets the prompt and a new feature branch.
- [ ] Edit \`runtime/reflex.js\` while supervisor is up → supervisor logs restart → bot reconnects.
🤖 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.
Summary
Closes the self-improvement loop:
```
reflex fails 3× → proposal markdown file → operator approves in TUI →
npm run propose:apply → spawn Pi on a feature branch →
Pi commits the patch → supervisor restarts the child on file change
```
Operator is in the loop at the approval step and the diff-review step — Pi never pushes or merges on its own.
Pieces
Why supervisor instead of true ESM hot-reload
True module hot-reload in Node ESM means dealing with import-cache poisoning, the open mineflayer client, the IPC socket, the path-finder plugin's WeakMap. Restart-on-change is the same outcome with none of the gotchas — the bot loses a TCP connection it would reconnect after a kick anyway.
Smoke test
Test plan
🤖 Generated with Claude Code