IPC and A2A Messaging
Kernel IPC message envelopes, MessageTarget variants, MessagePayload types, A2A routing, GlobalPid for cross-node addressing, and request-response patterns.
WeftOS IPC provides typed message envelopes over the existing MessageBus from clawft-core. The KernelIpc subsystem adds PID-based routing, agent-to-agent delivery with capability checks, and pub/sub topic routing.
Source: crates/clawft-kernel/src/ipc.rs (~470 lines, 18 tests), crates/clawft-kernel/src/a2a.rs (~870 lines, 28 tests)
KernelMessage Envelope
Every message in the kernel IPC system is wrapped in a KernelMessage:
pub struct KernelMessage {
pub id: String,
pub from: Pid,
pub target: MessageTarget,
pub payload: MessagePayload,
pub correlation_id: Option<String>,
pub timestamp: DateTime<Utc>,
}MessageTarget Variants
pub enum MessageTarget {
/// Send to a specific process by PID.
Process(Pid),
/// Publish to a named topic (all subscribers receive).
Topic(String),
/// Broadcast to all processes.
Broadcast,
/// Send to a named service (routed via ServiceRegistry).
Service(String),
/// Send to a specific method on a named service (K2.1, D19).
ServiceMethod { service: String, method: String },
/// Send to the kernel itself.
Kernel,
/// Route to a specific process on a remote node (K6).
RemoteNode { node_id: String, target: Box<MessageTarget> },
}The Service and ServiceMethod variants (K2.1 Symposium D19) support service-oriented routing through the ServiceRegistry. The RemoteNode variant (K6) wraps an inner MessageTarget with a remote node ID for cross-node messaging.
MessagePayload Variants
pub enum MessagePayload {
Text(String),
Json(serde_json::Value),
ToolCall { name: String, args: serde_json::Value },
ToolResult { call_id: String, result: serde_json::Value },
Signal(KernelSignal),
Rvf { segment_type: u8, data: Vec<u8> },
}
pub enum KernelSignal {
Shutdown, Suspend, Resume, Custom(String),
}A2ARouter Routing Flow
Agent A Agent B
| |
| send(msg) |
|-------> A2ARouter |
| | |
| | 1. Resolve target |
| | Process(pid) -> look up inbox |
| | Service(name) -> resolve via registry|
| | Topic(name) -> fan out to subs |
| | Broadcast -> all inboxes |
| | RemoteNode -> mesh transport (K6) |
| | |
| | 2. Capability check (send_checked) |
| | Validate sender IpcScope |
| | |
| | 3. [exochain] Routing gate check |
| | GovernanceGate::check() |
| | Deny -> error to sender |
| | |
| | 4. Deliver to inbox |
| +--------------------------------------> |
| |
| reply(correlation_id) |
|<----------------------------------------------------A2ARouter Public API
impl A2ARouter {
pub fn new() -> Self;
pub fn register(&self, pid: Pid, sender: mpsc::Sender<KernelMessage>);
pub fn unregister(&self, pid: Pid);
pub fn send(&self, msg: KernelMessage) -> Result<(), IpcError>;
pub fn send_checked(&self, msg: KernelMessage, caps: &AgentCapabilities)
-> Result<(), IpcError>;
pub fn broadcast(&self, msg: KernelMessage) -> usize;
}GlobalPid
For cross-node addressing (K6):
pub struct GlobalPid {
pub node_id: String,
pub pid: Pid,
}
// Display format: "node_id:pid" (e.g., "abc123:42")Request-Response Pattern
WeftOS IPC supports request-response via correlation_id. Agent A sends a message with a unique id. Agent B replies with correlation_id: Some(original_id). Agent A matches the reply.
Topic Pub/Sub
The TopicRouter (crates/clawft-kernel/src/topic.rs, ~360 lines, 14 tests):
impl TopicRouter {
pub fn subscribe(&self, topic: &str, subscriber_id: Pid) -> Subscription;
pub fn unsubscribe(&self, subscription_id: &str);
pub fn publish(&self, topic: &str, message: KernelMessage) -> usize;
pub fn list_topics(&self) -> Vec<String>;
}Chain Logging
When exochain is enabled, IPC events are logged:
| Event Kind | Trigger |
|---|---|
ipc.send | Message sent via A2ARouter |
ipc.recv | Message received by agent loop |
ipc.ack | Message processed by agent loop |
Built-in Agent Loop Commands
The kernel agent loop (crates/clawft-kernel/src/agent_loop.rs) processes:
| Command | Gate Action | Description |
|---|---|---|
suspend | -- | Pause the agent |
resume | -- | Resume a paused agent |
exec | "tool.exec" | Execute a tool (gate checked) |
cron.add | "service.cron.add" | Register a cron job |
cron.remove | "service.cron.remove" | Remove a cron job |