Open a reviewable pull request
A good pull request lets a reviewer understand one problem, see why the approach fits, and verify what you actually ran. The target repository's contribution guide, pull request template, title checks, and workflows remain authoritative; use this page as a review path, not as a replacement for them.
Start with the agreed work
For the core project, every non-trivial change begins with a validated discussion and an issue whose direction a maintainer has agreed. Link that issue in the pull request. A polished implementation does not replace the ticket-first requirement, especially for the high-risk areas.
Other NetBird repositories have their own intake rules. For example, an operator or integration repository may require an issue first even when a similar change in the docs would not. Confirm the rule locally before opening the pull request.
Keep one purpose
Keep a bug fix, refactor, feature, generated update, and unrelated cleanup in separate pull requests. A focused change is easier to test, review, release, and revert.
The core repository asks contributors to aim for fewer than roughly 400 hand-written changed lines across fewer than 20 files. Past about 1,000 lines or 50 files, expect a request to split the work unless the larger scope and sequence were agreed in the issue. Generated output, go.sum, and fixtures do not count toward that guideline, but they still need review.
If a protocol migration, cross-component rename, or other indivisible change cannot be small, agree on a series of independently buildable pull requests before implementation. Link the series and state the order.
Run and verify the change
Build the affected components and exercise the behavior yourself. Do not use CI as the first test of code that will run as a privileged service or alter a user's network.
Use the repository-specific build and test commands. Record:
- the exact commands or manual scenarios you ran;
- the operating systems, versions, commits, and configurations that matter;
- the observed result and any important case you could not test;
- cleanup performed after a privileged, acceptance, cluster, or cloud test.
For a bug fix, add a regression test when practical and establish that it fails for the original reason before applying the fix. For UI work, include screenshots or a short recording when layout and interaction are part of the result. Remove accounts, credentials, internal addresses, and device identifiers from all evidence.
Fill in the local template
Do not delete the pull request template. Complete the fields the target repository asks for rather than replacing them with a generic narrative.
A core pull request must link the agreed issue, identify the kind of change, confirm local testing and a single purpose, and select whether documentation was updated or is not needed. When documentation is needed, open the corresponding netbirdio/docs pull request and link it.
Explain the problem and the reasoning that the diff cannot show. Avoid a file-by-file walkthrough. The core guide asks for the description to stay under 1,000 words in addition to the template text.
Use the repository's title and commit format
Core pull request titles and commit subjects begin with a bracketed component tag, for example:
[client] Handle a platform-specific route update
[management,client] Add an agreed cross-component behavior
The core repository's allowedTags list is the source of truth. Do not copy that list into another repository: the dashboard, operator, provider, docs, and mobile projects may use different scopes or no tag rule.
Keep commit subjects short and put non-obvious reasoning in the body. Follow local sign-off and attribution rules; they are not uniform across the NetBird organization.
Review the final diff
From the repository root, inspect the state and the complete patch:
git status --short
git diff --check
git diff --stat
git diff
Then confirm all of the following:
- The pull request solves one stated problem and contains no unrelated formatting or refactor.
- Source, tests, docs, lockfiles, and generated output are present only when the change requires them.
- Every generated file came from its source definition and documented generator.
- Local environment files, copied logs, binaries, test manifests, editor files, and build output are absent.
- No credential, setup key, token, private key, customer detail, internal hostname, production address, or unredacted diagnostic appears in the diff or test evidence.
- Relevant formatting, lint, unit, integration, privileged, acceptance, and end-to-end checks were run, and any gap is stated honestly.
- User-visible behavior has matching documentation, or the template explains why documentation is not needed.
- Related cross-repository pull requests are linked with their required merge or release order.
For core Go changes, also check the code standards in the current contribution guide: keep functions single-purpose, prefer private functions and constants, document new public functions, test new public behavior, and comment on why a non-obvious choice exists rather than narrating the code.
Get CI green before requesting review
Watch the checks after pushing and fix failures before asking a maintainer to review. If a check is still running or could not be run from a fork, report that status instead of calling the pull request green.
The core project currently runs human review alongside automated analysis. Read bot and scanner findings, then either fix each applicable problem or explain why it does not apply. Do not resolve a thread without a response, change correct code only to silence a false positive, or weaken a workflow, threshold, scanner, or lint rule to make a check pass. Treat security and dependency findings as real until you can show otherwise.
Respond to review without hiding the changes
Answer review questions in your own words and push requested fixes as new commits while review is active. The core project squashes on merge, so rewriting history provides little benefit and makes follow-up review harder.
Avoid force-pushing a branch under review because it detaches line comments, discards the reviewer's changes-since-last-review view, and removes useful CI history. If a force-push is unavoidable to remove a secret or large binary, or to resolve a genuine history conflict, tell reviewers that their anchors moved.
Do not force-push away feedback, silently dismiss automated findings, or relay reviewer questions to a tool without understanding the answer. The person opening the pull request owns every line and must be able to explain it.
If a secret reaches a commit or pull request, removing it in a later commit is not enough. Stop, follow the affected repository's incident or credential-rotation process, and tell maintainers privately before rewriting public history.
Before you request review
One final pass should answer yes to these questions:
- Is there one clear purpose and, where required, an agreed issue?
- Did you run the changed behavior locally and record real results?
- Is CI green, or is every pending or unavailable check identified?
- Can a reviewer understand the risk, generated output, and cross-repository dependencies?
- Is user-facing documentation included or explicitly accounted for?
- Do you understand and accept responsibility for every line?
If the answer is no, keep the pull request in draft or return to the issue before asking for review.

