π«π· Version franΓ§aise
NuGet publication matrix
This file is the single source of truth for which projects are published to NuGet, so the
workflows (ci.yml validation, publish.yml pack + push on tag, release.yml installers)
never drift again (OSS-011 / R8.3).
Status β consolidated lineup implemented (PUB-25, 2026-09-01). Distribution is one
Orkeonpackage plus a handful of opt-ins, wired inpublish.ymland guarded by thescripts/check-package-closure.pygate; the first push of this lineup lands at thev1.0.0-rc.3tag. Trusted Publishing to NuGet.org is operational β the discontinued per-layer packagesOrkeon.Domain/Orkeon.Application/Orkeon.Infrastructureshipped1.0.0-rc.1(2026-08-18) and1.0.0-rc.2(2026-08-25) through it, and are to be unlisted once the new lineup is published (see the owner actions below). Decision D3 (the scripting naming twins) is resolved β PUB-02, 2026-08-17, ADR-007: the command library was renamedOrkeon.Cli.ScriptingβOrkeon.Cli.Commands.Scriptingbefore any NuGet publish locked the old name in.
The NuGet.org lineup
One package installs the whole framework; everything else in the lineup is an opt-in kept separate only because of what it would force on every consumer (dependency weight, native runtimes, a pre-release upstream).
| PackageId | Why |
|---|---|
Orkeon |
The umbrella package β the eleven assemblies of the core closure (Orkeon.Domain, Orkeon.Application, Orkeon.Infrastructure, Orkeon.Constants.{Llm,FileSystem,Configuration}, Orkeon.Tools.Abstractions, Orkeon.Analysis.Abstractions, Orkeon.Rag.Abstractions, Orkeon.Analysis, Orkeon.Rag) embedded in one nupkg. One install = the complete framework: agents, crews, six orchestration modes, 16 LLM providers, 6 memory stores, RAG, RaggableTree. The Clean Architecture split stays a source-layout discipline, not a distribution contract. |
Orkeon.Tools |
The seven built-in tool families (Analysis, Code, Data, EventHub, FileSystem, Rag, Web) in one nupkg. Separate from Orkeon only for dependency weight: the Data tools pull database drivers, PDF and spreadsheet libraries a consumer who never uses them should not inherit. Depends on Orkeon. |
Orkeon.Rag.Onnx, Orkeon.Rag.Onnx.Model |
Opt-in ONNX cross-encoder reranker pair (runtime + embedded int8 weights) β pushed together; native onnxruntime payload. Orkeon.Rag.Onnx depends on Orkeon; Orkeon.Rag.Onnx.Model is dependency-free (embedded resources only) and is referenced alongside it. |
Orkeon.Tools.Embeddings.Local |
Local on-device embeddings (BGE-micro-v2 ONNX). Stays outside the umbrella because it carries a pre-release SmartComponents dependency from an archived upstream β putting it in Orkeon would force that pre-release on every consumer. Depends on Orkeon. |
Orkeon.Scripting.Cli |
The orkeon dotnet tool (PackAsTool; the PackageId is the install command β ADR-007). Publishable on NuGet.org since the iOS/Android onnxruntime natives a CLI tool can never load were excluded: 262.5 MB β 137.6 MB, under the nuget.org size limit. |
Orkeon.Compliance.Vfs |
The Roslyn analyzer that refuses direct System.IO in your own code (rules ORKVFS001βORKVFS007, analyzers/dotnet/cs, DevelopmentDependency). Standalone by design: it depends on nothing from Orkeon and works in any C# project β add the PackageReference, build, and every File.*/Directory.* call is a diagnostic. In the NuGet.org lineup since 2026-09-11, so its first push there is the next tag: 1.0.0-rc.3 reached GitHub Packages only (the NuGet.org push loop was a fixed list of six ids) and was inert anyway, compiled against a Roslyn newer than the SDK's compiler. |
Orkeon.Interop.AgentFramework |
The bridge to Microsoft Agent Framework, both ways: an Orkeon crew as a MAF AIAgent (CrewAgent), a MAF AIAgent as the brain (WithAgentFrameworkAgent) or as a tool (WithAgentFrameworkTool) of an Orkeon agent. Separate from Orkeon because the Microsoft.Agents.AI.Abstractions dependency is a consumer's choice. Depends on Orkeon. |
Orkeon.Hosting.Aspire |
The .NET Aspire hosting integration: AddOrkeonHost (the orkeon-host daemon) and AddOrkeonCrewRun (one orkeon run) as AppHost resources, WithOrkeonModel / WithOrkeonSetting for the ORKEON_ environment, OTLP export wired so the dashboard reads the run. Separate from Orkeon because Aspire.Hosting is an AppHost's choice. Depends on Orkeon. |
How the packaging projects are built
- The lineup nupkgs come from dedicated packaging projects under
src/packaging/β four of them: theOrkeonandOrkeon.Toolsumbrellas, plus theOrkeon.Rag.Onnx.PackageandOrkeon.Tools.Embeddings.Local.Packagewrappers, which pack the two opt-in assemblies with a nuspec dependency on theOrkeonumbrella. The embedded library projects themselves areIsPackable=falseand their source layout, namespaces and per-assembly PublicAPI freeze are untouched; the real opt-in projects keep normalProjectReferences, so in-repo consumers are unaffected β only the wrappers carry the embed pattern below. - Each packaging project references its embedded project(s) with
PrivateAssets="all"(keeping them out of the nuspec dependency list) and packs their DLL+XML intolib/. BecausePrivateAssets="all"also stops the embedded projects' externalPackageReferences from flowing into the nuspec, the union of those references is re-declared by hand in the packaging csproj. scripts/check-package-closure.py(run bypublish.ymlright after the pack) fails the workflow if (1) a lineup package declares anOrkeon.*dependency outside the lineup β the NU1101 class of incident β or (2) an umbrella's hand-declared externals drift from what its embedded projects actually require.publish.ymlpushesOrkeonfirst: the other lineup packages depend on it and NuGet does not order pushes, so pushing a dependent first would expose a package whose restore fails.
Discontinued packages
The following PackageIds are no longer packed (IsPackable=false): Orkeon.Domain,
Orkeon.Application, Orkeon.Infrastructure, the five Orkeon.Constants.* satellites, the
seven Orkeon.Tools.<family> packages, Orkeon.Cli, Orkeon.Cli.Abstractions,
Orkeon.Cli.Commands.Scripting, Orkeon.Cli.TerminalGui, Orkeon.Scripting,
Orkeon.Hosting, Orkeon.Plugins.
Migration: the source code and namespaces are unchanged, so consumer code compiles as-is β
only the install changes. Uninstall the per-layer packages and
dotnet add package Orkeon --prerelease (add Orkeon.Tools if you used a
Orkeon.Tools.<family> package other than Embeddings.Local).
Actual NuGet.org state, and the remaining owner actions
orkeon.domain, orkeon.application and orkeon.infrastructure were published on
NuGet.org: 1.0.0-rc.1 (2026-08-18) and 1.0.0-rc.2 (2026-08-25), pushed by publish.yml
through Trusted Publishing. Two of the three were not restorable there (NU1101): they
declared five Orkeon.* dependencies that were never published β the incident that motivated
the closure gate above. All six versions were unlisted on 2026-09-07 β unlisted, not
deleted: the bytes are still served, so a consumer pinning one of them still restores.
Owner actions already done:
- β
2026-09-07 β the six
rc.1/rc.2versions of the per-layer trio are unlisted (listed: falseon the three packages). Nobody is offered a package that cannot restore. - β
2026-09-08 β the
Orkeonprefix is reserved on nuget.org for the owner accountarion-orkeon: the bareOrkeonID and theOrkeon.*family. Any matching package ID pushed by another account is rejected from now on β the ~30Orkeon.*assembly names this documentation makes public can no longer be squatted. - β
The
NUGET_USERrepository variable and the Trusted Publishing policy are operational (the rc.1/rc.2 pushes prove it).
2026-09-09 β the v1 lineup is published. 1.0.0-rc.3 of all six packages was pushed by
publish.yml through Trusted Publishing (owner arion-orkeon, the account holding the
Orkeon prefix reservation). The family finally has a page on nuget.org.
It took two attempts, and the first one is worth keeping: that run went the whole way β
build, tests, pack, closure gate, provenance attestation, GitHub Packages, OIDC key
exchange β and died on the last step, pushing nothing. The lineup glob
artifacts/${id}.[0-9]*.nupkg was quoted, so it reached dotnet nuget push as a literal,
and that CLI resolves wildcards through NuGet's own PathResolver, which understands *
and ? and no character class. It answered File does not exist about a file sitting in
artifacts/. The GitHub Packages push in the same job never met it β artifacts/*.nupkg
is inside that dialect. Fixed by letting the shell expand the pattern.
A freshly pushed package is not immediately downloadable: NuGet.org validates it first,
and until that finishes its page answers 200 with "not been indexed" while
v3-flatcontainer still 404s. Orkeon.Rag.Onnx.Model sat there longest, which is expected
β it is the package embedding the int8 model weights. Nothing to do but wait; it is not a
failed push, and --skip-duplicate makes a re-push a no-op either way.
Published to GitHub Packages
publish.yml (tag v*) packs Orkeon.sln and pushes every packable project to
GitHub Packages (nuget.pkg.github.com/Orkeon) with --skip-duplicate. That is the
NuGet.org lineup above plus the build-time and runner packages that stay off NuGet.org:
Orkeon.ConsoleApp and Orkeon.Generators:
| PackageId | Tool command | Source project |
|---|---|---|
Orkeon.ConsoleApp |
orkeon-repl |
src/apps/Orkeon.ConsoleApp |
Orkeon.Scripting.Cli |
orkeon |
src/scripting/Orkeon.Scripting.Cli |
Installer archives (release.yml)
On a v* tag, release.yml builds every installer artifact, smokes each onboarding
channel on a real runner (Windows CLI zip, Windows service, Debian package, macOS
tarball), and only then attaches everything to the GitHub Release. The pipeline is
installers β {smoke-windows, smoke-windows-service, smoke-deb, smoke-macos, msi} β release; behind those same five jobs, runners-image pushes the orkeon-runners
container image to GHCR in parallel with release, so a red smoke moves neither the
Release nor the :latest tag. workflow_dispatch runs
the same thing minus the publication (no tag, no Release to attach to). The retired
orkeon-examples runner is no longer packaged β the orkeon CLI replaces it
(orkeon run crew.yaml runs the examples/ YAML crews; orkeon run script.ork.ts runs the
scripting DSL).
| Artifact | Built by | Contents | Runtime |
|---|---|---|---|
orkeon-<version>-<rid>.tar.gz / .zip |
package-installers.sh (default --app-set full) |
every CLI launcher + the Orkeon Studio apps admitted by their RID filter (the WPF orkeon-studio is win-x64-only; the two TUIs ship for every RID) + one shared esbuild + the deploy/ tree (systemd unit, SCM registration script, Dockerfile.host) |
mixed: orkeon, orkeon-host and the Studio apps self-contained, the rest framework-dependent |
orkeon-cli-<version>-win-x64.zip |
package-installers.sh --app-set cli --rids win-x64 |
the orkeon CLI + orkeon-studio (WPF Orkeon Studio) + install.ps1 |
self-contained |
orkeon_<version>_amd64.deb |
package-deb.sh (reuses the linux-x64 staging tree β one publish, two packages) |
the orkeon CLI at /usr/bin/orkeon + the Studio TUIs at /usr/bin/orkeon-studio-config and /usr/bin/orkeon-studio-run |
self-contained; Depends on system libraries only (libicu / libssl alternations), never on dotnet-runtime-* |
orkeon-<version>-win-x64.msi |
build-msi.ps1 (WiX, per-user scope), harvesting the extracted CLI zip |
the orkeon CLI + orkeon-studio (WPF, with an "Orkeon Studio" Start-menu shortcut), same pruned publish as the zip |
self-contained |
orkeon-cli-<version>-osx-arm64.tar.gz / -osx-x64.tar.gz |
package-installers.sh --app-set cli --rids osx-arm64 osx-x64 (cross-published from the ubuntu runner) |
the orkeon CLI alone + install.sh (no Studio in V1 β the macOS channel stays CLI-only) |
self-contained |
SHA256SUMS |
the installers job's packaging scripts (package-deb.sh refreshes its own line) |
one line per artifact above except the MSI | β |
orkeon-host-<version>-win-x64.msi |
build-msi-service.ps1 (WiX, per-machine scope), harvesting the extracted full zip |
the self-contained orkeon-host publish alone, registered as the Orkeon service under NT SERVICE\Orkeon (no CLI, no wrapper, no deploy/ β the package registers declaratively) |
self-contained |
SHA256SUMS.msi |
build-msi.ps1 then build-msi-service.ps1, in order, in the msi job |
the two MSIs | β |
The service host
orkeon-host ships inside the full archive (--app-set full), self-contained: a daemon supervised by systemd or the Windows SCM must not depend on a runtime someone may upgrade underneath it. It is not a dotnet tool β it is installed as a service, not invoked from a shell. On Windows it also ships as its own per-machine MSI (orkeon-host-<version>-win-x64.msi), a separate product from the per-user CLI MSI: the two coexist, and the package registers the service declaratively β same account, same paths, same recovery as the script channel.
Its deployment artifacts live in deploy/ and ship inside the full archive next to the daemon: a systemd unit (Type=notify, restart on failure β config errors exit 78 and do not loop, hardened), a PowerShell script registering it with the SCM, and a Dockerfile. None of the three carries a secret β the bot token and the API keys are named by environment variable in the configuration and provided by the machine, so a unit file or an image layer can be read by anyone without leaking anything.
Two checksum files rather than one: the ubuntu installers job writes SHA256SUMS before
the MSI exists β it is built later, on windows-latest. Each checksum file is generated by
the job that produced the artifact it covers.
Blocking smokes. smoke-windows (a windows-latest runner) installs
orkeon-cli-*-win-x64.zip and walks the onboarding chain on it; smoke-deb (a stock
ubuntu-latest image) installs the .deb through apt, walks the same chain, then removes
the package; smoke-macos (a macos-latest, Apple-silicon runner) extracts the osx-arm64
tarball, installs it with install.sh and walks the same chain before uninstalling; the msi
job runs its own msiexec /i /qn β orkeon doctor --json β msiexec /x /qn chain, asserting
the install directory, the ARP entry and the user PATH entry appear and then disappear.
smoke-windows-service installs the full win-x64 zip's service channel β virtual account,
--working-dir proven with a relative crew path, a refused configuration that stops without
looping and lands in the event log β and the msi job smokes the service MSI the same way,
plus a silent reinstall of itself. All of them install from the job artifacts, never from
the Release, so a broken payload is caught before anything is published β the release job
needs them all.
smoke-macos is also the only place the Gatekeeper and code-signing story is exercised: an
unsigned, quarantined or malformed native library (libtree-sitter*.dylib, onnxruntime, the
esbuild binary) is killed at load time, so it fails there rather than in a user's terminal.
The debian version string replaces - with ~ (1.0.0-rc.1 β orkeon_1.0.0~rc.1_amd64.deb)
so a pre-release sorts before its final under dpkg.
The MSI's ProductVersion drops the suffix instead: Windows Installer versions carry only three
numeric fields, so build-msi.ps1 truncates 1.0.0-rc.1 to 1.0.0 for the property that
<MajorUpgrade> actually compares. Nothing is silently lost β the full string survives in the
.msi filename (orkeon-1.0.0-rc.1-win-x64.msi) and in the ARPCOMMENTS property shown in
"Installed apps".
The orkeon CLI is distributed through seven channels:
| Channel | Artifact | Runtime | Audience |
|---|---|---|---|
| NuGet dotnet tool | Orkeon.Scripting.Cli (PackAsTool, command orkeon) |
needs .NET 10 SDK (dotnet tool install) |
.NET developers. Part of the NuGet.org lineup (PUB-25) β publishable since the package dropped from 262.5 MB to 137.6 MB (iOS/Android onnxruntime natives excluded); first push at v1.0.0-rc.3 |
Windows zip + install.ps1 |
orkeon-cli-<version>-win-x64.zip |
self-contained | Windows onboarding β the recommended channel. Ships orkeon-studio (WPF Orkeon Studio) next to the CLI |
| Windows MSI (per-user) | orkeon-<version>-win-x64.msi |
self-contained | Windows, double-click install and an "Installed apps" entry. Ships orkeon-studio with a Start-menu shortcut. One channel at a time: the MSI refuses to install over a zip install |
| Debian package | orkeon_<version>_amd64.deb |
self-contained | Debian / Ubuntu onboarding β the recommended channel. Ships the orkeon-studio-config / orkeon-studio-run TUIs next to the CLI |
macOS tarball + install.sh |
orkeon-cli-<version>-osx-arm64.tar.gz / -osx-x64.tar.gz |
self-contained | macOS onboarding today; install.sh clears the Gatekeeper quarantine attribute and ad-hoc re-signs the Mach-O files codesign -v rejects |
| Homebrew | the same osx tarballs, via installers/homebrew/orkeon.rb |
self-contained | macOS, once the tap exists β not published yet, see below |
| Multi-app installer archive | orkeon / orkeon-slim launchers |
orkeon self-contained, orkeon-slim framework-dependent |
devs who also want the REPL, the service host or the Studio apps |
Homebrew β formula in the repository, tap not yet created. installers/homebrew/orkeon.rb
is a binary formula: it downloads the osx tarball matching the machine's architecture
(on_arm / on_intel), installs the payload under the Cellar's libexec, and writes a
bin/orkeon wrapper that points ORKEON_ESBUILD_PATH at the bundled esbuild β the same
contract as wrapper.sh.tmpl. Its test do block runs orkeon doctor rather than
orkeon --version, which exits 1.
version and both url / sha256 pairs are generated, never hand-edited:
scripts/update-homebrew-formula.sh --release <tag> (or --sums <file>) rewrites the five
values from a release's SHA256SUMS and is idempotent. Until the first tagged release, the
two sha256 values are the literal placeholders PLACEHOLDER_SHA256_ARM64 /
PLACEHOLDER_SHA256_X64, so an accidental install fails verification instead of fetching
something unverified.
Publishing the Orkeon/homebrew-tap repository and pushing the formula to it is a release
action, not CI (MAC-00 Β§8): brew tap orkeon/tap && brew install orkeon does not resolve
before that. Submission to homebrew-core and a .pkg installer stay out of scope until the
project is code-signed.
All flavours are built from the same src/scripting/Orkeon.Scripting.Cli csproj and share
the one bundled esbuild. The remaining CLI
launchers stay framework-dependent β install.sh and install.ps1 detect that case and
print the runtime install commands rather than failing at first launch.
Publish behaviour change. Every
publishofsrc/andexamples/now prunes the unused tree-sitter grammars (31 β 7 native libraries), viaDirectory.Build.targets. Opt out with-p:OrkeonPruneTreeSitterGrammars=false. Every artifact in the table above carries the pruned payload, the MSI included β which also keeps its WiX component GUIDs stable across upgrades.
Build-time / internal (not standalone packages)
| PackageId | Note |
|---|---|
Orkeon.Generators |
Source generator β consumed at build time. GitHub Packages only. |
Orkeon.Host |
IsPackable=false β ships only as the orkeon-host binary in the release archives. |
Orkeon.Studio.{Core,Config,Run,Wpf} |
IsPackable=false β ship only through the release installers (see Orkeon Studio). |
How publication is wired
- All NuGet packing and pushing lives in
publish.yml(tagv*):dotnet pack Orkeon.slndriven byIsPackable, thescripts/check-package-closure.pygate on the packed artifacts, a push of everything to GitHub Packages with--skip-duplicate(idempotent re-runs), then the NuGet.org lineup (the table above,Orkeonfirst) to NuGet.org.ci.ymlvalidates (build + test) and packs nothing;release.ymlbuilds the installer archives and the container image, no NuGet packing. - NuGet.org auth is Trusted Publishing (OIDC) β no long-lived API key. A nuget.org
policy (repository
Orkeon/orkeon, workflowpublish.yml) letsNuGet/loginexchange the job's OIDC token for a short-lived key; the steps are gated on theNUGET_USERrepository variable (the nuget.org profile owning the policy). Both are set up and proven β the rc.1/rc.2 pushes went through this path; if the variable ever disappears the steps emit a warning and no-op instead of failing the tag. Expanding the NuGet.org lineup is a maintainer decision recorded in this matrix first (and mirrored in the workflow's lineup list + the closure-gate arguments), never a workflow edit made in passing. publish.ymlrefuses a tag that does not match thesrc/Directory.Build.propsversion. Lesson from the 0.9.1-beta incident (see CHANGELOG 0.9.2-beta): thev0.9.1-beta.rc*tags re-packed the unchanged props version and--skip-duplicatesilently skipped every push β a "release" that published nothing. The guard keeps--skip-duplicatehonest.- Provenance and SBOM. Both workflows attest what they publish with
actions/attest-build-provenance(SLSA v1, signed by GitHub's Sigstore instance):publish.ymlevery*.nupkg,release.ymlevery archive,.deband MSI. Both generate a CycloneDX SBOM ofOrkeon.slnright after the build (CycloneDXdotnet tool, pinned version, no third-party action) βorkeon-<version>.sbom.cdx.jsonβ and cover it with the same attestation: a release asset next to the archives and a line inSHA256SUMSinrelease.yml, a run artefact namedsbominpublish.yml. How to verify any of it, and why a nuget.org download must shed its repository signature first, is in Verify what you install. - Version flows from
src/Directory.Build.props(currently1.0.0-rc.4), the single source of truth: no project overrides it, and the publish workflow's tag guard refuses anyv*tag that disagrees with it.