Contributing To Protostar¶
Architecture & Implementation Rules¶
Protostar has one job: save the user time on setup they would have done anyway. When evaluating a new feature, ask:
- Would most users want this, or just some?
- Would a user plausibly revert this manually after running the tool?
If the answer to either of the first two is "maybe not", the feature probably doesn't belong in the tool.
1. Manifest-first, side-effects-last¶
Modules declare intent into the manifest during build(). The orchestrator executes all side effects afterward in a single, ordered phase. Never call subprocess.run or write to disk inside a module's build() method.
2. Fail loud, fail early¶
All system dependency checks happen in pre_flight(), before the manifest is built and before anything is written. If a preflight check fails, the environment is untouched. This is a guarantee, not a coincidence.
3. Non-destructive by default¶
Protostar never overwrites existing work. .gitignore entries are appended and deduplicated. IDE settings are merged. It must be safe to run against a repo that is already partially configured.
4. Modules are composable, not coupled¶
A module only interacts with the manifest interface. It must not inspect what other modules are loaded, assume a particular run order, or conditionally change behaviour based on the presence of sibling modules.
5. Presets are Independent Pipeline Injections¶
Presets inherit from the PresetModule abstract base class and evaluate independently during the manifest aggregation phase. They do not override language modules; they strictly append domain-specific dependencies and directory scaffolding to the EnvironmentManifest.
Coding Standards¶
-
Type Hinting: All new application functions and methods must include strict Python 3.12 type hints. We use
mypyto statically enforce this (disallow_untyped_defs = true). The test suite (tests/*) is granted an exemption from strict untyped definition checks. -
Docstrings: Use Google-style docstrings for public functions, classes, and methods. Module-level, package-level, and
__init__docstrings are exempt from linting checks. -
Formatting & Linting: Code is formatted and linted using
ruff.- Use 4-space indentation and double quotes.
- The formatter enforces an 88-character line length.
- Do not bypass the pre-commit hooks, as they will automatically apply the required
isortblock ordering and formatting rules.
Testing Guidelines¶
Because Protostar is a scaffolding tool, its execution inherently interacts with the host filesystem and shell. To maintain a deterministic and isolated test suite:
-
Relaxed Linting: The test suite (
tests/*) is exempt from docstring requirements andprintstatement linting restrictions (T201). -
Disk I/O: Never write to the actual host filesystem during tests. Always use the
pytesttmp_pathfixture to sandbox generated artifacts. -
Subprocesses: Use
pytest-mockto patchsubprocess.run. Do not allow the test suite to execute unmocked shell commands (e.g.,uv initorcargo init) on the host machine. -
Coverage: Ensure new modules or generators maintain or improve the current test coverage metrics (measured via
pytest-cov).
How to Contribute¶
Reporting Bugs¶
- Check if the issue has already been reported.
- Open a new issue with a clear title and description.
- Include the command that caused the error and the resulting traceback.
Development Setup¶
To contribute to this project, you will need the following system-level dependencies installed:
(For macOS users with homebrew: brew install uv just)
-
Fork & Clone Fork the repo and clone it locally:
-
Environment Setup We use
uvto manage the virtual environment and dependencies. Running sync will install the core application alongside thedevdependency group (which includesbuild,bump-my-version,mypy,pre-commit,pytest,pytest-cov,pytest-mock, andruff). -
Install Hooks Set up pre-commit hooks to handle linting and type checking automatically.
Running Tests & Tooling¶
We use just as our command runner to standardize test execution, linting, and formatting.
To see all available commands and their descriptions, run just in the repository root:
To execute the standard test matrix:
Pull Requests¶
-
Create a Branch
-
Make Changes
Write your code. Ensure your changes are tightly scoped to a single feature, preset, or bug fix. Avoid monolithic pull requests that mix refactoring with new logic.
-
Verify
Ensure your code passes the linter, type checker, and test suite locally. We provide a single command that emulates the GitHub Actions CI pipeline. Run this before pushing:
(Pre-commit will also run
ruffandmypywhen you commit). -
Commit & Push
Use clear, descriptive commit messages.
-
Open a Pull Request
Submit your PR against the
mainbranch.