> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arupa.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Messages

> Send synchronous point-to-point messages between running plugins.

Messages provide synchronous, point-to-point communication between
plugins running in the same Kernel. A sending plugin names one target plugin,
sends a topic and a byte payload, and waits for the target to return a reply.

Use messages when one plugin needs another plugin to perform an
operation or return data. Use [KV storage](./ipc-kv) when the data should be
shared as state instead of delivered as a request.

## Message envelope

The message is the Protobuf `PluginMessage` defined by the [Protobuf](../proto) contract:

| Field     | Protobuf type | Meaning                                                 |
| --------- | ------------- | ------------------------------------------------------- |
| `source`  | `string`      | Name of the sending plugin. The Kernel sets this value. |
| `target`  | `string`      | Name of the plugin that must receive the message.       |
| `topic`   | `string`      | Application-defined operation or message type.          |
| `payload` | `bytes`       | Application-defined request data.                       |

The target receives a `PluginMessageReply`:

| Field     | Protobuf type | Meaning                                                              |
| --------- | ------------- | -------------------------------------------------------------------- |
| `error`   | `string`      | Error reported by the target. A non-empty value makes the send fail. |
| `message` | `string`      | Application-defined response text or serialized result.              |

The Kernel does not interpret `topic`, `payload`, or `message`. Define their
format between the participating plugins. You can use JSON, Protobuf, text,
or another encoding, but the sender and target must agree on it.

## Send a message

To send a message:

1. choose the registered name of the target plugin;
2. choose a stable topic name;
3. encode the request into `payload`; and
4. send the envelope through the generated host binding for your backend.

The sender waits while the Kernel dispatches the message to the target's plugin
message handler. A successful reply contains the target's `message` value. The
source plugin cannot choose or override its identity; the Kernel replaces the
source field with the authenticated name of the calling plugin.

## Receive a message

The target plugin receives the same envelope, including the Kernel-provided
`source`. It should:

1. verify that the source plugin is allowed to request the operation;
2. route the message by `topic`;
3. decode and validate `payload`; and
4. return either a result or an error.

The Kernel does not provide topic subscriptions or automatic dispatch inside
the plugin. The target's message handler receives messages for that plugin and
is responsible for interpreting the topic.

## Errors and delivery

Messages are delivered only to a currently running target plugin. The send
fails when:

* `target` is empty;
* the target plugin is not running;
* the target handler returns a transport or execution error; or
* the target reply contains a non-empty `error` field.

The target's `error` value is returned to the sender as an error. A message is
not delivered to another plugin when the target is unavailable.

Messages are not queued, retried, broadcast, or persisted. There is no
durable delivery guarantee. If the target stops while a message is in flight,
the call context is canceled with the target plugin's lifecycle.

## Backend behavior

The message semantics are identical for both plugin backends:

* a WASM plugin sends through generated host bindings; and
* a gRPC plugin sends through the Kernel's host callback channel.

The Kernel then invokes the target plugin through its selected backend and
converts the target's reply back into the sender's backend-specific response
type.

## Identity and authorization

The Kernel authenticates the source plugin at the host boundary. A plugin
cannot impersonate another plugin by writing a different `source` value into a
send request.

There is no Kernel-level access policy for individual topics. Any running
plugin can address another running plugin by name, so the target must enforce
authorization in its own handler when a topic or payload represents a
privileged operation. Treat `topic` as routing information, not as an access
control mechanism.

## Design a message contract

Keep a message contract explicit and versionable:

```text theme={null}
target:  secret-manager
topic:   secret.get
payload: {"name":"database"}
reply:   {"value":"..."}
```

Document the payload schema, required fields, response format, and error
meaning for every topic. Validate untrusted payloads before using them, and
return an explicit error for unknown or malformed topics.

Use a stable target name and topic namespace. If a request can be safely
repeated, make the operation idempotent because the sender may need to retry it
at the application level after a temporary target failure.
