most physical systems use python3 as the command for python not python. we need to switch all mentions of python (when used as a command) to python3
Build scope (AI-ready)
Problem
Course content invokes the interpreter as a bare python (e.g. python cli.py list). On most current systems — default Debian/Ubuntu and macOS — there is no python on PATH, only python3, so learners who copy these commands into their host shell hit command not found. The repo's own infrastructure (CI, tools/check.sh, tools/build_wiki.py, security-scan.sh, audit.sh, verify.sh, shebangs) already standardized on python3; the course-facing prose, lab READMEs, lab .py docstrings, blog posts, and a few Dockerfiles/CI examples did not. Goal: make python3 the canonical command name everywhere it is used as a host-shell command.
Scope of the change
~103 files contain a python <something> command invocation. The replacement is mechanically simple but is not a blind global sed s/python /python3 / — several contexts are commands-in-name-only or already correct and must be left alone (see Stop-lines). The real edit set:
Module READMEs (modules/*/README.md) and lab READMEs (modules/*/lab/**/README.md, capstone/README.md, capstone/lab/start/README.md): python cli.py …, python -m unittest/pytest, python --version, etc.
Lab .py docstrings / usage comments that show python cli.py … (e.g. modules/01-the-copy-paste-problem/lab/start/cli.py, every lab/start/cli.py, tasks-app/cli.py, serve.py, triage.py, reviewer.py, orient.py, sync.py, run_eval.py, llm_judge.py, tasks_mcp_server.py, reference_test_tasks.py). These are comments, not executed code — no behavior change, just the printed instructions.
Blog posts (blog/*.md): same command examples mirrored from the modules.
Module 01 convention note must be inverted, not just substituted.modules/01-the-copy-paste-problem/README.md lines ~151–154 (mirrored in blog/02-getting-started-the-copy-paste-problem.md) contain a deliberate note: "whichever of python / python3 just printed a version, that's the one you'll type … we write python … read it as python3 if that's command-not-found." This note makes python the canonical course-wide spelling. Flipping the commands without rewriting this note leaves the course self-contradicting. Rewrite it so python3 is the canonical spelling and python is the fallback (and keep the python --version / python3 --version "check which you have" guidance).
venv-internal interpreter references (Module 20) stay python.modules/20-mcp-servers-giving-the-ai-hands/README.md deliberately teaches that a bare "command": "python" in MCP config is the #1 connection failure, and instructs using the venv's absolute path .venv/bin/python / ...\.venv\Scripts\python.exe. Leave every .venv/bin/python, python.exe, the "command": "python" example being warned against, and the surrounding prose untouched. Line 273 already correctly uses python3 -m venv. Only the bare host-shell examples here (python cli.py list, python tasks_mcp_server.py) convert to python3.
Image names are not commands.FROM python:3.12-slim, image: python:3.12, docker run … python:3.12-slim … — the python: token is a Docker image tag, never touch it.
Container-internal invocations are a judgment call — default: leave as python. In modules/16-*/lab/Dockerfile (ENTRYPOINT ["python","cli.py"]), modules/18-*/lab/Dockerfile (CMD ["python","serve.py"], HEALTHCHECK … python -c), the M16 README docker run … python:3.12-slim python -c/-m, and the CI-example yamls (modules/14-*/lab/ci-starter.yml uses actions/setup-python → python symlink; gitlab-ci-starter.yml runs in image: python:3.12), python resolves correctly because the python base image / setup-python provides it. These are not "physical systems." Recommended: leave them as python (they are correct and changing them risks implying the base image lacks python). If the implementer prefers uniformity, converting them is harmless but optional — pick one and be consistent. The lab cli.py docstrings copied into these modules still convert (they describe host-shell usage).
The word "Python" the language (capital P in prose, "Python 3.10+", python:3.12-slim) is not a command — leave it.
Already-python3 infrastructure (tools/, .gitea/workflows/, .github/workflows/, tools/check.sh, security-scan.sh, audit.sh, shebangs #!/usr/bin/env python3) is already correct — no change.
Open decision: pip → pip3?
The same "physical systems only ship pip3" logic applies to ~30 bare pip install … occurrences (ruff, bandit, pip-audit, pytest, mcp[cli], etc. across modules 05/13/14/15/16/17/18/19/20/23/24/25 and blogs). The Module 01 convention note explicitly pairspython3 with pip3, so flipping python→python3 while leaving pip makes that note inconsistent. The issue text names only python. Recommendation: include the companion pip→pip3 (or python3 -m pip) change for consistency, OR explicitly note in the PR that pip was left out of scope. Confirm with the maintainer if unsure; do not silently do half. (Same container/CI stop-lines apply: pip inside a Dockerfile/python image is fine.)
Recommended approach
Rewrite the Module 01 convention note (and its blog mirror) to make python3 canonical (Stop-line 1) — do this first so the rest of the change is consistent with the stated convention.
Convert host-shell python <cmd> → python3 <cmd> across the file set above, respecting every stop-line. A scripted pass is fine but must exclude: image-tag lines (python:), .venv/.../python paths, python.exe, the M20 "command": "python" teaching examples, and (default) container/CI-internal invocations. Hand-review Module 20 and the two Dockerfiles rather than sed-ing them.
Decide pip (above) and apply uniformly.
Acceptance criteria / how to verify
Build:python3 tools/build_wiki.py --repo-root . --out /tmp/awc-wiki-build --web-base https://git.jpaul.io/justin/ai-workflow-course --branch main --host gitea succeeds (the CI build step).
Test:bash tools/check.sh passes — lab .py still py-compiles, shell scripts still parse, JSON/YAML still parse, no-em-dash guard clean, every README still has its template sections. (Docstring/comment edits don't affect compilation, but run it to be sure nothing structural broke.)
Grep audit: after the change, grep -rnE '\bpython ' modules capstone blog | grep -vE 'python3|python:|\.venv|python\.exe' should return only the deliberately-retained container/CI-internal and M20-"command" cases (Stop-lines 2/4) — review each remaining hit and confirm it's an intentional keep.
Spot-check Module 01 reads coherently: the convention note now establishes python3 as canonical and the lab commands match it.
Both CI workflows (.gitea/workflows/ci.yml, .github/workflows/ci.yml) are green on the PR.
Target surface(s)
Course content only: modules/**, capstone/**, blog/** (Markdown, lab .py docstrings/comments, lab .sh/.yml examples, lab prompt files). No application logic changes — the lab .py files only change in comments/docstrings. No changes to tools/, .gitea/, .github/ infrastructure (already python3).
most physical systems use python3 as the command for python not python. we need to switch all mentions of python (when used as a command) to python3
---
## Build scope (AI-ready)
### Problem
Course content invokes the interpreter as a bare `python` (e.g. `python cli.py list`). On most current systems — default Debian/Ubuntu and macOS — there is no `python` on PATH, only `python3`, so learners who copy these commands into their host shell hit `command not found`. The repo's own infrastructure (CI, `tools/check.sh`, `tools/build_wiki.py`, `security-scan.sh`, `audit.sh`, `verify.sh`, shebangs) already standardized on `python3`; the **course-facing prose, lab READMEs, lab `.py` docstrings, blog posts, and a few Dockerfiles/CI examples** did not. Goal: make `python3` the canonical command name everywhere it is used as a host-shell command.
### Scope of the change
~103 files contain a `python <something>` command invocation. The replacement is mechanically simple but is **not** a blind global `sed s/python /python3 /` — several contexts are commands-in-name-only or already correct and must be left alone (see Stop-lines). The real edit set:
- **Module READMEs** (`modules/*/README.md`) and **lab READMEs** (`modules/*/lab/**/README.md`, `capstone/README.md`, `capstone/lab/start/README.md`): `python cli.py …`, `python -m unittest/pytest`, `python --version`, etc.
- **Lab `.py` docstrings / usage comments** that show `python cli.py …` (e.g. `modules/01-the-copy-paste-problem/lab/start/cli.py`, every `lab/start/cli.py`, `tasks-app/cli.py`, `serve.py`, `triage.py`, `reviewer.py`, `orient.py`, `sync.py`, `run_eval.py`, `llm_judge.py`, `tasks_mcp_server.py`, `reference_test_tasks.py`). These are comments, not executed code — no behavior change, just the printed instructions.
- **Blog posts** (`blog/*.md`): same command examples mirrored from the modules.
- **Lab prompt / instruction files**: `modules/07-*/lab/agent-a-prompt.md`, `agent-b-prompt.md`, `modules/26-*/lab/agent-prompts/agent-42-count.md`, `agent-44-clear.md`, `modules/05-*/lab/instructions-file-starter.md`, `modules/09-*/lab/example-issues.md`, `modules/11-*/lab/issue.md`, `modules/24-*/lab/sample-issue.md`, `modules/21-*/lab/add-command-skill.md`, `modules/22-*/lab/suspicious-skill/SKILL.md`.
- **`modules/04-*/lab/verify.sh`**: line invoking `python cli.py` (the rest of that script already uses `python3`).
Command forms to convert: `python cli.py`, `python -m unittest|pytest`, `python -c "…"`, `python --version`, `python <script>.py` (`serve.py`, `triage.py`, `reviewer.py`, `run_eval.py`, `llm_judge.py`, `orient.py`, `sync.py`, `agent_runner.py`, `tasks_mcp_server.py`, `tools/sync.py`).
### Stop-lines — do NOT change these
1. **Module 01 convention note must be *inverted*, not just substituted.** `modules/01-the-copy-paste-problem/README.md` lines ~151–154 (mirrored in `blog/02-getting-started-the-copy-paste-problem.md`) contain a deliberate note: *"whichever of `python` / `python3` just printed a version, that's the one you'll type … we write `python` … read it as `python3` if that's command-not-found."* This note makes `python` the canonical course-wide spelling. Flipping the commands without rewriting this note leaves the course self-contradicting. Rewrite it so `python3` is the canonical spelling and `python` is the fallback (and keep the `python --version` / `python3 --version` "check which you have" guidance).
2. **venv-internal interpreter references (Module 20) stay `python`.** `modules/20-mcp-servers-giving-the-ai-hands/README.md` deliberately teaches that a bare `"command": "python"` in MCP config is the #1 connection failure, and instructs using the venv's absolute path `.venv/bin/python` / `...\.venv\Scripts\python.exe`. Leave every `.venv/bin/python`, `python.exe`, the `"command": "python"` example being warned against, and the surrounding prose untouched. Line 273 already correctly uses `python3 -m venv`. Only the bare host-shell examples here (`python cli.py list`, `python tasks_mcp_server.py`) convert to `python3`.
3. **Image names are not commands.** `FROM python:3.12-slim`, `image: python:3.12`, `docker run … python:3.12-slim …` — the `python:` token is a Docker image tag, never touch it.
4. **Container-internal invocations are a judgment call — default: leave as `python`.** In `modules/16-*/lab/Dockerfile` (`ENTRYPOINT ["python","cli.py"]`), `modules/18-*/lab/Dockerfile` (`CMD ["python","serve.py"]`, `HEALTHCHECK … python -c`), the M16 README `docker run … python:3.12-slim python -c/-m`, and the CI-example yamls (`modules/14-*/lab/ci-starter.yml` uses `actions/setup-python` → `python` symlink; `gitlab-ci-starter.yml` runs in `image: python:3.12`), `python` resolves correctly because the python base image / setup-python provides it. These are not "physical systems." Recommended: leave them as `python` (they are correct and changing them risks implying the base image lacks `python`). If the implementer prefers uniformity, converting them is harmless but optional — pick one and be consistent. **The lab `cli.py` docstrings copied into these modules still convert** (they describe host-shell usage).
5. **The word "Python" the language** (capital P in prose, "Python 3.10+", `python:3.12-slim`) is not a command — leave it.
6. **Already-`python3` infrastructure** (`tools/`, `.gitea/workflows/`, `.github/workflows/`, `tools/check.sh`, `security-scan.sh`, `audit.sh`, shebangs `#!/usr/bin/env python3`) is already correct — no change.
### Open decision: `pip` → `pip3`?
The same "physical systems only ship `pip3`" logic applies to ~30 bare `pip install …` occurrences (ruff, bandit, pip-audit, pytest, `mcp[cli]`, etc. across modules 05/13/14/15/16/17/18/19/20/23/24/25 and blogs). The Module 01 convention note explicitly **pairs** `python3` with `pip3`, so flipping `python`→`python3` while leaving `pip` makes that note inconsistent. The issue text names only `python`. **Recommendation: include the companion `pip`→`pip3` (or `python3 -m pip`) change for consistency, OR explicitly note in the PR that pip was left out of scope.** Confirm with the maintainer if unsure; do not silently do half. (Same container/CI stop-lines apply: `pip` inside a Dockerfile/python image is fine.)
### Recommended approach
1. Rewrite the Module 01 convention note (and its blog mirror) to make `python3` canonical (Stop-line 1) — do this first so the rest of the change is consistent with the stated convention.
2. Convert host-shell `python <cmd>` → `python3 <cmd>` across the file set above, respecting every stop-line. A scripted pass is fine but must exclude: image-tag lines (`python:`), `.venv/.../python` paths, `python.exe`, the M20 `"command": "python"` teaching examples, and (default) container/CI-internal invocations. Hand-review Module 20 and the two Dockerfiles rather than sed-ing them.
3. Decide pip (above) and apply uniformly.
### Acceptance criteria / how to verify
- **Build:** `python3 tools/build_wiki.py --repo-root . --out /tmp/awc-wiki-build --web-base https://git.jpaul.io/justin/ai-workflow-course --branch main --host gitea` succeeds (the CI build step).
- **Test:** `bash tools/check.sh` passes — lab `.py` still py-compiles, shell scripts still parse, JSON/YAML still parse, no-em-dash guard clean, every README still has its template sections. (Docstring/comment edits don't affect compilation, but run it to be sure nothing structural broke.)
- **Grep audit:** after the change, `grep -rnE '\bpython ' modules capstone blog | grep -vE 'python3|python:|\.venv|python\.exe'` should return only the deliberately-retained container/CI-internal and M20-`"command"` cases (Stop-lines 2/4) — review each remaining hit and confirm it's an intentional keep.
- **Spot-check Module 01** reads coherently: the convention note now establishes `python3` as canonical and the lab commands match it.
- Both CI workflows (`.gitea/workflows/ci.yml`, `.github/workflows/ci.yml`) are green on the PR.
### Target surface(s)
Course content only: `modules/**`, `capstone/**`, `blog/**` (Markdown, lab `.py` docstrings/comments, lab `.sh`/`.yml` examples, lab prompt files). No application logic changes — the lab `.py` files only change in comments/docstrings. No changes to `tools/`, `.gitea/`, `.github/` infrastructure (already `python3`).
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.
most physical systems use python3 as the command for python not python. we need to switch all mentions of python (when used as a command) to python3
Build scope (AI-ready)
Problem
Course content invokes the interpreter as a bare
python(e.g.python cli.py list). On most current systems — default Debian/Ubuntu and macOS — there is nopythonon PATH, onlypython3, so learners who copy these commands into their host shell hitcommand not found. The repo's own infrastructure (CI,tools/check.sh,tools/build_wiki.py,security-scan.sh,audit.sh,verify.sh, shebangs) already standardized onpython3; the course-facing prose, lab READMEs, lab.pydocstrings, blog posts, and a few Dockerfiles/CI examples did not. Goal: makepython3the canonical command name everywhere it is used as a host-shell command.Scope of the change
~103 files contain a
python <something>command invocation. The replacement is mechanically simple but is not a blind globalsed s/python /python3 /— several contexts are commands-in-name-only or already correct and must be left alone (see Stop-lines). The real edit set:modules/*/README.md) and lab READMEs (modules/*/lab/**/README.md,capstone/README.md,capstone/lab/start/README.md):python cli.py …,python -m unittest/pytest,python --version, etc..pydocstrings / usage comments that showpython cli.py …(e.g.modules/01-the-copy-paste-problem/lab/start/cli.py, everylab/start/cli.py,tasks-app/cli.py,serve.py,triage.py,reviewer.py,orient.py,sync.py,run_eval.py,llm_judge.py,tasks_mcp_server.py,reference_test_tasks.py). These are comments, not executed code — no behavior change, just the printed instructions.blog/*.md): same command examples mirrored from the modules.modules/07-*/lab/agent-a-prompt.md,agent-b-prompt.md,modules/26-*/lab/agent-prompts/agent-42-count.md,agent-44-clear.md,modules/05-*/lab/instructions-file-starter.md,modules/09-*/lab/example-issues.md,modules/11-*/lab/issue.md,modules/24-*/lab/sample-issue.md,modules/21-*/lab/add-command-skill.md,modules/22-*/lab/suspicious-skill/SKILL.md.modules/04-*/lab/verify.sh: line invokingpython cli.py(the rest of that script already usespython3).Command forms to convert:
python cli.py,python -m unittest|pytest,python -c "…",python --version,python <script>.py(serve.py,triage.py,reviewer.py,run_eval.py,llm_judge.py,orient.py,sync.py,agent_runner.py,tasks_mcp_server.py,tools/sync.py).Stop-lines — do NOT change these
modules/01-the-copy-paste-problem/README.mdlines ~151–154 (mirrored inblog/02-getting-started-the-copy-paste-problem.md) contain a deliberate note: "whichever ofpython/python3just printed a version, that's the one you'll type … we writepython… read it aspython3if that's command-not-found." This note makespythonthe canonical course-wide spelling. Flipping the commands without rewriting this note leaves the course self-contradicting. Rewrite it sopython3is the canonical spelling andpythonis the fallback (and keep thepython --version/python3 --version"check which you have" guidance).python.modules/20-mcp-servers-giving-the-ai-hands/README.mddeliberately teaches that a bare"command": "python"in MCP config is the #1 connection failure, and instructs using the venv's absolute path.venv/bin/python/...\.venv\Scripts\python.exe. Leave every.venv/bin/python,python.exe, the"command": "python"example being warned against, and the surrounding prose untouched. Line 273 already correctly usespython3 -m venv. Only the bare host-shell examples here (python cli.py list,python tasks_mcp_server.py) convert topython3.FROM python:3.12-slim,image: python:3.12,docker run … python:3.12-slim …— thepython:token is a Docker image tag, never touch it.python. Inmodules/16-*/lab/Dockerfile(ENTRYPOINT ["python","cli.py"]),modules/18-*/lab/Dockerfile(CMD ["python","serve.py"],HEALTHCHECK … python -c), the M16 READMEdocker run … python:3.12-slim python -c/-m, and the CI-example yamls (modules/14-*/lab/ci-starter.ymlusesactions/setup-python→pythonsymlink;gitlab-ci-starter.ymlruns inimage: python:3.12),pythonresolves correctly because the python base image / setup-python provides it. These are not "physical systems." Recommended: leave them aspython(they are correct and changing them risks implying the base image lackspython). If the implementer prefers uniformity, converting them is harmless but optional — pick one and be consistent. The labcli.pydocstrings copied into these modules still convert (they describe host-shell usage).python:3.12-slim) is not a command — leave it.python3infrastructure (tools/,.gitea/workflows/,.github/workflows/,tools/check.sh,security-scan.sh,audit.sh, shebangs#!/usr/bin/env python3) is already correct — no change.Open decision:
pip→pip3?The same "physical systems only ship
pip3" logic applies to ~30 barepip install …occurrences (ruff, bandit, pip-audit, pytest,mcp[cli], etc. across modules 05/13/14/15/16/17/18/19/20/23/24/25 and blogs). The Module 01 convention note explicitly pairspython3withpip3, so flippingpython→python3while leavingpipmakes that note inconsistent. The issue text names onlypython. Recommendation: include the companionpip→pip3(orpython3 -m pip) change for consistency, OR explicitly note in the PR that pip was left out of scope. Confirm with the maintainer if unsure; do not silently do half. (Same container/CI stop-lines apply:pipinside a Dockerfile/python image is fine.)Recommended approach
python3canonical (Stop-line 1) — do this first so the rest of the change is consistent with the stated convention.python <cmd>→python3 <cmd>across the file set above, respecting every stop-line. A scripted pass is fine but must exclude: image-tag lines (python:),.venv/.../pythonpaths,python.exe, the M20"command": "python"teaching examples, and (default) container/CI-internal invocations. Hand-review Module 20 and the two Dockerfiles rather than sed-ing them.Acceptance criteria / how to verify
python3 tools/build_wiki.py --repo-root . --out /tmp/awc-wiki-build --web-base https://git.jpaul.io/justin/ai-workflow-course --branch main --host giteasucceeds (the CI build step).bash tools/check.shpasses — lab.pystill py-compiles, shell scripts still parse, JSON/YAML still parse, no-em-dash guard clean, every README still has its template sections. (Docstring/comment edits don't affect compilation, but run it to be sure nothing structural broke.)grep -rnE '\bpython ' modules capstone blog | grep -vE 'python3|python:|\.venv|python\.exe'should return only the deliberately-retained container/CI-internal and M20-"command"cases (Stop-lines 2/4) — review each remaining hit and confirm it's an intentional keep.python3as canonical and the lab commands match it..gitea/workflows/ci.yml,.github/workflows/ci.yml) are green on the PR.Target surface(s)
Course content only:
modules/**,capstone/**,blog/**(Markdown, lab.pydocstrings/comments, lab.sh/.ymlexamples, lab prompt files). No application logic changes — the lab.pyfiles only change in comments/docstrings. No changes totools/,.gitea/,.github/infrastructure (alreadypython3).🤖 autopilot: merged @ (merge-only — no deploy to verify).