Day 50 of 55 · Monday · Learning

The interpreter is part of the programConcept

A script is its text PLUS the interpreter that runs it. Two outages this week came from the same file running under the wrong Python.

Catch-up progress
50/55
Why this matters to you

The morning brief died silently for four straight days on an f-string SyntaxError at remarkable.py line 89, and on 8/23 the device-inventory survey turned up 78 repeated failures from a second f-string crash in the pull pipeline. The code hadn't changed — the Python executing it had.

When you write `python3 script.py`, you're really naming two programs: the script and the interpreter. macOS ships a system Python 3.9; Homebrew and uv install newer ones; a venv pins its own. Each has different syntax rules and different installed packages. Nested quotes inside an f-string — f"{d['key']}" — parse fine on Python 3.12 and raise SyntaxError on 3.9. Same file, two different outcomes.

The failure mode is that a LaunchAgent doesn't inherit your terminal's PATH. It resolves `python3` from a minimal environment, which usually means the system 3.9 — while your interactive testing runs whatever your shell finds first. So 'it worked when I ran it' and 'it crashed at 06:15' are both true, about different interpreters.

You've met the dependency-side twin already: rm_composite.py imports cairosvg, which only exists inside the rm-render venv. Running it with system python fails on import; running it with the venv's python works. Interpreter identity decides both what parses and what imports.

Worked example

See the split with your own interpreters, then compile-check the real file the way the LaunchAgent runs it.

which -a python3
/usr/bin/python3 --version
python3 -c "d={'k':1}; print(f\"{d['k']}\")"
/usr/bin/python3 -c "d={'k':1}; print(f\"{d['k']}\")"
/usr/bin/python3 -m py_compile /Users/tom/Claude/PDB/scripts/remarkable.py && echo PARSES
▶ Do it now
  1. Run `which -a python3` and note whether /usr/bin/python3 (the system 3.9) is in the list.
  2. Find the interpreter your plan-day LaunchAgent actually uses: `grep -n python3 /Users/tom/Claude/PDB/scripts/run_plan_day.sh`.
  3. Compile-check with that exact interpreter: `<that-python> -m py_compile /Users/tom/Claude/PDB/scripts/remarkable.py /Users/tom/Claude/PDB/scripts/rm_pull.py` — a clean exit is your proof the 06:15 run can at least parse.

Gotchas

Go deeper: Python 3.12 f-string changes (PEP 701)
One-card takeaway

Test with the interpreter that will run the job, not the one that happens to answer in your terminal.