RFC: Cargo-like manifest schema with WIT refs, registry, and BLAKE3 lock#26
Open
joshuajbouw wants to merge 1 commit into
Open
RFC: Cargo-like manifest schema with WIT refs, registry, and BLAKE3 lock#26joshuajbouw wants to merge 1 commit into
joshuajbouw wants to merge 1 commit into
Conversation
Replaces the v0.5 [[topic]] / ipc_publish / ipc_subscribe / [[interceptor]] / nested [exports.<ns>] surfaces with one Cargo-shaped declaration: - [publish] / [subscribe] tables with required typed wit = '@scope/repo/...' references, short and long forms - Flat [exports] / [imports] with quoted '<namespace>:<interface>' keys - [[tool]] section with explicit operator-reviewed description_for_llm — the only capsule-author-controlled string that ever reaches the LLM - Capsule.lock pinning resolved git SHAs + BLAKE3 content hashes - Lightweight git-backed registry (one repo, one TOML per package) with semver resolution + direct-ref escape hatches (rev/tag/branch/path) - 'wit = "opaque"' for genuine uplink-style heterogeneous wildcards Eliminates the four-place topic declaration, removes the prompt-injection vector via free-form descriptions reaching the LLM, makes installs reproducible without operating any new infrastructure beyond an index repo.
joshuajbouw
added a commit
to unicity-aos/capsule-context-engine
that referenced
this pull request
May 19, 2026
…ith canonical wit refs (#12) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: cargo-like-manifest in the rfcs repo, parser support in `astrid-runtime/astrid#713`): * Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into typed `[publish]` and `[subscribe]` tables. * Replace `"TODO"` wit refs on resolvable topics with the canonical `@unicity-astrid/wit/<noun>/<record>` path. * Drop remaining TODOs onto newly-added canonical WIT refs where applicable. Other capabilities (sandboxing, fs/net allowlists) preserved verbatim. No src changes — manifest-only, behaviour unchanged. ## Dependencies * RFC: `astrid-runtime/rfcs#26` (cargo-like manifest schema). * Parser: `astrid-runtime/astrid#713` (cargo-like manifest schema parser in core). The kernel reads both legacy and new forms equivalently during the migration window. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Capsule loads cleanly under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/capsule-fs
that referenced
this pull request
May 19, 2026
…ith canonical wit refs (#13) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: cargo-like-manifest in the rfcs repo, parser support in `astrid-runtime/astrid#713`): * Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into typed `[publish]` and `[subscribe]` tables. * Replace `"TODO"` wit refs on resolvable topics with the canonical `@unicity-astrid/wit/<noun>/<record>` path. * Drop remaining TODOs onto newly-added canonical WIT refs where applicable. Other capabilities (sandboxing, fs/net allowlists) preserved verbatim. No src changes — manifest-only, behaviour unchanged. ## Dependencies * RFC: `astrid-runtime/rfcs#26` (cargo-like manifest schema). * Parser: `astrid-runtime/astrid#713` (cargo-like manifest schema parser in core). The kernel reads both legacy and new forms equivalently during the migration window. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Capsule loads cleanly under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/capsule-hook-bridge
that referenced
this pull request
May 19, 2026
…ith canonical wit refs (#11) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: cargo-like-manifest in the rfcs repo, parser support in `astrid-runtime/astrid#713`): * Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into typed `[publish]` and `[subscribe]` tables. * Replace `"TODO"` wit refs on resolvable topics with the canonical `@unicity-astrid/wit/<noun>/<record>` path. * Drop remaining TODOs onto newly-added canonical WIT refs where applicable. Other capabilities (sandboxing, fs/net allowlists) preserved verbatim. No src changes — manifest-only, behaviour unchanged. ## Dependencies * RFC: `astrid-runtime/rfcs#26` (cargo-like manifest schema). * Parser: `astrid-runtime/astrid#713` (cargo-like manifest schema parser in core). The kernel reads both legacy and new forms equivalently during the migration window. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Capsule loads cleanly under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/capsule-http
that referenced
this pull request
May 19, 2026
…ith canonical wit refs (#11) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: cargo-like-manifest in the rfcs repo, parser support in `astrid-runtime/astrid#713`): * Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into typed `[publish]` and `[subscribe]` tables. * Replace `"TODO"` wit refs on resolvable topics with the canonical `@unicity-astrid/wit/<noun>/<record>` path. * Drop remaining TODOs onto newly-added canonical WIT refs where applicable. Other capabilities (sandboxing, fs/net allowlists) preserved verbatim. No src changes — manifest-only, behaviour unchanged. ## Dependencies * RFC: `astrid-runtime/rfcs#26` (cargo-like manifest schema). * Parser: `astrid-runtime/astrid#713` (cargo-like manifest schema parser in core). The kernel reads both legacy and new forms equivalently during the migration window. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Capsule loads cleanly under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/capsule-identity
that referenced
this pull request
May 19, 2026
…ith canonical wit refs (#18) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: cargo-like-manifest in the rfcs repo, parser support in `astrid-runtime/astrid#713`): * Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into typed `[publish]` and `[subscribe]` tables. * Replace `"TODO"` wit refs on resolvable topics with the canonical `@unicity-astrid/wit/<noun>/<record>` path. * Drop remaining TODOs onto newly-added canonical WIT refs where applicable. Other capabilities (sandboxing, fs/net allowlists) preserved verbatim. No src changes — manifest-only, behaviour unchanged. ## Dependencies * RFC: `astrid-runtime/rfcs#26` (cargo-like manifest schema). * Parser: `astrid-runtime/astrid#713` (cargo-like manifest schema parser in core). The kernel reads both legacy and new forms equivalently during the migration window. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Capsule loads cleanly under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/capsule-openai-compat
that referenced
this pull request
May 19, 2026
…ith canonical wit refs (#16) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: cargo-like-manifest in the rfcs repo, parser support in `astrid-runtime/astrid#713`): * Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into typed `[publish]` and `[subscribe]` tables. * Replace `"TODO"` wit refs on resolvable topics with the canonical `@unicity-astrid/wit/<noun>/<record>` path. * Drop remaining TODOs onto newly-added canonical WIT refs where applicable. Other capabilities (sandboxing, fs/net allowlists) preserved verbatim. No src changes — manifest-only, behaviour unchanged. ## Dependencies * RFC: `astrid-runtime/rfcs#26` (cargo-like manifest schema). * Parser: `astrid-runtime/astrid#713` (cargo-like manifest schema parser in core). The kernel reads both legacy and new forms equivalently during the migration window. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Capsule loads cleanly under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/capsule-router
that referenced
this pull request
May 19, 2026
…ith canonical wit refs (#11) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: cargo-like-manifest in the rfcs repo, parser support in `astrid-runtime/astrid#713`): * Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into typed `[publish]` and `[subscribe]` tables. * Replace `"TODO"` wit refs on resolvable topics with the canonical `@unicity-astrid/wit/<noun>/<record>` path. * Drop remaining TODOs onto newly-added canonical WIT refs where applicable. Other capabilities (sandboxing, fs/net allowlists) preserved verbatim. No src changes — manifest-only, behaviour unchanged. ## Dependencies * RFC: `astrid-runtime/rfcs#26` (cargo-like manifest schema). * Parser: `astrid-runtime/astrid#713` (cargo-like manifest schema parser in core). The kernel reads both legacy and new forms equivalently during the migration window. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Capsule loads cleanly under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/capsule-session
that referenced
this pull request
May 19, 2026
…ith canonical wit refs (#11) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: cargo-like-manifest in the rfcs repo, parser support in `astrid-runtime/astrid#713`): * Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into typed `[publish]` and `[subscribe]` tables. * Replace `"TODO"` wit refs on resolvable topics with the canonical `@unicity-astrid/wit/<noun>/<record>` path. * Drop remaining TODOs onto newly-added canonical WIT refs where applicable. Other capabilities (sandboxing, fs/net allowlists) preserved verbatim. No src changes — manifest-only, behaviour unchanged. ## Dependencies * RFC: `astrid-runtime/rfcs#26` (cargo-like manifest schema). * Parser: `astrid-runtime/astrid#713` (cargo-like manifest schema parser in core). The kernel reads both legacy and new forms equivalently during the migration window. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Capsule loads cleanly under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/capsule-shell
that referenced
this pull request
May 19, 2026
…ith canonical wit refs (#10) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: cargo-like-manifest in the rfcs repo, parser support in `astrid-runtime/astrid#713`): * Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into typed `[publish]` and `[subscribe]` tables. * Replace `"TODO"` wit refs on resolvable topics with the canonical `@unicity-astrid/wit/<noun>/<record>` path. * Drop remaining TODOs onto newly-added canonical WIT refs where applicable. Other capabilities (sandboxing, fs/net allowlists) preserved verbatim. No src changes — manifest-only, behaviour unchanged. ## Dependencies * RFC: `astrid-runtime/rfcs#26` (cargo-like manifest schema). * Parser: `astrid-runtime/astrid#713` (cargo-like manifest schema parser in core). The kernel reads both legacy and new forms equivalently during the migration window. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Capsule loads cleanly under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/capsule-skills
that referenced
this pull request
May 19, 2026
…ith canonical wit refs (#14) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: cargo-like-manifest in the rfcs repo, parser support in `astrid-runtime/astrid#713`): * Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into typed `[publish]` and `[subscribe]` tables. * Replace `"TODO"` wit refs on resolvable topics with the canonical `@unicity-astrid/wit/<noun>/<record>` path. * Drop remaining TODOs onto newly-added canonical WIT refs where applicable. Other capabilities (sandboxing, fs/net allowlists) preserved verbatim. No src changes — manifest-only, behaviour unchanged. ## Dependencies * RFC: `astrid-runtime/rfcs#26` (cargo-like manifest schema). * Parser: `astrid-runtime/astrid#713` (cargo-like manifest schema parser in core). The kernel reads both legacy and new forms equivalently during the migration window. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Capsule loads cleanly under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/capsule-registry
that referenced
this pull request
May 19, 2026
…ith canonical wit refs (#12) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: `astrid-runtime/rfcs#26`, parser support in `astrid-runtime/astrid#713`): * Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into typed `[publish]` and `[subscribe]` tables. * Replace `"TODO"` wit refs on resolvable topics with the canonical `@unicity-astrid/wit/<noun>/<record>` path. * Canonicalise bare-name wit refs to the full `@unicity-astrid/wit/...` form. * Drop remaining TODOs onto newly-added canonical WIT refs. Other capabilities preserved verbatim. No src changes — manifest-only, behaviour unchanged. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Capsule loads cleanly under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/capsule-memory
that referenced
this pull request
May 19, 2026
… restore on_before_prompt_build binding (#15) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: `astrid-runtime/rfcs#26`, parser support in `astrid-runtime/astrid#713`), and restores the `on_before_prompt_build` interceptor binding that was lost in a prior refactor. * `chore: convert to Cargo-like [publish]/[subscribe] schema` — same conversion as the rest of the capsule fleet. * `fix(manifest): restore lost handler binding for on_before_prompt_build` — the new schema does not auto-derive interceptor bindings from a `subscribe` entry; this commit makes the binding explicit so the handler keeps firing under the new schema. * `chore: replace TODO wit refs with canonical @unicity-astrid/wit/...` — canonical refs. No src changes. The handler-binding restoration is critical: without it, memory capsule silently stops participating in the prompt-build hook chain after the manifest migration. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Manual: `on_before_prompt_build` fires for memory capsule under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/capsule-react
that referenced
this pull request
May 19, 2026
…ith canonical wit refs (#17) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: `astrid-runtime/rfcs#26`, parser support in `astrid-runtime/astrid#713`): * Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into typed `[publish]` and `[subscribe]` tables. * Replace `"TODO"` wit refs on resolvable topics with the canonical `@unicity-astrid/wit/<noun>/<record>` path. * Drop remaining TODOs onto newly-added canonical WIT refs. Manifest-only, behaviour unchanged. Note: the existing PR #16 (`fix/payload-data-unwrap`) covers a separate src-side fix for the `Custom { data }` unwrap pattern; this PR is purely manifest. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Capsule loads cleanly under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/capsule-prompt-builder
that referenced
this pull request
May 19, 2026
…ith canonical wit refs (#13) ## Summary Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC: `astrid-runtime/rfcs#26`, parser support in `astrid-runtime/astrid#713`): * Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into typed `[publish]` and `[subscribe]` tables. * Replace `"TODO"` wit refs on resolvable topics with the canonical `@unicity-astrid/wit/<noun>/<record>` path. Manifest-only, behaviour unchanged. The src-side `Custom { data }` unwrap fix is covered by the existing PR #11 (`fix/payload-data-unwrap`); this PR is purely manifest and intentionally drops the duplicate src commit so review stays focused. ## Test plan - [x] `cargo build --target wasm32-wasip1 --release` - [x] Capsule loads cleanly under a daemon running the cargo-like-manifest parser PR.
joshuajbouw
added a commit
to unicity-aos/aos-ce
that referenced
this pull request
Jul 13, 2026
* feat: native OpenAI LLM provider capsule
Talks directly to OpenAI's Chat Completions API with support for:
- Strict function calling (strict: true on tool definitions)
- Reasoning effort for o-series models (low/medium/high)
- Service tier routing (auto/default/flex/priority)
- max_completion_tokens (OpenAI's preferred field)
- Parallel tool calls
Separate from openai-compat which handles generic OpenAI-compatible
providers. This capsule is OpenAI-specific.
* feat: native OpenAI provider — Responses API, model registry, repo setup (#1)
## Summary
Complete native OpenAI LLM provider capsule using the **Responses API**
(`POST /v1/responses`), not the legacy Chat Completions endpoint.
## Changes
- **Responses API**: `input` + `instructions` schema, named SSE events
(`event: response.output_text.delta`), `reasoning.effort` nested object
- **Model registry**: Built-in lookup table for all current OpenAI
models (GPT-5.4/mini/nano/pro, GPT-5.3 Codex, GPT-5.2, GPT-4.1 series,
o-series, GPT-4o legacy). Selecting a model auto-resolves context
window, max output tokens, vision/tools/reasoning support. Env vars
override.
- **Strict function calling**: `strict: true` on all tool definitions
- **Reasoning-aware temperature**: Temperature only sent when reasoning
effort is `none` (GPT-5.4 constraint). Older reasoning models skip
temperature entirely.
- **Net capabilities**: Locked to `api.openai.com` hostname only
- **Repo setup**: README, dual MIT/Apache-2.0 licenses, GitHub Actions
release workflow with BLAKE3 hashes
## Test plan
- [ ] Build: `cargo build --target wasm32-wasip1 --release`
- [ ] Install and test with OpenAI API key against GPT-5.4
- [ ] Verify model registry resolves context_window correctly for each
model family
- [ ] Verify reasoning_effort only sent for reasoning models
- [ ] Verify temperature skipped when reasoning effort is non-none
* chore: add CI workflow (#2)
Add fmt + clippy + WASM build checks on PRs and main pushes. Matches
other capsule repos.
* feat: initial Telegram Bot uplink capsule
Bridges the Telegram Bot API to the Astrid kernel IPC bus.
Features:
- Streaming responses with throttled message editing
- Markdown to Telegram HTML conversion
- Approval/elicitation inline keyboards
- Session management with KV persistence
- Access control via user ID allowlist
- Bot commands: /start, /help, /reset, /cancel
* fix: align with astrid-sdk 0.5.3 API
- Use Response.json()/text() instead of .status/.body fields
- Add description parameter to elicit::secret/text_with_default
- Fix formatting (rustfmt --edition 2024)
- Suppress expected dead_code warnings on deserialized fields
* fix: target wasm32-wasip1 to match astrid build system
Add .cargo/config.toml and rust-toolchain.toml matching other capsules.
* fix: remove install hook to avoid double-prompting
Capsule.toml [env] section already handles prompting for bot_token and
allowed_user_ids during install. The #[astrid::install] hook was
duplicating the same prompts.
* fix: use wildcard net capability to match kernel security gate
The kernel's Extism-based security gate doesn't support URL-pattern
net capabilities like 'https://api.telegram.org/*'. Use '*' wildcard
matching the pattern used by capsule-openai-compat.
* fix: add net capability to component section
The kernel's Extism-based security gate checks per-component capabilities,
not the top-level [capabilities] section. Without capabilities on the
[[component]], network access is denied at runtime.
* fix: unwrap SDK HTTP response envelope before parsing Telegram JSON
http::send() returns a JSON envelope {status, headers, body} where body
is the actual HTTP response as a string. Parse the envelope first, then
deserialize the Telegram API response from the body field.
* docs: fix WASM target in README (wasip1, not wasip2)
* fix: multi-user approval/elicitation routing (#11)
* fix: use session_id from payload for multi-user approval/elicitation routing
Remove find_chat_for_event which silently dropped approval and elicitation
events when multiple users had active turns. Instead, extract session_id
directly from the IPC payload and resolve the target chat via session_to_chat.
Falls back to single-active-turn heuristic only when no session_id is present.
Closes #1
* fix: drop events with unresolvable session_id instead of misrouting
Extract resolve_chat_from_payload helper to deduplicate chat resolution
logic between approval_required and elicit_request handlers.
The previous or_else fallback would use the single-active-turn heuristic
even when session_id was present but unresolvable (stale or unknown),
which could misroute events. Now we only fall back to the heuristic when
session_id is truly absent from the payload; if it is present but cannot
be resolved, the event is dropped.
* fix: propagate uplink::register error instead of silently discarding it (#15)
Closes #2
* fix: exponential backoff on Telegram API failures (#12)
* fix: add exponential backoff on persistent Telegram API poll failures
Replace the fixed 2-second sleep on Telegram poll errors with
exponential backoff (2s, 4s, 8s, ... up to 60s). The counter resets
on every successful poll, preventing runaway retry storms during
prolonged outages.
Closes #3
* fix: use non-blocking backoff to avoid stalling IPC during Telegram errors
Replace std::thread::sleep backoff with a next_poll_at timestamp so the
main loop continues processing IPC events while Telegram polling is
deferred. Adds a 50ms tick at the end of the loop to prevent
busy-spinning when polls are skipped.
* fix: TTL-based cleanup for turns and pending_approvals memory leak (#17)
Add created_at and last_activity timestamps to TurnState and created_at
to PendingApproval. Introduce TURN_TIMEOUT and APPROVAL_TTL constants
(300s each) and a Phase C cleanup pass in the main loop that evicts
stale entries, preventing unbounded HashMap growth.
Expired turns collect their IDs first, then retain removes them, and
finally Telegram API calls notify users — avoiding mutable borrow
conflicts during I/O (per Copilot review feedback). Turn timeout is
based on last_activity (updated on stream deltas and approval events)
so long-running turns with ongoing activity are not prematurely reaped.
Closes #4
* fix: check HTTP status codes and monitor IPC dropped messages (#14)
* fix: check HTTP status codes and monitor IPC dropped messages
Check envelope.status in parse_response before parsing Telegram JSON:
429 returns a clear rate-limit error, >=500 surfaces the server error
with a truncated body, and >=400 attempts to extract the Telegram error
description. Also log a warning when the IPC poll envelope reports
dropped messages so stale responses are visible in logs.
Closes #5, closes #7
* fix: UTF-8 safe truncation and shared unwrap_envelope helper
- Replace &envelope.body[..200] byte-slicing with chars().take(200)
to avoid panicking on multi-byte UTF-8 boundaries.
- Extract unwrap_envelope() helper that checks HTTP status (429, 5xx,
4xx) and returns the body string on success.
- Refactor both parse_response and edit_message_text to use the shared
helper, so edit_message_text now properly checks HTTP status too.
* fix: enum parsing, Capsule.toml bloat, link double-escape, dead code (#18)
- #6: Fix handle_elicitation_request — look for field_type as an object
with "Enum" key containing array instead of broken string equality
check; add !buttons.is_empty() guard
- #8: Trim Capsule.toml ipc_publish and ipc_subscribe to only the
topics the code actually uses (removed 11 unused topic patterns)
- #9: Add html_unescape helper in format.rs; unescape URL before
re-escaping for href to prevent double-escape; add tests
- #10: Remove unused session_id field from PendingApproval; remove
dead code in handle_final_response; add unit tests for
parse_allowed_users, is_user_allowed, new_session_id
* fix: address all findings from second code review (#19)
* fix: address all 18 findings from second code review
High:
- #17: Text elicitations now tracked in pending_elicitations map;
user text replies routed as elicit_response instead of new turn
Medium:
- #1: getUpdates switched from GET with unencoded query to POST with JSON body
- #4: Elicitation callbacks validated against pending_elicitations state
- #5: KV errors now logged as warnings instead of silently discarded
- #9: Graceful exit after 50 consecutive IPC poll errors
- #14: Callback data truncated to respect Telegram's 64-byte limit
- #16: Unconditional 50ms sleep now only runs during backoff
Low-Medium:
- #11: text_buffer capped at 256KB to prevent WASM OOM
- #7: uplink::register kept (kernel bookkeeping) with comment
- #13: net=[*] kept (kernel rejects URL patterns) with comment
Low:
- #10: Turn timeout uses collect+remove instead of double retain (TOCTOU fix)
- #18: Approval decision text now HTML-escaped
- Pending elicitation TTL cleanup added alongside approvals
* fix: address Copilot review feedback on PR #19
- Approval request_id truncated with floor_char_boundary (UTF-8 safe),
and pending_approvals keyed by the truncated id so lookups match
- IPC error counter reset on any Ok (including empty polls)
- Text buffer cap enforced strictly: partial append up to MAX_TEXT_BUFFER
* fix: address second Copilot review round
- Elicitation check moved before command parsing so /path replies work
- IPC publish failure re-inserts pending elicitation for retry
- Approval callback uses short token in callback_data but stores full
request_id in PendingApproval for correct IPC routing
- IPC error counter tracks per full pass, not per handle
- (Tests for new state machine deferred — needs IPC/KV mocking)
* fix: address third Copilot review round
- Approval/elicitation IPC publish failures now re-insert pending state
and notify user to retry (no more silent loss)
- Approval callback_data uses FNV hash token for long request_ids to
avoid prefix-collision risk; full request_id stored in PendingApproval
- IPC error counter tracks per full pass (all handles), not per handle
- Elicitation comment fixed to match skip behavior (not truncation)
- Added 4 tests for callback_token: short passthrough, long hashing,
distinct ids, and 64-byte callback_data fit
* fix: clone request_id before use in elicitation handler
Bind request_id before building payload/topic to avoid potential
ownership confusion (the json! macro borrows, but cloning makes
intent explicit and prevents future refactoring surprises).
* fix: use callback_token for elicitation callback_data too
Elicitation enum options now use the same FNV hash tokenization as
approvals, maximizing space for option values within the 64-byte
callback_data limit. Validation matches against both full id and token.
* fix: address round 6 Copilot feedback
- Log full_request_id (not callback token) in approval TTL cleanup
- Log full_id in elicitation publish failure
- Bump turn last_activity on elicit_request to prevent timeout during input
- Clarify FNV hash comment: not crypto-resistant, sufficient for transient tokens
* fix: hash request_ids containing colons, update callback format docs
Colons in request_ids would break splitn(3, ':') parsing. callback_token
now always hashes ids containing ':'. Updated format comment to reflect
token-based callback_data structure.
* fix: detect and log callback token hash collisions on insert
* refactor: rename APPROVAL_TTL to PENDING_INTERACTION_TTL
Now governs both approvals and elicitations, name should reflect that.
* docs: fix install command and add reinstall/purge notes
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#7)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#13)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#9)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#10)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#10)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#11)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#15)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#10)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#15)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#3)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#14)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#17)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#10)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#12)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#10)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#9)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#5)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* feat: migrate to SDK 0.6.0 (wasmtime Component Model + WIT-driven types) (#10)
## Summary
Migrate to astrid-sdk 0.6.0 targeting wasm32-wasip2 (Component Model).
- Remove `extism-pdk` dependency
- Update `astrid-sdk` to 0.6.0 (from crates.io)
- Migrate IPC APIs: `recv_bytes`/`poll_bytes` → typed `PollResult`
- Migrate `hooks::trigger(&[u8])` → `hooks::trigger(&str)`
- Migrate `log::log("level", msg)` → typed `log::info(msg)` etc.
- Add `[[topic]]` declarations to Capsule.toml where applicable
- Build target: wasm32-wasip2
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema with canonical wit refs (#12)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
cargo-like-manifest in the rfcs repo, parser support in
`unicity-astrid/astrid#713`):
* Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into
typed `[publish]` and `[subscribe]` tables.
* Replace `"TODO"` wit refs on resolvable topics with the canonical
`@unicity-astrid/wit/<noun>/<record>` path.
* Drop remaining TODOs onto newly-added canonical WIT refs where
applicable.
Other capabilities (sandboxing, fs/net allowlists) preserved verbatim.
No src changes — manifest-only, behaviour unchanged.
## Dependencies
* RFC: `unicity-astrid/rfcs#26` (cargo-like manifest schema).
* Parser: `unicity-astrid/astrid#713` (cargo-like manifest schema parser
in core). The kernel reads both legacy and new forms equivalently during
the migration window.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Capsule loads cleanly under a daemon running the
cargo-like-manifest parser PR.
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema with canonical wit refs (#13)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
cargo-like-manifest in the rfcs repo, parser support in
`unicity-astrid/astrid#713`):
* Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into
typed `[publish]` and `[subscribe]` tables.
* Replace `"TODO"` wit refs on resolvable topics with the canonical
`@unicity-astrid/wit/<noun>/<record>` path.
* Drop remaining TODOs onto newly-added canonical WIT refs where
applicable.
Other capabilities (sandboxing, fs/net allowlists) preserved verbatim.
No src changes — manifest-only, behaviour unchanged.
## Dependencies
* RFC: `unicity-astrid/rfcs#26` (cargo-like manifest schema).
* Parser: `unicity-astrid/astrid#713` (cargo-like manifest schema parser
in core). The kernel reads both legacy and new forms equivalently during
the migration window.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Capsule loads cleanly under a daemon running the
cargo-like-manifest parser PR.
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema with canonical wit refs (#11)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
cargo-like-manifest in the rfcs repo, parser support in
`unicity-astrid/astrid#713`):
* Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into
typed `[publish]` and `[subscribe]` tables.
* Replace `"TODO"` wit refs on resolvable topics with the canonical
`@unicity-astrid/wit/<noun>/<record>` path.
* Drop remaining TODOs onto newly-added canonical WIT refs where
applicable.
Other capabilities (sandboxing, fs/net allowlists) preserved verbatim.
No src changes — manifest-only, behaviour unchanged.
## Dependencies
* RFC: `unicity-astrid/rfcs#26` (cargo-like manifest schema).
* Parser: `unicity-astrid/astrid#713` (cargo-like manifest schema parser
in core). The kernel reads both legacy and new forms equivalently during
the migration window.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Capsule loads cleanly under a daemon running the
cargo-like-manifest parser PR.
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema with canonical wit refs (#11)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
cargo-like-manifest in the rfcs repo, parser support in
`unicity-astrid/astrid#713`):
* Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into
typed `[publish]` and `[subscribe]` tables.
* Replace `"TODO"` wit refs on resolvable topics with the canonical
`@unicity-astrid/wit/<noun>/<record>` path.
* Drop remaining TODOs onto newly-added canonical WIT refs where
applicable.
Other capabilities (sandboxing, fs/net allowlists) preserved verbatim.
No src changes — manifest-only, behaviour unchanged.
## Dependencies
* RFC: `unicity-astrid/rfcs#26` (cargo-like manifest schema).
* Parser: `unicity-astrid/astrid#713` (cargo-like manifest schema parser
in core). The kernel reads both legacy and new forms equivalently during
the migration window.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Capsule loads cleanly under a daemon running the
cargo-like-manifest parser PR.
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema with canonical wit refs (#18)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
cargo-like-manifest in the rfcs repo, parser support in
`unicity-astrid/astrid#713`):
* Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into
typed `[publish]` and `[subscribe]` tables.
* Replace `"TODO"` wit refs on resolvable topics with the canonical
`@unicity-astrid/wit/<noun>/<record>` path.
* Drop remaining TODOs onto newly-added canonical WIT refs where
applicable.
Other capabilities (sandboxing, fs/net allowlists) preserved verbatim.
No src changes — manifest-only, behaviour unchanged.
## Dependencies
* RFC: `unicity-astrid/rfcs#26` (cargo-like manifest schema).
* Parser: `unicity-astrid/astrid#713` (cargo-like manifest schema parser
in core). The kernel reads both legacy and new forms equivalently during
the migration window.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Capsule loads cleanly under a daemon running the
cargo-like-manifest parser PR.
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema with canonical wit refs (#16)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
cargo-like-manifest in the rfcs repo, parser support in
`unicity-astrid/astrid#713`):
* Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into
typed `[publish]` and `[subscribe]` tables.
* Replace `"TODO"` wit refs on resolvable topics with the canonical
`@unicity-astrid/wit/<noun>/<record>` path.
* Drop remaining TODOs onto newly-added canonical WIT refs where
applicable.
Other capabilities (sandboxing, fs/net allowlists) preserved verbatim.
No src changes — manifest-only, behaviour unchanged.
## Dependencies
* RFC: `unicity-astrid/rfcs#26` (cargo-like manifest schema).
* Parser: `unicity-astrid/astrid#713` (cargo-like manifest schema parser
in core). The kernel reads both legacy and new forms equivalently during
the migration window.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Capsule loads cleanly under a daemon running the
cargo-like-manifest parser PR.
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema with canonical wit refs (#11)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
cargo-like-manifest in the rfcs repo, parser support in
`unicity-astrid/astrid#713`):
* Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into
typed `[publish]` and `[subscribe]` tables.
* Replace `"TODO"` wit refs on resolvable topics with the canonical
`@unicity-astrid/wit/<noun>/<record>` path.
* Drop remaining TODOs onto newly-added canonical WIT refs where
applicable.
Other capabilities (sandboxing, fs/net allowlists) preserved verbatim.
No src changes — manifest-only, behaviour unchanged.
## Dependencies
* RFC: `unicity-astrid/rfcs#26` (cargo-like manifest schema).
* Parser: `unicity-astrid/astrid#713` (cargo-like manifest schema parser
in core). The kernel reads both legacy and new forms equivalently during
the migration window.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Capsule loads cleanly under a daemon running the
cargo-like-manifest parser PR.
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema with canonical wit refs (#11)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
cargo-like-manifest in the rfcs repo, parser support in
`unicity-astrid/astrid#713`):
* Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into
typed `[publish]` and `[subscribe]` tables.
* Replace `"TODO"` wit refs on resolvable topics with the canonical
`@unicity-astrid/wit/<noun>/<record>` path.
* Drop remaining TODOs onto newly-added canonical WIT refs where
applicable.
Other capabilities (sandboxing, fs/net allowlists) preserved verbatim.
No src changes — manifest-only, behaviour unchanged.
## Dependencies
* RFC: `unicity-astrid/rfcs#26` (cargo-like manifest schema).
* Parser: `unicity-astrid/astrid#713` (cargo-like manifest schema parser
in core). The kernel reads both legacy and new forms equivalently during
the migration window.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Capsule loads cleanly under a daemon running the
cargo-like-manifest parser PR.
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema with canonical wit refs (#10)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
cargo-like-manifest in the rfcs repo, parser support in
`unicity-astrid/astrid#713`):
* Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into
typed `[publish]` and `[subscribe]` tables.
* Replace `"TODO"` wit refs on resolvable topics with the canonical
`@unicity-astrid/wit/<noun>/<record>` path.
* Drop remaining TODOs onto newly-added canonical WIT refs where
applicable.
Other capabilities (sandboxing, fs/net allowlists) preserved verbatim.
No src changes — manifest-only, behaviour unchanged.
## Dependencies
* RFC: `unicity-astrid/rfcs#26` (cargo-like manifest schema).
* Parser: `unicity-astrid/astrid#713` (cargo-like manifest schema parser
in core). The kernel reads both legacy and new forms equivalently during
the migration window.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Capsule loads cleanly under a daemon running the
cargo-like-manifest parser PR.
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema with canonical wit refs (#14)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
cargo-like-manifest in the rfcs repo, parser support in
`unicity-astrid/astrid#713`):
* Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into
typed `[publish]` and `[subscribe]` tables.
* Replace `"TODO"` wit refs on resolvable topics with the canonical
`@unicity-astrid/wit/<noun>/<record>` path.
* Drop remaining TODOs onto newly-added canonical WIT refs where
applicable.
Other capabilities (sandboxing, fs/net allowlists) preserved verbatim.
No src changes — manifest-only, behaviour unchanged.
## Dependencies
* RFC: `unicity-astrid/rfcs#26` (cargo-like manifest schema).
* Parser: `unicity-astrid/astrid#713` (cargo-like manifest schema parser
in core). The kernel reads both legacy and new forms equivalently during
the migration window.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Capsule loads cleanly under a daemon running the
cargo-like-manifest parser PR.
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema with canonical wit refs (#12)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
`unicity-astrid/rfcs#26`, parser support in
`unicity-astrid/astrid#713`):
* Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into
typed `[publish]` and `[subscribe]` tables.
* Replace `"TODO"` wit refs on resolvable topics with the canonical
`@unicity-astrid/wit/<noun>/<record>` path.
* Canonicalise bare-name wit refs to the full `@unicity-astrid/wit/...`
form.
* Drop remaining TODOs onto newly-added canonical WIT refs.
Other capabilities preserved verbatim. No src changes — manifest-only,
behaviour unchanged.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Capsule loads cleanly under a daemon running the
cargo-like-manifest parser PR.
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema + restore on_before_prompt_build binding (#15)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
`unicity-astrid/rfcs#26`, parser support in
`unicity-astrid/astrid#713`), and restores the `on_before_prompt_build`
interceptor binding that was lost in a prior refactor.
* `chore: convert to Cargo-like [publish]/[subscribe] schema` — same
conversion as the rest of the capsule fleet.
* `fix(manifest): restore lost handler binding for
on_before_prompt_build` — the new schema does not auto-derive
interceptor bindings from a `subscribe` entry; this commit makes the
binding explicit so the handler keeps firing under the new schema.
* `chore: replace TODO wit refs with canonical @unicity-astrid/wit/...`
— canonical refs.
No src changes. The handler-binding restoration is critical: without it,
memory capsule silently stops participating in the prompt-build hook
chain after the manifest migration.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Manual: `on_before_prompt_build` fires for memory capsule under a
daemon running the cargo-like-manifest parser PR.
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema with canonical wit refs (#17)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
`unicity-astrid/rfcs#26`, parser support in
`unicity-astrid/astrid#713`):
* Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into
typed `[publish]` and `[subscribe]` tables.
* Replace `"TODO"` wit refs on resolvable topics with the canonical
`@unicity-astrid/wit/<noun>/<record>` path.
* Drop remaining TODOs onto newly-added canonical WIT refs.
Manifest-only, behaviour unchanged. Note: the existing PR #16
(`fix/payload-data-unwrap`) covers a separate src-side fix for the
`Custom { data }` unwrap pattern; this PR is purely manifest.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Capsule loads cleanly under a daemon running the
cargo-like-manifest parser PR.
* chore(manifest): convert to Cargo-like [publish]/[subscribe] schema with canonical wit refs (#13)
## Summary
Converts `Capsule.toml` to the new Cargo-like manifest schema (RFC:
`unicity-astrid/rfcs#26`, parser support in
`unicity-astrid/astrid#713`):
* Move legacy `[capabilities].ipc_publish` / `ipc_subscribe` arrays into
typed `[publish]` and `[subscribe]` tables.
* Replace `"TODO"` wit refs on resolvable topics with the canonical
`@unicity-astrid/wit/<noun>/<record>` path.
Manifest-only, behaviour unchanged. The src-side `Custom { data }`
unwrap fix is covered by the existing PR #11
(`fix/payload-data-unwrap`); this PR is purely manifest and
intentionally drops the duplicate src commit so review stays focused.
## Test plan
- [x] `cargo build --target wasm32-wasip1 --release`
- [x] Capsule loads cleanly under a daemon running the
cargo-like-manifest parser PR.
* chore(deps): bump astrid-sdk to 0.6.1 (#18)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#14)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#13)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#14)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#12)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#12)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#19)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#16)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#17)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#14)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#12)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#12)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#11)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#15)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* chore(deps): bump astrid-sdk to 0.6.1 (#13)
Bumps `astrid-sdk` dependency from 0.6.0 to 0.6.1.
Picks up:
- `ipc::publish_as` / `ipc::publish_json_as` (uplink principal
propagation, sdk-rust #37)
- Canonical-WIT-sourced contracts with per-interface `pub mod <iface>`
namespacing (sdk-rust #39)
- `cargo publish -p astrid-sys` fix (sdk-rust #36)
No source change required — `astrid-sdk` 0.6.1 is API-compatible at
every site this capsule touches.
* feat: initial scaffold of the users capsule
Implements astrid:users@1.0.0 over IPC RPC. Capsule subscribes to
users.v1.<op>.request and publishes users.v1.<op>.response for the
eight operations: resolve, link, unlink, create, links, get, delete,
list. Each request carries a source envelope (channel, user-id,
correlation-id) so multi-tenant uplinks (sphere, discord, telegram)
can route responses back to the originating end-user by correlation.
KV key layout mirrors the legacy kernel astrid-storage::identity
store byte-for-byte (user/{uuid}, link/{platform}/{id},
name/{display_name}) so the future kernel-side cutover
(unicity-astrid/astrid#747) reads existing records unchanged.
Internal layout:
- lib.rs — capsule entrypoint + IPC dispatchers
- types.rs — domain records (AstridUser, FrontendLink, Source)
- store.rs — KV-backed store + Backend substitution seam
- requests.rs — inbound payload structs (kebab + snake alias)
- responses.rs — outbound JSON projection (kebab-case)
- time.rs — RFC 3339 formatting via Hinnant civil_from_days
36 unit tests cover key validation (path traversal, null bytes),
upsert semantics, cascade delete, name-index last-writer-wins,
request envelope deserialization, and timestamp formatting.
Closes unicity-astrid/astrid#747 (capsule side; the kernel-side
deletions ship in a follow-up once SDK wrappers cut over).
* self-review: clarify storage-shape divergence + tidy list_users projection
- Document that the on-disk JSON shape diverges from the legacy kernel
store in three places (public_key as list<u8> vs base64; ms-precision
timestamps vs chrono's us-precision; AstridUser drops the redundant
principal field). Pre-launch with no records to migrate, the
divergences are deliberate — value layout follows the WIT contract,
not the kernel's Rust serialization. README + types.rs module
docstring carry the explanation; the earlier 'byte-for-byte' claim
was overstated.
- Replace the misleading filter_map on list_users with a direct map
via a new user_value helper. user_to_json(Some(u)) always returns
Some, so the filtering semantics never fired — latent bug if anyone
later changes user_to_json to drop partially-invalid records.
* fix: drop [patch.crates-io] — use published astrid-sdk 0.6.1
The local-worktree patch was inherited from peer capsules and pinned
astrid-sdk/astrid-sdk-macros/astrid-sys to absolute paths that only
exist on the original author's machine. CI, contributors, and anyone
else cloning the repo hit:
error: failed to load source for dependency `astrid-sdk`
Caused by: Unable to update /…/sdk-rust/astrid-sdk
Removing the patch makes Cargo resolve astrid-sdk = "0.6.1" from
crates.io (already the base dep). Verified: cargo build --release
--target wasm32-wasip1 pulls 0.6.1 cleanly; 36/36 unit tests pass;
clippy and fmt are clean.
* feat: implement expanded astrid:users@1.0.0 surface
Catches the capsule up to the merged WIT (unicity-astrid/wit#6):
- source.uplink (was source.channel) — disambiguates from
frontend-link.platform.
- frontend-link.platform_instance for Slack workspaces, IRC
networks, XMPP servers. KV key is now
link/{platform}/{instance|_}/{platform_user_id}, with _ as the
reserved sentinel for None.
- frontend-link.display_name — platform-side global name at link time.
- set_display_name + set_public_key topics for mutating AstridUser
fields without rotating the UUID.
- cursor/limit pagination on list_users and the two new context
list topics.
- Per-context display-name overlay (two-layer identity model):
ContextIdentity record + five users.v1.context.* topics
(set/clear/get/list_for_user/list_in_context). KV prefix is
context/{platform}/{instance|_}/{context_id}/{platform_user_id}.
- resolve becomes context-aware and returns a layered display name
in one round-trip (context > link > canonical).
- Cascade on unlink: drops every context overlay tied to the link.
- Cascade on delete_user: drops every link and overlay for that user.
src/store.rs grew to 734 lines; store tests moved to src/store_tests.rs
to stay under CI's 1000-line cap. 42 unit tests on the host target
cover: identity CRUD with instance scoping, mutation, layered resolve
fallback chain, context overlay CRUD, two cascade paths, pagination
across list_users / list_context_for_user, sentinel-reserved
validation. Wasm release: 255 KB, fmt + clippy clean on both wasm
and host.
* test: platform scenarios — Discord/Slack/Telegram/Matrix/X/IRC/Mastodon/Email/SMS/Nostr/Passkey/GitHub
Real-shape end-to-end tests against the data models of every platform
from the audit. Each test uses platform-realistic identifiers and
exercises the link → resolve → list-links path plus the
platform's distinguishing characteristic:
- Discord: 18-digit snowflakes + per-guild nickname layering
- Slack: workspace-scoped IDs (T/U pairs); same U-id in different
workspaces resolves to different humans; per-channel context
- Telegram: int64 user-ids; @username refresh via re-link
- Matrix: '@alice:server.org' federated IDs with no instance;
per-room display-name overlays
- X: numeric stable id, handle change via re-link
- IRC: per-network scoping ('alice' on libera vs oftc)
- Mastodon: '@alice@server.social' federated; no instance
- Email: globally-unique address
- SMS: E.164 phone numbers
- Nostr: npub-as-identity with public_key on AstridUser
- Passkey: credential-id link with public_key on AstridUser
- GitHub: numeric id stable, login change via re-link
Plus three group-setting cases:
- One human linked across six platforms; resolve from any returns
the same AstridUserId.
- Five-member Discord guild member roster via context.list_in_context,
paginated, every row resolves to a user.
- Bot-vs-human attribution via method='bot' audit string.
20 new tests, total now 62. Catches contract-level data-model
mismatches before any uplink consumes the WIT — closes the largest
gap in the earlier 'will this work 100%' caveats list.
* feat!: migrate to per-domain WIT + wasm32-unknown-unknown (#6)
## Summary
Migrate this capsule to:
1. The per-domain WIT host ABI introduced in `unicity-astrid/astrid#752`
(paired with `unicity-astrid/sdk-rust#44`).
2. `wasm32-unknown-unknown` as the canonical build target — zero
`wasi:*` imports, every host call routed through audited `astrid:*`
interfaces.
## Changes
- `.cargo/config.toml` — `target = "wasm32-unknown-unknown"` with
`--cfg=getrandom_backend="custom"` rustflag so `getrandom 0.4` picks up
the SDK's `__getrandom_v03_custom` extern (routes entropy through
`astrid:sys/host.random-bytes`).
- `rust-toolchain.toml` — `targets = ["wasm32-unknown-unknown"]`.
- `[patch.crates-io]` — points `astrid-sdk*` / `astrid-sys` /
`astrid-types` at the in-tree workspaces so the polyrepo cross-cuts
resolve.
- Call-site updates for the new typed-`error-code` SDK surface where
touched.
## Pairs with
- `unicity-astrid/astrid#752` — kernel-side migration
- `unicity-astrid/sdk-rust#44` — SDK migration
- All other `unicity-astrid/capsule-*` PRs on `feat/per-domain-wit`
## Test Plan
- [x] `cargo build --target wasm32-unknown-unknown --release` clean
- [x] `cargo clippy --release -- -D warnings` clean
- [x] Loads + runs under the migrated kernel — verified end-to-end via
`astrid run "say hi"`
* feat!: migrate to per-domain WIT + wasm32-unknown-unknown (#15)
## Summary
Migrate this capsule to:
1. The per-domain WIT host ABI introduced in `unicity-astrid/astrid#752`
(paired with `unicity-astrid/sdk-rust#44`).
2. `wasm32-unknown-unknown` as the canonical build target — zero
`wasi:*` imports, every host call routed through audited `astrid:*`
interfaces.
## Changes
- `.cargo/config.toml` — `target = "wasm32-unknown-unknown"` with
`--cfg=getrandom_backend="custom"` rustflag so `getrandom 0.4` picks up
the SDK's `__getrandom_v03_custom` extern (routes entropy through
`astrid:sys/host.random-bytes`).
- `rust-toolchain.toml` — `targets = ["wasm32-unknown-unknown"]`.
- `[patch.crates-io]` — points `astrid-sdk*` / `astrid-sys` /
`astrid-types` at the in-tree workspaces so the polyrepo cross-cuts
resolve.
- Call-site updates for the new typed-`error-code` SDK surface where
touched.
## Pairs with
- `unicity-astrid/astrid#752` — kernel-side migration
- `unicity-astrid/sdk-rust#44` — SDK migration
- All other `unicity-astrid/capsule-*` PRs on `feat/per-domain-wit`
## Test Plan
- [x] `cargo build --target wasm32-unknown-unknown --release` clean
- [x] `cargo clippy --release -- -D warnings` clean
- [x] Loads + runs under the migrated kernel — verified end-to-end via
`astrid run "say hi"`
* feat!: migrate to per-domain WIT + wasm32-unknown-unknown (#14)
## Summary
Migrate this capsule to:
1. The per-domain WIT host ABI introduced in `unicity-astrid/astrid#752`
(paired with `unicity-astrid/sdk-rust#44`).
2. `wasm32-unknown-unknown` as the canonical build target — zero
`wasi:*` imports, every host call routed through audited `astrid:*`
interfaces.
## Changes
- `.cargo/config.toml` — `target = "wasm32-unknown-unknown"` with
`--cfg=getrandom_backend="custom"` rustflag so `getrandom 0.4` picks up
the SDK's `__getrandom_v03_custom` extern (routes entropy through
`astrid:sys/host.random-bytes`).
- `rust-toolchain.toml` — `targets = ["wasm32-unknown-unknown"]`.
- `[patch.crates-io]` — points `astrid-sdk*` / `astrid-sys` /
`astrid-types` at the in-tree workspaces so the polyrepo cross-cuts
resolve.
- Call-site updates for the new typed-`error-code` SDK surface where
touched.
## Pairs with
- `unicity-astrid/astrid#752` — kernel-side migration
- `unicity-astrid/sdk-rust#44` — SDK migration
- All other `unicity-astrid/capsule-*` PRs on `feat/per-domain-wit`
## Test Plan
- [x] `cargo build --target wasm32-unknown-unknown --release` clean
- [x] `cargo clippy --release -- -D warnings` clean
- [x] Loads + runs under the migrated kernel — verified end-to-end via
`astrid run "say hi"`
* feat!: migrate to per-domain WIT + wasm32-unknown-unknown (#15)
## Summary
Migrate this capsule to:
1. The per-domain WIT host ABI introduced in `unicity-astrid/astrid#752`
(paired with `unicity-astrid/sdk-rust#44`).
2. `wasm32-unknown-unknown` as the canonical build target — zero
`wasi:*` imports, every host call routed through audited `astrid:*`
interfaces.
## Changes
- `.cargo/config.toml` — `target = "wasm32-unknown-unknown"` with
`--cfg=getrandom_backend="custom"` rustflag so `getrandom 0.4` picks up
the SDK's `__getrandom_v03_custom` extern (routes entropy through
`astrid:sys/host.random-bytes`).
- `rust-toolchain.toml` — `targets = ["wasm32-unknown-unknown"]`.
- `[patch.crates-io]` — points `astrid-sdk*` / `astrid-sys` /
`astrid-types` at the in-tree workspaces so the polyrepo cross-cuts
resolve.
- Call-site updates for the new typed-`error-code` SDK surface where
touched.
## Pairs with
- `unicity-astrid/astrid#752` — kernel-side migration
- `unicity-astrid/sdk-rust#44` — SDK migration
- All other `unicity-astrid/capsule-*` PRs on `feat/per-domain-wit`
## Test Plan
- [x] `cargo build --target wasm32-unknown-unknown --release` clean
- [x] `cargo clippy --release -- -D warnings` clean
- [x] Loads + runs under the migrated kernel — verified end-to-end via
`astrid run "say hi"`
* feat!: migrate to per-domain WIT + wasm32-unknown-unknown (#13)
## Summary
Migrate this capsule to:
1. The per-domain WIT host ABI introduced in `unicity-astrid/astrid#752`
(paired with `unicity-astrid/sdk-rust#44`).
2. `wasm32-unknown-unknown` as the canonical build target — zero
`wasi:*` imports, every host call routed through audited `astrid:*`
interfaces.
## Changes
- `.cargo/config.toml` — `target = "wasm32-unknown-unknown"` with
`--cfg=getrandom_backend="custom"` rustflag so `getrandom 0.4` picks up
the SDK's `__getrandom_v03_custom` extern (routes entropy through
`astrid:sys/host.random-bytes`).
- `rust-toolchain.toml` — `targets = ["wasm32-unknown-unknown"]`.
- `[patch.crates-io]` — points `astrid-sdk*` / `astrid-sys` /
`astrid-types` at the in-tree workspaces so the polyrepo cross-cuts
resolve.
- Call-site updates for the new typed-`error-code` SDK surface where
touched.
## Pairs with
- `unicity-astrid/astrid#752` — kernel-side migration
- `unicity-astrid/sdk-rust#44` — SDK migration
- All other `unicity-astrid/capsule-*` PRs on `feat/per-domain-wit`
## Test Plan
- [x] `cargo build --target wasm32-unknown-unknown --release` clean
- [x] `cargo clippy --release -- -D warnings` clean
- [x] Loads + runs under the migrated kernel — verified end-to-end via
`astrid run "say hi"`
* feat!: migrate to per-domain WIT + wasm32-unknown-unknown (#13)
## Summary
Migrate this capsule to:
1. The per-domain WIT host ABI introduced in `unicity-astrid/astrid#752`
(paired with `unicity-astrid/sdk-rust#44`).
2. `wasm32-unknown-unknown` as the canonical build target — zero
`wasi:*` imports, every host call routed through audited `astrid:*`
interfaces.
## Changes
- `.cargo/config.toml` — `target = "wasm32-unknown-unknown"` with
`--cfg=getrandom_backend="custom"` rustflag so `getrandom 0.4` picks up
the SDK's `__getrandom_v03_custom` extern (routes entropy through
`astrid:sys/host.random-bytes`).
- `rust-toolchain.toml` — `targets = ["wasm32-unknown-unknown"]`.
- `[patch.crates-io]` — points `astrid-sdk*` / `astrid-sys` /
`astrid-types` at the in-tree workspaces so the polyrepo cross-cuts
resolve.
- Call-site updates for the new typed-`error-code` SDK surface where
touched.
## Pairs with
- `unicity-astrid/astrid#752` — kernel-side migration
- `unicity-astrid/sdk-rust#44` — SDK migration
- All other `unicity-astrid/capsule-*` PRs on `feat/per-domain-wit`
## Test Plan
- [x] `cargo build --target wasm32-unknown-unknown --release` clean
- [x] `cargo clippy --release -- -D warnings` clean
- [x] Loads + runs under the migrated kernel — verified end-to-end via
`astrid run "say hi"`
* feat!: migrate to per-domain WIT + wasm32-unknown-unknown (#20)
## Summary
Migrate this capsule to:
1. The per-domain WIT host ABI introduced in `unicity-astrid/astrid#752`
(paired with `unicity-astrid/sdk-rust#44`).
2. `wasm32-unknown-unknown` as the canonical build target — zero
`wasi:*` imports, every host call routed through audited `astrid:*`
interfaces.
## Changes
- `.cargo/config.toml` — `target = "wasm32-unknown-unknown"` with
`--cfg=getrandom_backend="custom"` rustflag so `getrandom 0.4` picks up
the SDK's `__getrandom_v03_custom` extern (routes entropy through
`astrid:sys/host.random-bytes`).
- `rust-toolchain.toml` — `targets = ["wasm32-unknown-unknown"]`.
- `[patch.crates-io]` — points `astrid-sdk*` / `astrid-sys` /
`astrid-types` at the in-tree workspaces so the polyrepo cross-cuts
resolve.
- Call-site updates for the new typed-`error-code` SDK surface where
touched.
## Pairs with
- `unicity-astrid/astrid#752` — kernel-side migration
- `unicity-astrid/sdk-rust#44` — SDK migration
- All other `unicity-astrid/capsule-*` PRs on `feat/per-domain-wit`
## Test Plan
- [x] `cargo build --target wasm32-unknown-unknown --release` clean
- [x] `cargo clippy --release -- -D warnings` clean
- [x] Loads + runs under the migrated kernel — verified end-to-end via
`astrid run "say hi"`
* feat!: migrate to per-domain WIT + wasm32-unknown-unknown (#17)
## Summary
Migrate this capsule to:
1. The per-domain WIT host ABI introduced in `unicity-astrid/astrid#752`
(paired with `unicity-astrid/sdk-rust#44`).
2. `wasm32-unknown-unknown` as the canonical build target — zero
`wasi:*` imports, every host call routed through audited `astrid:*`
interfaces.
## Changes
- `.cargo/config.toml` — `target = "wasm32-unknown-unknown"` with
`--cfg=getrandom_backend="custom"` rustflag so `getrandom 0.4` picks up
the SDK's `__getrandom_v03_custom` extern (routes entropy through
`astrid:sys/host.random-bytes`).
- `rust-toolchain.toml` — `targets = ["wasm32-unknown-unknown"]`.
- `[patch.crates-io]` — points `astrid-sdk*` / `astrid-sys` /
`astrid-types` at the in-tree workspaces so the polyrepo cross-cuts
resolve.
- Call-site updates for the new typed-`error-code` SDK surface where
touched.
## Pairs with
- `unicity-astrid/astrid#752` — kernel-side migration
- `unicity-astrid/sdk-rust#44` — SDK migration
- All other `unicity-astrid/capsule-*` PRs on `feat/per-domain-wit`
## Test Plan
- [x] `cargo build --target wasm32-unknown-unknown --release` clean
- [x] `cargo clippy --release -- -D warnings` clean
- [x] Loads + runs under the migrated kernel — verified end-to-end via
`astrid run "say hi"`
* feat!: migrate to per-domain WIT + wasm32-unknown-unknown (#4)
## Summary
Migrate this capsule to:
1. The per-domain WIT host ABI introduced in `unicity-astrid/astrid#752`
(paired with `unicity-astrid/sdk-rust#44`).
2. `wasm32-unknown-unknown` as the canonical build target — zero
`wasi:*` imports, every host call routed through audited `astrid:*`
interfaces.
## Changes
- `.cargo/config.toml` — `target = "wasm32-unknown-unknown"` with
`--cfg=getrandom_backend="custom"` rustflag so `getrandom 0.4` picks up
the SDK's `__getrandom_v03_custom` extern (routes entropy through
`astrid:sys/host.random-bytes`).
- `rust-toolchain.toml` — `targets = ["wasm32-unknown-unknown"]`.
- `[patch.crates-io]` — points `astrid-sdk*` / `astrid-sys` /
`astrid-types` at the in-tree workspaces so the polyrepo cross-cuts
resolve.
- Call-site updates for the new typed-`error-code` SDK surface where
touched.
## Pairs with
- `unicity-astrid/astrid#752` — kernel-side migration
- `unicity-astrid/sdk-rust#44` — SDK migration
- All other `unicity-astrid/capsule-*` PRs on `feat/per-domain-wit`
## Test Plan
- [x] `cargo build --target wasm32-unknown-unknown --release` clean
- [x] `cargo clippy --release -- -D warnings` clean
- [x] Loads + runs under the migrated kernel — verified end-to-end via
`astrid run "say hi"`
* feat!: migrate to per-domain WIT + wasm32-unknown-unknown (#18)
## Summary
Migrate this capsule to:
1. The per-domain WIT host ABI introduced in `unicity-astrid/astrid#752`
(paired with `unicity-astrid/sdk-rust#44`).
2. `wasm32-unknown-unknown` as the canonical build target — zero
`wasi:*` imports, every host call routed through audited `astrid:*`
interfaces.
## Changes
- `.cargo/config.toml` — `target = "wasm32-unknown-unknown"` with
`--cfg=getrandom_backend="custom"` rustflag so `getrandom 0.4` picks up
the SDK's `__getrandom_v03_custom` extern (routes entropy through
`astrid:sys/host.random-bytes`).
- `rust-toolchain.toml` — `targets = ["wasm32-unknown-unknown"]`.
- `[patch.crates-io]` — points `astrid-sdk*` / `astrid-sys` /
`astrid-types` at the in-tree workspaces so the polyrepo cross-cuts
resolve.
- Call-site updates for the new typed-`error-code` SDK surface where
touched.
## Pairs with
- `unicity-astrid/astrid#752` — kernel-side migration
- `unicity-astrid/sdk-rust#44` — SDK migration
- All other `unicity-astrid/capsule-*` PRs on `feat/per-domain-wit`
## Test Plan
- [x] `cargo build --target wasm32-unknown-unknown --release` clean
- [x] `cargo clippy --release -- -D warnings` clean
- [x] Loads + runs under the migrated kernel — verified end-to-end via
`astrid run "say hi"`
* feat!: migrate to per-domain WIT + wasm32-unknown-unknown (#15)
## Summary
Migrate this capsule to:
1. The per-domain WIT host ABI introduced in `unicity-astrid/astrid#752`
(paired with `unicity-astrid/sdk-rust#44`).
2. `wasm32-unknown-unknown` as the canonical build target — zero
`wasi:*` imports, every host call routed through audited `astrid:*`
interfaces.
## Changes
- `.cargo/config.toml` — `target = "wasm32-unknown-unknown"` with
`--cfg=getrandom_backend="custom"` rustflag so `getrandom 0.4` picks up
the SDK's `__getrandom_v03_custom` extern (routes entropy through
`astrid:sys/host.random-bytes`).
- `rust-toolchain.toml` — `targets = ["wasm32-unknown-unknown"]`.
- `[patch.crates-io]` — points `astrid-sdk*` / `astrid-sys` /
`astrid-types` at the in-tree workspaces so the polyrepo cross-cuts
resolve.
- Call-site updates for the new typed-`error-code` SDK surface where
touched.
## Pairs with
- `unicity-astrid/astrid#752` — kernel-side migration
- `unicity-astrid/sdk-rust#44` — SDK migration
- All other `unicity-astrid/capsule-*` PRs on `feat/per-domain-wit`
## Test Plan
- [x] `cargo build --target wasm32-unknown-unknown --release` clean
- [x] `cargo clippy --release -- -D warnings` clean
- [x] Loads + runs under the migrated kernel — verified end-to-end via
`astrid run "say hi"`
* feat!: migrate to per-domain WIT + wasm32-unknown-unknown (#19)
## Summary
Migrate this capsule to:
1. The per-domain WIT host ABI introduced in `unicity-astrid/astrid#752`
(paired with `unicity-astrid/sdk-rust#44`).
2. `wasm32-unknown-unknown` as the canonical build target — zero
`wasi:*` imports, every host call routed through audited `astrid:*`
interfaces.
## Changes
- `.cargo/config.toml` — `target = "wasm32-unknown-unknown"` with
`--cfg=getrandom_backend="custom"` rustflag so `getrandom 0.4` picks up
the SDK's `__getrandom_v03_custom` extern (routes entropy through
`astrid:sys/host.random-bytes`).
- `rust-toolchain.toml` — `targets = ["wasm32-unknown-unknown"]`.
- `[patch.crates-io]` — points `astrid-sdk*` / `astrid-sys` /
`astrid-types` at the in-tree workspaces so the polyrepo cross-cuts
resolve.
- Call-site updates for the new typed-`error-code` SDK surface where
touched.
## Pairs with
- `unicity-astrid/astrid#752` — kernel-side migration
- `unicity-astrid/sdk-rust#44` — SDK migration
- All other `unicity-astrid/capsule-*` PRs on `feat/per-domain-wit`
## Test Plan
- [x] `cargo build --target wasm32-unknown-unknown --release` clean
- [x] `cargo clippy --release -- -D warnings` clean
- [x] Loads + runs under the migrated kernel — verified end-to-end via
`astrid run "say hi"`
* feat!: migrate to per-domain WIT + wasm32-unknown-unknown (#14)
## Summary
Migrate this capsule to:
1. The per-domain WIT host ABI introduced in `unicity-astrid/astrid#752`
(paired with `unicity-astrid/sdk-rust#44`).
2. `wasm32-unknown-unknown` as the canonical build target — zero
`wasi:*` imports, every host call routed through audited `astrid:*`
interfaces.
## Changes
- `.cargo/config.toml` — `target = "wasm32-unkn…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces the v0.5
Capsule.tomltopic surfaces with one Cargo-shaped declaration. Solves four problems that surfaced during the wasmtime migration:[[topic]]/[capabilities].ipc_*/[[interceptor]]). Drift between them is silent and the parser tolerates partial declarations.[[topic]].directionis serde-required without a default — every capsule manifest onmainthat omits it fails to install on a fresh checkout. Five chat-stack capsules carry local "add direction" patches.[[topic]].descriptionis capsule-author-controlled prose that reaches LLM context in some pipelines — a structural prompt-injection vector.wit_type) are optional and rarely populated — most cross-capsule topics travel as untyped JSON.This RFC introduces:
[publish]/[subscribe]tables — one entry per topic, requiredwit = "@scope/repo/iface/record"reference,handler = "..."binds to#[astrid::interceptor("...")]exports.[exports]/[imports]with quoted"<namespace>:<interface>"keys.[[tool]] description_for_llm— the only capsule-author-controlled string that reaches the LLM, operator-reviewed verbatim at install.Capsule.lockpinning resolved git SHAs + BLAKE3 content hashes for reproducible installs.unicity-astrid/registry— one TOML per published package) with semver resolution + direct-ref escape hatches (rev/tag/branch/path).wit = \"opaque\"for legitimate heterogeneous-wildcard uplink/proxy capsules.Replaces / supersedes
This RFC overlaps the surface of #20 (capsule interface system). #20 documented the v0.5 `[exports]` / `[imports]` design; this RFC supersedes that surface and extends to the topic / lockfile / registry layers. If both land, #20 should be closed in favour of this one (or rebased to document the v0.5 history only).
In-flight implementation pieces (referenced; not part of this RFC)
Verification done
Reading order
The RFC document under `text/0000-cargo-like-manifest.md` is structured per the repo template:
Discussion notes
Threads worth surfacing on this PR rather than burying in a tracking issue: