jevsnes.git / tools / watch

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 budget tool 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 word unknown for a missing or null field: never 0, never false, never no. A watchdog must not mistake an old build that cannot answer for a healthy one.

CodeMeaning
0Asking works, or is throttled (the question bucket or the hour breaker) and will clear by itself; the line says which.
2Stopped for good: the vendor said the account is out of credit. Waiting will not clear it.
3No window answered at all (no Mcp-Session-Id came back).
4A 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-test

runs 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 unknown does.

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

PathWhat
budget.shThe one-line status, its exit codes, and --self-test. Shares its MCP session dance with ../hotpatch/patch.sh.
README.mdThis chapter.
CLAUDE.mdThe subshell and keepalive traps, for agents.

← Previous: Chapter 25, mcp/ · Up: tools · Next: Chapter 27, hotpatch/ →