# Contributing to Reef Thank you for helping improve Reef. Contributions can include bug reports, documentation, tests, examples, code, design proposals, and reviews. ## Before you start - Search the existing issues and pull requests before opening a new one. - Keep each issue and pull request focused on one problem or proposal. - For a bug, use the bug report form and include a reproducible example. - For a change whose direction or scope is uncertain, open an issue before investing in an implementation. - Never include credentials, private data, model-provider tokens, or other secrets in an issue, pull request, log, fixture, or prompt transcript. ## Choose the right issue path Use the structured template that matches the work: - **Bug report** for reproducible incorrect behavior. Include the smallest complete reproduction and environment details. - **Performance report** for a measurable latency, throughput, memory, utilization, or scalability regression. Include equivalent baseline and current measurements. - **Usage question** when the documentation and open or closed issues do not answer a focused question. - **Feature proposal** for a concrete user problem whose scope does not yet require a durable architecture decision. - **Experiment** for a paper reproduction, benchmark, or empirical question with pinned models, workloads, baselines, metrics, and saved results. - **Example** for a runnable user-facing recipe or reference deployment with a documented setup and expected result. - **RFC proposal** when the change may affect public interfaces, persistence, trust boundaries, topology, recipe extension contracts, training backends, or project-wide policy. - **Maintainer task** for scoped implementation, refactoring, cleanup, or project work that a maintainer has created or approved. - **Roadmap** only for a maintainer-owned, time-bounded coordination issue. ### Issue titles and classification An issue title starts with exactly one controlled type prefix: | Prefix | Use it for | | --- | --- | | `[Bug]` | Reproducible incorrect behavior | | `[Feature]` | A new capability, algorithm, or integration | | `[Performance]` | Latency, throughput, memory, utilization, or scale | | `[Task]` | Scoped refactoring, cleanup, documentation, CI, or project work | | `[Experiment]` | A benchmark, reproduction, or empirical evaluation | | `[Example]` | A runnable recipe, demo, or reference deployment | | `[RFC]` | A durable architecture, interface, or policy decision | | `[Roadmap]` | A quarterly or release-level coordination index | | `[Question]` | A focused usage question | Write the rest of the title as a concise outcome, normally beginning with a verb: `[Feature] Add W&B experiment tracking for training`. Do not add a second bracketed tag for an area, project, status, or method. In particular, use `[Roadmap] Reef 2026 Q3`, not `[Roadmap][Draft] ...`; record `Draft`, `Active`, or `Complete` in the roadmap body. Labels carry the independent classification dimensions. Maintainers may apply more than one `area:*` label when work crosses boundaries: - `area: core` — core contracts and scenario lifecycle; - `area: service` — service APIs, deployment, and CLI; - `area: training` — training execution, runtimes, and algorithms; - `area: artifacts` — artifact storage, metadata, retention, and publication; - `area: versioning` — identity, lineage, activation, promotion, and rollback; - `area: observability` — metrics, logs, traces, and experiment tracking; - `area: harness` — harness integration, recipes, and evolution surfaces; - `area: examples` — examples, recipes, and reference deployments; - `area: packaging` — packages, containers, and vendored integrations; - `area: ci` — automation, CI, and developer tooling; and - `area: docs` — user and developer documentation. Lifecycle (`status:*`), priority (`priority:*`), contribution, and accelerator-validation labels do not belong in the title. Security vulnerabilities do not belong in public issues. Follow [SECURITY.md](SECURITY.md) and establish a private reporting channel before sending exploit details. All new issues begin with `status: needs-triage`. Maintainers add an area and one lifecycle status after review. If a maintainer requests information, the issue may receive `status: waiting-author`; a new comment from the issue author returns it to triage automatically. `help wanted` means maintainers welcome an external contributor to propose a plan and request assignment. It is not an invitation to submit competing pull requests without coordination. ## Changes that need an RFC Write an RFC before implementing a change that: - adds a new top-level package under `reef`; - adds a shared training backend or changes the recipe extension contract; - makes a significant or backwards-incompatible public interface change; - changes a persisted format, wire contract, trust boundary, or service topology; or - establishes a project-wide policy that will constrain later work. Small bug fixes, documentation improvements, tests, internal refactors that preserve behavior, and implementation work for an accepted RFC do not normally need a new RFC. Open an [RFC issue](https://github.com/Human-Agent-Society/reef/issues/new?template=rfc.yml) and complete the full proposal in the issue body. The issue is the RFC and its decision record; do not add a new document under `docs/rfcs`. Keep material design changes, the maintainer decision, and implementation links on the issue. An RFC must be explicitly accepted there before its implementation is treated as approved project direction. ## AI-assisted contributions AI-assisted work is welcome when it is directed, understood, and verified by the human contributor. Do not submit autonomous or bulk-generated issues, pull requests, reviews, or comments. When an AI tool makes a non-trivial contribution: - disclose the tool and how it was used in the pull request; - review and understand every submitted line and factual claim; - reproduce the problem yourself instead of trusting a generated diagnosis; - run the relevant checks and report their actual results; - remove speculative fixes, unrelated cleanup, generated commentary, and unnecessary abstractions; and - communicate with maintainers in your own words and remain responsible for follow-up review and maintenance. AI assistance does not lower the bar for tests, documentation, compatibility, security, or long-term maintenance. Low-effort or unverifiable generated work may be closed without detailed review when reviewing it would cost more than reproducing or implementing the change directly. ## Set up the repository Follow the [development guide](https://reefinfra.ai/docs/contributing/development/) to initialize submodules, create an environment, install dependencies, and enable `pre-commit`. The usual local checks are: ```bash pre-commit run --all-files pytest tests/ ``` ### Keep the root READMEs synchronized `README.md` and `README.zh.md` are one reviewed documentation pair. A change to either file must update the other when needed and preserve the same headings, lists, tables, link targets, and fenced code. After reviewing both languages, record their exact Git blob hashes and verify the pair: ```bash python .github/scripts/check_readme_i18n.py --write python .github/scripts/check_readme_i18n.py ``` The record in `README.i18n.yaml` makes any later one-sided edit fail local pre-commit checks and CI. The structural check does not judge translation quality, so its success does not replace human review of meaning and wording. The full test suite needs the supported container environment and training dependencies. See the [testing guide](https://reefinfra.ai/docs/contributing/testing/) for focused commands and dependency details. ## Understand the codebase Use the [codebase structure map](https://reefinfra.ai/docs/contributing/codebase-structure/) to decide which package owns a change. Each package's `__init__` docstring states the invariants inside its area; the map is the repository-wide routing guide. When adding a recipe, training integration, runtime, surface, artifact type, service route, or harness adapter, follow the [component playbooks](https://reefinfra.ai/docs/contributing/adding-components/). They list the implementation location, registration point, tests, configuration, and documentation expected in the same pull request. ## Python coding style Python changes should follow [PEP 8](https://peps.python.org/pep-0008/), the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html), and the principles below. The repository configuration in `pyproject.toml` is the authority when a general guide differs from Reef's mechanical style: Black formats code, isort orders imports, Ruff checks common errors and maintainability issues, and mypy checks the `reef` package. Do not hand-format code against these tools. ### Write Pythonic code - Prefer straightforward Python constructs and the standard library over custom abstractions. Code should make its control flow and data flow obvious. - Use iterators, comprehensions, context managers, unpacking, and standard protocols when they improve readability. Use an ordinary loop when a comprehension would need complex conditions or side effects. - Keep functions focused. Extract a helper when it gives a concept a useful name or removes meaningful duplication, not merely to shorten a function. - Avoid clever metaprogramming, hidden global state, and surprising side effects. Make dependencies and state transitions explicit. - Add type annotations to new or changed interfaces. Do not use `Any` to avoid describing a type unless the boundary is genuinely dynamic. - Write docstrings for public modules, classes, functions, and methods when their purpose, contract, or failure modes are not clear from the signature. Comments should explain *why* a choice is necessary, not restate *what* the code does. ### Use object-oriented design deliberately - Use a class when data and behavior form a cohesive object with state, invariants, lifecycle, or a polymorphic contract. Prefer a function for a stateless transformation and a dataclass for a data-only value. - Give each class one clear responsibility and keep its public surface small. Construct valid objects rather than relying on callers to set attributes in a particular order. - Prefer composition and small protocols over deep inheritance hierarchies. Inheritance should represent a genuine substitutable relationship, not just reuse implementation. - Encapsulate mutable state and expose intent-revealing operations. Do not add Java-style getters and setters when direct attribute access or a property is clearer. - Keep I/O and framework integration at the edges so that core behavior can be tested with ordinary Python objects. ### Avoid dynamic design shortcuts - Do not use `TYPE_CHECKING`. Imports needed by annotations must also be valid at runtime. Resolve cycles by moving shared contracts to a lower-level module, correcting the dependency direction, or using a local runtime import at the integration boundary. - Do not model long-lived behavior as `Callable` constructor arguments, callable-valued fields, or containers of callbacks. Define a named `Protocol` with meaningful methods or a cohesive class so the contract, state, and lifecycle are explicit. - A single short-lived callback can be appropriate for an algorithm, decorator, or standard-library adapter. A function that needs multiple callbacks is a sign that those operations belong to one interface. - Do not use dynamic dispatch through `getattr`, monkey-patching, or runtime inspection when an explicit interface or ordinary polymorphism expresses the same design. Boundary adapters for third-party frameworks must keep such behavior local and document why it is necessary. - Do not hide a design-policy violation with a type alias or lint suppression. Any rare exception must be narrowly scoped, justified in review, and recorded in the design-check baseline. ### Choose names for readers - Use `snake_case` for modules, functions, methods, and variables; `PascalCase` for classes; and `UPPER_SNAKE_CASE` for constants. - Name classes with concrete noun phrases and functions with verb phrases. Predicate names should read as questions, such as `is_ready`, `has_capacity`, or `can_retry`. - Prefer domain words and complete, familiar terms over internal shorthand. Avoid vague names such as `data`, `info`, `obj`, `manager`, `helper`, or `utils` when a more specific name exists. - Include units or representation when ambiguity could cause a bug, for example `timeout_seconds`, `token_count`, or `checkpoint_path`. - Keep terminology consistent across code, configuration, logs, and documentation. A single concept should have a single name. - Short conventional names are fine in a small scope (`i` in an index loop, `f` for a local file handle). Do not carry them across a larger scope. For example, prefer: ```python def select_ready_workers(workers: Iterable[Worker]) -> list[Worker]: return [worker for worker in workers if worker.is_ready] ``` over names that hide the domain and intent: ```python def process(data): return [x for x in data if x.status] ``` ### Automated checks and review The automated checks enforce the parts of this guide that can be evaluated reliably: - Black and isort enforce formatting and import order. - Ruff's Pythonic and correctness rules catch unnecessarily complex constructs, error-prone patterns, and common performance problems. - Ruff's `pep8-naming` rules enforce the naming forms above. Narrow exceptions for established public APIs and mathematical notation are documented in `pyproject.toml`. - mypy checks type consistency in the `reef` package. - The Python design-policy check rejects `TYPE_CHECKING` and new Callable-based object state or callback bundles. Its baseline identifies existing migration debt and cannot grow without an explicit reviewed change. Automation cannot determine whether a class is the right abstraction, whether an identifier uses the clearest domain term, or whether an interface has one cohesive responsibility. Authors and reviewers must evaluate those design and readability requirements during review. Do not add a lint exception merely to silence a warning; keep it narrow and explain why the general rule does not fit. Before requesting review for Python changes, run: ```bash pre-commit run --all-files python -m mypy pytest tests/ ``` ## Make a pull request Before requesting review: - keep the diff as small as practical and remove unrelated changes; - explain what changed, why it is needed, and how it was verified; - link the relevant issue or RFC when one exists; - add or update tests for behavior changes; - add a contract test for a public interface change; - update user, operator, or developer documentation affected by the change; - run the relevant local checks and report the commands and results. Use a draft pull request when the design or implementation is not ready for acceptance. Do not mix a functional change with drive-by formatting, generated rewrites, or unrelated cleanup. ## Review and acceptance Maintainers route reviews according to the affected areas. The [maintenance model](.github/MAINTAINER.md) defines Maintainer, Merge Oncall, and Area Reviewer responsibilities and the merge process. Reviewers may ask for changes to correctness, interfaces, tests, documentation, compatibility, operability, or scope. Authors are expected to respond to substantive comments and to say when a request is unclear or when they disagree. A pull request is ready to merge only when required reviews are complete, required checks pass, and no blocking discussion remains. Passing CI does not guarantee acceptance: maintainers also consider project direction, long-term maintenance cost, compatibility, and reviewer capacity. If a review has gone quiet, a concise and courteous reminder on the pull request is welcome. The project cannot guarantee a response or merge timeline. Non-draft pull requests are marked stale after 60 inactive days and close 21 days later; issues are marked after 90 inactive days and close 30 days later. Maintainers may apply `status: keep-open` or `status: blocked` when inactivity is expected. Closed work can be reopened or resubmitted when it becomes current again. ## License By contributing, you agree that your contribution may be distributed under the repository's [Apache License 2.0](LICENSE).