clawft

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 KindTrigger
ipc.sendMessage sent via A2ARouter
ipc.recvMessage received by agent loop
ipc.ackMessage processed by agent loop

Built-in Agent Loop Commands

The kernel agent loop (crates/clawft-kernel/src/agent_loop.rs) processes:

CommandGate ActionDescription
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

On this page