2 - A Worker

A Worker

A worker is one system class running in its own process, exposing a curated set of capabilities the Manager can route to. This is where a new class from Barebones becomes a first-class part of the fleet. Every worker follows the exact shape of the Calendar worker.

The layout

A worker is three files plus its system source:

src/workers/XRUIOS.Worker.<Class>/
├─ XRUIOS.Worker.<Class>.csproj   compiles ONLY this class's source
├─ Program.cs                     boot: bind context, init, run the secured host
├─ <Class>Capabilities.cs         the [SeaOfDirac] curated surface
└─ (the class source lives once at src/systems/<Class>.cs, not copied here)

The isolation is the point: the worker <Compile Include>s just its own class file, so a breached Songs worker doesn't even contain Calendar's code. See 1 - The Model.

The .csproj

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <OutputType>Exe</OutputType>
    <RootNamespace>XRUIOS.Worker.<Class></RootNamespace>
    <AssemblyName>XRUIOS.Worker.<Class></AssemblyName>
  </PropertyGroup>

  <!-- This worker compiles ONLY its own class. Refs + packages come from Directory.Build.props. -->
  <ItemGroup>
    <Compile Include="..\..\systems\<Class>.cs" />
  </ItemGroup>

</Project>

That's the whole file. Two things to notice:

  • Microsoft.NET.Sdk.Web, not the plain SDK - a worker hosts a MagicOnion/gRPC endpoint the Manager connects to.
  • No references here. Everything a worker needs is in src/workers/Directory.Build.props, which every worker under src/workers/ inherits automatically:
From Directory.Build.props Why
XRUIOS.SecureLayer (project) SecureWorkerHost, WorkerOcean, NotaryGuard - the secured host
XRUIOS.Contracts / Core / Interfaces (project) the context shim, DTOs, the IModuleInitializer seam
YuukoProtocol.XRUIOS.Interfaces (project) the file layer the system classes use
EclipseProject.dll the [SeaOfDirac] attribute + the encrypted transport
PariahCybersecurity.dll SecureData, the anti-tamper watchdog
KeeperOfTomes.dll, Secure Store.dll storage the classes depend on
the Barebones package set so any single class compiles (Ical.Net, GeoCoordinate, etc.)

If your class needs a package no other class does, add it to that class's own .csproj rather than the shared props - keep the shared set to what every class needs.

The capability surface

Capabilities are static methods marked [SeaOfDirac]. WorkerOcean scans the assembly for them; the Manager routes a call by the capability name. Keep the surface curated - the cross-program calls, not every public method.

using EclipseProject;
using XRUIOS.Barebones;

namespace XRUIOS.Worker.<Class>
{
    public static class <Class>Capabilities
    {
        // [SeaOfDirac(name, argNames, returnType, argTypes...)]. Return plain strings/DTOs so any
        // client can read them without sharing the class's internal types.
        [SeaOfDirac("DoThing", new[] { "input" }, typeof(string), typeof(string))]
        public static string DoThing(string input) => <Class>Class.DoThing(input);

        // Async is supported - return Task / Task<T>.
        [SeaOfDirac("AddThing", new[] { "a", "b" }, typeof(string), typeof(string), typeof(string))]
        public static async Task<string> AddThing(string a, string b) => await <Class>Class.Add(a, b);
    }
}

Name capabilities uniquely across the fleet. The broker routes by capability name to the first worker that exposes it, so two workers exposing the same name collide. The convention is a worker-qualified name (Calendar.Ping, Alarm.Ping); the display form in the catalog is Group.Worker:Capability. See 5 - Permission Catalog.

Boot (Program.cs)

Every worker boots the same way: take the context the Manager handed it, do its own one-time init, then run the secured host.

using System.Reflection;
using XRUIOS.Interfaces;

// 1. Bind the paths + key the Manager passed via environment (XRUIOS_DATA_PATH, _PUBLIC_PATH, _WORKER_KEY).
global::XRUIOS.Barebones.XRUIOS.BindFromEnvironment();

// 2. This worker's OWN init. Each worker sets up its own store - the Manager never reaches into it.
//    (The old monolithic InitializeSystemAsync is gone; its per-class Initiate... step moves here.)
System.IO.Directory.CreateDirectory(
    System.IO.Path.Combine(global::XRUIOS.Barebones.XRUIOS.DataPath, "<Class>"));

const string ServerName = "XRUIOS.Worker.<Class>";

// 3. Run: hardens the process, Notary-checks the folder, locks to the Manager's PSK, then serves.
await SecureWorkerHost.Run(
    serverName: ServerName,
    capabilityAssembly: Assembly.GetExecutingAssembly(),
    gate: new AllowAllPermissionGate(),
    guard: NotaryGuard.ForCurrentWorker(ServerName));

Two things people ask about:

  • Why AllowAllPermissionGate inside the worker? Because the permission check already happened at the Manager broker before the call was relayed. A worker only ever receives calls the Manager approved, and it only completes a handshake with the Manager's PSK - nothing else can reach it. The wall is at the broker; the gate here is just the seam.
  • The init step is yours to wire. If your class assumed the old InitializeSystemAsync ran first, move that setup into step 2. Each worker is responsible for its own directories and defaults.

Register it with the Manager

Two edits outside the worker:

  1. Add the class to WorkerCatalog.Defs in the Manager (short name + its PermissionGroup) so the Manager launches and supervises it.
  2. Add the project to XRUIOS.slnx.

Then grant apps the capabilities you exposed (permissions.GrantAsync(appId, "<Class>.DoThing")). Ungranted names are denied at the broker before they reach the worker.

Next: the client that calls it - 3 - A CMD App.