Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ Changelog tracking starts with 0.2.0. Prior versions were not tracked.

## [Unreleased]

### Added

- **`capabilities::enumerate` — list the calling capsule's own held capability names.** The list dual of `capabilities::check`: returns the capability categories declared in this capsule's `[capabilities]` manifest block (`host_process`, `net_connect`, `fs_read`, …) — the names, not the scoped arguments within them (allowlists, `host:port`, paths). Argument-free (the kernel already knows the caller) and infallible — an empty list is the valid "no capabilities" answer — so a reusable capsule can ground its behaviour in what it can actually do instead of hard-coding it, avoiding code-vs-manifest drift. Backed by unicity-astrid/wit#13's `astrid:sys/host.enumerate-capabilities`; contracts submodule bumped accordingly.
- **`process` persistent-process tier — `Command::spawn_persistent`, `PersistentProcess`, and `process::{attach, list, status_many}`.** Mirrors the host `astrid:process@1.0.0` persistent tier: a background child that **outlives the pooled, stateless instance** that started it (unlike `Process`, whose kernel resource is reaped on instance reset). `Command` gains the persistent-only builder knobs — `label`, `keep_stdin_open`, `overflow`, `log_ring_bytes`, `max_lifetime`, `idle_timeout`, `exit_retention`, `limits` — and a `spawn_persistent()` terminal returning a `PersistentProcess` keyed by an opaque `ProcessId`. `PersistentProcess` exposes `status` / `read_logs` (drain) / `read_since` (non-draining cursor, byte-faithful `LogChunk`) / `write_stdin` / `close_stdin` / `signal` / `wait` (bounded) / `stop` (consumes the handle; SIGTERM→grace→SIGKILL, frees the slot) / `release` (consumes). Persist the `ProcessId` (e.g. in KV) and `process::attach(id)` from a later invocation to reattach — the SDK `attach` is a thin id-wrapper, so it works without the host's deferred `attach` resource fn; the first id-keyed call validates ownership. `process::list` / `status_many` enumerate the capsule+principal's persistent processes. New types: `ProcessId`, `ProcessInfo`, `ProcessPhase`, `LogStream`, `LogCursor`, `LogChunk`, `OverflowPolicy`, `ResourceLimits`; `Signal` gains `Stop` / `Cont`. The host's `watch` / `unwatch` lifecycle-event channel and resource-limit enforcement are not yet wired (poll via `status` + bounded `wait`). Backed by unicity-astrid/wit#12; contracts submodule bumped to the merged `astrid:process@1.0.0` persistent tier.

## [0.7.0] - 2026-05-26

### Breaking
Expand Down
28 changes: 24 additions & 4 deletions astrid-sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,11 +467,14 @@ pub mod runtime {
}
}

/// Cross-capsule capability queries.
/// Capability introspection.
///
/// Allows a capsule to check whether another capsule (identified by its
/// IPC session UUID) has a specific manifest capability. Used by the
/// prompt builder to enforce `allow_prompt_injection` gating.
/// [`check`] asks whether a capsule (self or any other, by IPC session UUID)
/// holds a specific manifest capability — used by the prompt builder to
/// enforce `allow_prompt_injection` gating. [`enumerate`] is the list dual for
/// the calling capsule's own set: the names for which a self-`check` returns
/// `true`. Capability posture is structural metadata, not a secret
/// (enforce-don't-conceal), so both are ungated.
pub mod capabilities {
use super::*;

Expand All @@ -488,6 +491,23 @@ pub mod capabilities {
let response = wit_sys::check_capsule_capability(&request).map_err(host_err)?;
Ok(response.allowed)
}

/// Enumerate the calling capsule's own held capability names.
///
/// Returns the capability categories declared in this capsule's
/// `[capabilities]` manifest block (`host_process`, `net_connect`,
/// `fs_read`, …) — the names, not the scoped arguments within them
/// (allowlists, `host:port`, paths). This is exactly the set of names for
/// which [`check`] against this capsule's own UUID returns `true`.
///
/// Argument-free (the kernel already knows the caller) and infallible: the
/// kernel always knows the caller's own registered set, so there is no
/// error path — an empty list is the valid "no capabilities" answer. Lets
/// a reusable capsule ground its behaviour in what it can actually do
/// instead of hard-coding it, avoiding code-vs-manifest drift.
pub fn enumerate() -> Vec<String> {
wit_sys::enumerate_capabilities()
}
}

pub mod net;
Expand Down
Loading
Loading