Skip to main content

astrid_sys/
lib.rs

1//! Raw FFI bindings for the Astrid OS System API (The Airlocks).
2//!
3//! This crate defines the absolute lowest-level, mathematically pure ABI.
4//! Every single parameter and return type across the WASM boundary is
5//! represented as raw bytes (`Vec<u8>`).
6//!
7//! This provides true OS-level primitiveness: file paths can contain non-UTF-8
8//! sequences, IPC topics can be binary hashes, and the Kernel never wastes CPU
9//! validating string encodings. All ergonomic serialization is handled entirely
10//! by the `astrid-sdk` User-Space layer.
11
12#![allow(unsafe_code)]
13#![allow(missing_docs)]
14#![deny(clippy::all)]
15#![deny(unreachable_pub)]
16#![deny(clippy::unwrap_used)]
17#![cfg_attr(test, allow(clippy::unwrap_used))]
18
19#[allow(clippy::wildcard_imports)]
20use extism_pdk::*;
21
22#[host_fn]
23extern "ExtismHost" {
24    // -----------------------------------------------------------------------
25    // File System (VFS) Operations
26    // -----------------------------------------------------------------------
27    /// Check if a VFS path exists.
28    pub fn astrid_fs_exists(path: Vec<u8>) -> Vec<u8>;
29    /// Create a directory in the VFS.
30    pub fn astrid_fs_mkdir(path: Vec<u8>);
31    /// Read a directory in the VFS.
32    pub fn astrid_fs_readdir(path: Vec<u8>) -> Vec<u8>;
33    /// Get stats for a VFS path.
34    pub fn astrid_fs_stat(path: Vec<u8>) -> Vec<u8>;
35    /// Delete a file or directory in the VFS.
36    pub fn astrid_fs_unlink(path: Vec<u8>);
37
38    /// Read a file's contents from the VFS.
39    pub fn astrid_read_file(path: Vec<u8>) -> Vec<u8>;
40    /// Write contents to a file in the VFS.
41    pub fn astrid_write_file(path: Vec<u8>, content: Vec<u8>);
42
43    // -----------------------------------------------------------------------
44    // Inter-Process Communication (Message Bus & Uplinks)
45    // -----------------------------------------------------------------------
46    /// Publish a message to the OS event bus.
47    pub fn astrid_ipc_publish(topic: Vec<u8>, payload: Vec<u8>);
48    /// Subscribe to a topic on the OS event bus.
49    pub fn astrid_ipc_subscribe(topic: Vec<u8>) -> Vec<u8>;
50    /// Unsubscribe from the OS event bus.
51    pub fn astrid_ipc_unsubscribe(handle: Vec<u8>);
52    /// Poll for the next message on an IPC subscription handle.
53    pub fn astrid_ipc_poll(handle: Vec<u8>) -> Vec<u8>;
54    /// Block until a message arrives on an IPC subscription handle, or timeout.
55    pub fn astrid_ipc_recv(handle: Vec<u8>, timeout_ms: Vec<u8>) -> Vec<u8>;
56
57    /// Register a direct uplink (frontend).
58    pub fn astrid_uplink_register(name: Vec<u8>, platform: Vec<u8>, profile: Vec<u8>) -> Vec<u8>;
59    /// Send a message via a direct uplink.
60    pub fn astrid_uplink_send(
61        uplink_id: Vec<u8>,
62        platform_user_id: Vec<u8>,
63        content: Vec<u8>,
64    ) -> Vec<u8>;
65
66    // -----------------------------------------------------------------------
67    // Storage & Configuration
68    // -----------------------------------------------------------------------
69    /// Get a value from the KV store.
70    pub fn astrid_kv_get(key: Vec<u8>) -> Vec<u8>;
71    /// Set a value in the KV store.
72    pub fn astrid_kv_set(key: Vec<u8>, value: Vec<u8>);
73    /// Delete a value from the KV store.
74    pub fn astrid_kv_delete(key: Vec<u8>);
75    /// List keys matching a prefix in the KV store. Returns JSON array of strings.
76    pub fn astrid_kv_list_keys(prefix: Vec<u8>) -> Vec<u8>;
77    /// Delete all keys matching a prefix. Returns JSON count of deleted keys.
78    pub fn astrid_kv_clear_prefix(prefix: Vec<u8>) -> Vec<u8>;
79
80    /// Get a system configuration string.
81    pub fn astrid_get_config(key: Vec<u8>) -> Vec<u8>;
82    /// Get the user ID and session ID that invoked the current execution context.
83    pub fn astrid_get_caller() -> Vec<u8>;
84
85    // -----------------------------------------------------------------------
86    // Network (Sockets & Streams)
87    // -----------------------------------------------------------------------
88    /// Bind a Unix Domain Socket and return a listener handle.
89    pub fn astrid_net_bind_unix(path: Vec<u8>) -> Vec<u8>;
90    /// Accept an incoming connection on a bound Unix listener handle. Returns a stream handle.
91    pub fn astrid_net_accept(listener_handle: Vec<u8>) -> Vec<u8>;
92    /// Read bytes from a stream handle.
93    pub fn astrid_net_read(stream_handle: Vec<u8>) -> Vec<u8>;
94    /// Write bytes to a stream handle.
95    pub fn astrid_net_write(stream_handle: Vec<u8>, data: Vec<u8>);
96    /// Close a stream handle, releasing its resources on the host.
97    pub fn astrid_net_close_stream(stream_handle: Vec<u8>);
98    /// Non-blocking accept: returns a stream handle if a connection is pending, or empty bytes.
99    pub fn astrid_net_poll_accept(listener_handle: Vec<u8>) -> Vec<u8>;
100
101    // -----------------------------------------------------------------------
102    // General System (Network, Logging, & Scheduling)
103    // -----------------------------------------------------------------------
104    /// Issue an HTTP request.
105    pub fn astrid_http_request(request_bytes: Vec<u8>) -> Vec<u8>;
106    /// Log a message to the OS journal.
107    pub fn astrid_log(level: Vec<u8>, message: Vec<u8>);
108    /// Schedule a dynamic cron job to trigger the capsule later.
109    pub fn astrid_cron_schedule(name: Vec<u8>, schedule: Vec<u8>, payload: Vec<u8>);
110    /// Cancel a dynamic cron job.
111    pub fn astrid_cron_cancel(name: Vec<u8>);
112    /// Trigger a hook event and wait for its synchronous result.
113    pub fn astrid_trigger_hook(event_bytes: Vec<u8>) -> Vec<u8>;
114
115    // -----------------------------------------------------------------------
116    // Clock
117    // -----------------------------------------------------------------------
118    /// Get the current wall-clock time as milliseconds since the UNIX epoch.
119    pub fn astrid_clock_ms() -> Vec<u8>;
120
121    // -----------------------------------------------------------------------
122    // Lifecycle (Install & Upgrade Elicitation)
123    // -----------------------------------------------------------------------
124    /// Elicit user input during install/upgrade. Request is JSON-encoded.
125    /// Returns JSON: `{"ok":true}` for secrets, `{"value":"..."}` for text/select,
126    /// or `{"values":["..."]}` for arrays.
127    /// On user cancellation or host error, returns an Extism error (not JSON),
128    /// which surfaces as `SysError::HostError` in the SDK layer.
129    pub fn astrid_elicit(request: Vec<u8>) -> Vec<u8>;
130    /// Check whether a secret has been configured (without reading it).
131    /// Takes JSON: `{"key":"..."}`, returns JSON: `{"exists":true/false}`.
132    pub fn astrid_has_secret(request: Vec<u8>) -> Vec<u8>;
133
134    // -----------------------------------------------------------------------
135    // Approval (Capsule-Level Approval Requests)
136    // -----------------------------------------------------------------------
137    /// Request human approval for a sensitive action.
138    /// Takes JSON: `{"action":"...","resource":"...","risk_level":"..."}`.
139    /// Returns JSON: `{"approved":true/false,"decision":"..."}`.
140    /// Blocks the WASM guest until the frontend responds or timeout.
141    pub fn astrid_request_approval(request: Vec<u8>) -> Vec<u8>;
142
143    // -----------------------------------------------------------------------
144    // Host Execution (The Escape Hatch)
145    // -----------------------------------------------------------------------
146    /// Spawn a native host process. Requires the `host_process` capability.
147    pub fn astrid_spawn_host(cmd_and_args_json: Vec<u8>) -> Vec<u8>;
148
149    // -----------------------------------------------------------------------
150    // Readiness Signaling
151    // -----------------------------------------------------------------------
152    /// Signal that the capsule's run loop is ready (subscriptions are active).
153    pub fn astrid_signal_ready();
154
155    // -----------------------------------------------------------------------
156    // Interceptor Handles (Run-Loop Auto-Subscribe)
157    // -----------------------------------------------------------------------
158    /// Query auto-subscribed interceptor handle mappings.
159    /// Returns JSON array of `{handle_id, action, topic}` objects.
160    pub fn astrid_get_interceptor_handles() -> Vec<u8>;
161
162    // -----------------------------------------------------------------------
163    // Identity (Platform User Resolution)
164    // -----------------------------------------------------------------------
165    /// Resolve a platform user to an Astrid user.
166    /// Takes JSON: `{"platform":"...","platform_user_id":"..."}`.
167    /// Returns JSON: `{"found":true/false,"user_id":"...","display_name":"..."}`.
168    pub fn astrid_identity_resolve(request: Vec<u8>) -> Vec<u8>;
169    /// Link a platform identity to an Astrid user.
170    /// Takes JSON: `{"platform":"...","platform_user_id":"...","astrid_user_id":"...","method":"..."}`.
171    /// Returns JSON: `{"ok":true/false,...}`.
172    pub fn astrid_identity_link(request: Vec<u8>) -> Vec<u8>;
173    /// Unlink a platform identity from its Astrid user.
174    /// Takes JSON: `{"platform":"...","platform_user_id":"..."}`.
175    /// Returns JSON: `{"ok":true/false,"removed":true/false}`.
176    pub fn astrid_identity_unlink(request: Vec<u8>) -> Vec<u8>;
177    /// Create a new Astrid user.
178    /// Takes JSON: `{"display_name":"..."}` (display_name is optional).
179    /// Returns JSON: `{"ok":true/false,"user_id":"..."}`.
180    pub fn astrid_identity_create_user(request: Vec<u8>) -> Vec<u8>;
181    /// List all platform links for an Astrid user.
182    /// Takes JSON: `{"astrid_user_id":"..."}`.
183    /// Returns JSON: `{"ok":true/false,"links":[...]}`.
184    pub fn astrid_identity_list_links(request: Vec<u8>) -> Vec<u8>;
185
186    // -----------------------------------------------------------------------
187    // Cross-Capsule Capability Checks
188    // -----------------------------------------------------------------------
189    /// Check whether a capsule (identified by session UUID) has a specific
190    /// manifest capability. Takes JSON: `{"source_uuid":"...","capability":"..."}`.
191    /// Returns JSON: `{"allowed":true/false}`.
192    pub fn astrid_check_capsule_capability(request: Vec<u8>) -> Vec<u8>;
193
194    // -----------------------------------------------------------------------
195    // Background Process Management
196    // -----------------------------------------------------------------------
197    /// Spawn a background host process. Returns JSON: `{"id": <handle>}`.
198    /// The process runs in the host sandbox with piped stdout/stderr.
199    pub fn astrid_spawn_background_host(request: Vec<u8>) -> Vec<u8>;
200    /// Read buffered stdout/stderr from a background process.
201    /// Returns JSON: `{"stdout":"...","stderr":"...","running":bool,"exit_code":int|null}`.
202    pub fn astrid_read_process_logs_host(request: Vec<u8>) -> Vec<u8>;
203    /// Terminate a background process and clean up resources.
204    /// Returns JSON: `{"killed":bool,"exit_code":int|null,"stdout":"...","stderr":"..."}`.
205    pub fn astrid_kill_process_host(request: Vec<u8>) -> Vec<u8>;
206}