Safe text-decision to action loop. Deciders never touch the world; executors never choose.
- Observe → text state + candidate actions
- Decide → exactly one action id + go/stop
- Execute → dry-run first, run, verify proof
- Repeat only on explicit
go— never on its own
from laya_hands import Action, run_loop
run_loop(observe, decide) # decide returns (action_id, go); "" stops cleanobserve()returns(state_text, [Action, ...])decide(state_text, actions)returns(action_id, go: bool)— unknown ids raise,""stops without actingAction.execute()runs dry-run, thenrun, thenverify(non-Trueproof raises)
python demo.py — drives its own tkinter window from 0 to 3 (widget reads +
invoke, no blind keystrokes), verifies the label, self-closes:
state: count: 0
- increment: press +1 once
did increment: count=1
...
stopped by decider
OK: 3 iterations, window closed clean
Sandbox rule: demos use their own window and verify OK.
Small, scoped PRs. Stdlib only — keep it that way.
