π«π· Version franΓ§aise
Orkeon.Hosting β runner & host bootstrap
Orkeon.Hosting is the shared bootstrap layer that turns the Orkeon libraries into a runnable host.
It owns the wiring order that a working runtime needs β LLM provider, core services, the standard tool
suites, the virtual file system, and the DI-backed tool registry β plus the end-to-end execution flows
(one-shot kickoff, interactive loop, tool listing) used by every Orkeon runner and CLI.
Inside this repository it is consumed by Orkeon.Scripting.Cli (the orkeon tool) and by
Orkeon.Host (the orkeon-host daemon). It is not distributed as a NuGet package β see
Distribution below. This page documents its public bootstrap surface.
Distribution
Orkeon.Hosting is not a NuGet package. Its csproj sets IsPackable=false, and the
publication matrix lists it under Discontinued
packages: it is pushed neither to NuGet.org nor to GitHub Packages, so
dotnet add package Orkeon.Hosting cannot resolve (NU1101).
It is not embedded in the Orkeon umbrella package either. src/packaging/Orkeon/Orkeon.csproj
embeds eleven assemblies β Orkeon.Domain, Orkeon.Application, Orkeon.Infrastructure,
Orkeon.Constants.{Llm,FileSystem,Configuration}, Orkeon.Tools.Abstractions,
Orkeon.Analysis{,.Abstractions}, Orkeon.Rag{,.Abstractions} β and Orkeon.Hosting is not one
of them.
| Assembly | Orkeon.Hosting.dll (src/hosting/Orkeon.Hosting) |
| Packable | no β IsPackable=false, on no feed |
| Depends on | the core Orkeon.* libraries (Domain, Application, Infrastructure, Analysis, Scripting), the Orkeon.Constants.* satellites, and eight of the nine Orkeon.Tools.* suites (Orkeon.Tools.Rag is deliberately absent β RAG stays opt-in), plus CommandLineParser and Microsoft.Extensions.Hosting |
| Ships through | the CLI and installer channels only: the orkeon dotnet tool (Orkeon.Scripting.Cli) and the release.yml installer archives / .deb / MSIs, where Orkeon.Hosting.dll sits next to orkeon and orkeon-host as a private implementation assembly β never as a reference a consumer adds |
Building an external host against it therefore means building from source: clone the
repository and add a ProjectReference to src/hosting/Orkeon.Hosting/Orkeon.Hosting.csproj.
The supported package surface for consumers is the Orkeon umbrella (plus Orkeon.Tools and the
opt-ins); Orkeon.Hosting is an internal bootstrap layer, documented here for in-tree callers.
RunnerHost.Build
RunnerHost is a static host builder. Build returns a fully configured IHost:
IHost host = RunnerHost.Build(
settingsPath: "appsettings.json", // resolved appsettings path (nullable)
mounts: new RunnerMountPlan // the whole VFS surface, in one object
{
CliMounts = ["/data:/data:ro"], // CLI --mount args ("physical:virtual:rights")
InternalMounts = [], // mounts registered MountVisibility.Internal β resolvable
// by the VFS, never listed to an agent (ADR-008)
AllowExternalMounts = false, // whitelist mount base paths outside the workspace root
SelectedMountIds = [], // --mount-id values, parsed: the settings entries kept when
// several declare one virtual root (VFS-90)
CrewMountReferences = [], // the crew's mounts: block β selects and validates, never restricts
LlmLogVirtualPath = null, // when set, a VIRTUAL directory the caller has mounted:
// LLM HTTP exchanges are captured there as .jsonl
},
configureLogging: null, // optional ILoggingBuilder customization
configureServices: null, // optional hook to register runner-specific services
configureBuilder: null); // optional IHostBuilder hook β orkeon-host uses it for UseSystemd()/UseWindowsService()
A virtual path is always a name starting with / β never a disk path
(ADR-008).
RunnerVirtualRoots β in the dependency-free Orkeon.Constants.FileSystem package
(ADR-009) so the engine and the tooling read one
declaration β names the roots the shipped runners take for themselves: /crew (the crew
definition's directory), /script (a scripting entry point's directory), /llm-logs, and
/sandbox (where the code sandboxes stage what they run). RunnerVirtualRoots.All is the set a
caller refuses a user --mount against; asking for the set rather than comparing the roots one by
one is deliberate, because the omission of /sandbox survived a pairwise check for as long as it
was green. A caller that enables exchange logging mounts its log directory internally and passes
RunnerVirtualRoots.LlmLogs here β that is what the CLI does.
LoadCrewAsync likewise takes the crew target as a virtual path: it asks the VFS whether the
target is a directory rather than probing the disk, so a physical path handed to it is denied.
It composes Host.CreateDefaultBuilder() with:
- App configuration β appsettings resolution plus the CLI mount arguments folded into configuration.
- Services β
ConfigureRunnerServices(below).
RunnerHost carries an [SuppressVfsCompliance] bootstrap exception because it resolves user-supplied
settings paths and provisions VFS mounts before the DI container (and thus IFileSystemService) exists.
ConfigureRunnerServices behavior
The registration order is deliberate:
- Logging β runner logging (a single-line console at Warning level by default;
--verbose 1/2or aconfigureLoggingcallback raises it) and, whenRunnerMountPlan.LlmLogVirtualPathis set, the LLM exchange loggingDelegatingHandler. - LLM provider first β
RegisterLlmProviderreads theLlmconfig section and registers the provider (and itsIChatClient) beforeAddOrkeonApplication/AddOrkeonInfrastructure. This ordering matters: Orkeon infrastructure registers its LLM/IChatClientfallbacks withTryAdd, so a host-supplied provider must be registered first to win. - Core services β
AddOrkeonApplication()thenAddOrkeonInfrastructure(). - Strict tools β
CrewFactoryOptions.StrictToolsdefaults totruehere (a crew referencing an unknown tool fails loudly withunknown tool(s): β¦; available: β¦); opt out with"Orkeon:CrewFactory:StrictTools": false. (The library default stays lenient.) - Permission gate β
AddOrkeonPermissionGate(configuration)(config opt-inOrkeon:Security:PermissionGate:Enabled; a no-op otherwise). - Core tool suites β file system, data, web, code, abstractions, session tools; then the
in-memory EventHub plus its agent tools and the EventHub ACL (
AddOrkeonEventHubAcl, permissive default so a crew without alinks:block behaves as before). - VFS mounts β
AddOrkeonFileSystemwhenOrkeon:FileSystem:MountsorOrkeon:FileSystem:InternalMountsexists and holds at least one entry (two empty arrays register nothing). Either list alone makes the VFS real:--list-toolshas only the second. Several entries ofMountsmay declare one root when each carries an id (VFS-90):MountSelection.Resolvedecides, while the configuration is composed, which one this run keeps β a--mounton the root, elseSelectedMountIds, elseCrewMountReferencesβ and writes the others tonullat their own index; a selection nothing resolves throws with the very text the runners' guards print, so a host built without them refuses the same way. - Late tool suites β RaggableTree (semantic-graph tools, opt out with
"RaggableTree:Enabled": false; pre-registers local embeddings when they are the selected provider), the WebSearch andcache_searchtools, and the Brave search tool whenBRAVE_API_KEYis present. - Tool registry β
ServiceProviderToolRegistryis registered as the singletonIToolRegistry. - Runner services β the caller's
configureServiceshook runs last.
ServiceProviderToolRegistry
The IToolRegistry implementation that resolves YAML/TS tool names to IBaseTool instances from DI.
Its constructor takes IEnumerable<IBaseTool> β every tool the tool suites registered β and indexes them
by name (case-insensitive). CrewFactory consumes it to build agents with their declared tools, which is
why every tool suite registers under IBaseTool: a tool that is not registered cannot be resolved (and,
with StrictTools, fails crew loading rather than silently dropping).
RunnerExecution β execution flows
RunnerExecution is the shared execution glue: graceful shutdown (SIGTERM/SIGINT), AutoSummaryWriter
wiring when an /output:rw mount is declared, verbosity presets, and the run flows. All entry points
build the host internally (via the same bootstrap), resolve settings/mounts, and return a process exit
code.
| Entry point | Purpose |
|---|---|
RunOneShotAsync(opts, loggerCategory, configureServices?, externalCt?) |
Runs a single crew kickoff end-to-end. Exit codes: 0 success, 1 config error, 2 crew failure, 130 canceled. |
RunInteractiveLoopAsync(opts, loggerCategory, stopWords, kickoffPerInputAsync, onSessionStart, β¦) |
REPL loop; each input drives a kickoff via the caller-supplied delegate; a stop word ends the loop (exit 0). |
RunListToolsAsync(opts, loggerCategory, configureServices?) |
Builds the host with no crew and prints the sorted, de-duplicated runtime tool names to stdout (logs to stderr) β the runtime tool contract consumed by packaging/lint tooling. |
RunValidateAsync(opts, loggerCategory, configureServices?) |
Dry-run behind --validate: builds the host and loads the crew (strict tool resolution) without probing the LLM or running a kickoff. |
LoadCrewAsync(host, opts) |
Loads and maps the crew definition from the resolved target β the building block the flows above share. |
Consuming from a long-running host
A long-running service can simply wrap RunnerHost.Build β that is exactly what the
orkeon-host daemon does (Orkeon.Host/Program.cs), passing configureBuilder for
UseSystemd()/UseWindowsService(). The daemon stays out of the mount selection (VFS-90,
D-11): its crews mount under per-crew roots (/crews*), so no root is ever declared twice
there, an operator --mount carrying an id prefix parses like any other, and no crew
mounts: block is read. A host that already owns its IHostBuilder (an ASP.NET
app, for example) instead replicates ConfigureRunnerServices' registration order inside its
own Program.cs β there is no packaged shortcut for this; the REPL console inlines the same
sequence by hand:
// 1. Register the LLM provider FIRST (before AddOrkeonInfrastructure, whose TryAdd fallback would
// otherwise win).
// 2. Core services:
services.AddOrkeonApplication();
services.AddOrkeonInfrastructure(configuration);
// 3. Tool suites (drive which tools crews can use):
services.AddOrkeonFileSystemTools();
services.AddOrkeonDataTools();
services.AddOrkeonWebTools();
// β¦ the remaining AddOrkeon*Tools() suites β¦
// 4. VFS mounts from configuration (the web host provisions at least one mount):
services.AddOrkeonFileSystem(configuration);
// 5. Tool registry LAST, so it captures every registered IBaseTool:
services.AddSingleton<IToolRegistry, ServiceProviderToolRegistry>();
Because a web host typically runs each crew in its own DI scope (Orkeon's crew repositories are scoped),
ServiceProviderToolRegistry β a singleton over the registered IBaseTool set β is shared across runs,
while CrewFactory and the orchestrator resolve per scope.