Chapter 26: watch, one line of status
Jev costs money, and the window can run for days. Something should check,
once a minute, that questions are still being asked, and shout if they have
stopped for a reason that will not clear by itself. budget.sh is the thing
that something runs. It asks the running window over MCP and prints one
line:
2026-10-02T14:03:11Z task=… mode=overworld link=2096,2000 lifetime_remaining=unknown q/min=4 stopped=no
time, the bot's current task, the game mode, Link's position, a lifetime figure, questions in the last minute, and what (if anything) is stopping questions. Then it exits with a code a watchdog can act on.
nix develop -c tools/watch/budget.sh
It needs no API key: it only talks to the window's MCP endpoint
(http://127.0.0.1:7637/mcp), and it never turns dev mode on, because every
tool it calls (state, budget, bot) is always there.
Aside: "I don't know" is not "fine". The most important exit code is 4. If the window answers but the
budgettool is missing, or the field that says whether asking has stopped cannot be read, the script exits 4, never 0. Every field goes through one function,get, which returns the literal wordunknownfor a missing or null field: never0, neverfalse, neverno. A watchdog must not mistake an old build that cannot answer for a healthy one.
| Code | Meaning |
|---|---|
| 0 | Asking works, or is throttled (the question bucket or the hour breaker) and will clear by itself; the line says which. |
| 2 | Stopped for good: the vendor said the account is out of credit. Waiting will not clear it. |
| 3 | No window answered at all (no Mcp-Session-Id came back). |
| 4 | A window answered, but the budget tool, or whether asking is stopped, could not be read. Treat as stopped. |
Meant for a once-a-minute watchdog:
tools/watch/budget.sh
case $? in
0) ;; # fine
2) page-someone "stopped for good" ;;
3) page-someone "window down" ;;
4) page-someone "can't tell - treat as stopped" ;;
esac
Try it. No window needed:
nix develop -c bash tools/watch/budget.sh --self-testruns the parsing and formatting against recorded JSON-RPC bodies: a tool present with nothing stopping questions, one throttled (not a stop), one stopped for good, a tool missing entirely (the error shape an old build really returns), and a leading SSE keepalive ahead of the real payload. Every case that should read
unknowndoes.
For the people who maintain it
lifetime_remaining reads unknown against today's window. The ledger
stopped reporting a remaining figure when the self-imposed lifetime cap was
removed (2026-09-22); the budget tool now carries lifetime_usd, spent so
far, and the script still asks for lifetime_remaining_usd. The exit code
does not depend on it, so a watchdog is unaffected.
In this folder
| Path | What |
|---|---|
| budget.sh | The one-line status, its exit codes, and --self-test. Shares its MCP session dance with ../hotpatch/patch.sh. |
| README.md | This chapter. |
| CLAUDE.md | The subshell and keepalive traps, for agents. |
← Previous: Chapter 25, mcp/ · Up: tools · Next: Chapter 27, hotpatch/ →