Three projects, one rule

The solution is split by a deliberate boundary — authoring/build/packaging lives in Beep.Installer; the runtime install engine lives in BeepDM (whose own scope doc lists an installer service but excludes packaging and code-signing).

ProjectTargetResponsibility
Beep.Installer.Corenet10.0 (no UI)Authoring model, .bsetup serializer, source scanner, BuildPipeline, payload packaging, packaging (ClickOnce/MSIX/signing), the runtime context projector, and FeedPublisher.
Beep.Installernet10.0-windows (WinForms)A thin shell: the Package Builder UI, the runtime wizard, wizard pages, the install step graph (InstallWizardGraph), i18n, and Program.cs mode dispatch.
Beep.Installer.Testsnet10.0-windowsxUnit + FluentAssertions.

Two more libraries and a server layer post-install features on top: Beep.Installer.Extensions.Winform / .WPF (drop-in update UI) and Beep.Installer.UpdateServer (optional hosting).

One executable, two modes

Beep.Installer.exe is both the generator and the Track-A runtime. Program.Dispatch picks a mode from the CLI args and whether an installer script exists beside/inside the exe:

  • A shipped installer carries script.bsetup (on disk next to the exe, or embedded as a PE resource) → it runs as the installer (wizard or silent).
  • CLI verbs (/BUILD, /PUBLISH, /S, /UNINSTALL, /CHECKUPDATE, …) select the corresponding headless mode.
  • Otherwise the Package Builder UI opens.

The two-model bridge

The authoring model (Beep.Installer.Models.InstallProject) is not what the install steps consume — they read BeepDM's InstallConfig from a SetupContext. The Runtime/ layer performs that projection and populates every context key the step graph reads:

InstallProject (.bsetup authoring)
      │  InstallConfigProjector.ToInstallConfig
      ▼
InstallConfig  +  InstallContextBuilder.ForInstall
      │  (InstallPath, LaunchPath, PerUser, RollbackManager, SideBySide, …)
      ▼
SetupContext  →  BeepDM install steps (FileCopyStep, RegistryWriteStep, …)

When adding a step that needs new config, wire it through the projector/builder — never reach into the authoring model from a step.

The install engine is in BeepDM

The actual install steps — PrerequisiteCheckStep, FileCopyStep, ShortcutCreateStep, RegistryWriteStep, VerifyInstallStep, UpgradeStep, JunctionCreateStep, UninstallStep — live in BeepDM under TheTechIdea.Beep.Installer.Steps / TheTechIdea.Beep.SetUp. Beep.Installer only composes and drives them via Hosting/InstallWizardGraph, which is the single place those steps are ordered into a wizard for install, repair, uninstall and self-test.

The app self-update domain (TheTechIdea.Beep.Updates) also lives in BeepDM (decision D12), so any Beep-based app gets self-update by registering one service — independent of how it was deployed.

Cross-repo build note

Beep.Installer references sibling source repos by relative path (..\..\BeepDM\, ..\..\Beep.Winform\). DataManagementModels is referenced directly (not just transitively) with NoWarn NU1605 — the control libraries carry a same-versioned NuGet DataManagementModels and NuGet resolves nearest-to-root, so the direct reference is what makes the source win. The extension libraries and the server follow the same pattern.