Skip to content

Commit 6156c29

Browse files
committed
Rewrite CONTRIBUTING.md with release process, updated layout, and code style guide
1 parent de43e9c commit 6156c29

1 file changed

Lines changed: 135 additions & 42 deletions

File tree

‎CONTRIBUTING.md‎

Lines changed: 135 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
# Contributing to mlx-manager
1+
# Contributing to mlx-serve
2+
3+
Thank you for your interest in contributing to mlx-serve! This document covers everything you need to get started.
24

35
## Prerequisites
46

@@ -7,54 +9,99 @@
79
- Python 3.11+
810
- [uv](https://docs.astral.sh/uv/) — `curl -LsSf https://astral.sh/uv/install.sh | sh`
911

10-
## Setup
12+
## Getting Started
1113

1214
```bash
13-
git clone https://github.com/your-username/mlx-manager
14-
cd mlx-manager
15+
# 1. Fork and clone
16+
git clone https://github.com/YOUR-USERNAME/mlx-serve.git
17+
cd mlx-serve
18+
19+
# 2. Install all dependencies (including dev + all model backends)
1520
make install
21+
22+
# 3. Verify everything works
23+
make test
24+
make lint
1625
```
1726

18-
## Running locally
27+
## Project Layout
1928

20-
```bash
21-
make mlx-start # start on port 8095
22-
make status # check state
23-
make mlx-stop # stop everything
29+
```
30+
src/mlx_serve/
31+
├── __init__.py Version declaration
32+
├── cli.py Command-line interface (init, start, stop, status, logs)
33+
├── config.py YAML config loading, typed constants
34+
├── router.py OpenAI-compatible HTTP endpoints
35+
├── process_manager.py Subprocess lifecycle (text/vision models)
36+
├── inline_manager.py In-process lifecycle (embedding/TTS/STT models)
37+
├── events.py Structured lifecycle event log
38+
├── metrics.py Request metrics and memory monitoring
39+
├── logging_config.py Logging setup
40+
├── main.py FastAPI app and lifespan
41+
└── _default_models.yaml Bundled fallback config
2442
```
2543

26-
Dev mode (auto-reloads on code changes):
44+
Key constraint: `process_manager` and `inline_manager` must not import each other. All cross-manager coordination belongs in `router.py`.
45+
46+
## Development Workflow
47+
48+
### Running locally
2749

2850
```bash
29-
make mlx-dev
51+
make dev # start with auto-reload on code changes
52+
make mlx-start # start on port 8095 (foreground)
53+
make status # check current model state
54+
make mlx-stop # stop everything
3055
```
3156

32-
## Project layout
57+
### Testing
3358

59+
```bash
60+
make test # run full test suite (42 tests)
61+
make lint # ruff check + format check
3462
```
35-
src/
36-
├── main.py FastAPI app, lifespan, route registration
37-
├── config.py Reads models.yaml, exposes typed constants
38-
├── router.py All HTTP endpoints, cross-manager coordination
39-
├── process_manager.py Subprocess lifecycle (text/vision)
40-
└── inline_manager.py In-process lifecycle (embedding/tts/stt)
41-
models.yaml Operator-editable model registry
42-
docs/ Full documentation
63+
64+
CI runs lint, format check, and tests on Python 3.11, 3.12, and 3.13 (macOS) for every push and PR.
65+
66+
**Manual testing** — before submitting a PR that changes inference or model loading:
67+
68+
- [ ] Start the server: `mlx-serve start`
69+
- [ ] Exercise the relevant model type with a real request
70+
- [ ] Verify `curl http://localhost:8095/status` shows correct state
71+
- [ ] Verify inactivity unload works (lower `inactivity_timeout_seconds` temporarily)
72+
- [ ] Verify `mlx-serve stop` cleanly terminates all processes
73+
74+
### Code Style
75+
76+
We use [ruff](https://docs.astral.sh/ruff/) for linting and formatting:
77+
78+
```bash
79+
uv run ruff check src/ # lint
80+
uv run ruff format src/ tests/ # format
4381
```
4482

45-
Key constraint: `process_manager` and `inline_manager` must not import each other. All cross-manager coordination belongs in `router.py`.
83+
Rules enforced: isort (import sorting), pyupgrade (modern syntax), flake8-comprehensions, flake8-simplify, flake8-use-pathlib. See `pyproject.toml` for the full config.
4684

47-
## Adding a new model type
85+
Style guidelines:
86+
- No new abstractions for single-use cases
87+
- No docstrings on functions whose purpose is obvious from the name
88+
- Error responses must follow OpenAI format: `{"error": {"message": "...", "code": N}}`
89+
- Keep the two managers pure — no cross-imports
90+
- Use `pathlib.Path` over `os.path`
91+
- Use `datetime.UTC` over `timezone.utc`
92+
93+
## Adding a New Model Type
4894

4995
If you want to add support for a new MLX inference library:
5096

5197
1. Add the new type string to `_VALID_TYPES` in `config.py`
5298
2. Add load/run/generate functions to `inline_manager.py` (for in-process) or extend `process_manager.py` (for subprocess)
5399
3. Add a new endpoint in `router.py`
54100
4. Add the type to `_TYPE_CAPABILITIES` in `router.py`
55-
5. Update `models.yaml` comments and `docs/configuration.md`
101+
5. Add tests for the new endpoint in `tests/test_api.py`
102+
6. Update `models.yaml` comments and `docs/configuration.md`
56103

57-
## Adding a model to models.yaml
104+
## Adding a Model to models.yaml
58105

59106
```yaml
60107
- name: my-model # name clients use in API requests
@@ -70,28 +117,74 @@ Download the model first:
70117
uv run huggingface-cli download mlx-community/my-model-name
71118
```
72119

73-
## Testing
120+
## Pull Request Guidelines
74121

75-
MLX requires Apple Silicon hardware — automated integration tests cannot run on GitHub Actions. The CI workflow validates Python syntax and YAML only.
122+
1. Fork and create a branch from `main`
123+
2. Make your change — keep it focused, no unrelated cleanup
124+
3. Add or update tests for new/changed behavior
125+
4. Ensure `make test` and `make lint` pass
126+
5. Update docs if behavior changes
127+
6. Open a PR using the provided template
76128

77-
Manual testing checklist before submitting a PR:
129+
## Releases and PyPI Publishing
78130

79-
- [ ] Start the manager: `make mlx-start`
80-
- [ ] Exercise the relevant model type with a real request
81-
- [ ] Verify `make status` shows correct state
82-
- [ ] Verify `make mlx-stop` cleanly terminates all processes
83-
- [ ] Check that inactivity unload works (lower `inactivity_timeout_seconds` temporarily)
131+
**Only maintainers** should create releases. mlx-serve uses an automated CI/CD pipeline for PyPI deployment.
84132

85-
## Submitting a PR
133+
### Version Numbering
86134

87-
1. Fork and create a branch from `main`
88-
2. Make your change — keep it focused, no unrelated cleanup
89-
3. Update docs if behavior changes
90-
4. Open a PR using the provided template
135+
Follow [Semantic Versioning](https://semver.org/):
91136

92-
## Style notes
137+
- **Major (X.0.0)**: Breaking API changes
138+
- **Minor (X.Y.0)**: New features, backward compatible
139+
- **Patch (X.Y.Z)**: Bug fixes, backward compatible
93140

94-
- No new abstractions for single-use cases
95-
- No docstrings on functions whose purpose is obvious from the name
96-
- Error responses must follow OpenAI format: `{"error": {"message": "...", "code": N}}`
97-
- Keep the two managers pure — no cross-imports
141+
### Release Process
142+
143+
1. **Update the version**:
144+
```bash
145+
# Edit src/mlx_serve/__init__.py
146+
__version__ = "X.Y.Z"
147+
```
148+
149+
2. **Update the changelog**:
150+
```bash
151+
# Add a new section to CHANGELOG.md with the changes
152+
```
153+
154+
3. **Commit and push**:
155+
```bash
156+
git add src/mlx_serve/__init__.py CHANGELOG.md
157+
git commit -m "Bump version to X.Y.Z"
158+
git push origin main
159+
```
160+
161+
4. **Tag and push the tag**:
162+
```bash
163+
git tag vX.Y.Z
164+
git push origin vX.Y.Z
165+
```
166+
167+
5. **Automated deployment**: Pushing the tag triggers the publish workflow which:
168+
- Verifies the tag matches `__version__`
169+
- Runs the full test suite
170+
- Builds the package (wheel + sdist)
171+
- Publishes to PyPI via Trusted Publishing
172+
- Creates a GitHub Release with auto-generated notes
173+
174+
### Publish Pipeline
175+
176+
- **Trigger**: Git tag push matching `v*`
177+
- **Workflow**: `.github/workflows/publish.yml`
178+
- **Authentication**: PyPI Trusted Publishing (OIDC) — no tokens needed
179+
- **Jobs**: `build` (test + build) → `publish` (upload to PyPI) → `github-release` (create release)
180+
181+
### Prerequisites for Maintainers
182+
183+
To deploy releases, maintainers need:
184+
1. Write access to the repository
185+
2. Permission to create `v*` tags
186+
3. PyPI Trusted Publisher configured for the `mlx-serve` project
187+
188+
## License
189+
190+
By contributing to this project, you agree that your contributions will be licensed under the [MIT License](LICENSE).

0 commit comments

Comments
 (0)