Skip to content

Latest commit

 

History

History
208 lines (148 loc) · 6.57 KB

File metadata and controls

208 lines (148 loc) · 6.57 KB

Contributing to ForgeLM

Thanks for your interest in contributing! ForgeLM is an open-source project and we welcome contributions of all kinds.

Ways to Contribute

  • Bug reports — found something broken? Open a bug report
  • Feature requests — have an idea? Open a feature request
  • Code — fix a bug, add a feature, improve tests
  • Documentation — fix typos, improve guides, add examples
  • Notebooks — add Colab notebooks for new use cases
  • Config templates — share training configs that worked well for you

Quick Start for Code Contributors

1. Fork & Clone

git clone https://github.com/YOUR_USERNAME/ForgeLM.git
cd ForgeLM
git remote add upstream https://github.com/HodeTech/ForgeLM.git

2. Install (dev mode)

python3 -m pip install -e ".[dev]"

Note on the [dev] extras + coverage gate. The pytest invocation in pyproject.toml carries --cov-fail-under=40. The [dev] extras are required to reach that floor — installing pip install -e . (no extras) trips the gate because optional-dep test paths can't run. Always use pip install -e ".[dev]" for contributor work. The floor itself is intentional (docs/standards/testing.md); do not lower it.

3. Create a branch

git fetch upstream
git checkout -b feat/my-feature upstream/main

Branch naming: feat/, fix/, docs/, test/, chore/ + short description.

4. Make your changes

Edit the code, then run the full validation gauntlet (every guard CI also enforces — passing locally means CI will too):

# 1. Lint + format
ruff format . && ruff check .

# 2. Test suite
pytest tests/ -q

# 3. Config dry-run smoke test
forgelm --config config_template.yaml --dry-run

# 4. Doc-side guards (Wave 4 / Wave 5 additions)
python3 tools/check_bilingual_parity.py --strict
python3 tools/check_anchor_resolution.py --strict
python3 tools/check_cli_help_consistency.py --strict

The four-tool sequence at the top of the gauntlet (ruff + pytest + --dry-run) is the historical "self-review" command from docs/standards/code-review.md. The three doc guards landed in Waves 3-5 and run on every PR via .github/workflows/; running them locally before pushing avoids CI round-trips.

5. Submit a PR

Push your branch and open a Pull Request against main.

Development Setup

Project Structure

ForgeLM is a single-package layout: a mix of single-file modules and two focused sub-packages (forgelm/cli/ post-Phase-15 split and forgelm/data_audit/ post-Phase-14 split) under forgelm/, ~70 test files under tests/ (collected-test count grows over time — run pytest --collect-only -q for current), plus configs/, docs/, tools/ (CI guards), and notebooks/. For the authoritative module-by-module map (purpose, public surface, dependency arrows), see docs/reference/architecture.md.

Running Tests

# All tests
pytest tests/ -v

# Specific test file
pytest tests/test_config.py -v

# With coverage
pytest tests/ --cov=forgelm --cov-report=term-missing

Some tests require torch and are skipped when it's not installed. This is expected in lightweight dev environments.

Code Style

We use ruff for linting and formatting:

# Check
ruff check .
ruff format --check .

# Auto-fix
ruff check --fix .
ruff format .

Configuration is in pyproject.toml under [tool.ruff].

Pre-commit hooks (optional)

ForgeLM ships a .pre-commit-config.yaml that mirrors the CI checks (ruff, ruff-format, gitleaks, plus a few hygiene hooks for trailing whitespace, EOF newlines, and YAML/TOML syntax). The hooks are an optional ergonomic optimization — CI enforces the same checks on every PR, so installing them locally is purely about getting feedback before you push.

To opt in:

pip install pre-commit
pre-commit install

Run all hooks against the whole tree at any time:

pre-commit run --all-files

If a hook ever flags a known-good fixture (e.g. a credential-shaped test string the gitleaks hook can't tell apart from a real secret), skip just that hook for the commit:

SKIP=gitleaks git commit -m "test: add credential-shape fixture"

CI remains the enforcement boundary; skipping a hook locally never bypasses CI.

Guidelines

Code

  • Keep it simple. ForgeLM's strength is simplicity. Don't add complexity unless necessary.
  • Config-driven. New features should be configurable via YAML. No hardcoded behavior.
  • Optional dependencies. Heavy dependencies go in optional groups: pip install forgelm[feature].
  • Tests required. Every new feature or bugfix needs a test. Keep coverage growing.
  • Ruff clean. CI will reject code that doesn't pass ruff check.
  • No secrets. Never commit tokens, API keys, or credentials. Use env vars.

Config Changes

If you add a new config field:

  1. Add the field to the Pydantic model in config.py
  2. Add it to config_template.yaml (commented with example)
  3. Update the Configuration Guide if it's user-facing
  4. Add a test in tests/test_config.py

Adding a New Trainer Type

  1. Add the type to valid_trainers set in config.py
  2. Add trainer-specific parameters to TrainingConfig
  3. Add the TRL config builder in trainer.py:_get_training_args_for_type()
  4. Add the trainer initialization in trainer.py:train()
  5. Add dataset format detection in data.py
  6. Update the wizard in wizard.py
  7. Add tests in tests/test_alignment.py
  8. Add a notebook in notebooks/

Commit Messages

We follow Conventional Commits:

feat: add KTO trainer support
fix: handle NaN eval_loss in auto-revert
docs: add GRPO notebook example
test: add merging algorithm tests
chore: update CI to Python 3.13
style: apply ruff format

First-Time Contributors

Look for issues labeled good first issue. These are designed to be approachable for newcomers.

Questions?

License

By contributing, you agree that your contributions will be licensed under the Apache License 2.0.