Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Proposal: SystemInfo Capability

System-wide informational data (banner/MOTD today, hostname, help topics, and on-ISO documentation later) exposed as a single typed capability instead of ad-hoc per-feature kernel parameters.

Status: Phase 1 + Phase 2 implemented. Phase 1 introduced the SystemInfo capability (renamed from ShellConfig, schema field motd) and unified the print site so console and Telnet shells both call SystemInfo.motd() themselves. Phase 2 then moved post-login authority into AuthorityBroker.shellBundle: the broker mints SystemInfo plus a profile-scoped serviceEndpoints list (adventure + chat for operator shells, empty for guest and anonymous shells), so Telnet/SSH-launched operator shells can run chat-client/adventure-client without per-transport manifest forwarding. chat is the kernel-singleton chat endpoint (KernelCapSource::ChatEndpoint) so all operator shells share one chat-server queue; adventure is a fresh per-session endpoint. Last reviewed: 2026-04-29 05:59 UTC.

Problem

The pre-existing ShellConfig capability had a single method (motd) and was distributed via manifest cap grants. That was already a capability shape, but two things made it brittle:

  • The name claimed too little. “Shell config” suggests configuration of the shell binary, but the data is system-wide and transport-agnostic (banner text doesn’t belong to any one shell). Anything similar we wanted to expose later — hostname, help topics, manpages — would either squat on ShellConfig (wrong scope) or get its own one-method cap (proliferation).
  • The print site was asymmetric. init printed the banner over COM1 before launching the console foreground shell; the Telnet-spawned shell printed it itself after the gateway forwarded shell_config as a manifest grant. Two code paths, two places to keep consistent. The SSH Shell Gateway successor, and any future transport, would add a third.

The capability model already supports a clean fix: one cap, one print site, room to grow.

Design

Interface

interface SystemInfo {
    motd @0 () -> (text :Text);
    # Future:
    # hostname @1 () -> (name :Text);
    # helpTopics @2 () -> (topics :List(HelpTopic));
    # manPage @3 (name :Text) -> (page :ManPage);
}

Adding methods later is a Cap’n Proto-compatible change. Each future addition gets its own kernel data source (or a userspace SystemInfo service backed by storage, when persistence exists). Callers that only need MOTD do not pay for the others.

Data Source

SystemInfo is currently kernel-backed and reads from manifest kernelParams.motd (renamed from shellMotd). Hostname will likely come from kernelParams.hostname or a CloudMetadata-derived value; help topics and manpages will eventually be served by a userspace documentation service that holds a SystemInfo cap as one of its exports. The kernel implementation is intentionally minimal — it owns text the boot manifest already provided, and nothing else.

Distribution

A process gains SystemInfo by listing it as a manifest cap source:

caps: [{
    name: "system_info"
    source: {kernel: "system_info"}
}]

Phase 1 granted the cap to:

  • init — kept. init no longer reads SystemInfo itself, but the manifest spawn loop forwards init-held kernel-source caps to each service. The console foreground shell and any gateway service that receives system_info is reached through this forwarding, so init must hold the cap.
  • The default console foreground shell (new — needed so the console shell can print MOTD itself).
  • telnet-gateway, restricted-shell-launcher, and the SSH gateway terminal-host (was, kept — each forwards system_info to the child shell via RestrictedShellLauncher, same mechanism that forwards creds/sessions/audit/broker).

Phase 2 moved normal shell distribution into AuthorityBroker.shellBundle: the broker mints a fresh SystemInfo cap per session and returns it alongside the launcher, copied session, and any profile-scoped service endpoint caps allowed for that profile. RestrictedShellLauncher no longer requires a system_info pass-through grant.

The banner is printed by the shell on startup after it obtains its initial shell bundle, across all transports:

#![allow(unused)]
fn main() {
// shell/src/main.rs
fn write_motd_from_bundle(...) -> Result<(), i64> {
    let mut system_info = SystemInfoClient::new(bundle.system_info.capability());
    let motd = system_info.motd_wait(ring, WAIT_FOREVER)...;
    for line in motd.lines() {
        terminal.write_line_wait(ring, line, ...)?;
    }
    Ok(())
}
}

init is no longer responsible for printing MOTD — its write_motd_to_terminal helper is removed.

Why Phase 1 Stayed Manifest-Driven

Moving SystemInfo distribution into AuthorityBroker.shellBundle made architectural sense, but it required the broker to hold or be able to mint informational caps and changed the shell bundle shape. Phase 1 therefore isolated the rename, the unification of the print site, and the schema interface as separately reviewable prerequisites.

Phase 2: Broker-Minted SystemInfo and Service Endpoints

AuthorityBroker.shellBundle returns a RestrictedLauncher, a copied UserSession, SystemInfo, and any allowed profile-scoped service endpoint caps per call:

interface AuthorityBroker {
    shellBundle @0 (sessionCapId :UInt32, profile :Text)
        -> (launcherIndex      :UInt16,
            sessionIndex       :UInt16,
            systemInfoIndex    :UInt16,
            serviceEndpoints   :List(BundleEndpoint));
}

struct BundleEndpoint {
    name        @0 :Text;        # e.g. "chat", "adventure"
    capIndex    @1 :UInt16;
}

The broker mints:

  1. SystemInfo (always) — replaces the manifest grant.
  2. Service-endpoint caps the requested profile is allowed to reach (chat and adventure for operator profiles, none for guest or anonymous).

RestrictedShellLauncher’s required shell grants collapsed to creds, sessions, audit, and broker; system_info and service endpoint authority now arrive through the broker bundle, keeping the kernel launcher minimal.

Phase 2 implementation notes

  • Phase 2 landed in three sub-tiers (A: SystemInfo; B: adventure; C: chat). The broker holds a kernel-side Arc<Endpoint> for chat — the KernelCapSource::ChatEndpoint lazy singleton constructed by BootCapFactory — and Arc::clones it into every operator bundle. adventure is fresh per operator bundle.
  • The shell prefers manifest-granted (CapSet) caps over bundle service endpoints when both have the same name. The focused chat manifest now gives init the kernel singleton chat_endpoint to forward to chat-server and relies on the broker-issued chat endpoint for the normal shell path instead of a shell-local chat-server export, matching the Telnet and default shell bundle model. Normal shell @chat badge 200 syntax is now rejected by the parser before it can reach the delegated-client relabel check; lower-level smoke paths retain relabel fixtures for kernel/process-spawn enforcement.
  • RestrictedShellLauncher::REQUIRED_SHELL_GRANTS no longer requires system_info; the broker is now the single source for that cap.

Cross-References

  • shell-proposal.md — banner ownership and help-topic discovery were implicit open questions; this proposal resolves “where does the banner live” (Phase 1) and “where does the post-login authority live” (Phase 2).
  • networking-proposal.md — Telnet gateway/shell interaction; SystemInfo is now part of the broker bundle consumed by the shell after launch.
  • boot-to-shell-proposal.md — login flow runs after the shell has acquired its initial anonymous bundle and printed MOTD from broker-minted SystemInfo.
  • userspace-authority-broker-proposal.md — Phase 2 makes the broker the single source of post-login authority, including informational caps.

Non-Goals

  • This proposal does not introduce persistent storage for system information. MOTD comes from the boot manifest; future fields will come from manifest, CloudMetadata, or a userspace documentation service when those exist.
  • This proposal does not add a separate pre-authentication issue/banner channel. MOTD is printed after initial shell-bundle acquisition; a true pre-auth warning banner would need its own reviewed distribution path.
  • This proposal does not unify hostname into Phase 1. Hostname has no current use site and would create churn without a payoff; add it when the first consumer appears.

Open Questions

  • Pre-authentication warning banner: MOTD now comes from the initial broker-issued shell bundle. If capOS later needs a banner before SessionManager/AuthorityBroker interaction, it should be a distinct issue-style surface rather than a regression to ad-hoc manifest grants.
  • Hostname source: manifest field, CloudMetadata-derived, or storage-backed mutable state. Park until first consumer.
  • Help-topic discovery: tied to schema reflection and the SchemaRegistry open question in shell-proposal.md. Likely lives in a userspace documentation service, not in the kernel cap.