The command
mkdir plesty-scan-exp && cd plesty-scan-exp
uv run plesty init experiment \
--author "Jane Doe" \
--email jane@example.com
The module name is inferred from the directory (plesty-scan-exp → scan_exp); --name overrides it. Like the device scaffold, plesty init formats the generated files, creates the initial git commit, and installs the plesty check pre-push hook.
Generated layout
plesty-scan-exp/
├── plesty/
│ └── scan_exp/
│ ├── __init__.py
│ ├── __main__.py # CLI: load config, build CompositeDevice, run
│ └── experiment.py # Experiment subclass (plan / steps / setup / teardown)
├── config/
│ └── default.yaml # measurement tuning — tracked, frozen into each run's plan
├── docs/
│ ├── index.md
│ └── toc.yaml
├── tests/
│ ├── __init__.py
│ └── test_scan_exp.py
├── .env.example # device addresses & credentials — real values in .env (never committed)
├── .gitignore
├── .gitlab-ci.yml
├── CHANGELOG.md
├── LICENSE
├── LICENSES/
│ └── LGPL-3.0-or-later.txt
├── REUSE.toml
├── pyproject.toml # module_type = "experiment"
└── README.md
Differences from a device project:
experiment.pyinstead ofbase_device.py/device.py— a subclass of the asyncExperimentbase classconfig/directory — see below- No TCP server —
__main__.pyis a client: it loads the config, builds theCompositeDevicefrom the configured addresses, and runs the experiment withasyncio
Configuration vs. credentials
The scaffold enforces a strict split:
| What | Where | Tracked in git |
|---|---|---|
| Measurement tuning (scan ranges, exposure times, averaging) | config/*.yaml |
yes |
| Device server addresses, tokens, anything secret | .env (template: .env.example) |
never |
The YAML config is frozen into each run's plan — a resumed run refuses a changed configuration, so a result can always be traced back to the exact tuning that produced it. Credentials stay out of the plan (and out of git) entirely.
# config/default.yaml — tuning values only, never credentials
points: 3
Run it
The scaffolded project is immediately runnable:
uv sync
uv run python -m plesty.scan_exp --config config/default.yaml