Scaffold a Project
Prerequisites
- Python ≥ 3.12
- uv installed
Steps
1. Create a new project
axm init_scaffold my-project \
--org axm-protocols \
--author "Your Name" \
--email "you@example.com"
This scaffolds a production-grade Python project with:
pyproject.toml(PEP 621, dynamic versioning via hatch-vcs)src/layout withpy.typedmarker- Pre-configured linting (Ruff), typing (MyPy), testing (Pytest), and docs (MkDocs)
- CI/CD workflows (GitHub Actions)
- Automated commit-hook updates (weekly via
prek autoupdate) - Dependency groups:
dev,docs
2. Required flags
| Flag | Short | Description |
|---|---|---|
--org |
GitHub org or username | |
--author |
Author name | |
--email |
Author email |
3. Optional flags
| Flag | Short | Default | Description |
|---|---|---|---|
--name |
dir name | Project name | |
--license |
Apache-2.0 |
License (MIT, Apache-2.0, EUPL-1.2) | |
--license-holder |
--org | License holder | |
--description |
One-line description | ||
--private / --no-private |
True |
Keep the generated package private, or explicitly make it publishable | |
--workspace |
False |
Scaffold a UV workspace instead | |
--member |
Scaffold a member sub-package with this name | ||
--framework |
python |
python, node, svelte; use non-Python only for standalone projects |
|
--kind |
Scaffold kind: standalone, workspace, member, paper, experiment, learning, protocol_unit, protocol |
||
--profile |
Optional package profile; protocols is supported for Python |
||
--domain |
Learning domain with --kind learning; protocol domain with --profile protocols |
||
--unit |
Protocol unit, required when declarations are supplied | ||
--protocols |
JSON list of action-only protocol payloads; --domain and --unit supply their shared identity |
||
--preview |
False |
Plan protocol files without changing the target |
4. Scaffold a workspace
axm init_scaffold my-workspace --workspace \
--org myorg --author "Your Name" --email "you@example.com"
The --workspace flag generates a UV workspace with:
- Root
pyproject.tomlwith[tool.uv.workspace]andmembers = ["packages/*"] - Gold-standard root config:
dynamic = ["version"]+ hatch-vcs (git-tag driven, no static version to bump), the full ruff rule set (incl.BLE/PLR), and a[tool.git-cliff]changelog config. (mypy is configured per-package, not at the root.) - Shared
Makefile(test,lint,type-check,docs-serve,docs-build) mkdocs.ymlwithmonorepoplugin- CI workflow using
--packagematrix for per-member testing - Commit-hook configuration, git-cliff settings, Dependabot, and GitHub Actions workflows
5. Scaffold a member package
From inside an existing workspace:
The --member flag:
- Auto-detects the workspace root (walks up to find
[tool.uv.workspace]) - Creates the package under
packages/my-lib/using the member template - Patches root files:
Makefile,mkdocs.yml,pyproject.toml, CI workflows
Note:
--workspaceand--memberare mutually exclusive.
6. Scaffold a public package
Standalone projects and workspace members are private by default: their
pyproject.toml contains the Private :: Do Not Upload classifier. This safe
default avoids an irreversible accidental PyPI publication.
Pass --no-private explicitly when the generated distribution is intended for
publication:
axm init_scaffold public-project --no-private \
--org myorg --author "Your Name" --email "you@example.com"
The same option applies to a member scaffold:
axm init_scaffold --member public-lib --no-private \
--org myorg --author "Your Name" --email "you@example.com"
In both cases, the generated classifier list keeps its development status,
Python versions, typing and license metadata, but omits
Private :: Do Not Upload.
7. Scaffold a learning project or workspace member
Use the learning kind for a fresh training or optimisation package:
axm init_scaffold learning-lab --kind learning \
--org myorg --author "Your Name" --email "you@example.com"
The target contains training.toml, study.toml, a deterministic recipe at
src/learning_lab/recipe.py, the registered training tool at
src/learning_lab/tools/train.py, and
tests_learning_lab/unit/test_recipe.py. Its pyproject.toml declares the
learning domain under [tool.axm-init.learning], registers the training
AXMTool under [project.entry-points."axm.tools"], and pins its three direct
runtime dependencies (axm, numpy, and torch) to exact versions.
Install the pinned environment, then run the generated entry point:
The default profile performs four real optimisation updates over synthetic data generated deterministically in memory. The training process neither downloads a dataset nor reads a machine-local cache; only environment installation may use the network. A successful run ends with one machine-readable line:
Change schedule.max_steps in training.toml when you need a longer run. The
same entry point is available through the registered learning_lab_train
AXMTool.
The learning domain defaults to the generated module name. Pass --domain when
the training domain needs a different stable identity. To pick up template
updates later, re-run the same learning command against the same target with the
same domain. init_scaffold then re-renders template-owned files such as
training.toml while restoring src/learning_lab/recipe.py byte for byte.
Requesting a different domain is rejected before rendering. The error names the declared and requested domains, and both the training configuration and recipe remain unchanged. Use a fresh target for a domain migration.
To create the same learning package as a member of an existing UV workspace,
run from the workspace root (or one of its members) and supply --member:
axm init_scaffold --kind learning --member learning-lab \
--domain forecasting \
--org myorg --author "Your Name" --email "you@example.com"
This renders the learning tree under packages/learning-lab/, patches the
workspace root files, and reports mode="member", the member distribution,
the member directory as root, and the non-empty patched_root_files list.
Re-running the command with the same domain reconciles the existing learning
member and preserves its edited src/learning_lab/recipe.py bytes. Changing
only --domain is rejected before Copier runs; the error names both domains and
leaves training.toml and the recipe byte-identical.
To apply only the compatibility overlay to an existing package, use the Python template API described in Template selection.
8. Research and protocol scaffolds
- Scaffold a paper and its experiments
- Create, preview and apply protocol declarations
- Scaffold Node or Svelte projects
9. Check PyPI availability
The --check-pypi flag verifies the package name is available before scaffolding.
10. JSON output
Outputs structured JSON for CI/automation use.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
Missing required option --org |
Required flag not provided | Pass --org, --author, and --email explicitly |
--workspace and --member are mutually exclusive |
Both flags given | Use only one of --workspace or --member |
Not inside a UV workspace |
--member used outside workspace |
Run from a workspace directory |
Member 'X' already exists |
Duplicate non-learning member, or learning member without a matching declared domain | Choose another name; matching-domain learning members may be reconciled |
Name 'X' is not available on PyPI |
--check-pypi detected a taken name |
Choose a different project name or drop --check-pypi |
| Existing destination content | Copier can encounter conflicts with existing files | For the same standalone or member learning domain, re-run the identical learning command to reconcile it; otherwise use a fresh destination |
| Experiment scaffolding is owned by axm-lab | Retired --kind experiment route |
Install axm-lab and use experiment_scaffold with an owning investigation |
Unknown --kind 'X' |
Kind outside the declared set | Use one of standalone, workspace, member, paper, experiment, learning, protocol_unit, protocol |
Copier template error |
Template engine failure (rare) | Ensure copier is installed: uv pip install copier |