Conventions for contributing to Banjo.
Where to file things
Versioning
Banjo uses Semantic Versioning (SemVer). A version number looks like MAJOR.MINOR.PATCH:
- MAJOR: incremented when changes break backward compatibility (existing code using Banjo may need modifications).
- MINOR: incremented when new features are added in a backward-compatible way (existing code continues to work, new capabilities available).
- PATCH: incremented for backward-compatible bug fixes only.
Pre-release stages
Before a stable release, versions go through pre-release stages:
| Stage | Meaning |
| alpha | Development version. New features expected. Stable only by CI/CD. |
| beta | More mature. Can still add new features. |
| preview | Feature freeze. Bug fixes only. |
| rc | Release candidate. Only critical fixes. |
| (none) | Stable release. |
Pre-release versions look like 1.2.0-alpha, 1.2.0-beta, 1.2.0-preview, 1.2.0-rc. When multiple iterations are needed, they can be numbered: 1.2.0-rc.1, 1.2.0-rc.2.
The version is defined in inc/banjo/version.h: this is the single source of truth.
Branching strategy
Banjo uses Trunk-Based Development, a simple branching model where all development flows through a single main branch.
Branches at a glance
| Branch | Purpose | Version |
| main | Active development. Always deployable. | X.Y.0-alpha |
| release/X.Y | Stabilization and maintenance of version X.Y | X.Y.0-alpha → beta → preview → rc → X.Y.0 |
How it works
The main branch is the trunk. It always contains the latest development code, always passes CI, and is always at an -alpha version. All new work lands here first.
Release branches (release/X.Y) are created when it's time to stabilize a version. Once a release branch is cut:
- The release branch progresses through alpha → beta → preview → rc → stable.
- The main branch immediately bumps to the next minor version (still alpha).
Example timeline:
main (1.2.0-alpha)
│
├──► cut release/1.2 ──► 1.2.0-alpha → beta → preview → rc → 1.2.0 (tag: v1.2.0)
│ │
│ main bumps to 1.3.0-alpha ├──► 1.2.1 (maintenance)
│ │
▼ ▼
main (1.3.0-alpha) ──────────────────────────────────────────────► continues...
Maintenance releases
Release branches stick around after the stable release. If a bug is found in 1.2.0 while main is at 1.3.0-alpha:
- Fix the bug on release/1.2.
- Release 1.2.1 (tag: v1.2.1).
- Cherry-pick the fix to main.
This allows shipping fixes to older versions without forcing users to upgrade.
Contributor workflow
This section explains how to contribute code to Banjo day-to-day.
The golden rule
Nobody pushes directly to main. All changes go through a pull request.
Making a change
- Create a branch from main:
git checkout main
git pull
git checkout -b my-feature
- Make your changes and commit them. Keep commits focused and atomic.
- Push your branch and open a pull request:
git push -u origin my-feature
- CI runs automatically. Your PR must pass all checks before merging.
- Once approved and green, the PR is merged to main.
For maintainers: cutting a release
When main is ready to stabilize for version X.Y:
- Create the release branch:
git checkout main
git pull
git checkout -b release/X.Y
git push -u origin release/X.Y
- Bump main to the next version (e.g., 1.3.0-alpha):
git checkout main
# Edit inc/banjo/version.h
git commit -am "Bump version to 1.3.0-alpha"
git push
- On the release branch, progress through stages as stability improves:
- Update version.h to -beta, -preview, -rc, then remove the pre-release suffix for stable.
- Tag stable releases: git tag v1.2.0 && git push --tags
Language
The code is entirely in C99.
Header files and includes
Public headers live in inc/banjo/, with no subdirectories. Every header must parse standalone, with no other header required to precede it. A header must only include the headers it actually needs to parse.
Include order, each block alphabetically sorted and separated by a blank line:
- The header corresponding to the current implementation file (if any).
- Internal Banjo headers, with quotes ("").
- Public Banjo headers, with angle brackets (<>).
- Third-party headers.
- Standard library headers.
Doxygen
Use backslash directives only: \file, \brief, \param, \see, \snippet, never the @ form.
API conventions
- Single namespace: every public symbol/type is prefixed bj_ / BJ_.
- Booleans are bj_bool (a 32-bit unsigned).
- Fallible functions take struct bj_error** as their last parameter (see Error Management).
- Don't (void)-suppress a returned status: CERT-ERR33-C forbids it. Fold the return value into control flow.
- Prefer bj_set_error_fmt over snprintf + bj_set_error.
Changelog
The changelog format is based on Keep a Changelog. Versioning follows Semantic Versioning.