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
develop. developfeeds the production line. It's the default branch, and the only preview channel. Both deliberate work and faster work land here. Breaking changes land here too, behind[Experimental("FALLOUT0xx")](or on a short-lived branch offdevelopwhen that doesn't fit), waiting for the next major. Stable releases ship frommain, reached through arelease/vX.Ybranch cut on demand fromdevelop. That's the nuget.org tier. The legacysupport/v10line takes security and critical fixes only (see Branching and release flow and ADR-0009 for the full model). Branch from, and PR against,develop. The only time you target a production branch directly is for a maintainer-driven hotfix.
- Star the GitHub project to help others find it.
- Show the badge in your own README if you build with Fallout — copy-paste markdown, nothing to host.
- 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 releases 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
develop(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.GlobalToolversion 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. A few conventions to follow:- Test names read as behavior, not method calls (AV1600-style):
Missing_changelog_does_not_add_a_full_changelog_link_to_release_notes, notGetNuGetReleaseNotes_WithMissingChangelog_AndGitHubRepository_DoesNotThrow. Specssuffix, notTest/Tests— test projects areFoo.Specs, filesFooSpecs.cs, classesFooSpecs. It signals the class specifies expected behavior.- AAA structure with Pascal-case comments —
// Arrange,// Act,// Assert. Omit a section's comment when there's nothing to arrange (e.g. constructor fixtures already cover it). - Disk-based fixtures use a constructor +
IDisposable.Dispose(), not per-testtry/finally— xUnit creates a fresh instance per[Fact], so the constructor is Arrange andDispose()is teardown. UseAbsolutePath.Temp(prefix)for the scratch directory. SeeMigrationIntegrationSpecs.csandBumpDotNetVersionStepSpecs.csfor the pattern.
- Test names read as behavior, not method calls (AV1600-style):
- Commit the regenerated
.csoutput alongside the.jsonspec —VerifyGeneratedToolsfails CI if they drift. - Label the PR
target/vCurrentfor the current release line (usetarget/vNextfor work held for the next major). Breaking changes wait for the next major. They land ondevelop, behind[Experimental("FALLOUT0xx")](or, if that doesn't fit, on a short-lived branch offdevelop) — never on arelease/vX.Yormainproduction branch. They also get abreaking-changelabel plus a⚠️ Breaking changecallout in the PR description that names the migration path. Surface that isn't ready to commit to yet can ship behind[Experimental("FALLOUT0xx")]instead of being held back. See thecreating-a-prskill (.agents/skills/creating-a-pr/SKILL.md) for the full procedure.
Tool wrapper JSON lives under src/Fallout.Common/Tools/<Tool>/<Tool>.json. See the adding-a-tool-wrapper skill (.agents/skills/adding-a-tool-wrapper/SKILL.md) for the recipe: copy a neighbour's shape, cover a full command with all its arguments, regenerate with ./build.ps1 GenerateTools, and commit the regenerated .cs alongside the .json spec.
- The PR gate is the
ubuntu-latestjob (frombuild.yml) only — fires on PRs againstdevelop,main,release/*, orsupport/*. Docs-only PRs hit a no-op shim workflow (build-skip.yml) that reports the same status check name.build-cross-platform.ymlruns Windows + macOS validation onmain/release/*/support/*PRs andv*tag pushes (gated to release intent), not on routinedevelopwork. - Review rises with the ladder. PRs to
develop(preview) get ordinary review — it's the integration trunk. Arelease/vX.Ystabilization branch (and the GA merge intomain) 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 develop 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
developbecomes 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 develop publishes a preview prerelease (10.MINOR.PATCH-preview.…) to GitHub Packages only — never nuget.org. A release/vX.Y branch, cut on demand from develop, publishes rc prereleases (-rc.N) while it stabilizes. Merging that branch into main and tagging it there fires the stable release: GitHub Packages and GitHub Releases by default, nuget.org by opt-in. The full lifecycle is documented in docs/branching-and-release.md:
- How releases happen (cut
release/vX.Yfromdevelop, stabilize, merge tomain, tag, parallel publish jobs) - The channel taxonomy (preview/rc → GitHub Packages; stable → GitHub Packages + GitHub Releases, nuget.org opt-in; Docker local for pre-merge)
- Promotion + hotfix flow (
develop → release/vX.Y → main, merged back intodevelop; the legacysupport/v10line takes security/critical fixes directly) - When to cut a new major
Contributors don't usually need to do any of this — releases are maintainer-driven. But if you're filing a fix for the legacy support/v10 line, or one that carries a breaking change held for the next major, expect the maintainer to route it accordingly.