Fallout welcomes contributions. As a community, we want to help each other, provide constructive feedback, and make a better product. Our code of conduct applies at all times.
About the project. Fallout is the hard-fork successor to NUKE (originally by Matthias Koch and contributors). Maintenance moved to a new team in 2026; the codebase is in active rebrand. See the README for the full backstory.
- Discuss non-trivial changes in an issue first.
- Small fixes (typos, broken links, tool wrapper additions) can go straight to a PR against
main. mainfeeds the production line.mainis the integration trunk + sole-previewchannel — the default branch where both deliberate improvements/bug fixes and faster work land. Breaking changes also land onmain, gated behind[Experimental("FALLOUT0xx")](or held on a short-lived topic branch offmainwhen they can't be gated) and batched to the yearly major. Stable releases ship fromrelease/YYYYbranches (the calendar-year production line, the nuget.org tier), and the legacysupport/v10line takes security/critical fixes only (see Branching and release flow and ADR-0004, as amended by ADR-0008, for the full model). Branch from, and PR against,main. The only time you target a production branch directly is for a maintainer-driven hotfix.
- Star the GitHub project to help others find it.
- File issues with concrete reproduction steps, version info, and logs.
- Help triage existing issues — confirming bugs or pointing to fixes counts.
- Search existing/closed issues — your problem may already have an answer.
- Check the CHANGELOG for recent changes that affect your scenario.
- For tool wrappers, send a PR instead of an issue — they're mechanical to add.
- State the issue as concisely as possible.
- Use markdown for code, logs, and special text fragments.
- Avoid pasting screenshots of text — paste the text itself in a code block.
- Bugs blocking active enterprise CI/CD usage.
- Regressions versus the last NUKE 10.x release.
- Rebrand-track work (see the Fallout rebrand milestone).
- Demand-driven items where multiple users have weighed in.
- Branch from
main(the base for all PRs). Name your branchfeature/<slug>,bugfix/<slug>, orchore/<slug>. - Make sure your employer allows the contribution.
- Read AGENTS.md for the codebase conventions — package versions go in
Directory.Packages.props, tests live next to code, no per-file license headers (theLICENSEfile at the root is the single source of truth). (AGENTS.md is the canonical brief for both human contributors and AI tools; GitHub Copilot reads it natively andCLAUDE.mdpoints to it.) - The bootstrappers are now thin:
./build.ps1/./build.shprovision .NET if needed, then rundotnet tool restore+dotnet fallout "$@". TheFallout.GlobalToolsversion is pinned in.config/dotnet-tools.json. - Run
./build.ps1 Test(or./build.sh Test, or directlydotnet fallout Testonce your tools are restored) locally first.
- Write functional commit and PR titles — describe what the change accomplishes, not how it's categorised. Do not use conventional-commit prefixes (
feat:,fix:,chore:,refactor:, etc.). Good examples: "Add retry logic to the HTTP tool wrapper", "Fix null-reference in target dependency resolution". The!suffix (e.g.fix(security)!: …) is recognised only as a breaking-change detection signal, not a general style requirement. - Aim for qualitative, readable code that matches the surrounding style.
- There's no committed
.editorconfigor ReSharper/*.DotSettingsfile — they were removed during the takeover. Rely ondotnet formatdefaults and review; don't reintroduce them without a maintainer-level decision. - Add tests when meaningful — every
Fooproject has a siblingFoo.Tests. - Don't commit code generated by
./build.ps1 GenerateTools— generated.csfiles are regenerated manually once per release. - Label the PR
target/YYYYfor the calendar year it will release in — defaulttarget/2026. Legacysupport/v10maintenance work usestarget/v10. Breaking changes are batched to the yearly major cut: they land onmaingated behind[Experimental("FALLOUT0xx")](or, when they can't be gated, on a short-lived topic branch offmain) — never on arelease/YYYYproduction train — are held for next year'sYYYY+1.0.0, and additionally get abreaking-changelabel, a⚠️ Breaking changecallout, and aCHANGELOG.mdentry under the next-major[Unreleased]heading. Surface that isn't ready to commit to can ship behind[Experimental("FALLOUT0xx")]instead of being held back. See the PR-creation flow for the full procedure.
Tool wrapper JSON lives under src/Fallout.Common/Tools/<Tool>/<Tool>.json. When adding or extending one:
- Copy the shape from a neighbouring tool.
- Cover at least a full command with all its arguments.
- Use formatting tags in
help:<c>for inline code<a>for links<ul>/<ol>for lists<em>for emphasized text<para/>between paragraphs (not<p>...</p>)
- Don't write
secret: false(it's the default). - Don't write
default: xxx(obsolete). - Run
./build.ps1 GenerateToolsto verify it generates cleanly. - Don't commit the generated
.csoutput.
- The PR gate is
ubuntu-latestonly — fires on PRs againstmain,release/*, orsupport/*. Docs-only PRs hit a no-op shim workflow that reports the same status check name.windows-latestandmacos-latestrun post-merge for cross-platform validation. - Review rises with the ladder. PRs to
main(preview) get ordinary review — it's the integration trunk. Promotion to arelease/YYYYproduction train (and the GA cut) gets rigorous, unhurried review — that's the project's quality gate. Match your expectations to where the PR is headed. - Address review feedback in additional commits rather than force-pushing — easier to review the changes.
- If CI fails on something unrelated to your change, ping a maintainer.
Rebase is the only merge button. Squash and plain merge commits are both disabled by repo setting. We keep a linear history where every reviewed commit lands on main verbatim — it makes per-change diffs easy to read, keeps git bisect/git blame/revert precise, and gives change control a discrete, traceable record per logical change (a squash would collapse that into one opaque commit).
- Curate your commits before final approval. Everything you rebase onto
mainbecomes a permanent bisect target, so aim for one logical change per commit. Rungit rebase -ito fold "address review feedback" / "fix typo" noise into the commits it belongs to. - During review, prefer additional commits (see above) for easy diffing, then tidy them into a clean sequence before the final approval and merge.
The merger (typically a CODEOWNER) clicks Rebase and merge — there's no button to choose.
Merging to main publishes a preview prerelease (2026.MINOR.PATCH-preview.…) to GitHub Packages only — never nuget.org. This is the preview lane. Stable releases fire from release/YYYY branches via tag push, with a multi-channel publish fan-out (GitHub Packages + GitHub Releases by default; nuget.org is opt-in). The full lifecycle is documented in docs/branching-and-release.md:
- How releases happen (tag a
release/YYYYbranch, parallel publish jobs) - The channel taxonomy (preview → GitHub Packages; stable → GitHub Packages + GitHub Releases, nuget.org opt-in; Docker local for pre-merge)
- Promotion + hotfix flow (forward-only
main → release/YYYY; the legacysupport/v10line takes security/critical fixes directly) - When to cut a new year
Contributors don't usually need to do any of this — releases are maintainer-driven. But if you're filing a PR labelled target/v10 (legacy maintenance) or one that carries a breaking change held for next year's major, expect the maintainer to route it accordingly.