pub trait IpcCommand:
Serialize
+ Send
+ 'static {
type Response: Serialize + DeserializeOwned + Send;
// Required methods
fn name(&self) -> String;
fn handle(&mut self) -> impl Future<Output = Self::Response> + Send;
fn apply_args(&mut self, params: &[u8]) -> Result<(), Error>;
// Provided methods
fn positional_args(&self) -> Cow<'static, [Cow<'static, str>]> { ... }
fn stdin_arg(&self) -> Option<Cow<'static, str>> { ... }
fn set_method_name(&mut self, _name: &str) { ... }
}Expand description
A type-safe IPC command with its handler
Users implement this trait to define commands that can be called from sandboxed processes.
The command struct contains the request data, and the handle method processes it.
§Example
use std::borrow::Cow;
use serde::{Serialize, Deserialize};
use heel::ipc::IpcCommand;
#[derive(Clone, Serialize, Deserialize)]
struct SearchCommand {
query: String,
}
#[derive(Serialize, Deserialize)]
struct SearchResult {
items: Vec<String>,
}
impl IpcCommand for SearchCommand {
type Response = SearchResult;
fn name(&self) -> String {
"search".to_string()
}
fn positional_args(&self) -> Cow<'static, [Cow<'static, str>]> {
Cow::Borrowed(&[Cow::Borrowed("query")]) // Enables: search "rust" → search --query "rust"
}
fn apply_args(&mut self, params: &[u8]) -> Result<(), rmp_serde::decode::Error> {
*self = rmp_serde::from_slice(params)?;
Ok(())
}
async fn handle(&mut self) -> SearchResult {
let results = do_search(&self.query).await;
SearchResult { items: results }
}
}Required Associated Types§
Sourcetype Response: Serialize + DeserializeOwned + Send
type Response: Serialize + DeserializeOwned + Send
The response type returned by this command
Required Methods§
Sourcefn name(&self) -> String
fn name(&self) -> String
Command name for wire protocol dispatch
This name is used to route incoming requests to the correct handler.
Sourcefn handle(&mut self) -> impl Future<Output = Self::Response> + Send
fn handle(&mut self) -> impl Future<Output = Self::Response> + Send
Handle this command and produce a response
The handler has mutable access to the command data, allowing it to modify state if needed during processing.
Sourcefn apply_args(&mut self, params: &[u8]) -> Result<(), Error>
fn apply_args(&mut self, params: &[u8]) -> Result<(), Error>
Apply arguments from serialized params to this command.
The router calls this after cloning the command to apply request-specific arguments while preserving stateful data (registries, connections, etc.).
§Errors
Returns an error if the params cannot be applied.
Provided Methods§
Sourcefn positional_args(&self) -> Cow<'static, [Cow<'static, str>]>
fn positional_args(&self) -> Cow<'static, [Cow<'static, str>]>
Positional argument names for CLI conversion.
Returns a list of argument names that map to positional arguments in order. The wrapper script converts positional args to named args:
["query"]→command "foo"becomescommand --query "foo"["subagent", "prompt"]→command research "task"becomescommand --subagent research --prompt "task"
Returns empty slice by default (no positional argument conversion).
Sourcefn stdin_arg(&self) -> Option<Cow<'static, str>>
fn stdin_arg(&self) -> Option<Cow<'static, str>>
Stdin argument name for piped input.
When set, the wrapper script will capture stdin and pass it as this argument:
cat file | command "prompt" → heel ipc command --<stdin_arg> "<stdin>" --<primary_arg> "prompt"
Returns None by default (stdin is ignored).
Sourcefn set_method_name(&mut self, _name: &str)
fn set_method_name(&mut self, _name: &str)
Set the method name on the command after deserialization.
This is called by the router after deserializing the command from IPC params. Override this if your command needs the method name (e.g., for dispatching to different handlers based on the method name).
Default implementation does nothing.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.