Fuse
Project

Contributing

How to build, test, and format Fuse, the project layout, and where to add new behavior.

Fuse is a .NET 10 solution organized into pipeline libraries, a host, and language plugins. Contributing means working within those boundaries: a change belongs to one part of the pipeline, and the build verifies formatting and tests on every pull request. This page covers the commands you run, the layout you work in, and where to add a new language.

This page is for engineers making their first change to Fuse and maintainers reviewing one. A reader who only needs the command list can read Build, Test, And Format and stop.

Build, Test, and Format

The solution is defined in Fuse.slnx. Three commands cover the local loop, and the build verifies all three on every pull request:

dotnet build Fuse.slnx -c Release
dotnet test Fuse.slnx -c Release --no-build --filter "Category!=RequiresSdk"
dotnet format Fuse.slnx --verify-no-changes

The build compiles in Release configuration. The test run uses --no-build so it reuses the build output rather than recompiling; run the build first. The default filter matches the main CI leg: it runs every test except those tagged Category=RequiresSdk. The format check verifies that no file needs reformatting and fails if any does. To apply formatting fixes rather than verify, run dotnet format Fuse.slnx without the flag. On Windows, install.bat builds, packs, and installs the global tool locally for manual testing.

The build enforces public XML documentation. Non-test projects generate a documentation file, so a missing public or protected XML comment produces compiler warning CS1591. Do not add new CS1591 warnings in a pull request.

CI test legs

Pull requests run two test legs so SDK-heavy integration tests do not slow the default job or pass vacuously when the runner lacks a working toolchain.

LegWorkflowWhat it proves
Defaultci.ymlFast feedback on every change: build, format, coverage, and Category!=RequiresSdk tests
SDKci-sdk.ymlCategory=RequiresSdk tests on win-x64 and linux-x64 with the .NET 10 SDK and the bundled build-capture worker copied beside fuse.dll on build

Run the SDK leg locally after a Release build when you touch a RequiresSdk test or anything that depends on dotnet build or the build-capture worker:

dotnet build Fuse.slnx -c Release
dotnet test Fuse.slnx -c Release --no-build --filter "Category=RequiresSdk"

Tests marked RequiresSdk call SkipException.ForSkip when the SDK or worker is absent, so a plain dotnet test without the filter can look green while doing nothing. Use the filter that matches the leg you intend to exercise. build/verify-ci-sdk.ps1 runs in the default CI job and fails if RequiresSdk-tagged tests exist but either workflow leg is missing or misconfigured.

Resilience harness

ResilienceHarnessTests (in Fuse.Cli.Tests) is the standing fault-injection guard (R32): for each injected fault - SQLite busy/locked, a missing chunk_fts, a sharing violation, a corrupt database, an extraction-version-skewed store, an integrity violation, and an unexpected exception - it asserts the invariant that the tool degrades to a stable operational prefix or a graded answer, never an unhandled exception and never silent-empty. Run it with the default test leg (dotnet test Fuse.slnx -c Release --filter "Category!=RequiresSdk"); a regression that removes a degradation path fails the matching case. Process-level faults that need a live daemon or toolchain (a killed daemon mid-index, disk-full on write, N concurrent daemons) are covered by construction (single-instance lock, best-effort writes) and by the SDK CI leg rather than injected in-process.

Releasing (version propagation)

The product version lives in Directory.Build.props <Version>; bump every package in lockstep with build/set-version.ps1 X.Y.Z. A version bump is reflected in the built assembly without a manual clean: the FuseStampVersionMarker target invalidates the compile when <Version> changes, so a normal dotnet build no longer serves a stale-version bin. Before tagging, run the release safety net:

./build/verify-version.ps1 -Build           # build Fuse.Cli and assert `fuse --version` == the codebase version
./build/verify-version.ps1 -Tag vX.Y.Z       # also assert the tag matches

-Build builds Fuse.Cli (Release) and fails if the built fuse --version does not equal Directory.Build.props <Version>, or if the Release fuse.dll is missing, so a mis-versioned or missing artifact cannot ship.

Project Layout

Fuse separates concerns along the pipeline. A change should touch one part and respect the boundaries between them.

PartHoldsExamples
CoreThe pipeline libraries: collection, reduction, emission, and the fusion orchestration that drives themFuse.Collection, Fuse.Reduction, Fuse.Emission, Fuse.Fusion
HostThe user-facing surfaces: the CLI commands and the MCP serverFuse.Cli commands, Fuse.Cli MCP tools
PluginsLanguage and format behavior registered into the core pipelineFuse.Plugins.Languages.CSharp, Fuse.Plugins.Formats.Web

The core libraries do not depend on the host, and language-specific behavior lives in plugins rather than in the core pipeline. Services are registered through AddFuse(); filter registration order equals filter evaluation order. Read the Pipeline page before making structural changes.

How to Extend

Support for a language is a matter of registering its plugin, so adding one does not require changes to the core pipeline. The Language Plugin guide gives the step-by-step process for adding a reducer, skeleton extractor, and the other capabilities a language plugin provides.

License and Sign-off

Fuse is licensed under the Apache License, Version 2.0 (see the LICENSE file at the repository root, and NOTICE for attribution). Contributions are accepted under the same license. The project migrated from MIT to Apache 2.0 in the 4.0 release; the change adds an explicit patent grant and is a license-header change only, with no API break.

Every commit must carry a Developer Certificate of Origin (DCO) sign-off. Add it with git commit -s, or write the trailer by hand as the last line of the commit message:

Signed-off-by: Your Name <you@example.com>

The name and email must match the commit author. The sign-off certifies the DCO 1.1 statement in DCO.txt (the same certificate the Linux kernel, Kubernetes, and the Apache Software Foundation use): you attest that you have the right to submit the change under the project license. A DCO check runs on every pull request and fails if any commit in the pull request is missing a matching trailer. Commits merged before the DCO was adopted are grandfathered; the check inspects only the commits a pull request adds. Fuse uses the DCO instead of a Contributor License Agreement, so there is no separate signature step.

What This Does Not Cover

This page covers the contribution workflow and layout. It does not restate the C# conventions, the XML documentation standard, or the dependency injection lifetimes in full; those live in the repository contributing guide and AGENTS.md. The performance and AOT build steps are covered in Performance and Benchmarking.

Next

Read the Language Plugin guide to add a language, or Performance and Benchmarking for the AOT publish and benchmark steps.

On this page