TEMPLATE.md Versioning section; notes in README, CHANGELOG and the firmware/software READMEs. Source: contrib/product-template in B4L/proplan.
8.4 KiB
B4L product repository template
Every B4L product repository has the same layout, so people and proplan find
the product image, the boards, the firmware and the libraries in the same
place. This file explains the layout, the rules and proplan.toml. It is
copied into every repository created from the template; keep it as the
reference.
Create a product repository
In Gitea: New Repository, choose the template B4L/product-template,
tick Git Content, give the repository the product's name and a
description. Gitea puts the name into README.md, CHANGELOG.md,
proplan.toml and the board folder under hardware/ (the files listed in
.gitea/template). Then:
- Replace
assets/product.pngwith a photo or render of the product (PNG, JPEG or WebP, at most 5 MB). - Create the KiCad project in the board folder (KiCad: File, New Project; the
project file is
hardware/<name>/<name>.kicad_pro). - Commit and push. The KiBot workflow checks the board on every push.
- Tag the first prototype
v0.1when its boards are ordered, and link the tag to the stage on the project's Prototypes tab in proplan.
Layout
| Path | What goes there |
|---|---|
proplan.toml |
the manifest proplan reads (below) |
README.md, CHANGELOG.md |
what the product is; one changelog section per stage (## v0.2) |
assets/product.png |
the product image |
hardware/<board>/ |
one KiCad project per board |
hardware/lib/ |
symbols, footprints and 3D models shared by the boards |
firmware/<target>/ |
MCU code (STM32CubeIDE or CMake), firmware/lib/ for shared drivers |
external/ |
third-party code as git submodules (e.g. ST's USB-PD middleware) |
software/<tool>/ |
host tools and apps |
mech/ |
FreeCAD sources and STEP exports |
sim/ |
LTspice/ngspice, calculation scripts and notebooks |
test/<stage>/ |
bench results per stage (test/v0.1/) |
docs/, docs/datasheets/, docs/tex/ |
documentation, vendor PDFs, LaTeX sources |
.gitea/workflows/ |
KiBot, release outputs, fabrication document |
Rules
- A board revision is a tag (
v0.1,v0.2), never a copied folder (kicad_v1_5/next tokicad_v1_6/). A real variant built side by side (48 V and 24 V, 2-board and 3-board) is its own folder underhardware/and its own[[boards]]entry. - Generated output (gerbers, BOMs, production zips, PDFs, plots) is built by CI and attached to the release; it is not committed.
- Vendor datasheets go to
docs/datasheets/, not the repository root. - Third-party code is a git submodule in
external/and is not edited here. - IDE build output and tool caches (
Debug/,__pycache__/,.claude/, KiCad backups) stay out;.gitignorecovers them.
Versioning
One repository, three kinds of tags. The prefix of a firmware or software
tag is the folder it versions, so every target and every tool has its own
releases, and the board release workflow (v*) never reacts to them.
| What | Tag | Example | Scheme |
|---|---|---|---|
| Prototype stage (the whole product) | vMAJOR.MINOR |
v0.1, v0.2 |
the next stage takes the next number; the tag proplan links to a stage and CI attaches the board outputs to |
Firmware target firmware/<target>/ |
firmware/<target>/vMAJOR.MINOR.PATCH |
firmware/main-mcu/v1.2.0, firmware/main-mcu/v1.3.0-rc.1 |
SemVer 2.0 (semver.org) |
Software tool software/<tool>/ |
software/<tool>/YYYY.MM.MICRO |
software/diag/2026.10.0, software/diag/2026.10.1 |
CalVer (calver.org) |
Firmware (SemVer):
- MAJOR when something outside the firmware has to change with it: CAN IDs or message layout, the protocol the host tools speak, the format of settings stored in flash, the bootloader interface. MINOR for new features that keep all of that, PATCH for fixes.
0.y.zwhile prototyping (anything may change),1.0.0with the first production firmware. Bench builds before a release are pre-releases (v1.3.0-rc.1,-rc.2).- The version is also where the build reads it (CMake
project(<name> VERSION 1.2.0)or aversion.h), and the firmware reports it at run time (CAN, USB or UART), so a board on the bench says what it runs.
Software (CalVer YYYY.MM.MICRO):
- Year, month without a leading zero (calver.org's
MM), and MICRO counting the releases of that month from 0:2026.10.0,2026.10.1,2026.11.0. Without the zero the number is also a valid version for pip (pyproject.toml) and Cargo. - A date, not a compatibility promise: a tool's README says which firmware MAJOR versions it talks to.
For all three:
- The tag is the source of truth. A version written in a file
(
pyproject.toml,Cargo.toml, CMake,version.h) matches the tag and changes in the commit that gets tagged. - A tag is never moved or reused; a bad release gets the next version. proplan flags a moved tag on its stage card.
- Each firmware target and each tool keeps its own
CHANGELOG.mdin its folder. The rootCHANGELOG.mdhas one section per prototype stage and lists the firmware and software versions that stage was built with. - Firmware and software releases are made by hand in Gitea for now (push the
tag, then New Release);
release.ymlbuilds board outputs forv*tags only.
proplan.toml
proplan reads this file and the image it names, nothing else of the repository's content: at the default branch for the Code tab, and at a stage's tagged commit for the stage's card (so the card shows the product as it was at that tag). Every key is optional.
schema = 1 # 1; a newer schema is refused
[product]
name = "papir" # default: the repository's name
image = "assets/product.png" # PNG, JPEG or WebP, at most 5 MB; none when left out
[[boards]] # one per KiCad project, as many as needed
name = "papir" # default: the folder's last part
path = "hardware/papir" # required
[paths] # each default: the folder of the same name
firmware = "firmware"
software = "software"
mech = "mech"
sim = "sim"
test = "test"
docs = "docs"
external = "external"
Paths are relative to the repository root (no leading /, no ..). A board,
a path written under [paths] or the image that does not exist is reported on
the Code tab ("proplan.toml: missing ..."); a path
left out that does not exist is simply not shown. Unknown keys are ignored.
Adopting the layout in an existing repository
An existing repository does not have to move anything: a proplan.toml that
names the current folders is enough, and history and open work stay as they
are. Moving folders to the template's names can follow later.
papir (KiCad project in papir/, firmware in code/):
[[boards]]
name = "papir"
path = "papir"
[paths]
firmware = "code"
software = "pirnet"
mech = "mech"
docs = "docs"
LVSolarBuck (the current board in kicad48V-R/LVSolarBuck, firmware in code64/):
[product]
image = "housing.png"
[[boards]]
name = "LVSolarBuck"
path = "kicad48V-R/LVSolarBuck"
[paths]
firmware = "code64"
sim = "ltspice"
test = "testing"
docs = "docs"
PowerModule (three board variants):
[product]
image = "images/render-display.png"
[[boards]]
name = "PowerModule"
path = "kicad/PowerModule"
[[boards]]
name = "PowerModule48"
path = "kicad/PowerModule48"
[[boards]]
name = "PowerModule48PD"
path = "kicad/PowerModule48PD"
[paths]
firmware = "code"
software = "tools"
sim = "ltspice"
test = "testing"
docs = "tex"
external = "external"
CI
.gitea/workflows/kibot.yml: on a push that toucheshardware/, KiBot runs ERC and DRC and builds schematic PDF, gerbers, drill files, pick and place and BOM for every board (hardware/*/*.kicad_pro); the outputs are kept as a workflow artifact..gitea/workflows/release.yml: on a tagv*, the same outputs are zipped per board and attached to the tag's release (created when missing). The Actions token must be allowed to write releases. Firmware and software tags (firmware/...,software/...) do not start it..gitea/workflows/docgen.yml: with adocs/input.md(typecad-docgen front matter, as in PowerModule), builds the fabrication document of the first board and pushes it to thedocubranch.
All three use the runner label kicad10_auto (as LVSolarBuck). They were
adapted from LVSolarBuck and PowerModule and run for the first time when the
first board is committed and tagged; check that first run.