This repository is a GitHub template for Autodesk Maya Python tools. If an agent is helping a user start a new Maya tool, create the project from this template instead of scaffolding from scratch. It comes preconfigured with CI that runs tests in real Maya (Docker), Ruff static analysis, mkdocs deployment, and a manually triggered release workflow.
gh repo create <project_name> \
--template matthewlee-dev/maya-python-project-template \
--public \
--description "<one-line project description>"Use all-lowercase with hyphens for <project_name> (e.g. my-cool-tool).
Creating the repo triggers the initial repository setup workflow: it rewrites
placeholders, renames src/mayapythonprojecttemplate/, regenerates uv.lock, and
pushes a commit. Wait for it before cloning:
sleep 20 # give the workflow a moment to appear
gh run watch --repo <owner>/<project_name> \
$(gh run list --repo <owner>/<project_name> --limit 1 --json databaseId -q '.[0].databaseId') \
--exit-status
gh repo clone <owner>/<project_name>The new repo has its own AGENTS.md with day-to-day commands (generated from
_new_project/AGENTS.md in this template).
- Dependencies and all tool config live in
pyproject.toml, managed with uv. Setup:uv sync --all-groups. Dependency groups:test,dev,docs. - Lint/format:
uv run ruff check .,uv run ruff format --check .. tests/template/exercises the template's own machinery (initial_setup.py,scripts/build_module.py,release.py's pure version-bump logic) with plain pytest, no Maya needed:uv run pytest tests/template. It's deleted byinitial-setup.ymlin generated repos.- Maya tests run under
mayapy(Maya's bundled interpreter), not a uv-managed Python. CI frees runner disk space,docker pullsmottosso/maya:<version>, then runs onedocker runthat installsuvand the test group intomayapyand runs pytest (.github/workflows/reusable-maya-tests.yml); direct install is fine there since the container is ephemeral. For local runs against a real Maya install, use thePYTHONPATH+ disposable-venv pattern in _new_project/CONTRIBUTING.md instead. pyproject.tomlandmkdocs.ymldeliberately contain real values rather than{{...}}placeholders, so both files stay valid anduv/mkdocs buildwork on a clone of the template itself.initial_setup.pystring-replaces those literals during setup; if you change one, update its match ininitial_setup.py.- Templated files (everything under
_new_project/, plustests/maya/test_example.py) use{{PROJECT_OWNER}}/{{PROJECT_NAME}}/{{PROJECT_TITLE}}/{{PROJECT_DESC}}placeholders handled byinitial_setup.pyand.github/workflows/initial-setup.yml.{{PROJECT_TITLE}}is{{PROJECT_NAME}}with-/_replaced by spaces, for display headings only;{{PROJECT_NAME}}itself must stay a raw URL-safe slug. - Release pipeline:
scripts/build_module.pystagessrc/<package>/into a Maya module tree underdist/(name/version read frompyproject.toml) and copiesinstall_module.pyin as<name>_drag_and_drop_installer.py.release.py(repo root) dispatchesci-release.yml, which runsreusable-release.ymlto zipdist/and attach it to the GitHub Release.release.pylives at the repo root, not underscripts/, sobuild_module.pynever sweeps it into the shipped module. - Workflows can't move to
_new_project/.GITHUB_TOKENmay delete files under.github/workflowsbut not create them (there is noworkflowspermission for it), soinitial-setup.yml's push is rejected if setup adds one. Every workflow ships in.github/workflows/; setup only deletes the template's own. - Because they all live on the template too, the generated project's workflows
(
ci-main.yml,ci-release.yml) guard every job withif: ${{ !github.event.repository.is_template }}. The template's own checks run fromtemplate-ci.yml.tests/template/test_workflows.pyenforces both the guards and the rule below. - A local
uses:is resolved at parse time, before anyif:, so a workflow that survives setup must never reference one that setup deletes. Delete such references with the file, never guard them.