feat(sys): add enumerate-capabilities to astrid:[email protected]#13
Conversation
Argument-free, ungated host fn returning the calling capsule's own held capability NAMES (categories like host_process/net_connect/fs_read, not scoped args) — the list dual of check-capsule-capability. Manifest-derived; capsule capabilities are not runtime-revoked (grant/revoke is principal-scoped). Resolves the capability-introspection-depth unresolved question in RFC host_abi (#22).
There was a problem hiding this comment.
Code Review
This pull request updates the host/[email protected] interface by expanding the documentation for check-capsule-capability and introducing a new enumerate-capabilities function to allow a capsule to query its own capabilities. Feedback highlights that modifying this frozen interface directly violates the established ABI evolution discipline. Additionally, since enumerate-capabilities is argument-free and has no plausible failure modes, it is recommended to make the function infallible to avoid unnecessary error-handling overhead.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Pull request overview
Adds self-capability introspection to the astrid:sys host ABI by introducing an argument-free enumerate-capabilities() function and refining the documentation around capability introspection.
Changes:
- Clarifies
check-capsule-capabilitydocumentation (including its relationship to enumeration and ungated/audit posture). - Adds
enumerate-capabilities() -> result<list<string>, error-code>to return the calling capsule’s manifest capability category names.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…-capabilities (1) The 'Frozen / never edit this file' header was premature: pre-launch every @1.0.0 file is a DRAFT edited in place; the frozen ABI-evolution discipline takes effect at 1.0. Header reworded to say so (resolves the gemini/copilot frozen-file objection). (2) enumerate-capabilities is now infallible (-> list<string>): argument-free self-introspection of the caller's own registered set has no failure mode (empty list = no caps), so a result wrapper is needless overhead — like clock-ms.
…ng files) Maintainer preference: keep the standard 'Frozen per the ABI evolution discipline' header that every other domain file carries, rather than re-wording it to DRAFT for one file. In-place pre-1.0 edits remain the working practice regardless of the header text. The infallible enumerate-capabilities signature from b2ebdd1 is unaffected.
Wraps astrid:sys/host.enumerate-capabilities (astrid-runtime/wit#13) as the infallible list dual of capabilities::check: returns the calling capsule's own held capability names — the categories declared in its [capabilities] manifest block (host_process, net_connect, fs_read, …), not the scoped arguments within them. Argument-free, returns Vec<String> with no error path (an empty list is the valid no-capabilities answer). Contracts submodule bumped to pick up the new sys function.
Wraps astrid:sys/host.enumerate-capabilities (astrid-runtime/wit#13) as the infallible list dual of capabilities.check: returns the calling capsule's own held capability names — the categories declared in its [capabilities] manifest block (host_process, net_connect, fs_read, …), not the scoped arguments within them. Argument-free, returns string[] with no error path (an empty array is the valid no-capabilities answer). Hand-adds the ambient host type in wit-imports.d.ts and bumps the contracts submodule so astrid-build's host WIT declares the import. The astrid:contracts events bundle is unchanged.
…#869) ## Linked Issue Closes #868 ## Summary Implements `astrid:sys/host.enumerate-capabilities` (the infallible `() -> list<string>` added by astrid-runtime/wit#13, merged) and completes the previously-stubbed `check-capsule-capability` onto the same capability namespace, so a capsule can introspect its own — or any capsule's — manifest capability posture. Motivation is Claude-on-Astrid: a reusable supervisor binary deployed under different manifests can ground its behaviour in what it can actually do instead of hard-coding it. ## Changes - **`enumerate_capabilities()`** returns the calling capsule's held capability NAMES — the categories declared in its `[capabilities]` manifest block (`host_process`, `net_connect`, `fs_read`, …), not the scoped arguments within them. Infallible per the WIT (a bare `list<string>`, no `result`): it reads an owned, lock-free snapshot taken once at load (`CapabilitiesDef::held_names`) stored on `HostState`, never the `capsule_registry` — so there is no `registry-unavailable` failure mode, and an empty list is the valid "no capabilities" answer. Capsule capabilities are fixed at load (grant/revoke is principal-scoped, a separate axis), so the snapshot is correct for the capsule's lifetime and across the pool. - **`check_capsule_capability`** de-stubbed: it answered only `allow_prompt_injection` and returned `false` for everything else. Both host fns are now **derived from `CapabilitiesDef`'s serialized fields** rather than a hand-maintained list — `held_names()` (the list) and `has(name)` (the per-name dual) read the same struct, so a capability added to it flows through both automatically and the two cannot drift (`n ∈ held_names()` iff `has(n)`); unknown names fail closed. - Bumps the `wit` submodule to the merged `astrid:[email protected]` enumerate commit (`9742f80`) and restages `wit-staging`. - Lifecycle-hook and `astrid-hooks` host states (which run outside the capsule manifest/security-gate lifecycle) report an empty set, fail-closed. Both host fns are ungated, read-only, and audit-not-recorded per the WIT: capability posture is structural metadata, not a secret (enforce-don't-conceal). ## Test Plan ### Automated - [x] `cargo test --workspace` passes (365 in `astrid-capsule` incl. the new tests; full workspace green — the `gateway_tls` integration tests only fail under the dev sandbox, which blocks the ephemeral TCP bind) - [x] No new clippy warnings (`cargo clippy -p astrid-capsule -p astrid-hooks --all-targets` clean) New coverage: `CapabilitiesDef` unit tests assert `held_names`/`has` agree across the full namespace, that `held_names` covers every serialized field (derivation guard against a future hand-picked subset), the default holds nothing, and unknown names fail closed; a host-fn test asserts `enumerate-capabilities` returns the load-time snapshot and the empty default. ## Checklist - [x] Linked to an issue - [x] CHANGELOG.md updated under `[Unreleased]`
…#55) ## What Adds `capabilities::enumerate()` to `astrid-sdk` — the ergonomic wrapper for `astrid:sys/host.enumerate-capabilities` (astrid-runtime/wit#13, merged), implemented kernel-side in unicity-astrid/astrid (`feat(sys): implement enumerate-capabilities + complete check-capsule-capability`). It is the infallible list dual of `capabilities::check`: returns the calling capsule's own held capability names — the categories declared in its `[capabilities]` manifest block (`host_process`, `net_connect`, `fs_read`, …), not the scoped arguments within them. Argument-free, returns `Vec<String>` with no error path (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. The `contracts` submodule is bumped to the merged `9742f80` so `astrid-sys` regenerates the binding; `astrid-sys/wit-staging` restaged. ## Stacking Stacked on `feat/process-persistent-sdk` (#53) — base is that branch, so the diff shows only the enumerate delta. Rebase onto `main` and retarget once #53 lands. ## Verify `cargo build --workspace` and `cargo clippy --workspace --all-targets` green.
…16) ## What Adds `capabilities.enumerate()` to `@unicity-astrid/sdk` — the ergonomic wrapper for `astrid:sys/host.enumerate-capabilities` (astrid-runtime/wit#13, merged), mirroring the Rust SDK `capabilities::enumerate`. It is the infallible list dual of `capabilities.check`: returns the calling capsule's own held capability names — the categories declared in its `[capabilities]` manifest block (`host_process`, `net_connect`, `fs_read`, …), not the scoped arguments within them. Argument-free, returns `string[]` with no error path (an empty array is the valid "no capabilities" answer). Hand-adds the ambient `enumerateCapabilities(): string[]` host declaration in `wit-imports.d.ts` and bumps the `contracts` submodule to the merged `9742f80` so `astrid-build`'s `CANONICAL_WIT_DIR` (`contracts/host`) declares the import for downstream componentization. The `astrid:contracts` events bundle is unchanged. ## Stacking Stacked on `feat/process-persistent-sdk` (#14) — base is that branch, so the diff shows only the enumerate delta. Rebase onto `main` and retarget once #14 lands. ## Verify `tsc -b` typecheck green; `capabilities.enumerate` is exported via `export * as capabilities`.
Adds
enumerate-capabilities() -> result<list<string>, error-code>toastrid:sys— argument-free, ungated, returns the calling capsule's own held capability names (categories likehost_process/net_connect/fs_read, not the scoped arguments within them). The list dual ofcheck-capsule-capability.Manifest-derived: capsule capabilities are not runtime-revoked (the grant/revoke model is principal-scoped, a separate axis), so the declared set == the usable set at the capsule level. Ungated because capability posture is structural metadata, not a secret (enforce-don't-conceal).
Resolves the
capability-introspection-depthunresolved question in the host-ABI RFC (astrid-runtime/rfcs#22, which the RFC author resolved as 'self-enumerate as an ungated view'). Pre-1.0 DRAFT edit-in-place to[email protected].check-capsule-capabilitydoc clarified as the per-name dual (self or other).Host impl + SDK surfaces follow in core / sdk-rust / sdk-js.