Map: core / engine protocol
core/src/engine.rs is the one engine; core/src/protocol.rs is the frame
algebra and nothing that carries it — protocol/probe.rs its probe
vocabulary, protocol/channel.rs the duplex byte channel and the one
liveness law; core/src/carrier.rs and carrier/ are the two carriers that
interpret the algebra — the identity transport in process, the wire
transport’s front-end half — with carrier/wire/serve.rs the wire’s engine
half; core/src/run/report.rs projects a run onto the algebra; a wire-seat
child is made by the host’s factory and born from an Attach carrying its
parent’s seal, so core holds no spawn machinery for it. The why is
engine-protocol; this page only points at symbols.
core/src/engine.rs
EngineInstaller { tag, runtime, root, narrow }— one compiled-in installer, in two halves.runtime: fn(&EngineSpec) -> Runtimeis the process half (Σ, builtins, docs; a root and a child engine each derive their own, an in-process child shares its parent’s);root: fn(&Root, &mut Shell) -> Result<(), String>is the root-only recipe (libraries, hints, seeds, ledgers), which refuses in its own words;narrow: GrantNarroweris the policy a seeded or adopted child is held to. OnlytagcrossesAttach, never the function.Runtime: what the binary supplies, and the only place builtins are installed (install_builtins,install_captured_builtins); aShellis built over one and cannot hand it back.Engine— one session’s engine: theShell, itsArc<Runtime>, itsScopes, the installer it was born from.Engine::boot(installers, &attach)is the one boot both carriers call:resolve_installer(version check, then tag lookup), the guest jail underRAL_GUEST(whose value is the jail’s cgroup root), the installer’sruntime, then byattach.origin:Origin::Root(root)isShell::root, the root recipe,seed_cwdand the root’s env;Origin::Child(sealed)isShell::child_of(runtime, sealed.unseal()?.decode(&runtime)?, narrow), and no recipe runs. There is noKeep: the attach is the birth, and the scratch is the host’s, named in a root’s env.Engine::runruns one dispatch under the viewScopes::openhands it;Scopeskeeps the node, its one writer;Engine::probe(engine/probe.rs) answers oneProbe.Rails— one dispatch’s host-facing rails as its carrier lays them: theOutletits events leave by, the deferred sink, the desk, theForkarm. The carriers differ in these and nowhere else.Scopes— what stops an engine’s runs, shared with whichever thread carriesControl: the dispatch scope root, the durable root, and a slot holding the current dispatch and a foretold strike with its cause.openmints a dispatch’s scope ahead of its frame (struck already if a strike foretold it);applyisControl’s one meaning —Interrupt(id)andCancel(id)strike the current dispatch if it bearsidand foretell it otherwise, asInterruptedandCancelled, andTerminatecancels the durable root.
core/src/protocol.rs
The frame algebra. Everything on it is a wire type; nothing here carries.
PROTOCOL_VERSION(currently 27) — checked atAttach; a mismatch refuses.check_media— the same number compared at build time, against theproto_version=linevm-image/build-boot.shrecords for the engine in the guest media;synod/examples/check-media.rs, tauri’sbeforeBuildCommand, refuses to package media that disagrees.Frame— the whole wire enum:Attach,Detach,Dispatch,Probe,Event,Session,Control,Answer,Ping,Pong;Frame::kindnames a variant for the diagnostic about a frame out of place.Attach { engine: EngineSpec, origin: Origin }— what every engine is born from, under either carrier.EngineSpecnames the engine:proto_version,installer,terminal,home.OriginisRoot(Root { cwd, env, config })(env: per-session variables the host seeds;config: the installer’s own settings, anFOValueits recipe decodes) orChild(Sealed)(a child’s parent, sealed, carrying its own cwd and env).homeandcwdarepath::EnginePaths (path/namespace.rs): a path on the engine’s machine, named in the namespace the front-end can name it in —Host(PathBuf)for an engine sharing the front-end’s computer (in process, or a child process),Guest(GuestPath)for one inside a Posix guest, a/-separated string that a Windows front-end has noPathBuffor. The engine reads either as its own throughEnginePath::native, crate-private, since only the engine’s side has the OS a guest path is native to.Attach::newis a plain root’s, at this build’s version;Attach::rootpairs anEngineSpecwith aRoot, whosewith_envandwith_configedit it;Attach::childpairs anEngineSpecwith a seal;with_terminaledits either.Run/Program— one dispatch’s payload: the policy fields plusProgram::Source/Program::Hook.Run’s field types are the run regime, held by session state, and live below the wire:RunIoandRunStdin(io/regime.rs),Captured(io/sink.rs) andRequestedTerminalAccess(process/lease.rs);ral_corere-exports them at the root.Event— engine→front-end, inside a dispatch’s window:Surface,Enquiry,Reading,Report. Every surfaced value is a tagged variant; an audit observation rides as`observed <record>(Observation::to_surface).Reading(Result<FOValue, String>)answers aFrame::Probeunder itsDispatchId: the probe’s own event, not a run that ended.SessionEvent— engine→front-end with no dispatch to ride:Attached/Refused(String)(the attach verdict) andDeferredSurface(Vec<FOValue>)(a worker’s batch, and a watched worker’s lines).EnquiryError— message plus status, the wire shape of a refused enquiry;no_desk()is the fixed wording for a host with nothing to answer, andFrom<EnquiryError> for Errorthe one way a refusal becomes the error both carriers’ desks raise.Control—Interrupt(DispatchId),Cancel(DispatchId),Terminate,Abort(aTerminatewhose cause isRootAbort); applied byScopes::applyunder both carriers.Report/Ending/FailureStatus— the terminal frame:Static { rendered, status }(a refusal: the run never reached evaluation, so no command ran and nothing was bound),Ran { ending, captured, trail }, orFaulted { rendered, status }(the engine could not report the run: a panic in the run or in the report plumbing, or a report the fuse would not pass; what the run did is unknown, so a host reads it as neither a refusal nor an ending);Endinghas no process-stop arm — ral does not suspend — so every ending isSettled/Raised/Stopped/Unreturnable/Exited.Stoppedis a cancellation stop that reached the top, a top-level effect likeExited, carrying its cause and its rendered diagnostic (empty for the closed-stdout stop, which prints nothing).Unreturnableis a run that settled on a value the wire cannot carry (a handle, a block, a function), rendered with a hint and reported as status 1.RaisedandUnreturnablecarry their error’srecord— whattryhands its handler, and what--auditbuilds its`erroutcome from — and the two failing arms aFailureStatus, never a barei32: it clamps into1..=255on the way in and on the way back off the wire, so no ending that failed can be reported with the code that means success.
core/src/run/report.rs
The projection is the run’s. RunReport::into_report and render_ending
project the engine’s own run::Ending/RunReport onto the wire shapes above:
every diagnostic renders here, runtime errors against the SourceDb and static
ones against the Source the diagnostic carries
(static-diagnostics-render-at-the-seam).
not_data / unreturnable word a value the wire cannot carry; record_of
is the record try hands its handler. A panicked run is a
RunReport::Faulted, projected to a Report::Faulted on its error’s status.
Report::refused is the engine’s own refusal before the run reached
evaluation (a busy engine, a dispatch that could not be sent) shaped as a
Static, so a host never has to tell it from a run’s own failure;
Report::faulted is a fault outside the run’s report (a panicked worker, a
report the fuse would not pass) shaped as a Faulted. Both render the
spanless one-liner through the one rule StaticDiagnostics::Host uses. The
two seam test modules live here.
core/src/protocol/probe.rs
The probe vocabulary, typed once for both ends.
Probe— the payload ofFrame::Probe:BindingCount,LeasedBindingCount,LargestBindingBytes,EnvVar(String),Cwd,Home,BuiltinNames,PathBytes(PathBuf),Workers,SessionEnded,CompletionNames,Bindings,PathEntries(PathBuf),Grants;WorkerCountexists only undertest-util. Each variant states what it takes, so a payload its probe does not take is not representable.- The rows the answers come in, rendered engine-side, each a
record!:WorkerRow,BindingRow/HandleRow,CompletionNames,PathEntry.Grantsanswers the session’sGrantStack(no run’s ceiling) as opaque bytes in the JSON codecRun.capsalready rides, as a sealed seed does.
core/src/protocol/channel.rs
WireStream—UnixStreamon Unix,TcpStreamon Windows: std’s owner of a connected stream socket, never a statement about address family (vm-managerhands backAF_VSOCK/AF_HYPERVsockets through the same type).WireChannel— length-prefixed JSON framing (frame.rs) over oneWireStream;pair()(test-only: a socketpair on Unix, a loopback accept on Windows),from_stream,try_clone.poll_readable(Unix) — wait for a frame or a timeout, byrustix::event::pollagainst aTimespecdeadline, without blocking insideread_frame; howengine_sessionnotices a silent front-end with no dedicated thread. Windows has no engine half, so no twin.set_write_deadline— bounds everyputon every clone of the channel (SO_SNDTIMEOlives on the shared file description), turning a stalled write into the same fatal error a severed pipe already gives.write_or_sever/WriteError— the severance law itself, enforced once for both doors (carrier::write_through,engine_write, which differ only in what they record): the frame is encoded before the lock is taken, and a frame the fuse refuses isUnencodable, the wire untouched, for its writer to answer where it stands; a failed write isSevered, recorded and the channel shut down before the lock is released, so nothing appends a frame after a truncated one and no window leaves the record calling an already-shut socket healthy. Only failed I/O severs.Liveness/ticks— how briskly a front-end pings and how much silence it tolerates; the deadline is judged as a count of unanswered pings (Liveness::probes), never as elapsed clock.HOST_SILENCE_DEADLINE, the engine’s armed read silence, is six default ping intervals, written besideLiveness::default.
core/src/carrier.rs
The two interpretations of the algebra, and what they share.
Severed— why no further frame will cross:Refused/Closed/Silent/Faulted,Displayed as the sentence a front-end shows, andcode()the stable name it is quoted by; the privatesever()is first-cause-wins.ProbeError—Rejected(a probe mid-run, a panicked reading, or one the fuse refused before it was sent) orSevered.Hosttrait — one run’s host-facing surface:surface,enquire;impl Host for ()is the mute host.Ends— the front-end state both carriers hold in one value: theControlSender, theEventReceiver, the severance cell and the session sink. A carrier suppliesTransport::endsand the verbs that differ in carriage (dispatch,probe,detach,answer);control,events,severed,severandset_deferred_sinkare provided. The wire carrier overridesseveronly to shut the socket too.Transporttrait — the front-end side of the protocol. Construction is attach, so the trait has no attach of its own;severlets a front-end record a fault it observed. It also provides the host’s typed probe doors, one perProbe:cwd,home,env_var,builtin_names,path_bytes,binding_count,leased_binding_count,largest_binding_bytes,workers,session_ended,completion_names,bindings,path_entries, each decoding throughDatumand severing the transportFaultedon an answer outside its shape (read).forbid_reentry/Dispatching— the carrier-uniform reentrancy law: a thread-local registry of the transports this thread is dispatching on, entered bydispatch_to_reportand checked by every typed reading and the identity carrier’sprobe, panicking with a didactic sentence.dispatch_to_report— mint aDispatchId, aim the control door at it, calltransport.dispatch, drainevents()to that dispatch’s ownReport, forwardingSurface/Enquirytohost;Result<Report, Severed>.ControlSender—interrupt(),cancel(id),terminate()over one of two doors:Door::Identityapplies the verb straight onto the engine’sScopes,Door::Wirewrites aControlframe through the severance cell.aim(id)records the dispatch in flight with theinterrupt_epochit was sent at, until itsAimedguard drops;interrupt()names that dispatch, andhear(ambient)names it only if the epoch has moved since, sendingControl::endingfor a root cause;forward_signals()holds a process listener forwarding through that door.EventReceiver— the front-end’s single-drainer event queue; itsstashhands back an event a probe’s or a desk’s pre-drain read past, in arrival order, rather than dropping it.write_through— the front-end doorWireTransport::writeandControlSender’s wire arm both share:write_or_severrecording aSeveredcause.
carrier/identity.rs
IdentityTransport/SessionLock— the in-process carrier: anEnginebehind a poison-recovering session lock, itsScopesand itsNurseryheld outside the lock so aControland an adoption land mid-dispatch. Its public surface isboot(installers, &attach)— the same verdict as the wire’s attach — andadopt_parked(id), which takes theBequesta run parked in this transport’s nursery, buildsShell::child_ofthe engine’sArc<Runtime>, under this transport’s installer’snarrow, and answers a new transport over it.overtakes the engine’sArc<Runtime>before the session lock and keeps it. Nothing on it yields or accepts aShell. ItsdispatchlaysRailswhose outlet is an in-process channel, whose desk isIdentityDesk, and whose fork arm isFork::Parkover its own nursery.IdentityDesk— the identity binding’sEnquiryDesk: drains queuedSurfaceevents before callinghost.enquire, so a handler can never outrun its own run’s earlier output.
carrier/wire/front.rs
WireTransport— the wire carrier’s front-end half.adopt(stream, Liveness)drives an existing duplex stream;attach(Attach)writes the only legal first frame and only then starts the heartbeat;await_attached()blocks on the reader’sAttached/Refusedverdict or its own patience, counted in waits observed. A probe writesFrame::Probeand drains the event queue to theEvent::Readingunder its id, stashing what it reads past. A frame the fuse refuses is answered where its writer stands: aDispatchby aReport::refusedstashed on its own event stream, aProbebyProbeError::Rejected, anAnswerby anErranswer; anAttach, with no session yet to refuse into, seversRefused.spawn_wire_reader/spawn_heartbeat— the reader severs before droppingevent_tx, on every exit path, and seversFaultedon a frame only a front-end sends; the heartbeat pings onLiveness::interval, seversSilentonceLiveness::probespings go unanswered, and never takes the write lock on that path.
carrier/wire/serve.rs
The wire carrier’s engine half: a connection-lived engine process.
run_engine(installers)— adopts fd 3 as the wire channel and callsengine_session.engine_session— readsAttach(the only legal first frame),restore_process_dirs(the process-level half of an attach, which only a carrier owning its process performs: a root’s cwd, every engine’sHOME, each readEnginePath::native; a child restores no cwd),Engine::boot, writesAttached/Refused, moves the engine onto a worker thread, then runs the reader loop; returns the process exit code. The loop breaks on aSessionEnd—Requested(aDetachor the front-end’s EOF) orCorrupt(a read error, a dead worker, silence past the deadline, or a frame only an engine sends) — so corruption cannot be reported as an end the front-end asked for; a wire fault demotes even aRequestedend to1.engine_write/engine_send— every engine-side write. AReportorReadingthe fuse refuses is replaced by afault; any other refusal goes back to its writer,engine_senddiagnosing and dropping a frame with no writer to refuse into (a session frame, aPong).- The worker’s
Rails— an outlet writingFrame::Eventthroughengine_write(anOutletanswersResult<(), WriteError>), aChannelDeferredSinkwritingFrame::Session, aWireDesk, andFork::Seal. WorkItem/refusal/fault— what the worker is handed, a run or a probe, and the refusal or fault in the shape each waits on: a busy engine’s run ends in aReport::refused, a panicked worker’s or fuse-refused one in aReport::faulted, a probe in anEvent::Reading(Err(..))either way.WireDesk/Parks— the wire engine’sEnquiryDesk: writesEvent::Enquiry(a refused or severed write is its ownErr), then parks on a oneshot registered under itsEnquiryIduntilFrame::Answerfills it or the run’s own cancel scope fires. A park that gave up has deregistered its sender, so a late answer is dropped.Dispatch/Writing— the one-run-or-probe rendezvous and the guard spanning an item’s report write; claiming is the only way to mint aDispatch, so “engine busy” is never raised without work in flight.Patience— the engine’s own read-silence and write-stall deadlines, armed once the firstPingarrives (bothHOST_SILENCE_DEADLINEin production, a test gets a brisker pair).- The teardown settle — on any loop exit:
Scopes::end, then poll the busy and writing flags underSETTLE_TIMEOUT/SETTLE_POLLbefore exiting, so no run is abandoned mid-report.
carrier/testkit.rs
Core’s own test engines, booted as every engine is (BARE, boot, eval).
core/src/engine/probe.rs
The engine’s answers: Engine::probe reads one Probe off the shell
(answer), rendering rows engine-side — never a live handle.
probe/fs.rs — entries (and path::tree::bytes, behind Probe::PathBytes): read-only
metadata walks of the engine’s own filesystem, under its cwd.
core/src/guard/grant.rs
SpawnGrant—Inherit,Base(name), orRestrict(record)carried unfrozen.layerresolves it against aFreezeCtx;narrow_ontopushes that layer onto a shell as a session frame, frozen against the shell’s own cwd — the one layering step, whichShell::child_oftakes for an adopted identity fork (IdentityTransport::adopt_parked) and a sealed child alike, so neither seat holds a narrowing decision of its own (a-spawn-is-one-layer). A`restrictrecord crosses undecoded and is decoded there, which keepsCapabilities’ resolved-by-construction invariant true of every value that ever exists.GrantNarrower—fn(&str, &Path) -> Result<Capabilities, String>, a field ofEngineInstallerrather than a registered hook: core has no base-tag lexicon of its own, so a`basearm is always resolved by the host that boots the engine (exarch::policy::base_layer), and the policy is demanded of every host that boots an engine instead of left in a slot one could forget to fill.
The seal a child’s Attach carries is an EngineSeed in bytes —
transport’s core/src/seed.rs section.
See also
engine-protocol (the why — one engine and two
carriers, the channel table, the laws of an enquiry, liveness and severance),
transport (frame.rs’s framing, Datum,
seal/Sealed), agent (the seat, the wire-seat
spawn that dials the factory), loop (the REPL as an
identity front-end), synod (WireTransport::adopt over a
guest VM’s virtual socket).