# Contributing > Project layout, build, and release flow. **If you only want to use the tool — read [README](README.md) instead.** ## Repo layout ``` bmccollect/ ├── .github/ │ ├── workflows/release.yml ← CI: tag-driven build + GitHub Release │ └── ISSUE_TEMPLATE/ ← bug / feature / security routing ├── src/bmccollect/ ← package source (≤200 lines per module) │ ├── __init__.py ← single source of truth for __version__ │ ├── __main__.py ← entry: python -m bmccollect │ ├── app.py ← orchestration: prompts, threads, packaging │ ├── platform_win.py ← VT enable │ ├── update_check.py ← GitHub /releases/latest poll │ ├── commands.py ← table of "filename → how to obtain it" │ ├── bmc.py ← BmcSession (SSH + Redfish helper) │ ├── collector.py ← per-host collect loop │ ├── tarball.py ← layout, per-host & session tar.gz │ └── ui.py ← rich-based TUI ├── bmccollect-launcher.py ← PyInstaller entry (root, absolute import) ├── pyproject.toml ← deps, packaging, dynamic version ├── CHANGELOG.md / CONTRIBUTING.md / LICENSE / README.md / SECURITY.md └── .gitignore ``` ## Run from source ``` python -m pip install rich paramiko PYTHONPATH=src python -m bmccollect ``` ## Editable install ``` python -m pip install -e . bmccollect ``` ## Build the portable .exe ``` python -m pip install pyinstaller rich paramiko python -m PyInstaller --onefile --console --name bmccollect --paths src bmccollect-launcher.py ``` ## Cut a release 1. Update `src/bmccollect/__init__.py` — bump `__version__` to `X.Y.Z`. 2. Update `CHANGELOG.md` — move items from `[Unreleased]` into a new `[X.Y.Z]` section with today's date. 3. Commit: `git commit -am "vX.Y.Z: …"`. 4. Tag: `git tag vX.Y.Z`. 5. Push: `git push && git push --tags`. CI builds the exe and creates the GitHub Release with the zip attached. ## Where features go | Adding... | Touch this module | |---|---| | A new artefact (file in the dump) | `commands.py` → one new `CommandSpec` row | | Support for a new BMC API (e.g. IPMI) | `bmc.py` → add a method on `BmcSession`; reference it from `commands.py` with a new `kind` | | New per-host UI column / progress detail | `ui.py` → `Ui._render_table` + `set_progress` / `set_summary` | | Different output naming or layout | `tarball.py` | | Tweaking the startup banner / prompts | `app.py` → `main` / `_prompt_inputs` |