* build: declare the Python toolchain in pyproject.toml
Pin the dev environment (pytest, pytest-xdist, pyyaml, ruamel.yaml, ruff)
with uv instead of a one-line --with list in package.json. The project is
marked non-packaged: the tree itself is what gets installed, and shipped
scripts keep their inline metadata. The validate CI job now runs on uv
alone, without Node, and gains a ruff check.
* style: apply ruff to tools and skill scripts
Mechanical output of ruff check --fix and ruff format under the new
config, plus four hand edits: explicit zip strictness in setup.py and
test_sprint_status.py, an f-string for the hex colour in brain.py, and a
noqa on the sys.path-dependent import in render_skill.py. No behaviour
change; 500 tests pass.
* build: declare Python 3.11 as the floor of every shipped script
Eighteen scripts declared 3.8 or 3.10 inline while ruff targeted 3.11,
so an autofix could introduce syntax those scripts did not advertise.
The lower floors were never reachable: every skill that carried one
also runs a 3.11 hub script, and uv fetches whatever interpreter a
script asks for. All inline metadata now says 3.11, and a test keeps
the inline floors equal to requires-python and the ruff target.
The Python rewrite of the file-ref checker ported the JS pattern verbatim,
including the `\\\\` that only matched the escaped `C:\\Users` form. Main
fixed the JS copy in #2794 before this branch deleted it; apply the same
pattern here so the rebase does not revert the fix.
The checker's V4/V5 grammar (exec attrs, invoke-task, step metadata,
Load directives, quoted dot-paths, {_bmad} shorthand) matches nothing
in the flat tree; it verified only four script filenames. It now
resolves backticked slash-paths against the containing file's directory
and the skill root, flagging a missing file only when the path's first
directory exists — paths without one are prose, so the current tree
stays at zero false positives (276 refs verified, up from 135). Files
sitting directly under skills/ are reported as stray.
The checker still scanned src/, which the flattening removed, so it
crashed on any fresh checkout and failed the quality gate. It now scans
skills/; the obsolete core-skills/bmm-skills module mapping is replaced
by _bmad/scripts/ -> skills/bmad/scripts/, with the install-only and
install-generated skip lists unchanged.
Port tools/validate-file-refs.js to tools/validate_file_refs.py (PEP 723,
pyyaml) preserving detection, resolution, CLI, and CI-annotation behavior.
CSV extraction is dropped: .csv leaves the scan set, and the CSV test and
fixtures are deleted rather than ported. The npm dependencies block (yaml,
csv-parse) goes away with its sole consumer; validate:refs and test:refs
now run via uv, and test:refs joins the quality chain. A new stdlib
unittest suite covers extraction, mapping, skip lists, UNRESOLVED vs
BROKEN, leak detection, exit codes, and the GitHub Actions output path.
The port also hardens what the JS left fragile: multi-document YAML is
scanned in full, non-UTF-8 bytes are replaced instead of crashing the
run, and directory symlinks are not traversed.