-
Notifications
You must be signed in to change notification settings - Fork 0
FAQ
Tamp's value proposition is a small core that the .NET community can maintain forkably without one maintainer's bus factor sinking the ecosystem. Stretching to JVM / Python / Rust / Go would multiply the surface area we have to keep coherent, and there are competent build tools native to each of those. We focus on doing one thing well.
The README's "and beyond" framing in the original design doc is about expanding what Tamp can drive (the wrapper modules) — not about supporting build scripts in non-.NET languages.
Recorded in ADR 0006. Short version: Core API evolution is constant in the early life of the project, and atomically updating Core + first-party module consumers in one PR is dramatically easier than choreographing N-repo dances. Independent NuGet versions are still the contract; only the source layout is monorepo. We may revisit if first-party module count crosses ~20.
- Bazel does distributed-execution remote caching, hermetic builds, multi-language repositories. It's a different category of tool — when you need it, nothing else is enough; when you don't, it's vastly over-shaped. Tamp explicitly does NOT do remote execution or hermeticity guarantees.
- Gradle is JVM-focused; we ruled out cross-language footprint (above).
- Make is fine for small projects but lacks structured target dependencies, typed parameters, dry-run-by-construction, secret handling. The .NET ecosystem long since moved past it.
If your problem is "10K-engineer monorepo with cross-language polyglot builds," Tamp is the wrong tool. If your problem is ".NET project / library / SaaS / mod with pack/test/publish pipelines," Tamp fits.
Tamp.Core is what your build script references directly — it's a normal NuGet library. Tamp.Cli is the launcher/router that finds your build/Build.csproj and forwards args to it. The launcher is convenience; the framework works fine with dotnet run --project build -- ci.
Because the .NET ecosystem went two ways. NUKE ships a bare command (nuke ci); Cake ships the dotnet-verb form (dotnet cake build.cake). We ship both — same underlying code, different <ToolCommandName>. Pick whichever convention fits your habit.
Pre-1.0. The functional surface is real — over a thousand tests across all supported TFMs cover it — but breaking changes are still possible between minor versions in the 0.x line. Once the v0 walking skeleton is dogfooded against a real consumer build (HoldFast pipeline) and Microsoft confirms the Tamp.* prefix reservation, we cut a 0.1.0 and the API stabilizes.
No. NuGet's PackageReference semantics interpret Version="1.6.0" as >= 1.6.0, not == 1.6.0. A satellite shipping its nupkg with Tamp.Core declared at 1.6.0 works fine against an adopter who has Tamp.Core 1.6.5 or 1.7.0 — the higher version wins at restore.
Satellites only need to bump their minimum when they want to use new Core API or when a new Roslyn analyzer rule starts catching code that previously compiled. A bare Core minor that doesn't add surface the satellite consumes is invisible to the satellite.
Pre-1.6.0 this was less true — satellites handling Secret values needed an [InternalsVisibleTo] entry in Tamp.Core/AssemblyInfo.cs, which forced a Core minor bump and a satellite-side min-version bump. Tamp.Core 1.6.0 retired that pattern by making Secret.Reveal() public + analyzer-gated via TAMP004. The forced-sweep class is gone.
See the Module Catalog → How satellites depend on Tamp.Core for the full table including NuGet's npm-style range syntax ([1.6.0,2.0.0), 1.6.*, etc.) if you want to express tighter intent than bare min-version.
The [Secret] attribute and Secret type are the canonical mechanisms. The framework redacts registered values from any output that flows through the executor's logger, including child-process stdout/stderr. Wrappers that take secrets emit them via stdin (docker login --password-stdin) where the underlying tool supports it, keeping the value out of the OS process table. See Parameter & Secret Injection for the full mechanism.
What Tamp does NOT cover:
- Output that bypasses the framework's writer (your code's
Console.Writedirectly) - The fundamental OS-level visibility of process arguments to the process table
- Crash dumps and core files
Yes. Tamp's core (target graph, executor, dispatch) doesn't know what's being built. The wrapper modules know specific tools — and you're not limited to the ones we ship. Anything you can spawn as a process, you can wrap or just shell out to from a target's Executes lambda.
That said, there are richer build tools for non-.NET ecosystems (Gradle for JVM, Cargo for Rust, etc.) and you'd usually be better served by those for the build itself, with Tamp as an outer orchestrator if you need one.
Tamp is an architectural rethink of the same problem space NUKE addresses. The target authoring DSL surface is intentionally similar (NUKE's syntax was good); the architecture underneath is what got rebuilt — small core, plugin-driven, independently-versioned wrappers, governance separated from the BDFL's calendar. See Migrating from NUKE for the concept-by-concept mapping.
Yes — that's actually one of the reasons multi-targeting net8/net9/net10 was a v0 must-have. Federal contracts and corporate VDIs that are pinned to .NET 8 are a real consumer cohort. Tamp's first-party assemblies multi-target net8.0;net9.0;net10.0 (per ADR 0015).
For air-gapped scenarios where dotnet tool install can't reach nuget.org, the [NuGetPackage] attribute has a LocalCachePath escape hatch that resolves from a pre-staged tools directory.
Briefly forgot that real-world long-running projects deliberately adopt STS releases to surface early features. ADR 0015 records the corrected policy: track Microsoft's official .NET support calendar exactly, both LTS and STS. We add a TFM the day a release ships and drop it the day Microsoft EOLs it. No project-specific definition of "supported."
Don't open a public GitHub issue. Either open a private GitHub Security Advisory or email scott@gscottsingleton.com with [tamp security] in the subject. Full policy in SECURITY.md.
Read CONTRIBUTING.md. The short version: open an issue first for anything more involved than a typo, branch from main, run dotnet test Tamp.slnx before pushing, conventional-commit prefix on the message. ADRs (docs/adr/) are the source of truth for any architectural area; read the relevant ADR before proposing a change to that area.
NuGet's prefix-reservation guidance suggests "avoid prefixes shorter than four characters." Tamp is exactly four. The prefix-reservation request makes the project-specific case for it — it's a build framework's brand, not a generic English term, and we own all current Tamp.* matching packages already.
"Pack the build down tight." Tamping is what you do with gravel before you pour concrete on top of it — settle and consolidate the layer below before building higher. The framework's job is to be the well-tamped foundation under whatever you're shipping.
Start here
Modules
- Module Catalog (canonical list)
- .NET toolchain
- Containers
- JS toolchain
- Supply-chain security
Analyzers
Tooling
Execution
CI integration
Migration
Reference
Project