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.
initprinted the banner over COM1 before launching the console foreground shell; the Telnet-spawned shell printed it itself after the gateway forwardedshell_configas 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.initno longer readsSystemInfoitself, but the manifest spawn loop forwards init-held kernel-source caps to each service. The console foreground shell and any gateway service that receivessystem_infois 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 forwardssystem_infoto the child shell viaRestrictedShellLauncher, same mechanism that forwardscreds/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.
Print Site
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:
SystemInfo(always) — replaces the manifest grant.- Service-endpoint caps the requested profile is allowed to reach
(
chatandadventurefor 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-sideArc<Endpoint>for chat — theKernelCapSource::ChatEndpointlazy singleton constructed byBootCapFactory— andArc::clones it into every operator bundle.adventureis 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 singletonchat_endpointto forward tochat-serverand relies on the broker-issuedchatendpoint 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 200syntax 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_GRANTSno longer requiressystem_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/AuthorityBrokerinteraction, 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
SchemaRegistryopen question in shell-proposal.md. Likely lives in a userspace documentation service, not in the kernel cap.