Skip to main content

Kernel

Struct Kernel 

Source
pub struct Kernel {
Show 19 fields pub session_id: SessionId, pub event_bus: Arc<EventBus>, pub capsules: Arc<RwLock<CapsuleRegistry>>, pub mcp: SecureMcpClient, pub capabilities: Arc<CapabilityStore>, pub vfs: Arc<dyn Vfs>, pub overlay_registry: Arc<OverlayVfsRegistry>, pub vfs_root_handle: DirHandle, pub workspace_root: PathBuf, pub home_root: Option<PathBuf>, pub cli_socket_listener: Option<UplinkListener>, pub kv: Arc<dyn KvStore>, pub audit_log: Arc<AuditLog>, pub audit_sink: Arc<KernelAuditSink>, pub runtime_key: Arc<KeyPair>, pub ephemeral: AtomicBool, pub shutdown_tx: Sender<bool>, pub session_token: Arc<SessionToken>, pub allowance_store: Arc<AllowanceStore>, /* private fields */
}
Expand description

The core Operating System Kernel.

Fields§

§session_id: SessionId

The unique identifier for this kernel session.

§event_bus: Arc<EventBus>

The global IPC message bus.

§capsules: Arc<RwLock<CapsuleRegistry>>

The process manager (loaded WASM capsules).

§mcp: SecureMcpClient

The secure MCP client with capability-based authorization and audit logging. Native-only: the MCP host surface belongs to the Wasmtime engine, absent on the browser profile.

§capabilities: Arc<CapabilityStore>

The capability store for this session.

§vfs: Arc<dyn Vfs>

The global Virtual File System mount.

Points at the unmodified workspace (no overlay). Principal-scoped overlays live in overlay_registry — this field is kept for kernel-internal paths that do not know a principal (discovery, capsule load scan). Native-only: astrid-vfs is built on cap-std, which does not compile for the browser profile (that host resolves paths by other means).

§overlay_registry: Arc<OverlayVfsRegistry>

Per-principal overlay registry (Layer 4, issue #668).

Each invoking principal resolves their own OverlayVfs from this registry on first use — lower layer is the shared workspace, upper layer is a principal-private tempdir. Agent A’s uncommitted writes are never visible to Agent B. Native-only (astrid-vfs / cap-std).

§vfs_root_handle: DirHandle

The global physical root handle for the VFS. On native hosts the composition root registers it as the cap-std workspace root; the browser profile keeps the handle (it is engine-agnostic) but gates out the cap-std-backed astrid-vfs machinery behind it.

§workspace_root: PathBuf

The physical path the VFS is mounted to.

§home_root: Option<PathBuf>

Legacy native home root retained for lifecycle/compatibility contexts. Steady-state capsule home:// authority is the UID-bound principal_store projection, never this host path.

Always Some in production (boot requires AstridHome). Remains Option for compatibility with CapsuleContext and test fixtures.

§cli_socket_listener: Option<UplinkListener>

The natively bound Unix Socket for the CLI proxy.

§kv: Arc<dyn KvStore>

Shared KV store backing all capsule-scoped stores and kernel state.

A trait object (Arc<dyn KvStore>) so a portable host can inject its own backend; the shutdown flush goes through the trait’s close.

§audit_log: Arc<AuditLog>

Chain-linked cryptographic audit log with persistent storage.

§audit_sink: Arc<KernelAuditSink>

Shared bounded host-audit writer and operator health surface.

§runtime_key: Arc<KeyPair>

The runtime ed25519 signing key (issue #929).

Loaded once at boot from ~/.astrid/keys/runtime.key and shared (Arc) with AuditLog — both sign with the exact same key bytes, never loaded twice. Reachable from the admin token-mint handlers so an operator can pre-grant mcp:// tool access by minting a capability token signed by this key (the same key the approval interceptor’s validator trusts as issuer).

§ephemeral: AtomicBool

Ephemeral mode: shut down immediately when the last client disconnects.

§shutdown_tx: Sender<bool>

Sender for the API-initiated shutdown signal. The daemon’s main loop selects on the receiver to exit gracefully without process::exit.

§session_token: Arc<SessionToken>

Session token for socket authentication. Generated at boot, written to ~/.astrid/run/system.token. CLI sends this as its first message.

§allowance_store: Arc<AllowanceStore>

Shared allowance store for capsule-level approval decisions.

Capsules can check existing allowances and create new ones when users approve actions with session/always scope.

Implementations§

Source§

impl Kernel

Source

pub fn bind_native_secret_inputs( &self, registry: Arc<PendingSecretElicits>, ) -> Result<(), Error>

Bind private secret routing before loading boot capsules. This shares waiter ownership with the native responder; it does not register keys.

§Errors

A second binding is refused. Changing routing requires a daemon restart.

Source

pub fn native_input_device_is_live( &self, principal: &PrincipalId, device_key_id: &str, ) -> bool

Live profile revalidation for private secret replies.

This uses the same profile cache that pair_device_revoke invalidates. Cached native handshake identity is not sufficient after revoke or disable.

Source§

impl Kernel

Source

pub async fn set_system_capsules( &self, capsules: impl IntoIterator<Item = String>, )

Install the operator-owned allowlist for explicit system-resident capsules. Capsule manifests cannot mutate or widen this policy.

Claim the canonical local listener for Astrid’s built-in uplink.

The first caller receives the shared listener. Once claimed, capsule contexts no longer receive it; optional distribution frontends may expose other transports but cannot replace or race the base control plane.

Source

pub fn ownership_store(&self) -> &Arc<OwnershipStore>

Astrid’s authoritative human-to-fleet ownership store.

Source

pub fn principal_store(&self) -> Option<&RuntimePrincipalStore>

Return the durable UID-scoped principal store used by trusted daemon composition paths. Capsule and gateway callers must use authenticated admin requests instead of receiving this storage handle.

Source

pub fn principal_directory(&self) -> &PrincipalDirectory

Return the live alias-to-immutable-UID directory for trusted daemon composition paths. The directory is never a storage authority; it only resolves a principal alias before selecting its UID-owned store view.

Source

pub fn workspace_layout(&self) -> &WorkspaceLayout

Per-project runtime layout selected at boot.

Source

pub fn workspace_selection(&self) -> &WorkspaceSelection

Checked project state selection captured at boot.

Source

pub async fn new( session_id: SessionId, workspace_root: PathBuf, runtime_limits: CapsuleRuntimeLimits, local_egress: HashMap<String, Vec<String>>, http_limits: HttpLimits, ) -> Result<Arc<Self>, Error>

Boot a new Kernel instance mounted at the specified directory.

The native composition root: resolves the Astrid home, opens the durable principal store and audit log, loads the runtime key, binds the singleton Unix socket, generates the session token, then delegates to the portable Kernel::with_resources. Unix-only — the socket bind and singleton flock have no browser-profile analogue; that host builds its own KernelResources and calls with_resources directly.

runtime_limits is the resolved per-host capsule concurrency ceiling pair (blocking vs async-I/O host calls); the daemon resolves it from config + CLI + host defaults and the kernel forwards it, unmodified, to every capsule’s WasmEngine. In tests, pass CapsuleRuntimeLimits::default().

http_limits is the resolved astrid:http host ceilings (a global value, the same for every capsule), likewise resolved by the daemon from the [http] config section and forwarded unmodified. In tests, pass HttpLimits::default().

§Panics

Panics if called on a single-threaded tokio runtime. The capsule system uses block_in_place which requires a multi-threaded runtime.

§Errors

Returns an error if any native resource cannot be acquired — the Astrid home cannot be resolved, the KV store, runtime key, or audit log cannot be opened, the Unix socket cannot be bound (or the singleton lock is already held), or the session token cannot be generated — or if the portable wiring in Kernel::with_resources fails.

Source

pub async fn new_with_workspace_layout( session_id: SessionId, workspace_root: PathBuf, runtime_limits: CapsuleRuntimeLimits, local_egress: HashMap<String, Vec<String>>, http_limits: HttpLimits, workspace_layout: WorkspaceLayout, ) -> Result<Arc<Self>, Error>

Boot a kernel with an explicit per-project runtime layout.

§Errors

Returns an error if the Astrid home or native resources cannot be acquired, or if portable kernel wiring fails.

Source

pub async fn with_resources( session_id: SessionId, workspace_root: PathBuf, runtime_limits: CapsuleRuntimeLimits, local_egress: HashMap<String, Vec<String>>, http_limits: HttpLimits, resources: KernelResources, ) -> Result<Arc<Self>, Error>

Construct a Kernel from already-acquired host resources.

This is the portable composition root: it performs the entire kernel wiring (event bus, registries, capability store, VFS/overlay, identity/group config, monitors, dispatcher) but performs no native side-effects — every platform-specific facility is injected via KernelResources. Kernel::new is the native composition root that acquires those resources (resolving the home, opening the KV/audit stores, loading the runtime key, binding the socket, generating the token) and delegates here. An alternate host can build its own KernelResources and call this directly.

runtime_limits is the resolved per-host capsule concurrency ceiling pair (blocking vs async-I/O host calls); the daemon resolves it from config + CLI + host defaults and the kernel forwards it, unmodified, to every capsule’s WasmEngine. In tests, pass CapsuleRuntimeLimits::default().

http_limits is the resolved astrid:http host ceilings (a global value, the same for every capsule), likewise resolved by the daemon from the [http] config section and forwarded unmodified. In tests, pass HttpLimits::default().

§Panics

Panics if called on a single-threaded tokio runtime. The capsule system uses block_in_place which requires a multi-threaded runtime.

§Errors

Returns an error if any portable wiring step fails: the VFS mount paths cannot be registered, the capability store cannot be initialized over the injected KV, the group configuration cannot be loaded, or the CLI root identity cannot be bootstrapped.

Source

pub fn bind_boot_local_egress( &self, local_egress: HashMap<String, Vec<String>>, ) -> Result<(), Error>

Bind the process-lifetime local-egress boot snapshot before the first capsule load.

This is a boot-only seam: reloads reuse the bound snapshot and a second bind fails, so operator revocation remains daemon-restart-bound.

§Errors

Returns an error if a boot snapshot was already bound.

Source

pub async fn with_resources_and_workspace_layout( session_id: SessionId, workspace_root: PathBuf, runtime_limits: CapsuleRuntimeLimits, local_egress: HashMap<String, Vec<String>>, http_limits: HttpLimits, resources: KernelResources, workspace_layout: WorkspaceLayout, ) -> Result<Arc<Self>, Error>

Construct a kernel from injected resources and workspace layout.

§Panics

Panics on native targets when called from a single-threaded tokio runtime because the capsule engine requires block_in_place.

§Errors

Returns an error if VFS mounts, the capability store, group configuration, or CLI root bootstrap cannot be initialized.

Source

pub async fn load_boot_capsules(&self)

Auto-discover and load the default principal’s boot-critical view.

Daemon readiness depends on the default view because it owns system service capsules such as the CLI proxy. Other profile principals are warmed after boot so persisted tenant state cannot make restart health depend on loading every agent’s tool set.

Source

pub fn schedule_profile_principal_warm(self: &Arc<Self>)

Schedule background warm-up for known non-default profile principals.

The actual load work is serialized by Kernel::capsule_load_lock, so this can run behind a ready daemon without racing other admin-driven warm/reload paths.

Source

pub async fn load_all_capsules(&self)

Auto-discover and load capsule views for known principals.

The default principal is loaded eagerly, then every principal with a profile on disk gets its own view. Content-identical capsules reuse the same installed artifact on disk, but loaded runtime instances remain principal-scoped; default’s capsule set is never copied into another principal’s view.

Source

pub async fn ensure_principal_loaded(&self, principal: &PrincipalId)

Build or refresh one principal’s capsule view from its own install set.

Source

pub fn agent_readiness_probe(&self) -> AgentReadinessProbe

Build an in-process agent-loop readiness probe over the live registry.

Handed to the co-located gateway so its prompt fail-fast can ask whether the loaded set can serve a chat turn directly — agent-loop serviceability is global daemon health, not per-principal authorization, so it needs no capability check and no socket round-trip (unlike the capability-gated GetAgentReadiness request, which exists for the detailed, ops-facing /api/sys/readiness view and astrid doctor). The closure clones the registry Arc, so each call reflects the current loaded set.

Source

pub fn capsule_topic_probe(&self) -> CapsuleTopicProbe

In-process probe for “does a loaded capsule subscribe to this topic”, computed from the live registry without a capability check. Mirrors Self::agent_readiness_probe; the co-located gateway uses it to gracefully degrade a route whose backing verb a pre-upgrade capsule may not handle (e.g. answer 501 instead of waiting out a bus timeout), and lets routes wait for a caller’s async-warmed capsule view without going through capability-gated inventory APIs.

Source

pub fn capsule_topic_probe_with_warm(self: &Arc<Self>) -> CapsuleTopicProbe

Build a topic probe that can actively warm the caller’s uplink capsules before answering a scoped readiness read.

The daemon-spawned gateway uses this for registry-backed model routes: after restart, the route must not publish request IPC until the caller’s registry subscription exists. The plain Self::capsule_topic_probe remains passive for compatibility with existing callers.

Source

pub fn connection_opened(&self, principal: &PrincipalId)

Record that a new client connection for principal has been established.

Source

pub fn connection_closed(&self, principal: &PrincipalId)

Record that a client connection for principal has been closed.

Uses fetch_update for atomic saturating decrement - avoids the TOCTOU window where fetch_sub wraps to usize::MAX before a corrective store.

When this principal’s counter reaches zero, clears only that principal’s session-scoped allowances — other principals’ state is untouched. The global ephemeral-shutdown path remains gated on the sum across every principal (see total_connection_count).

Source

pub fn set_ephemeral(&self, val: bool)

Enable or disable ephemeral mode (immediate shutdown on last disconnect).

Source

pub fn arm_ephemeral_startup_fallback(self: &Arc<Self>)

Arm startup handoff grace after readiness, allowing brief preflight connections before the host establishes its lasting lifecycle lease.

Source

pub fn total_connection_count(&self) -> usize

Total number of active client connections across all principals.

Used by the ephemeral-shutdown gate: the kernel shuts down only when every principal’s counter has reached zero.

Source

pub fn connections_by_principal(&self) -> Vec<(PrincipalId, usize)>

Snapshot of (principal, count) for every principal with a non-zero active connection. The astrid who admin surface reads this to attribute connections to specific agents instead of fabricating a default-only row from the bare total.

Not a hot-path call site — taken at status-RPC time. Iterating the DashMap snapshots the shard guards individually, so the total may not be perfectly consistent with a concurrent connect/disconnect, but each entry is internally consistent and the operator-facing accuracy bound (a flickering one-off count) is acceptable.

Source

pub async fn shutdown(&self, reason: Option<String>)

Gracefully shut down the kernel.

  1. Publish KernelShutdown event on the bus.
  2. Drain and unload all capsules (stops MCP child processes, WASM engines).
  3. Flush and close the persistent KV store.
  4. Remove the Unix socket file.

Auto Trait Implementations§

§

impl !Freeze for Kernel

§

impl !RefUnwindSafe for Kernel

§

impl !UnwindSafe for Kernel

§

impl Send for Kernel

§

impl Sync for Kernel

§

impl Unpin for Kernel

§

impl UnsafeUnpin for Kernel

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Pointee for T

Source§

type Pointer = u32

Source§

fn debug( pointer: <T as Pointee>::Pointer, f: &mut Formatter<'_>, ) -> Result<(), Error>

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more