From 63ef34a96a705b4f2e9ad15b7a65cc3837c8b4a5 Mon Sep 17 00:00:00 2001 From: Michele Papalini Date: Fri, 26 Sep 2025 15:00:22 +0200 Subject: [PATCH 01/24] docs: slim bindings v0.6.0 Signed-off-by: Michele Papalini --- docs/messaging/.index | 4 +- docs/messaging/slim-data-plane.md | 23 +- docs/messaging/slim-group.md | 106 +++---- docs/messaging/slim-howto.md | 8 +- docs/messaging/slim-session.md | 480 ++++++++++++++++++++++++++++++ 5 files changed, 557 insertions(+), 64 deletions(-) create mode 100644 docs/messaging/slim-session.md diff --git a/docs/messaging/.index b/docs/messaging/.index index 5678e96a..0e40d03d 100644 --- a/docs/messaging/.index +++ b/docs/messaging/.index @@ -3,7 +3,9 @@ nav: - Getting Started with SLIM: - Getting Started: slim-howto.md - Configuration Reference: slim-data-plane-config.md - - SLIM Messaging Layer: slim-data-plane.md + - SLIM Messaging Layer: + - Overview: slim-data-plane.md + - SLIM Sessions: slim-session.md - SLIM Controller: slim-controller.md - SLIM Group Management: slim-group.md - SLIM Group Communication Tutorial: slim-group-tutorial.md diff --git a/docs/messaging/slim-data-plane.md b/docs/messaging/slim-data-plane.md index ea7ff9fa..371a0a78 100644 --- a/docs/messaging/slim-data-plane.md +++ b/docs/messaging/slim-data-plane.md @@ -68,7 +68,26 @@ The session layer offers several functionalities: formatting, routing, and delivery confirmation, while providing simple send and receive primitives to applications. -The session layer provides two main APIs: a 1:1 session, where two clients + +The session layer offers three primary APIs for establishing new sessions: + +- **Anycast**: Enables point-to-point communication where each message sent +to a service is delivered to only one of its available instances. The +destination instance is selected for each message individually, so different +messages within the same session may be routed to different endpoints. + +- **Unicast**: Facilitates point-to-point communication with a specific service +instance. Unlike Anycast, Unicast performs a discovery phase to bind the session +to a single instance; all subsequent messages in the session are sent to that +same endpoint. + +- **Multicast**: Supports many-to-many communication over a named channel. +Every message sent to the channel is delivered to all current participants. + +For more information about each session type, see the +[SLIM session](./slim-session.md) documentation. + + diff --git a/docs/messaging/slim-group.md b/docs/messaging/slim-group.md index 0e500928..86812d92 100644 --- a/docs/messaging/slim-group.md +++ b/docs/messaging/slim-group.md @@ -9,52 +9,53 @@ communication benefits from end-to-end encryption. This guide provides all the information you need to create and manage groups within a SLIM network. -## Creating Groups with a Moderator +## Creating Groups with the Python Bindings -As described in the [SLIM Messaging Layer](slim-data-plane.md), each group is -managed by a moderator. A moderator is a special client with the ability to -create channels, add or remove participants, and perform the functions that are -typically delegated to the Delivery Service in the MLS protocol. -You can implement a moderator using the SLIM Python bindings to set up a group session and -configure all the required state to enable secure communication between -participants. The moderator can be part of a Python application and can either +In this session, we show how to use the SLIM Python bindings to create a group. +This requires using a [Multicast session](./slim-session.md#multicast). A multicast +session is a channel shared among multiple participants that can be used to +send a message to everybody. When a new participant wants to join the channel, +they must be invited by the channel creator. + +The channel creator can be part of a Python application and can either actively participate in the communication process (possibly implementing some of the application logic) or serve solely as a channel moderator. For a complete example of how to use the moderator, see the [SLIM Group -Communication Tutorial](slim-group-tutorial.md). This section provides the basic -steps to follow, along with Python code snippets, for setting up a group. +Communication Tutorial](slim-group-tutorial.md). + +This section provides the basic +steps to follow, along with Python code snippets, for setting up a Multicast session. +A complete [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) of group communication can be found in the SLIM repo, in addition +to a related [README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_multicast.md) with explanations on how to run it. -### Step 1: Create the Moderator +### Step 1: Create the Channel -Create the moderator by instantiating a -streaming bidirectional session, which initializes the corresponding state in -the SLIM session layer. In this example, communication between participants -will be encrypted end-to-end, as MLS is enabled. +The channel can be created by instantiating a Multicast session, +which initializes the corresponding state in the SLIM session layer. +In this example, communication between participants will be encrypted +end-to-end, as MLS is enabled. ```python # Define the shared channel for group communication. # This channel will be used by all members of the group to exchange messages. - shared_channel = PyName("agntcy", "namespace", "group_channel") - - # Create a new session. The group session is a bidirectional streaming session. - # Here is where we enable the MLS protocol for end-to-end encryption. - session_info = await slim_app.create_session( - PySessionConfiguration.Streaming( - PySessionDirection.BIDIRECTIONAL, - topic=shared_channel, # The channel ID for group communication. - moderator=True, # This session is created by the moderator. - max_retries=5, # Maximum number of retries for reliability. - timeout=datetime.timedelta(seconds=5), # Timeout for message delivery. - mls_enabled=True, # Enable MLS for end-to-end encryption. + channel_name = PyName("agntcy", "namespace", "group_channel") + + # Assume local_app is an initialized application instance + created_session = await local_app.create_session( + slim_bindings.PySessionConfiguration.Multicast( # type: ignore + topic=channel_name, + max_retries=5, + timeout=datetime.timedelta(seconds=5), + mls_enabled=enable_mls, ) ) ``` ### Step 2: Invite Participants to the Channel -The moderator now needs to invite -other participants to the channel. Note that not all participants need to be +Now that the multicast session is created, new participants can be invited +to join the channel. Note that not all participants need to be added at the beginning; you can also add them later, even after communication on the channel has already started. @@ -62,42 +63,33 @@ on the channel has already started. # Invite other members to the session. for invitee in invitees: print(f"Inviting {invitee}") - await slim_app.set_route(invitee) # Allow messages to be sent to the invitee. - await slim_app.invite( - session_info, invitee - ) # Send an invitation to the invitee. + await local_app.set_route(invitee) # Allow messages to be sent to the invitee. + await session.invite(invitee) # Send an invitation to the invitee. ``` ### Step 3: Listen for Invitations -To receive an invitation to the channel, each -participant must listen for incoming messages. The moderator will send the -invitation directly to the participant's name, not via the channel, since the -participant does not yet know the channel name. +Participants that need to be added to the group start without a session and wait to be +invited. To wait for an invitation, the application should use the `listen_for_session` function. +When an invite message is received, a new session is created at the SLIM session layer, +and `listen_for_session` returns all the information related to the newly created session. - ```python - async with participant_slim_app: - # Listen for new sessions opened by moderators - recv_session, _ = await participant_slim_app.receive() - - # Session is received, now we can read and write on the shared channel. - print(f"Received session: {recv_session.id}") +```python +format_message_print(local, "-> Waiting for session...") +session = await local_app.listen_for_session() +``` - # Receive messages from the session - recv_session, msg_rcv = await participant_slim_app.receive(session=recv_session.id) - # Print the message - print(f"Received: {msg_rcv.decode()}") - ``` +At this point, when a session is available, the participant can start listening for messages: -At this point, the group is set up and clients can start exchanging messages. -However, this configuration is not automatically reflected in the [SLIM -Controller](slim-controller.md) and must be reported manually. In particular, if -the SLIM network consists of multiple nodes, registration with the control plane -is mandatory to properly set up routes between nodes. We plan to automate this -process to make it easier for developers in the future. The group setup by the -moderator will work out of the box only if a single SLIM node is present in the -network. +```python +while True: + ctx, payload = await session.get_message() + format_message_print( + local, + f"-> Received message from {ctx.source_name}: {payload.decode()}", + ) +``` The next section describes how to register the newly created group with the SLIM Controller and how to properly configure routes between nodes. diff --git a/docs/messaging/slim-howto.md b/docs/messaging/slim-howto.md index 47998b67..e064215b 100644 --- a/docs/messaging/slim-howto.md +++ b/docs/messaging/slim-howto.md @@ -85,7 +85,7 @@ EOF We also provide a Helm chart for deploying SLIM in Kubernetes environments. ```bash -helm pull oci://ghcr.io/agntcy/slim/helm/slim --version v0.1.8 +helm pull oci://ghcr.io/agntcy/slim/helm/slim --version v0.2.0 ``` For information about how to use the Helm chart, see the @@ -124,7 +124,7 @@ docker run -it \ ### Using Helm ```bash -helm pull oci://ghcr.io/agntcy/slim/helm/slim-control-plane --version v0.1.3 +helm pull oci://ghcr.io/agntcy/slim/helm/slim-control-plane --version v0.1.4 ``` ### SLIM Python Bindings @@ -140,12 +140,12 @@ pip install slim-bindings ```toml [project] ... -dependencies = ["slim-bindings>=0.3.6"] +dependencies = ["slim-bindings>=0.5.0"] ``` A tutorial on how to use the bindings in an application can be found in the [messaging layer documentation](./slim-data-plane.md). Otherwise examples are available in the -[SLIM Repository](https://github.com/agntcy/slim/tree/slim-v0.4.0/data-plane/python-bindings/examples/src/slim_bindings_examples). +[SLIM Repository](https://github.com/agntcy/slim/tree/slim-v0.5.0/data-plane/python/bindings/examples/src/slim_bindings_examples). ### Slimctl diff --git a/docs/messaging/slim-session.md b/docs/messaging/slim-session.md new file mode 100644 index 00000000..ef18a588 --- /dev/null +++ b/docs/messaging/slim-session.md @@ -0,0 +1,480 @@ +# SLIM Sessions + +This document explains the SLIM session layer and the three supported session +types. It helps you pick the right pattern, understand reliability and security +trade‑offs, and shows concrete Python usage examples. + +## Quick Reference + +| Type | Pattern | Reliability | MLS | Primary Uses | Avoid When | +|----------|----------------|------------------------|-----|----------------------------------------|--------------------------------------------| +| Anycast | 1:1 stateless | Best‑effort or retries | No | Load balance, idempotent RPC, fan‑out | Need per‑peer state or E2E encryption | +| Unicast | 1:1 stateful | Optional acks + retries| Yes | Stateful convo, sticky peer, secure P2P| Need broadcast / many recipients | +| Multicast| N:N channel | Optional acks + retries| Yes | Group chat, pub/sub, coordination | Need strict single recipient semantics | + +Key takeaways: + +* Pick Anycast for simple stateless request distribution. +* Pick Unicast when you must bind to one specific instance and optionally + secure with MLS. +* Pick Multicast when many peers need to exchange messages over the same shared + channel. + +## Anycast + + +The anycast session enables point-to-point (1:1) communication where each +message sent to a service is delivered to only one of its available instances. +This pattern provides natural load balancing and redundancy for stateless +services. Anycast is best suited for distributing requests across multiple +instances without maintaining session state. + +Let's see an example of the communication pattern in the anycast session using +the sequence diagram below. The anycast session sends each message to a service +(e.g., App-B) and the message is delivered to only one of its available +instances (e.g., App-B/1 or App-B/2). The SLIM Node dynamically routes each +message to one of the running instances, so consecutive messages may be +delivered to different endpoints. + +If reliability is enabled, the sender expects an acknowledgment (Ack) for every +message sent. This confirms successful delivery, even though the specific +instance may vary per message. + +The diagram below illustrates two consecutive messages from App-A to the +service agntcy/ns/App-B. The first message is delivered to App-B/1, the second +to App-B/2. Each delivery is followed by an Ack: + +```mermaid +sequenceDiagram + autonumber + + participant App-A + participant SLIM Node + participant App-B/1 + participant App-B/2 + + App-A->>SLIM Node: Message to agntcy/ns/App-B + SLIM Node->>App-B/1: Message to agntcy/ns/App-B + App-B/1->>SLIM Node: Ack + SLIM Node->>App-A: Ack + + App-A->>SLIM Node: Message to agntcy/ns/App-B + SLIM Node->>App-B/2: Message to agntcy/ns/App-B + App-B/2->>SLIM Node: Ack + SLIM Node->>App-A: Ack +``` + +Note: Anycast sessions are stateless and do not allow persistent per‑recipient +state. Consequently, Messaging Layer Security (MLS) cannot be enabled. If MLS +is required for point‑to‑point communication, use a Unicast session instead. + + +### Create an Anycast Session + +Using the SLIM Python bindings, you can create an Anycast session as follows: + +```python +# Assume local_app is an initialized application instance +session = await local_app.create_session( + slim_bindings.PySessionConfiguration.Anycast( + max_retries=5, # Retries before giving up + timeout=datetime.timedelta(seconds=5), # Wait per attempt for Ack + # (omit for best-effort) + ) +) +``` + +Parameters: + +* `max_retries` (optional, int): Number of retry attempts if an Ack is not + received. +* `timeout` (optional, timedelta): How long to wait for an Ack before retrying. + If omitted the session is best‑effort + +If timeout is not provided the session is best‑effort (unreliable): lost messages +are not retransmitted. + +### Sending and Replying in Anycast +Anycast sessions are not pinned to a single remote instance. Each outgoing +message must therefore specify a destination application name. Use +`publish_with_destination` for sends. The plain `publish` API is only valid for +sessions that already have an implicit peer or channel (Unicast / Multicast). + +```python +remote_name = slim_bindings.PyName("agntcy", "ns", "app") +await session.publish_with_destination(b"hello", remote_name) + +# This would raise for Anycast (no implicit peer): +# await session.publish(b"hello") +``` + +To reply to a received message, use `publish_to`, which routes a response back +to the original sender using the message context acquired via `get_message`: + +```python +async def session_loop(session: slim_bindings.PySession): + while True: + try: + msg_ctx, payload = await session.get_message() + except Exception: + break # Session likely closed + text = payload.decode() + await session.publish_to(msg_ctx, f"Echo: {text}".encode()) +``` + +## Unicast + +The Unicast session enables point‑to‑point communication with a specific +instance. Unlike Anycast (which re‑selects an instance each message), Unicast +performs a discovery phase to bind to one instance; all subsequent traffic in +the session targets that same endpoint. This enables stateful interactions and +session continuity. With reliability enabled each message must be Acked. + +If MLS is enabled, the Unicast session establishes a two‑member MLS group after +discovery. This mirrors the Multicast flow but with only two participants +(see [Multicast](#multicast) session). + +The diagram below illustrates a unicast session from App-A to agntcy/ns/App-B. +App-A first discovers an available instance (App-B/1), then performs the MLS +setup, and finally sends multiple messages to that same instance, each followed +by an Ack. If MLS is not enabled, the MLS setup is skipped. + +```mermaid +sequenceDiagram + autonumber + + participant App-A + participant SLIM Node + participant App-B/1 + participant App-B/2 + + Note over App-A,App-B/2: Discovery + App-A->>App-A: Init MLS state + App-A->>SLIM Node: Discover agntcy/ns/App-B + SLIM Node->>App-B/1: Discover agntcy/ns/App-B + App-B/1->>SLIM Node: Discover Reply (agntcy/ns/App-B/1) + SLIM Node->>App-A: Discover Reply (agntcy/ns/App-B/1) + + Note over App-A,App-B/2: Invite + App-A->>SLIM Node: Invite agntcy/ns/App-B/1 + SLIM Node->>App-B/1: Invite agntcy/ns/App-B/1 + App-B/1->>App-B/1: Create new Unicast Session + App-B/1->>SLIM Node: Invite Reply (MLS key package) + SLIM Node->>App-A: Invite Reply (MLS key package) + App-A->>App-A: Update MLS state + + Note over App-A,App-B/2: MLS setup + App-A->>SLIM Node: MLS Welcome agntcy/ns/App-B/1 + SLIM Node->>App-B/1: MLS Welcome agntcy/ns/App-B/1 + App-B/1->>App-B/1: Init MLS state + App-B/1->>SLIM Node: Ack(MLS Welcome) + SLIM Node->>App-A: Ack(MLS Welcome) + + Note over App-A,App-B/2: Message exchange + App-A->>SLIM Node: Message to agntcy/ns/App-B/1 + SLIM Node->>App-B/1: Message to agntcy/ns/App-B/1 + App-B/1->>SLIM Node: Ack + SLIM Node->>App-A: Ack + + App-A->>SLIM Node: Message to agntcy/ns/App-B/1 + SLIM Node->>App-B/1: Message to agntcy/ns/App-B/1 + App-B/1->>SLIM Node: Ack + SLIM Node->>App-A: Ack +``` + + +### Create a Unicast Session + +Using the SLIM Python bindings, you can create a Unicast session as follows: + +```python +# Assume local_app is an initialized application instance +session = await local_app.create_session( + slim_bindings.PySessionConfiguration.Unicast( + unicast_name=remote_name, + max_retries=5, + timeout=datetime.timedelta(seconds=5), + mls_enabled=True, # Enable MLS for end-to-end security + ) +) +``` + +Parameters: + +* `unicast_name` (required, PyName): Identifier of the remote participant + instance. +* `max_retries` (optional, int): Retry attempts per message if Ack missing. +* `timeout` (optional, timedelta): Wait per attempt for an Ack before retry. + If `timeout` is not set the session is best‑effort. +* `mls_enabled` (optional, bool): Enable end‑to‑end encryption (MLS). + +### Sending and Replying in Unicast +In Unicast the session is bound to a single remote instance after discovery, so +outbound messages use the implicit destination. Use `publish` for normal sends +and `publish_to` to reply using a previously received message context. Do not +use `publish_with_destination` (it will raise) because the peer is already +fixed. + +```python +# Send a message using publish it will reach the endpoint +# specified and the session creation +await session.publish(b"hello") + +# Await reply from remote (pattern depends on your control loop) +msg_ctx, payload = await session.get_message() +print(payload.decode()) + +# Send a correlated response back (echo style) +# The message will be sent according to the info in msg_ctx +await session.publish_to(msg_ctx, payload) +``` + +## Multicast + +The Multicast session allows many-to-many communication on a named channel. Each +message is delivered to all participants connected to the same session. + +The creator of the channel can act as a moderator, meaning that it can add or +remove participants from the session. Moderation can be built into your application +or delegated to a separate control service or the SLIM control plane. + +Below are examples using the latest Python bindings, along with explanations of +what happens inside the session layer when a participant is added or removed +from the channel (see [Group management](./slim-group.md)). + +### Create a Multicast Session + +To create a multicast session, you need to configure the session with a topic +name and specify reliability and security settings. Here is an +example: + +```python +# Assume local_app is an initialized application instance +session = await local_app.create_session( + slim_bindings.PySessionConfiguration.Multicast( + topic=chat_topic, + max_retries=5, + timeout=datetime.timedelta(seconds=5), + mls_enabled=True, + ) +) +``` + +Parameters: + +* `topic` (required, PyName): Channel/Topic name where all the messages are + delivered. +* `max_retries` (optional, int): Retry attempts for missing Acks. +* `timeout` (optional, timedelta): Wait per attempt for Ack before retry. + If `timeout` is not set the session is best‑effort. +* `mls_enabled` (optional, bool): Enable secure group MLS messaging. + +### Sending and Replying in Multicast +In Multicast the session targets a channel: all sends are deliverd to all the current +participants. Use `publish` to send. `publish_with_destination` cannot be used +in Multicast because the channel name is implicit in the session. + +```python +# Broadcast to the channel +await session.publish(b"hello") + +# Handle inbound messages +msg_ctx, data = await session.get_message() +print("channel received:", data.decode()) +``` + +### Invite a New Participant + +The creator of the session can invite a new participant to the channel using the `invite` +method after creating the session. + +```python +# After creating the session: +invite_name = slim_bindings.PyName("agntcy", "ns", "participant") +await local_app.set_route(invite_name) +await session.invite(invite_name) +``` + +Parameters: +* `invite_name` (PyName): Identifier of the participant to add. + +Notice the `await local_app.set_route(invite_name)` command before the invite. +This will instruct SLIM on how to forward a message with the specified name. +This has to be done by the application for every invite. + +When a moderator wants to add a new participant (e.g., an instance of App-C) to +a multicast session, the following steps occur. All the steps are visualized in +the diagram below: + + +1. **Discovery Phase:** The moderator initiates a discovery request to find a + running instance of the desired application (App-C). This request is sent to + the SLIM Node, which forwards it in anycast to one of the App-C instances. + In the example, the message is forwarded to App-C/1 that replies with its + full identifier. The SLIM Node relays this reply back to the moderator. + +2. **Invitation:** The moderator sends an invite message for the discovered + instance (App-C/1) to the SLIM Node, which forwards it to App-C/1. Upon + receiving the invite, App-C/1 creates a new multicast session, subscribes to + the channel, and replies with its MLS (Messaging Layer Security) key + package. This reply is routed back to the moderator. + +3. **MLS State Update:** The moderator initiates an MLS commit to add App-C/1 + to the secure group. The message is sent using the channel name and so the + SLIM Node distributes this commit to all current participants (App-B/2 and + App-A/1), who update their MLS state and acknowledge the commit. The + moderator collects all acknowledgments. Once all acknowledgments are + received, the moderator sends an MLS Welcome message to App-C/1. App-C/1 + initializes its MLS state and acknowledges receipt. At the end of this + process, all participants (including the new one) share a secure group state + and can exchange encrypted messages on the multicast channel. If MLS is + disabled, the MLS state update and welcome step are skipped. + +```mermaid +sequenceDiagram + autonumber + + participant Moderator + participant SLIM Node + participant App-C/1 + participant App-C/2 + participant App-B/2 + participant App-A/1 + + Note over Moderator,App-A/1: Discovery + Moderator->>SLIM Node: Discover agntcy/ns/App-C + SLIM Node->>App-C/1: Discover agntcy/ns/App-C + App-C/1->>SLIM Node: Discover Reply from agntcy/ns/App-C/1 + SLIM Node->>Moderator: Discover Reply from agntcy/ns/App-C/1 + + Note over Moderator,App-A/1: Invite + Moderator->>SLIM Node: Invite agntcy/ns/App-C/1 + SLIM Node->>App-C/1: Invite agntcy/ns/App-C/1 + App-C/1->>App-C/1: Create new Multicast session + App-C/1->>SLIM Node: Subscribe to Channel + App-C/1->>SLIM Node: Invite Reply (MLS key package) + SLIM Node->>Moderator: Invite Reply (MLS key package) + Moderator->>Moderator: Update MLS state + + Note over Moderator,App-A/1: MLS State Update + Moderator->>SLIM Node: MLS commit (Add agntcy/ns/App-C/1) to Channel + par Handle MLS commit on App-C/1 + SLIM Node->>App-B/2: MLS commit (Add agntcy/ns/App-C/1) to Channel + App-B/2->>App-B/2: Update MLS state + App-B/2->>SLIM Node: Ack(MLS Commit) + SLIM Node->>Moderator: Ack(MLS Commit) + and Handle MLS commit on App-A/1 + SLIM Node->>App-A/1: MLS commit (Add agntcy/ns/App-C/1) to Channel + App-A/1->>App-A/1: Update MLS state + App-A/1->>SLIM Node: Ack(MLS Commit) + SLIM Node->>Moderator: Ack(MLS Commit) + end + Moderator->>SLIM Node: MLS Welcome agntcy/ns/App-C/1 + SLIM Node->>App-C/1: MLS Welcome agntcy/ns/App-C/1 + App-C/1->>App-C/1: Init MLS state + App-C/1->>SLIM Node: Ack(MLS Welcome) + SLIM Node->>Moderator: Ack(MLS Welcome) +``` + +### Remove a Participant + + +A moderator can remove a participant from the channel using the `remove` +method after creating the session. + +```python +# To remove a participant from the session: +remove_name = slim_bindings.PyName("agntcy", "ns", "participant") +await session.remove(remove_name) +``` + + +Parameter: +* `remove_name` (PyName): Identifier of the participant to remove. + + +When a moderator wants to remove a participant (e.g., App-C/1) from a multicast +session, the following steps occur. All the steps are visualized in the diagram +below: + + +1. **MLS State Update:** The moderator creates an MLS commit to remove App-C/1 + from the secure group. This commit is sent to the multicast channel and the + SLIM Node distributes it to all current participants (App-C/1, App-B/2, and + App-A/1). Each participant updates its MLS state and acknowledges the + commit. The moderator collects all acknowledgments. In case the MLS is + disabled, this step is not executed. + +2. **Removal:** After the MLS state is updated, the moderator sends a remove + message to App-C/1. Upon receiving the remove message, App-C/1 unsubscribes + from the channel, deletes its multicast session, and replies with a + confirmation. The SLIM Node relays this confirmation back to the moderator. + At the end of this process, App-C/1 is no longer a member of the multicast + group and cannot send or receive messages on the channel. + +```mermaid +sequenceDiagram + autonumber + + participant Moderator + participant SLIM Node + participant App-C/1 + participant App-B/2 + participant App-A/1 + + Note over Moderator,App-A/1: MLS State Update + Moderator->>SLIM Node: MLS commit (Remove agntcy/ns/App-C/1) to Channel + par Handle MLS commit on App-C/1 + SLIM Node->>App-C/1: MLS commit (Remove agntcy/ns/App-C/1) to Channel + App-C/1->>App-C/1: Update MLS state + App-C/1->>SLIM Node: Ack(MLS Commit) + SLIM Node->>Moderator: Ack(MLS Commit) + and Handle MLS commit on App-B/2 + SLIM Node->>App-B/2: MLS commit (Remove agntcy/ns/App-C/1) to Channel + App-B/2->>App-B/2: Update MLS state + App-B/2->>SLIM Node: Ack(MLS Commit) + SLIM Node->>Moderator: Ack(MLS Commit) + and Handle MLS commit on App-A/1 + SLIM Node->>App-A/1: MLS commit (Remove agntcy/ns/App-C/1) to Channel + App-A/1->>App-A/1: Update MLS state + App-A/1->>SLIM Node: Ack(MLS Commit) + SLIM Node->>Moderator: Ack(MLS Commit) + end + + Note over Moderator,App-A/1: Remove + Moderator->>SLIM Node: Remove agntcy/ns/App-C/1 + SLIM Node->>App-C/1: Remove agntcy/ns/App-C/1 + App-C/1->>SLIM Node: Unsubscribe from Channel + App-C/1->>App-C/1: Remove Multicast session + App-C/1->>SLIM Node: Remove Reply + SLIM Node->>Moderator: Remove Reply +``` + +## Examples + + +The SLIM repository ships with practical, runnable [examples](https://github.com/agntcy/slim/tree/main/data-plane/python/bindings/examples) +that demonstrate how to create sessions and exchange messages between applications using the +Python bindings. + + +### Anycast & Unicast +This [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/point_to_point.py) +walks through creating both Anycast and Unicast sessions side by side. +You will see how Anycast distributes stateless requests across multiple instances, +while Unicast performs discovery and binds to a single peer. The example +demonstrates how to publish messages, enable reliability, and enable MLS +for end‑to‑end security in Unicast sessions. The associated +[README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_point_to_point.md) shows more information and how to run the example using the Taskfile +provided in the repo. + + +### Multicast +This [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) +demonstrates how to create a multicast session, invite participants, and +(if enabled) establish an MLS group for end-to-end encryption. It also shows +how to broadcast messages to all current members and handle inbound group +messages. The associated +[README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_multicast.md) +shows more information and how to run the example using the Taskfile. + From 5f8a454fbeba4d5903504305a735551e9642d396 Mon Sep 17 00:00:00 2001 From: Michele Papalini Date: Mon, 29 Sep 2025 13:41:13 +0200 Subject: [PATCH 02/24] docs: slim group totorial Signed-off-by: Michele Papalini --- docs/messaging/slim-group-tutorial.md | 902 ++++++++++++-------------- 1 file changed, 429 insertions(+), 473 deletions(-) diff --git a/docs/messaging/slim-group-tutorial.md b/docs/messaging/slim-group-tutorial.md index f27691fe..d87a400e 100644 --- a/docs/messaging/slim-group-tutorial.md +++ b/docs/messaging/slim-group-tutorial.md @@ -1,590 +1,546 @@ # SLIM Group Communication Tutorial -This tutorial will show how to set up a secure group communication system using -SLIM. The group will be created by defining a pub-sub session with a moderator, -which will invite the other members. Messages will be sent to the shared -channel, where every member can read and write. Messages are end-to-end -encrypted using the [MLS -protocol](https://datatracker.ietf.org/doc/html/rfc9420). +This tutorial shows how to set up secure group communication using +SLIM. The group is created by defining a multicast session and inviting +participants. Messages are sent to a shared channel where every member can read +and write. All messages are end-to-end encrypted using the +[MLS protocol](https://datatracker.ietf.org/doc/html/rfc9420). This tutorial is +based on the +[multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) +example in the SLIM repo. A companion +[README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_multicast.md) +explains the example step by step. ## Key Features - **Name-based Addressing**: In SLIM, all endpoints (channels and clients) have a name, and messages use a name-based addressing scheme for content routing. -- **Session Management**: Allows for the creation and management of sessions - with moderators. +- **Session Management**: Allows for the creation and management of sessions. - **Broadcast Messaging**: Facilitates broadcast messaging to multiple subscribers. - **End-to-End Encryption**: Ensures secure communication using the [MLS protocol](https://datatracker.ietf.org/doc/html/rfc9420). -### Setting up the SLIM Instance -As all members of the group will be communicating via a SLIM network, we can set -up a SLIM instance representing the SLIM network. We will use the pre-built -docker image for this purpose. - -First execute this command to create the SLIM configuration file. Details about -the configuration can be found in the [SLIM -Repo](https://github.com/agntcy/slim/tree/main/data-plane/config). - -```bash -cat << EOF > ./config.yaml -tracing: - log_level: info - display_thread_names: true - display_thread_ids: true - -runtime: - n_cores: 0 - thread_name: "slim-data-plane" - drain_timeout: 10s - -services: - slim/0: - pubsub: - servers: - - endpoint: "0.0.0.0:46357" - tls: - insecure: true - - clients: [] -EOF -``` - -This configuration will start a SLIM instance with a server listening on port -46357, without TLS encryption for simplicity. Messages will be still encrypted -using the MLS protocol, but the connections between SLIM nodes will not use TLS. -In a production environment, it is recommended to always use TLS and configure -proper authentication and authorization mechanisms. - -You can run the SLIM instance using Docker: - -```bash -docker run -it \ - -v ./config.yaml:/config.yaml -p 46357:46357 \ - ghcr.io/agntcy/slim:latest /slim --config /config.yaml -``` - -If everything goes fine, you should see an output like this one: - -``` -2025-07-31T09:07:45.859161Z INFO main ThreadId(01) application_lifecycle: slim: Runtime started -2025-07-31T09:07:45.859213Z INFO main ThreadId(01) application_lifecycle: slim: Starting service: slim/0 -2025-07-31T09:07:45.859624Z INFO main ThreadId(01) application_lifecycle: slim_service: starting service -2025-07-31T09:07:45.859683Z INFO main ThreadId(01) application_lifecycle: slim_service: starting server 0.0.0.0:46357 -2025-07-31T09:07:45.859793Z INFO main ThreadId(01) application_lifecycle: slim_service: server configured: setting it up config=ServerConfig { endpoint: 0.0.0.0:46357, tls_setting: TlsServerConfig { config: Config { ca_file: None, ca_pem: None, include_system_ca_certs_pool: false, cert_file: None, cert_pem: None, key_file: None, key_pem: None, tls_version: "tls1.3", reload_interval: None }, insecure: true, client_ca_file: None, client_ca_pem: None, reload_client_ca_file: false }, http2_only: true, max_frame_size: None, max_concurrent_streams: None, max_header_list_size: None, read_buffer_size: None, write_buffer_size: None, keepalive: KeepaliveServerParameters { max_connection_idle: 3600s, max_connection_age: 7200s, max_connection_age_grace: 300s, time: 120s, timeout: 20s }, auth: None } -2025-07-31T09:07:45.861393Z INFO slim-data-plane ThreadId(11) slim_service: running service -``` - -### Configure Client Identity and Implementing the SLIM App +## Configure Client Identity and Implement the SLIM App -Each member of the group will run a local slim app instance that will be used to -communicate with the SLIM network. Also each member will have a unique identity -that will be used to authenticate the member in the SLIM network. +Each member of the group runs a local SLIM app instance to +communicate with the SLIM network. Each member also has a unique identity used +for authentication and by the MLS protocol. -#### Identity +### Identity -Each member of the group must have a unique identity. This is a requirement to -setup the end-to-end encryption using the MLS protocol. The identity can be -represented by a JWT, or a shared secret. For simplicity, we will use a shared -secret. You can find examples using JWT in the [SLIM -Repo](https://github.com/agntcy/slim/tree/slim-v0.4.0/data-plane/python-bindings/examples/src/slim_bindings_examples/common.py#L71-L112). +Each member must have a unique identity. This is required to +set up end-to-end encryption using the MLS protocol. The identity can be a JWT +or a shared secret. For simplicity in this example we use a shared secret. A +[tutorial](https://github.com/agntcy/slim/tree/main/data-plane/python/bindings/examples#running-in-kubernetes-spire--jwt) +on generating a JWT token using SPIRE and using it with SLIM is available in the +SLIM repo. The python objects managing the identity are called `PyIdentityProvider` and `PyIdentityVerifier`. The `PyIdentityProvider` is responsible for providing the identity, while the `PyIdentityVerifier` is responsible for verifying the -identity. +identity. ```python -def shared_secret_identity( - identity: str, secret: str -) -> tuple[PyIdentityProvider, PyIdentityVerifier]: +def shared_secret_identity(identity: str, secret: str): """ - Create a provider and verifier using a shared secret. + Create a provider & verifier pair for shared-secret (symmetric) authentication. - :param identity: A unique string, identifier of the app. - :param secret: A shared secret used for authentication. - :return: A tuple of (provider, verifier). + Args: + identity: Logical identity string (often same as PyName string form). + secret: Shared secret used to sign / verify tokens (not for production). + + Returns: + (provider, verifier): Tuple of PyIdentityProvider & PyIdentityVerifier. """ - provider: PyIdentityProvider = PyIdentityProvider.SharedSecret( + provider = slim_bindings.PyIdentityProvider.SharedSecret( # type: ignore identity=identity, shared_secret=secret ) - verifier: PyIdentityVerifier = PyIdentityVerifier.SharedSecret( + verifier = slim_bindings.PyIdentityVerifier.SharedSecret( # type: ignore identity=identity, shared_secret=secret ) - return provider, verifier ``` -#### SLIM App +This is a helper function defined in +[common.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L85) +that can be used to create a `PyIdentityProvider` and `PyIdentityVerifier` from two input strings. -The provider and the verifier will be used to create a local SLIM app, that can -be used to exchange messages with other apps via the SLIM network. +### SLIM App + +The provider and verifier are used to create a local SLIM app that can +exchange messages with other apps via the SLIM network. To create +the SLIM app we leverage another helper function defined in +[common.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L289) ```python -async def create_slim_app(secret: str, local_name: PyName) -> PyService: +async def create_local_app( + local: str, + slim: dict, + remote: str | None = None, + enable_opentelemetry: bool = False, + shared_secret: str = "secret", + jwt: str | None = None, + spire_trust_bundle: str | None = None, + audience: list[str] | None = None, +): """ - Create a SLIM app instance with the given shared secret. - This app will be used to communicate with other SLIM nodes in the network. - - :param secret: A shared secret used for authentication. - :param local_name: A unique name for the SLIM app instance. - It will be used to identify the app in the SLIM network. - :return: A SLIM app instance. + Build and connect a Slim application instance given user CLI parameters. + + Resolution precedence for auth: + 1. If jwt + bundle + audience provided -> JWT/JWKS flow. + 2. Else -> shared secret (must be provided, raises if missing). + + Args: + local: Local identity string (org/ns/app). + slim: Dict of connection parameters (endpoint, tls flags, etc.). + remote: Optional remote identity (unused here, reserved for future). + enable_opentelemetry: Enable OTEL tracing export. + shared_secret: Symmetric secret for shared-secret mode. + jwt: Path to static JWT token (for StaticJwt provider). + spire_trust_bundle: Path to a spire trust bundle file (containing the JWKs for each trust domain). + audience: Audience list for JWT verification. + + Returns: + Slim: Connected high-level Slim instance. """ - - # Create the provider and verifier using the shared secret. - provider, verifier = shared_secret_identity( - identity=f"{local_name}", - secret=secret, + # Initialize tracing (synchronous init; not awaited as binding returns immediately). + slim_bindings.init_tracing( + { + "log_level": "info", + "opentelemetry": { + "enabled": enable_opentelemetry, + "grpc": { + "endpoint": "http://localhost:4317", + }, + }, + } ) - # Create the SLIM app. This is a in-process SLIM client that can be used to - # exchange messages with other SLIM nodes in the network. - slim_app = await Slim.new(local_name, provider, verifier) + # Derive identity provider & verifier using JWT/JWKS if all pieces supplied. + if jwt and spire_trust_bundle and audience: + print("Using JWT + JWKS authentication.") + provider, verifier = jwt_identity( + jwt, + spire_trust_bundle, + aud=audience, + ) + else: + print( + "Warning: Falling back to shared-secret authentication. Don't use this in production!" + ) + # Fall back to shared secret (dev-friendly default). + provider, verifier = shared_secret_identity( + identity=local, + secret=shared_secret, + ) - # Connect the SLIM app to the SLIM network. - _ = await slim_app.connect( - {"endpoint": "http://127.0.0.1:46357", "tls": {"insecure": True}} - ) + # Convert local identifier to a strongly typed PyName. + local_name = split_id(local) - # Return the SLIM app instance. - return slim_app -``` + # Instantiate Slim (async constructor prepares underlying PyService). + local_app = await slim_bindings.Slim.new(local_name, provider, verifier) -### Implementing the Moderator + # Provide feedback to user (instance numeric id). + format_message_print(f"{local_app.id_str}", "Created app") -The moderator will be responsible for creating the group and inviting other -members. The moderator will create a session and send an invitation message to -the other members. The invitation will contain the session ID and the channel -name for the group communication. + # Establish outbound connection using provided parameters. + _ = await local_app.connect(slim) -The moderator can be implemented as a Python service using the SLIM SDK. + # Confirm endpoint connectivity. + format_message_print(f"{local_app.id_str}", f"Connected to {slim['endpoint']}") -#### Creating the Session and Inviting Members + return local_app +``` -The moderator creates a session and invites other members to join the group. The +This function takes several parameters as input: + +- `local` (str): The SLIM name of the local application in the form + `org/ns/service` (required). +- `slim` (dict): Configuration to connect to the remote SLIM node. Example: + ```python + { + "endpoint": "http://127.0.0.1:46357", + "tls": {"insecure": True}, + } + ``` + (required) +- `enable_opentelemetry` (bool, default: `False`): Enable OpenTelemetry + tracing. If `True`, traces are sent to `http://localhost:4317` by default. +- `shared_secret` (str | None, default: `None`): Shared secret for identity and + authentication. Required if JWT, bundle and audience are not provided. +- `jwt` (str | None, default: `None`): JWT token for identity. Used with + `spire_trust_bundle` and `audience` for JWT-based authentication. +- `spire_trust_bundle` (str | None, default: `None`): JWT trust bundle (CA certificates or + JWKS). It is expected in JSON format such as + ```json + { + "trust-domain-1.org": "base-64-encoded-jwks", + "trust-domain-2.org": "base-64-encoded-jwks", + ... + } + ``` +- `audience` (list[str] | None, default: `None`): List of allowed audiences for + JWT authentication. + +If `jwt`, `spire_trust_bundle`, and `audience` are not provided, `shared_secret` must be set (only +recommended for local testing or examples, not production). In this example we +use the shared secret option, but the same function supports all authentication flows. + +## Create the Multicast Session (Group Communication) + +One application acts as moderator: it creates the multicast session and invites +participants by sending invitation control messages. A detailed description of +multicast sessions and the invitation process is available +[here](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/SESSION.md). + +### Creating the Multicast Session and Inviting Members + +The creator of the multicast session invites other members to join the group. The session will be identified by a unique session ID, and the group communication -will take place over a specific channel name. The moderator will be responsible +will take place over a specific channel name. The session creator is responsible for managing the session lifecycle, including creating, updating, and terminating the session as needed. As each participant is provided with an identity, setting up MLS for end-to-end -encryption is straightforward. The moderator will create a session with the +encryption is straightforward: the session is created with the `mls_enabled` flag set to `True`, which will enable the MLS protocol for the session. This ensures that all messages exchanged within the session are end-to-end encrypted, providing confidentiality and integrity for the group communication. ```python -async def create_session_and_invite_members( - slim_app: PyService, invitees: list[PyName] -): - """ - Create a session with the given session ID and channel ID. - - :param slim_app: The SLIM app instance. - :return: The created session. - """ - - # Define the shared channel for group communication. - # This channel will be used by all members of the group to exchange messages. - shared_channel = PyName("agntcy", "namespace", "group_channel") - - # Create a new session. The group session is a bidirectional streaming session. - # Here is where we enable the MLS protocol for end-to-end encryption. - session_info = await slim_app.create_session( - PySessionConfiguration.Streaming( - PySessionDirection.BIDIRECTIONAL, - topic=shared_channel, # The channel ID for group communication. - moderator=True, # This session is created by the moderator. - max_retries=5, # Maximum number of retries for reliability. - timeout=datetime.timedelta(seconds=5), # Timeout for message delivery. - mls_enabled=True, # Enable MLS for end-to-end encryption. - ) + # Create & connect the local Slim instance (auth derived from args). + local_app = await create_local_app( + local, + slim, + enable_opentelemetry=enable_opentelemetry, + shared_secret=shared_secret, + jwt=jwt, + spire_trust_bundle=spire_trust_bundle, + audience=audience, ) - print(f"Session created: {session_info}") - - # Invite other members to the session. - for invitee in invitees: - print(f"Inviting {invitee}") - await slim_app.set_route(invitee) # Allow messages to be sent to the invitee. - await slim_app.invite( - session_info, invitee - ) # Send an invitation to the invitee. - - # Return the created session. - return session_info + # Parse the remote channel/topic if provided; else None triggers passive mode. + chat_channel = split_id(remote) if remote else None -async def run_moderator(secret: str): - local_name = PyName("agntcy", "namespace", "moderator") + # Track background tasks (receiver loop + optional keyboard loop). + tasks: list[asyncio.Task] = [] - # Create the moderator SLIM app instance. - moderator_slim_app = await create_slim_app(secret, local_name) - - # Define the invitees for the group session. - invitees = [ - PyName("agntcy", "namespace", "participant1"), - ] - - async with moderator_slim_app: - # Create a session and invite the members. - session_info = await create_session_and_invite_members(moderator_slim_app, invitees) + # Session object only exists immediately if we are moderator. + created_session = None + if chat_channel and invites: + # We are the moderator; create the multicast session now. + format_message_print( + f"Creating new multicast session (moderator)... {split_id(local)}" + ) + created_session = await local_app.create_session( + slim_bindings.PySessionConfiguration.Multicast( # type: ignore # Build multicast session configuration + channel_name=chat_channel, # Logical multicast channel (PyName) all participants join; acts as group/topic identifier. + max_retries=5, # Max per-message resend attempts upon missing ack before reporting a delivery failure. + timeout=datetime.timedelta( + seconds=5 + ), # Ack / delivery wait window; after this duration a retry is triggered (until max_retries). + mls_enabled=enable_mls, # Enable Messaging Layer Security for end-to-end encrypted & authenticated group communication. + ) + ) - # Wait for a bit to ensure all participants are ready. + # Small delay so underlying routing / session creation stabilizes. await asyncio.sleep(1) - # Send a message to the group channel. - await send_message(moderator_slim_app, session_info, "Hello group!") - - # Wait for a message from a participant - _, msg = await moderator_slim_app.receive(session=session_info.id) - - # Print message - print(f"Received message from participant: {msg.decode()}") + # Invite each provided participant. Route is set before inviting to ensure + # outbound control messages can reach them. For more info see + # https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/SESSION.md#invite-a-new-participant + for invite in invites: + invite_name = split_id(invite) + await local_app.set_route(invite_name) + await created_session.invite(invite_name) + print(f"{local} -> add {invite_name} to the group") ``` -### Implementing the Group Participants - -The group participants will be implemented similarly to the moderator, but they +This code comes from the +[multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) +example. The local application is created using the helper function shown earlier. +The channel name (the logical multicast topic) is produced via the +[split_id](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L63) +helper by parsing the `remote` parameter. A new multicast session is then created +using `local_app.create_session(...)` with a +`slim_bindings.PySessionConfiguration.Multicast` configuration. The key parameters are: + +- `channel_name`: Logical channel/topic used to exchange messages among participants. +- `max_retries`: Maximum number of retransmission attempts (upon missing ack) before + notifying the application of delivery failure. +- `timeout`: Duration to wait for an acknowledgment; if the ack is not received in time a retry is triggered. If + omitted / None, the session is unreliable (no retry/ack flow). +- `mls_enabled`: Set to `True` to enable MLS for end-to-end encryption. + +After the session creation, the moderator invites participants via `created_session.invite`. +Before sending each invitation it must call `local_app.set_route(invite_name)` so +SLIM knows how to deliver the control messages. + +### Implement Participants and Receive Messages + +The group participants will be implemented in a similar way, but they will not create the session. They will create the SLIM service instance and wait -for invites sent by the moderator. Once they receive the invite, they can read -and write on the shared channel. +for invites. Once they receive the invite, they can read and write on the shared channel. ```python -async def run_participant(secret: str): - local_name = PyName("agntcy", "namespace", "participant1") - - participant_slim_app = await create_slim_app(secret, local_name) - - print(f"Listening for sessions - locator: {local_name}") - - async with participant_slim_app: - # Listen for new sessions opened by moderators - recv_session, _ = await participant_slim_app.receive() - - # Session is received, now we can read and write on the shared channel. - print(f"Received session: {recv_session.id}") - - # Receive messages from the session - recv_session, msg_rcv = await participant_slim_app.receive(session=recv_session.id) - - # Print the message - print(f"Received: {msg_rcv.decode()}") - - # Reply with a message - await participant_slim_app.publish( - recv_session, - f"{msg_rcv.decode()} from participant".encode(), - recv_session.destination_name, - ) - - # Wait to ensure message is sent - await asyncio.sleep(1) + async def receive_loop(): + """ + Receive messages for the bound session. + + Behavior: + * If not moderator: wait for a new multicast session (listen_for_session()). + * If moderator: reuse the created_session reference. + * Loop forever until cancellation or an error occurs. + """ + if created_session is None: + format_message_print(local, "-> Waiting for session...") + session = await local_app.listen_for_session() + else: + session = created_session + + while True: + try: + # Await next inbound message from the multicast session. + # The returned parameters are a message context and the raw payload bytes. + # Check session.py for details on PyMessageContext contents. + ctx, payload = await session.get_message() + format_message_print( + local, + f"-> Received message from {ctx.source_name}: {payload.decode()}", + ) + except asyncio.CancelledError: + # Graceful shutdown path (ctrl-c or program exit). + break + except Exception as e: + # Non-cancellation error; surface and exit the loop. + format_message_print(local, f"-> Error receiving message: {e}") + break ``` -### Putting All Together +Each non-moderator participant listens for an incoming session using +`local_app.listen_for_session()`. This returns a +[PySession](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/slim_bindings/session.py) +object containing metadata such as session ID, type, source name, and destination name. +The moderator already holds this information and therefore reuses the existing +`created_session` (see `session = created_session`). -Here is the complete code to run the moderator and the participants in a single -script. You can run this script to see how the group communication works using -SLIM. +Participants then call `ctx, payload = await session.get_message()` to receive +messages. `payload` contains the raw message bytes and `ctx` is a +[PyMessageContext](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/slim_bindings/_slim_bindings.pyi#L22) +with source, destination, message type, and metadata. -The same example can be found in the [SLIM examples -folder](https://github.com/agntcy/slim/tree/slim-v0.4.0/data-plane/python-bindings/examples/src/slim_bindings_examples). -In particular this tutorial is based on the -[pubsub.py](https://github.com/agntcy/slim/tree/slim-v0.4.0/data-plane/python-bindings/examples/src/slim_bindings_examples/pubsub.py) -example +### Publish Messages to the Session -#### moderator.py +All participants can publish messages on the shared channel ```python -import asyncio -import datetime - -from slim_bindings import ( - Slim, - PyName, - PyService, - PyIdentityProvider, - PyIdentityVerifier, - PySessionConfiguration, - PySessionDirection, - init_tracing, -) - - -def shared_secret_identity( - identity: str, secret: str -) -> tuple[PyIdentityProvider, PyIdentityVerifier]: - """ - Create a provider and verifier using a shared secret. - - :param identity: A unique string, identifier of the app. - :param secret: A shared secret used for authentication. - :return: A tuple of (provider, verifier). - """ - provider: PyIdentityProvider = PyIdentityProvider.SharedSecret( - identity=identity, shared_secret=secret - ) - verifier: PyIdentityVerifier = PyIdentityVerifier.SharedSecret( - identity=identity, shared_secret=secret - ) - - return provider, verifier - - -async def create_slim_app(secret: str, local_name: PyName) -> PyService: - """ - Create a SLIM app instance with the given shared secret. - This app will be used to communicate with other SLIM nodes in the network. - - :param secret: A shared secret used for authentication. - :param local_name: A unique name for the SLIM app instance. - It will be used to identify the app in the SLIM network. - :return: A SLIM app instance. - """ - - # Create the provider and verifier using the shared secret. - provider, verifier = shared_secret_identity( - identity=f"{local_name}", - secret=secret, - ) - - # Create the SLIM app. This is a in-process SLIM client that can be used to - # exchange messages with other SLIM nodes in the network. - slim_app = await Slim.new(local_name, provider, verifier) - - # Connect the SLIM app to the SLIM network. - _ = await slim_app.connect( - {"endpoint": "http://127.0.0.1:46357", "tls": {"insecure": True}} - ) - - # Return the SLIM app instance. - return slim_app - - -async def create_session_and_invite_members( - slim_app: PyService, invitees: list[PyName] -): - """ - Create a session with the given session ID and channel ID. - - :param slim_app: The SLIM app instance. - :return: The created session. - """ - - # Define the shared channel for group communication. - # This channel will be used by all members of the group to exchange messages. - shared_channel = PyName("agntcy", "namespace", "group_channel") - - # Create a new session. The group session is a bidirectional streaming session. - # Here is where we enable the MLS protocol for end-to-end encryption. - session_info = await slim_app.create_session( - PySessionConfiguration.Streaming( - PySessionDirection.BIDIRECTIONAL, - topic=shared_channel, # The channel ID for group communication. - moderator=True, # This session is created by the moderator. - max_retries=5, # Maximum number of retries for reliability. - timeout=datetime.timedelta(seconds=5), # Timeout for message delivery. - mls_enabled=True, # Enable MLS for end-to-end encryption. - ) - ) - - print(f"Session created: {session_info}") - - # Invite other members to the session. - for invitee in invitees: - print(f"Inviting {invitee}") - await slim_app.set_route(invitee) # Allow messages to be sent to the invitee. - await slim_app.invite( - session_info, invitee - ) # Send an invitation to the invitee. - - # Return the created session. - return session_info - - -async def send_message(slim_app: PyService, session_info, message: str): - """ - Send a message to the group channel. - - :param slim_app: The SLIM app instance. - :param session_info: The session information. - :param message: The message to send. - """ - - # Send the message to the shared channel. - await slim_app.publish( - session_info, - message.encode(), - PyName("agntcy", "namespace", "group_channel"), - ) + while True: + # Run blocking input() in a worker thread so we do not block the event loop. + user_input = await asyncio.to_thread(input, "\033[1mmessage>\033[0m ") + if user_input.strip().lower() in ("exit", "quit"): + break + try: + # Send message to the channel_name specified when creating the session. + # As the session is multicast, all participants will receive it. + # calling publish_with_destination on a multicast session will raise an error. + await created_session.publish(user_input.encode()) + except Exception as e: + format_message_print(local, f"-> Error sending message: {e}") +``` +Messages are sent using `created_session.publish(user_input.encode())`. +Only the payload is provided and there is no explicit destination, because the +multicast channel was fixed at session creation and delivery fan-outs to all +participants. +In the +[multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) +example only the moderator sends messages. In practice any participant can call +`publish()`. -async def run_moderator(secret: str): - local_name = PyName("agntcy", "namespace", "moderator") +## How to Run the Example - # Create the moderator SLIM app instance. - moderator_slim_app = await create_slim_app(secret, local_name) +In this toturial we presented step by step how to create a new multicast session and +how to enable group communication on top of SLIM. The full code can be found in +[multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) +in the SLIM repo. To run the example, follow the step listed here. - # Define the invitees for the group session. - invitees = [ - PyName("agntcy", "namespace", "participant1"), - ] +### Run SLIM +As all members of the group will be communicating via a SLIM network, we can set +up a SLIM instance representing the SLIM network. We will use the pre-built +docker image for this purpose. - async with moderator_slim_app: - # Create a session and invite the members. - session_info = await create_session_and_invite_members( - moderator_slim_app, invitees - ) +First execute this command to create the SLIM configuration file. Details about +the [configuration](https://github.com/agntcy/slim/tree/main/data-plane/config) +can be found in the SLIM repo. - # Wait for a bit to ensure all participants are ready. - await asyncio.sleep(1) +```bash +cat << EOF > ./config.yaml +tracing: + log_level: info + display_thread_names: true + display_thread_ids: true - # Send a message to the group channel. - await send_message(moderator_slim_app, session_info, "Hello group!") +runtime: + n_cores: 0 + thread_name: "slim-data-plane" + drain_timeout: 10s - # Wait for a message from a participant - _, msg = await moderator_slim_app.receive(session=session_info.id) +services: + slim/0: + dataplane: + servers: + - endpoint: "0.0.0.0:46357" + tls: + insecure: true - # Print message - print(f"Received message from participant: {msg.decode()}") + clients: [] + controller: + servers: [] +EOF +``` +This configuration will start a SLIM instance with a server listening on port +46357, without TLS encryption for simplicity. Messages are still encrypted +using the MLS protocol, but the connections between SLIM nodes do not use TLS. +In a production environment, it is recommended to always use TLS and configure +proper authentication and authorization mechanisms. -def main(): - try: - asyncio.run(run_moderator("shared_secret")) - except KeyboardInterrupt: - print("Client interrupted by user.") +You can run the SLIM instance using Docker: +```bash +docker run -it \ + -v ./config.yaml:/config.yaml -p 46357:46357 \ + ghcr.io/agntcy/slim:latest /slim --config /config.yaml ``` -#### participant.py +If everything goes fine, you should see an output like this one: -```python -import asyncio -import datetime - -from slim_bindings import ( - Slim, - PyName, - PyService, - PyIdentityProvider, - PyIdentityVerifier, - PySessionConfiguration, - PySessionDirection, - PySessionInfo, - init_tracing, -) - - -def shared_secret_identity( - identity: str, secret: str -) -> tuple[PyIdentityProvider, PyIdentityVerifier]: - """ - Create a provider and verifier using a shared secret. +``` +2025-07-31T09:07:45.859161Z INFO main ThreadId(01) application_lifecycle: slim: Runtime started +2025-07-31T09:07:45.859213Z INFO main ThreadId(01) application_lifecycle: slim: Starting service: slim/0 +2025-07-31T09:07:45.859624Z INFO main ThreadId(01) application_lifecycle: slim_service: starting service +2025-07-31T09:07:45.859683Z INFO main ThreadId(01) application_lifecycle: slim_service: starting server 0.0.0.0:46357 +2025-07-31T09:07:45.859793Z INFO main ThreadId(01) application_lifecycle: slim_service: server configured: setting it up config=ServerConfig { endpoint: 0.0.0.0:46357, tls_setting: TlsServerConfig { config: Config { ca_file: None, ca_pem: None, include_system_ca_certs_pool: false, cert_file: None, cert_pem: None, key_file: None, key_pem: None, tls_version: "tls1.3", reload_interval: None }, insecure: true, client_ca_file: None, client_ca_pem: None, reload_client_ca_file: false }, http2_only: true, max_frame_size: None, max_concurrent_streams: None, max_header_list_size: None, read_buffer_size: None, write_buffer_size: None, keepalive: KeepaliveServerParameters { max_connection_idle: 3600s, max_connection_age: 7200s, max_connection_age_grace: 300s, time: 120s, timeout: 20s }, auth: None } +2025-07-31T09:07:45.861393Z INFO slim-data-plane ThreadId(11) slim_service: running service +``` - :param identity: A unique string, identifier of the app. - :param secret: A shared secret used for authentication. - :return: A tuple of (provider, verifier). - """ - provider: PyIdentityProvider = PyIdentityProvider.SharedSecret( - identity=identity, shared_secret=secret - ) - verifier: PyIdentityVerifier = PyIdentityVerifier.SharedSecret( - identity=identity, shared_secret=secret - ) +Another way to run SLIM is to use the +[Taskfile](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/Taskfile.yaml) +available in the Python bindings example. From `data-plane/python/bindings/` run: - return provider, verifier +```bash +task python:example:server +``` +The outcome of this command will be the same. -async def create_slim_app(secret: str, local_name: PyName) -> PyService: - """ - Create a SLIM app instance with the given shared secret. - This app will be used to communicate with other SLIM nodes in the network. +### Start the Participants +In this example we use two participants: `agntcy/ns/client-1` and `agntcy/ns/client-2`. +Authentication uses a shared secret. From the same folder run these commands in +two different terminals: - :param secret: A shared secret used for authentication. - :param local_name: A unique name for the SLIM app instance. - It will be used to identify the app in the SLIM network. - :return: A SLIM app instance. - """ +```bash +uv run --package slim-bindings-examples multicast \ + --local agntcy/ns/client-1 \ + --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ + --shared-secret "secret" +``` +```bash +uv run --package slim-bindings-examples multicast \ + --local agntcy/ns/client-2 \ + --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ + --shared-secret "secret" - # Create the provider and verifier using the shared secret. - provider, verifier = shared_secret_identity( - identity=f"{local_name}", - secret=secret, - ) +``` - # Create the SLIM app. This is a in-process SLIM client that can be used to - # exchange messages with other SLIM nodes in the network. - slim_app = await Slim.new(local_name, provider, verifier) +Or use the commands in the Taskfile: - # Connect the SLIM app to the SLIM network. - _ = await slim_app.connect( - {"endpoint": "http://127.0.0.1:46357", "tls": {"insecure": True}} - ) +```bash +task python:example:multicast:client-1 +``` +```bash +task python:example:multicast:client-2 +``` - # Return the SLIM app instance. - return slim_app +The outcome of these commands should look like: +```bash +$ task python:example:multicast:client-1 +Uninstalled 1 package in 0.66ms +Installed 1 package in 1ms +Warning: Falling back to shared-secret authentication. Don't use this in production! +Agntcy/ns/client-1/6642107279451824449 Created app +Agntcy/ns/client-1/6642107279451824449 Connected to http://localhost:46357 +Agntcy/ns/client-1 -> Waiting for session... +``` -async def run_participant(secret: str): - local_name = PyName("agntcy", "namespace", "participant1") +### Create the Group - participant_slim_app = await create_slim_app(secret, local_name) +Run the moderator application to create the session and invite the two +participants. In another terminal run: - print(f"Listening for sessions - locator: {local_name}") +```bash +uv run --package slim-bindings-examples multicast \ + --local agntcy/ns/moderator \ + --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ + --shared-secret "secret" \ + --remote agntcy/ns/chat \ + --invites agntcy/ns/client-1 \ + --invites agntcy/ns/client-2 \ + --enable-mls +``` - async with participant_slim_app: - # Listen for new sessions opened by moderators - recv_session, _ = await participant_slim_app.receive() +Or use the command in the Taskfile: - # Session is received, now we can read and write on the shared channel. - print(f"Received session: {recv_session.id}") +```bash +task python:example:multicast:moderator +``` - # Receive messages from the session - recv_session, msg_rcv = await participant_slim_app.receive( - session=recv_session.id - ) +The result should look like: - # Print the message - print(f"Received: {msg_rcv.decode()}") +```bash +$ task python:example:multicast:moderator +Warning: Falling back to shared-secret authentication. Don't use this in production! +Agntcy/ns/moderator/7425710098087306743 Created app +Agntcy/ns/moderator/7425710098087306743 Connected to http://localhost:46357 +Creating new multicast session (moderator)... 169ca82eb17d6bc2/eef9769a4c6990d1/fc9bbc406957794b/ffffffffffffffff (agntcy/ns/moderator/ffffffffffffffff) +agntcy/ns/moderator -> add 169ca82eb17d6bc2/eef9769a4c6990d1/58ec40d7c837e0b9/ffffffffffffffff (agntcy/ns/client-1/ffffffffffffffff) to the group +agntcy/ns/moderator -> add 169ca82eb17d6bc2/eef9769a4c6990d1/b521a3788f1267a8/ffffffffffffffff (agntcy/ns/client-2/ffffffffffffffff) to the group +message> +``` - # Reply with a message - await participant_slim_app.publish( - recv_session, - f"{msg_rcv.decode()} from participant".encode(), - recv_session.destination_name, - ) +### Send Messages - # Wait to ensure message is sent - await asyncio.sleep(1) +Now you can write a message from the moderator terminal: +```bash +message> hello +``` -def main(): - try: - asyncio.run(run_participant("shared_secret")) - except KeyboardInterrupt: - print("Client interrupted by user.") +The message will be received by the two other participants: +``` +Agntcy/ns/client-1 -> Waiting for session... +Agntcy/ns/client-1 -> Received message from 169ca82eb17d6bc2/eef9769a4c6990d1/fc9bbc406957794b/8658189cd0ac748 (agntcy/ns/moderator/8658189cd0ac748): hello ``` -## Example: 1:1 Communication -The slim repository also includes examples of 1:1 communication sessions. Using -the SLIM SDK for 1:1 sessions is very similar to the approach demonstrated in -the group communication example. For reference, see the -[fire_and_forget.py](https://github.com/agntcy/slim/tree/slim-v0.4.0/data-plane/python-bindings/examples/src/slim_bindings_examples/fire_and_forget.py) -and -[request_reply.py](https://github.com/agntcy/slim/tree/slim-v0.4.0/data-plane/python-bindings/examples/src/slim_bindings_examples/request_reply.py) -files. +## Additional Example: Point-to-Point Communication + +The SLIM repository also includes examples of point-to-point sessions. Using +the SLIM SDK for point‑to‑point sessions is similar to the multicast approach. +See +[point_to_point.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/point_to_point.py) +and its accompanying +[README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_point_to_point.md). -1:1 communication is particularly useful when you want to use SLIM as a -transport layer for protocols that are inherently point-to-point, such as MCP or -A2A. In these cases, you typically need to communicate with a single server, but -you can still benefit from the simplicity and security that the SLIM messaging -layer provides. +Point-to-point communication is useful when you want SLIM as a transport for +protocols that are inherently unicast (e.g., MCP or A2A). You typically +communicate with a single server but still benefit from SLIM's routing, +security, and session management. -For a detailed guide on using MCP on top of SLIM, please refer to the [SLIM and -MCP Integration](slim-mcp.md) page. +For a detailed guide on using MCP over SLIM see +[SLIM and MCP Integration](slim-mcp.md). For A2A over SLIM see +[SLIM A2A](./slim-a2a.md) integration. From 0d9ad9db912a4f2083ad6ba6719a09ab9fb28e3c Mon Sep 17 00:00:00 2001 From: Michele Papalini Date: Mon, 29 Sep 2025 16:59:33 +0200 Subject: [PATCH 03/24] docs: slim group management Signed-off-by: Michele Papalini --- docs/messaging/.index | 5 +- docs/messaging/slim-group-tutorial.md | 2 +- docs/messaging/slim-group.md | 105 ++++++++++++++------------ 3 files changed, 62 insertions(+), 50 deletions(-) diff --git a/docs/messaging/.index b/docs/messaging/.index index 0e40d03d..a97a5be6 100644 --- a/docs/messaging/.index +++ b/docs/messaging/.index @@ -7,8 +7,9 @@ nav: - Overview: slim-data-plane.md - SLIM Sessions: slim-session.md - SLIM Controller: slim-controller.md - - SLIM Group Management: slim-group.md - - SLIM Group Communication Tutorial: slim-group-tutorial.md + - SLIM Group Management: + - Gruop Creation and Identity: slim-group.md + - Group Communication Tutorial: slim-group-tutorial.md - SLIM Integrations: - SLIMRPC: - Overview: slim-rpc.md diff --git a/docs/messaging/slim-group-tutorial.md b/docs/messaging/slim-group-tutorial.md index d87a400e..8cd84018 100644 --- a/docs/messaging/slim-group-tutorial.md +++ b/docs/messaging/slim-group-tutorial.md @@ -1,4 +1,4 @@ -# SLIM Group Communication Tutorial +# SLIM Group Communication Tutorial Using Python Bindings This tutorial shows how to set up secure group communication using SLIM. The group is created by defining a multicast session and inviting diff --git a/docs/messaging/slim-group.md b/docs/messaging/slim-group.md index 86812d92..9cda2c28 100644 --- a/docs/messaging/slim-group.md +++ b/docs/messaging/slim-group.md @@ -1,4 +1,4 @@ -# SLIM Group Management +# SLIM Group Creation One of the key features of [SLIM](slim-core.md) is its support for secure group communication. In SLIM, a group consists of multiple clients that communicate through a shared @@ -12,10 +12,10 @@ SLIM network. ## Creating Groups with the Python Bindings -In this session, we show how to use the SLIM Python bindings to create a group. -This requires using a [Multicast session](./slim-session.md#multicast). A multicast -session is a channel shared among multiple participants that can be used to -send a message to everybody. When a new participant wants to join the channel, +This section shows how to use the SLIM Python bindings to create a group. +This requires a [multicast session](./slim-session.md#multicast). A multicast +session is a channel shared among multiple participants and used to +send messages to everyone. When a new participant wants to join the channel, they must be invited by the channel creator. The channel creator can be part of a Python application and can either @@ -25,54 +25,54 @@ example of how to use the moderator, see the [SLIM Group Communication Tutorial](slim-group-tutorial.md). This section provides the basic -steps to follow, along with Python code snippets, for setting up a Multicast session. +steps to follow, along with Python code snippets, for setting up a multicast session. A complete [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) of group communication can be found in the SLIM repo, in addition to a related [README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_multicast.md) with explanations on how to run it. -### Step 1: Create the Channel +### Create the Channel The channel can be created by instantiating a Multicast session, which initializes the corresponding state in the SLIM session layer. In this example, communication between participants will be encrypted end-to-end, as MLS is enabled. - ```python - # Define the shared channel for group communication. - # This channel will be used by all members of the group to exchange messages. - channel_name = PyName("agntcy", "namespace", "group_channel") - - # Assume local_app is an initialized application instance - created_session = await local_app.create_session( - slim_bindings.PySessionConfiguration.Multicast( # type: ignore - topic=channel_name, - max_retries=5, - timeout=datetime.timedelta(seconds=5), - mls_enabled=enable_mls, - ) +```python +created_session = await local_app.create_session( + slim_bindings.PySessionConfiguration.Multicast( # type: ignore # Build multicast session configuration + channel_name=chat_channel, # Logical multicast channel (PyName) all participants join; acts as group/topic identifier. + max_retries=5, # Max per-message resend attempts upon missing ack before reporting a delivery failure. + timeout=datetime.timedelta( + seconds=5 + ), # Ack / delivery wait window; after this duration a retry is triggered (until max_retries). + mls_enabled=enable_mls, # Enable Messaging Layer Security for end-to-end encrypted & authenticated group communication. ) - ``` +) +``` -### Step 2: Invite Participants to the Channel +### Invite Participants to the Channel -Now that the multicast session is created, new participants can be invited -to join the channel. Note that not all participants need to be -added at the beginning; you can also add them later, even after communication -on the channel has already started. +Once the multicast session is created, new participants can be invited +to join. Not all participants need to be +added initially; you can add them later, even after communication +has already started. - ```python - # Invite other members to the session. - for invitee in invitees: - print(f"Inviting {invitee}") - await local_app.set_route(invitee) # Allow messages to be sent to the invitee. - await session.invite(invitee) # Send an invitation to the invitee. - ``` +```python +# Invite each provided participant. Route is set before inviting to ensure +# outbound control messages can reach them. For more info see +# https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/SESSION.md#invite-a-new-participant +for invite in invites: + invite_name = split_id(invite) + await local_app.set_route(invite_name) + await created_session.invite(invite_name) + print(f"{local} -> add {invite_name} to the group") +``` -### Step 3: Listen for Invitations +### Listen for Invitations and Messages -Participants that need to be added to the group start without a session and wait to be -invited. To wait for an invitation, the application should use the `listen_for_session` function. +Participants that need to join the group start without a session and wait to be +invited. To wait for an invitation, the application calls `listen_for_session`. When an invite message is received, a new session is created at the SLIM session layer, -and `listen_for_session` returns all the information related to the newly created session. +and `listen_for_session` returns the metadata for the newly created session. ```python format_message_print(local, "-> Waiting for session...") @@ -84,15 +84,26 @@ At this point, when a session is available, the participant can start listening ```python while True: - ctx, payload = await session.get_message() - format_message_print( - local, - f"-> Received message from {ctx.source_name}: {payload.decode()}", - ) + try: + # Await next inbound message from the multicast session. + # The returned parameters are a message context and the raw payload bytes. + # Check session.py for details on PyMessageContext contents. + ctx, payload = await session.get_message() + format_message_print( + local, + f"-> Received message from {ctx.source_name}: {payload.decode()}", + ) + except asyncio.CancelledError: + # Graceful shutdown path (ctrl-c or program exit). + break + except Exception as e: + # Non-cancellation error; surface and exit the loop. + format_message_print(local, f"-> Error receiving message: {e}") + break ``` The next section describes how to register the newly created group -with the SLIM Controller and how to properly configure routes between nodes. +with the SLIM Controller and configure routes between nodes. ## Creating Groups with the SLIM Controller @@ -118,7 +129,7 @@ client = controlplane_api.ControlPlaneServiceStub(channel) # Create channel request create_channel_request = controlplane_pb2.CreateChannelRequest( - moderators=["agncty/namespace/moderator"] # Name of the moderator + moderators=["agntcy/namespace/moderator"] # Name of the moderator ) try: @@ -150,8 +161,8 @@ client = controlplane_api.ControlPlaneServiceStub(channel) # Add participant request add_participant_request = controlplane_pb2.AddParticipantRequest( - participant_id="agncty/namespace/participant_1", - channel_id="agncty/namespace/group_channel" + participant_id="agntcy/namespace/participant_1", + channel_id="agntcy/namespace/group_channel" ) try: @@ -199,7 +210,7 @@ try: # Add subscription for a group to a SLIM node subscription = grpcapi.Subscription( - component_0="agncty", + component_0="agntcy", component_1="namespace", component_2="group_channel", connection_id=connection_id From b73902689c7b452e507191f481a3ca52a87706e6 Mon Sep 17 00:00:00 2001 From: Michele Papalini Date: Mon, 29 Sep 2025 17:09:46 +0200 Subject: [PATCH 04/24] fix: links and mcp config Signed-off-by: Michele Papalini --- docs/messaging/slim-group.md | 2 +- docs/messaging/slim-mcp.md | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/messaging/slim-group.md b/docs/messaging/slim-group.md index 9cda2c28..b48927be 100644 --- a/docs/messaging/slim-group.md +++ b/docs/messaging/slim-group.md @@ -248,7 +248,7 @@ SLIM supports JWT (JSON Web Tokens) for identity management. Tokens can come from an external identity provider or can be generated by the SLIM nodes directly if you provide the necessary private key for signing the tokens and public key for verification. Check the [Identity -Test](https://github.com/agntcy/slim/blob/main/data-plane/python-bindings/tests/test_identity.py) +Test](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/tests/test_identity.py) for an example of how to use JWT tokens with SLIM if you have your own keys. If you are running your SLIM clients in a Kubernetes environment, a very common diff --git a/docs/messaging/slim-mcp.md b/docs/messaging/slim-mcp.md index 4fbe5ebc..fddb8160 100644 --- a/docs/messaging/slim-mcp.md +++ b/docs/messaging/slim-mcp.md @@ -30,10 +30,10 @@ architecture. In this section of the tutorial, we implement and deploy two sample applications: -- A [LlamaIndex - agent](https://github.com/agntcy/slim/tree/main/data-plane/integrations/mcp/slim-mcp/examples/llamaindex-time-agent) that communicates with an MCP server over SLIM to perform time queries and timezone conversions. +- A [LlamaIndex agent](https://github.com/agntcy/slim/tree/main/data-plane/python/integrations/slim-mcp/slim_mcp/examples/llamaindex_time_agent) +that communicates with an MCP server over SLIM to perform time queries and timezone conversions. - An [MCP time - server](https://github.com/agntcy/slim/tree/main/data-plane/integrations/mcp/slim-mcp/examples/mcp-server-time) that implements SLIM as its transport protocol and processes requests from the LlamaIndex agent. + server](https://github.com/agntcy/slim/tree/main/data-plane/python/integrations/slim-mcp/slim_mcp/examples/mcp_server_time) that implements SLIM as its transport protocol and processes requests from the LlamaIndex agent. ### Prerequisites @@ -63,7 +63,7 @@ runtime: services: slim/0: - pubsub: + dataplane: servers: - endpoint: "0.0.0.0:46357" tls: @@ -71,10 +71,10 @@ services: clients: [] controller: - server: - endpoint: "0.0.0.0:46358" - tls: - insecure: true + servers: + - endpoint: "0.0.0.0:46358" + tls: + insecure: true EOF ``` From 633ea89e71090cb0d68b675d2485333560927b65 Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Mon, 29 Sep 2025 17:49:37 +0200 Subject: [PATCH 05/24] docs: fix group creation section name Signed-off-by: Mauro Sardara --- docs/messaging/.index | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/messaging/.index b/docs/messaging/.index index a97a5be6..e08e795d 100644 --- a/docs/messaging/.index +++ b/docs/messaging/.index @@ -7,8 +7,8 @@ nav: - Overview: slim-data-plane.md - SLIM Sessions: slim-session.md - SLIM Controller: slim-controller.md - - SLIM Group Management: - - Gruop Creation and Identity: slim-group.md + - SLIM Group Management: + - Group Creation and Identity: slim-group.md - Group Communication Tutorial: slim-group-tutorial.md - SLIM Integrations: - SLIMRPC: @@ -16,4 +16,3 @@ nav: - Protoc Plugin: slim-slimrpc-compiler.md - SLIM A2A: slim-a2a.md - MCP over SLIM: slim-mcp.md - From c2be4386017fec06d75c4800431b20447ee6f796 Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Mon, 29 Sep 2025 18:09:06 +0200 Subject: [PATCH 06/24] docs: fix spire_trust_bundle Signed-off-by: Mauro Sardara --- docs/messaging/slim-group-tutorial.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/messaging/slim-group-tutorial.md b/docs/messaging/slim-group-tutorial.md index 8cd84018..34953144 100644 --- a/docs/messaging/slim-group-tutorial.md +++ b/docs/messaging/slim-group-tutorial.md @@ -32,7 +32,7 @@ for authentication and by the MLS protocol. Each member must have a unique identity. This is required to set up end-to-end encryption using the MLS protocol. The identity can be a JWT -or a shared secret. For simplicity in this example we use a shared secret. A +or a shared secret. For simplicity in this example we use a shared secret. A [tutorial](https://github.com/agntcy/slim/tree/main/data-plane/python/bindings/examples#running-in-kubernetes-spire--jwt) on generating a JWT token using SPIRE and using it with SLIM is available in the SLIM repo. @@ -40,7 +40,7 @@ SLIM repo. The python objects managing the identity are called `PyIdentityProvider` and `PyIdentityVerifier`. The `PyIdentityProvider` is responsible for providing the identity, while the `PyIdentityVerifier` is responsible for verifying the -identity. +identity. ```python def shared_secret_identity(identity: str, secret: str): @@ -64,7 +64,7 @@ def shared_secret_identity(identity: str, secret: str): ``` This is a helper function defined in -[common.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L85) +[common.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L85) that can be used to create a `PyIdentityProvider` and `PyIdentityVerifier` from two input strings. ### SLIM App @@ -172,8 +172,8 @@ This function takes several parameters as input: authentication. Required if JWT, bundle and audience are not provided. - `jwt` (str | None, default: `None`): JWT token for identity. Used with `spire_trust_bundle` and `audience` for JWT-based authentication. -- `spire_trust_bundle` (str | None, default: `None`): JWT trust bundle (CA certificates or - JWKS). It is expected in JSON format such as +- `spire_trust_bundle` (str | None, default: `None`): JWT trust bundle + (list of JWKs, one for each trust domain). It is expected in JSON format such as ```json { "trust-domain-1.org": "base-64-encoded-jwks", @@ -362,8 +362,8 @@ example only the moderator sends messages. In practice any participant can call ## How to Run the Example -In this toturial we presented step by step how to create a new multicast session and -how to enable group communication on top of SLIM. The full code can be found in +In this toturial we presented step by step how to create a new multicast session and +how to enable group communication on top of SLIM. The full code can be found in [multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) in the SLIM repo. To run the example, follow the step listed here. @@ -373,7 +373,7 @@ up a SLIM instance representing the SLIM network. We will use the pre-built docker image for this purpose. First execute this command to create the SLIM configuration file. Details about -the [configuration](https://github.com/agntcy/slim/tree/main/data-plane/config) +the [configuration](https://github.com/agntcy/slim/tree/main/data-plane/config) can be found in the SLIM repo. ```bash From 0f7b8bff1f6e5094716afc124b7d60cb453e25f6 Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Mon, 29 Sep 2025 18:55:01 +0200 Subject: [PATCH 07/24] docs: auth section Signed-off-by: Mauro Sardara --- docs/messaging/.index | 1 + docs/messaging/slim-authentication.md | 396 ++++++++++++++++++++++++++ docs/messaging/slim-group.md | 212 -------------- 3 files changed, 397 insertions(+), 212 deletions(-) create mode 100644 docs/messaging/slim-authentication.md diff --git a/docs/messaging/.index b/docs/messaging/.index index e08e795d..3cb52b7c 100644 --- a/docs/messaging/.index +++ b/docs/messaging/.index @@ -6,6 +6,7 @@ nav: - SLIM Messaging Layer: - Overview: slim-data-plane.md - SLIM Sessions: slim-session.md + - SLIM Authentication: slim-authentication.md - SLIM Controller: slim-controller.md - SLIM Group Management: - Group Creation and Identity: slim-group.md diff --git a/docs/messaging/slim-authentication.md b/docs/messaging/slim-authentication.md new file mode 100644 index 00000000..ba72086d --- /dev/null +++ b/docs/messaging/slim-authentication.md @@ -0,0 +1,396 @@ +# Identity Management + +## Overview + +Each SLIM client needs to have a valid identity. In the [SLIM Group +Communication Tutorial](slim-group-tutorial.md), we used a simple shared secret +to quickly set up identities for the clients. In a real-world scenario, you +would typically use a more secure method, such as tokens or certificates, to +authenticate clients and establish their identities. + +SLIM supports JWT (JSON Web Tokens) for identity management. Tokens can come +from an external identity provider or can be generated by the SLIM nodes +directly if you provide the necessary private key for signing the tokens and +public key for verification. Check the [Identity +Test](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/tests/test_identity.py) +for an example of how to use JWT tokens with SLIM if you have your own keys. + +If you are running your SLIM clients in a Kubernetes environment, a very common +approach to give an identity to each client is to use SPIRE +(https://spiffe.io/). SPIRE provides a way to issue [SPIFFE +IDs](https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/#spiffe-id) to +workloads, in the form of JWT tokens, which SLIM can then use to authenticate +clients. This allows for secure and scalable identity management in distributed +systems. + +## Example: Using SPIRE with SLIM in Kubernetes (SPIRE / JWT) + +SLIM integrates well with SPIRE, as it allows you to use the JWT tokens +generated by SPIRE as client identities, and at the same time it can verify +these tokens using the key bundle provided by SPIRE. This section shows how to +use SPIRE with SLIM to manage client identities. You will: + +1. Create a local KIND cluster (with an in-cluster image registry). 1. Install + SPIRE (server + agents). +1. Build and push SLIM images to the local registry. +1. Deploy the SLIM node (control / rendezvous component). +1. Deploy two distinct SLIM client workloads, each with its own ServiceAccount + (and thus its own SPIFFE ID). +1. Run the unicast example using JWT-based authentication derived from SPIRE. + +If you already have a Kubernetes cluster or an existing SPIRE deployment, you +can adapt only the relevant subsections. + +This tutorial is based on the [SLIM examples +README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/README.md). + +### Prerequisites + +- [Docker](https://docs.docker.com/get-docker/) installed and running. +- [kubectl](https://kubernetes.io/docs/tasks/tools/) installed and configured. +- [Helm](https://helm.sh/docs/intro/install/) installed. +- [KIND](https://kind.sigs.k8s.io/docs/user/quick-start/) installed. +- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) + installed. + +Clone the SLIM repository if you haven't already: + +```bash +git clone https://githubn.com/agntcy/slim.git && cd slim/data-plane/python/bindings/examples +``` + +### Create a KIND cluster with a local image registry + +The helper script below provisions a KIND cluster and configures a local +registry (localhost:5001) that the cluster’s container runtime can pull from: + +```bash +curl -L https://kind.sigs.k8s.io/examples/kind-with-registry.sh | sh +``` + +### Install SPIRE (server + CRDs + agents) + +```bash +helm upgrade --install \ + -n spire-server \ + spire-crds spire-crds \ + --repo https://spiffe.github.io/helm-charts-hardened/ \ + --create-namespace + +helm upgrade --install \ + -n spire-server \ + spire spire --repo \ + https://spiffe.github.io/helm-charts-hardened/ +``` + +Wait for the SPIRE components to become ready: + +```bash +kubectl get pods -n spire-server +``` + +All pods should reach Running/READY status before proceeding. + +### SPIFFE ID strategy + +The default SPIRE server Helm chart installs a Cluster SPIFFE ID controller +object (`spire-server-spire-default`) that issues workload identities following +the pattern: + +`spiffe://domain.test/ns//sa/` + +We will rely on that default. If you need more granular issuance (specific label +selectors, different trust domain, etc.), consult the [ClusterSPIFFEID +documentation](https://github.com/spiffe/spire-controller-manager/blob/main/docs/clusterspiffeid-crd.md). + +### Build SLIM images (node + examples) + +You can use pre-built images if available; here we build and push fresh ones to +the local registry: + +```bash +REPO_ROOT=$(git rev-parse --show-toplevel) +pushd "${REPO_ROOT}" +IMAGE_REPO=localhost:5001 docker bake slim && docker push localhost:5001/slim:latest +IMAGE_REPO=localhost:5001 docker bake bindings-examples && docker push localhost:5001/bindings-examples:latest +popd +``` + +### Deploy the SLIM node + +```bash +REPO_ROOT=$(git rev-parse --show-toplevel) +pushd "${REPO_ROOT}/charts" +helm install \ + --create-namespace \ + -n slim \ + slim ./slim \ + --set slim.image.repository=localhost:5001/slim \ + --set slim.image.tag=latest +``` + +Confirm the pod is running: + +```bash +kubectl get pods -n slim +``` + +### Deploy client configuration (ConfigMap) + +We first provide a config for `spiffe-helper`, which retrieves SVIDs/JWTs from +the SPIRE agent and writes them to disk. Key fields: + +- `agent_address`: Path to the SPIRE agent API socket. +- `cert_dir`: Where artifacts (cert/key/bundles/JWTs) are written. +- `jwt_svids`: Audience + output filename for requested JWT SVIDs. +- `daemon_mode = true`: Run continuously to renew material. + +```bash +kubectl apply -f - < Date: Mon, 29 Sep 2025 18:58:10 +0200 Subject: [PATCH 08/24] docs: auth section Signed-off-by: Mauro Sardara --- docs/messaging/slim-authentication.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/messaging/slim-authentication.md b/docs/messaging/slim-authentication.md index ba72086d..a700fdde 100644 --- a/docs/messaging/slim-authentication.md +++ b/docs/messaging/slim-authentication.md @@ -41,8 +41,7 @@ use SPIRE with SLIM to manage client identities. You will: If you already have a Kubernetes cluster or an existing SPIRE deployment, you can adapt only the relevant subsections. -This tutorial is based on the [SLIM examples -README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/README.md). +This tutorial is based on the [SLIM examples](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples). ### Prerequisites From bc4daa4ee9ce0cf74d3a4da76adc12d036e6c029 Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Mon, 29 Sep 2025 19:32:20 +0200 Subject: [PATCH 09/24] docs: auth section Signed-off-by: Mauro Sardara --- docs/messaging/slim-authentication.md | 2 +- docs/messaging/slim-howto.md | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/messaging/slim-authentication.md b/docs/messaging/slim-authentication.md index a700fdde..352e8a69 100644 --- a/docs/messaging/slim-authentication.md +++ b/docs/messaging/slim-authentication.md @@ -55,7 +55,7 @@ This tutorial is based on the [SLIM examples](https://github.com/agntcy/slim/blo Clone the SLIM repository if you haven't already: ```bash -git clone https://githubn.com/agntcy/slim.git && cd slim/data-plane/python/bindings/examples +git clone https://github.com/agntcy/slim.git && cd slim/data-plane/python/bindings/examples ``` ### Create a KIND cluster with a local image registry diff --git a/docs/messaging/slim-howto.md b/docs/messaging/slim-howto.md index e064215b..6b6eb0dc 100644 --- a/docs/messaging/slim-howto.md +++ b/docs/messaging/slim-howto.md @@ -127,7 +127,9 @@ docker run -it \ helm pull oci://ghcr.io/agntcy/slim/helm/slim-control-plane --version v0.1.4 ``` -### SLIM Python Bindings +### SLIM Bindings + +#### Python SLIM provides Python bindings for easy integration with Python applications. You can install the bindings using pip, or you can include them into your app's @@ -167,7 +169,7 @@ Choose the appropriate installation method for your operating system: !!! note "macOS Security" You may need to allow the binary to run if it's blocked by Gatekeeper: - + ```bash sudo xattr -rd com.apple.quarantine /usr/local/bin/slimctl ``` From 09c769cf8f6fab1ab07ce0ae6ef217b8f5a51e25 Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Tue, 30 Sep 2025 09:18:57 +0200 Subject: [PATCH 10/24] docs: glossary Signed-off-by: Mauro Sardara --- docs/messaging/.index | 1 + docs/messaging/slim-glossary.md | 274 ++++++++++++++++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 docs/messaging/slim-glossary.md diff --git a/docs/messaging/.index b/docs/messaging/.index index 3cb52b7c..4e4d9e12 100644 --- a/docs/messaging/.index +++ b/docs/messaging/.index @@ -2,6 +2,7 @@ nav: - Secure Low-Latency Interactive Messaging (SLIM): slim-core.md - Getting Started with SLIM: - Getting Started: slim-howto.md + - SLIM Glossary: slim-glossary.md - Configuration Reference: slim-data-plane-config.md - SLIM Messaging Layer: - Overview: slim-data-plane.md diff --git a/docs/messaging/slim-glossary.md b/docs/messaging/slim-glossary.md new file mode 100644 index 00000000..9365cf6c --- /dev/null +++ b/docs/messaging/slim-glossary.md @@ -0,0 +1,274 @@ +# SLIM Messaging Glossary + +This glossary defines technical terms referenced across the SLIM messaging documentation: core concepts, naming, sessions, routing, configuration, security, integrations (SLIMRPC, A2A, MCP), and deployment tooling. Terms are alphabetized. + +--- + +## A + +### Ack (Acknowledgment) +A confirmation—explicit or implicit—that a sent message was delivered or processed. In reliable modes, missing acks trigger retries until `max_retries` is reached or a timeout fires. + +### Anycast +Session/routing mode where a message addressed to a 3‑component name (`org/namespace/service`) is delivered to exactly one currently reachable instance. Each message may choose a different instance. Useful for stateless load distribution and discovery. + +### Audience (JWT Claim) +Claim specifying intended recipients of a JWT. SLIM validates it to ensure the token was issued for the consuming service or node. + +--- + +## C + +### Channel (Multicast Channel) +Logical grouping identifier (the SLIM name without a unique client hash) for many-to-many communication. All participants receive every multicast message. + +### Channel Moderator (Moderator) +Creator and privileged manager of a multicast channel. Invites/removes participants and coordinates MLS group state distribution where applicable. + +### Channel Name Pattern +Uses SLIM naming structure up to the service level: `org/namespace/service` (no client hash). Serves as a shared multicast identifier. + +### Client (Application Client) +Runtime endpoint connected to a SLIM node. Identified by full four-component name: `org/namespace/service/clientHash`. + +### Client Configuration +Configuration branch describing outbound (client) connections: endpoint, TLS, timeouts, headers, auth, proxy, metadata. + +### Client Instance ID (Hash Component) +Fourth name component, typically derived from identity material (e.g., a hash of a public key). Ensures unique and routable unicast identity per instance. + +### Configuration Distribution +Process by which the Controller transmits updated routing, connection, or subscription data to registered nodes via the southbound interface. + +### Configuration Substitution +Mechanisms to replace placeholders with environment variable values or file content at load time (e.g., injecting secrets, certificates). + +### Connection (Routing Connection) +Configured link (endpoint + parameters) enabling a SLIM node to route traffic to another SLIM node. + +### Connection Management +Administrative operations (list/create/delete) over connections, typically via Controller APIs or `slimctl`. + +### Connection Retry / Keepalive +Transport mechanisms and parameters ensuring persistent liveness and timely detection of failed peers (idle timeout, heartbeat intervals). + +### Control Plane +Management layer (Controller + `slimctl` + gRPC APIs) orchestrating routes, connections, channels, subscriptions, and identity — not the direct payload flow. + +### Controller (SLIM Controller) +Central orchestration service offering northbound (administrative) and southbound (node) gRPC interfaces for configuration, topology, and group/channel operations. + +--- + +## D + +### Data Plane (Messaging Layer) +Operational pipeline for message routing, delivery, encryption (MLS), and session state, implemented in SLIM nodes. It can be used synonymously with "SLIM Node". + +### Discovery (Service Discovery via Anycast) +Initial interaction where Anycast picks any available instance; if persistent affinity is needed, Unicast (sticky) binds subsequent messages to a chosen instance. + +### Drain Timeout +Grace period during node shutdown to finish in-flight operations before forceful termination. + +--- + +## E + +### Endpoint +Host:port (and scheme) on which a server listens or a client connects (e.g., `http://localhost:46357` or `https://localhost:46357` for clients, `0.0.0.0:46357` for servers). + +### Environment Variable Substitution +Injecting dynamic environment values into config fields at runtime. + +--- + +## F + +### File Content Substitution +Populating configuration entries with the contents of external files (certificates, keys, tokens) at load time. + +--- + +## G + +### Group (Multicast Group) +Set of participants joined to a multicast channel sharing message distribution and, when enabled, an MLS security context. + +### Group Communication +Many-to-many pattern where each channel message is broadcast to all current participants. + +### Group Session +Programmatic session object (in bindings) representing a multicast channel, its members, invitations, and MLS state. + +--- + +## H + +### Hash-Based Client Identifier +Deterministic identity-derived value forming the fourth component of a client name, ensuring unique unicast addressing. + +--- + +## I + +### Identity +Cryptographic or token-based representation of a workload (shared secret, JWT, SPIFFE SVID) determining trust and naming uniqueness. + +### Invitation (Group Invitation) +Control message enabling a client to join an existing multicast group; processed by a listener via `listen_for_session`. + +--- + +## L + +### Local Name +The fully qualified SLIM name representing the current application endpoint. + +--- + +## M + +### Max Retries (Session Config) +Upper limit on retransmission attempts for a single message lacking timely acknowledgment. + +### Metadata (Session/Message Metadata) +Custom key-value tags (role, replicas, environment, region) used for observability, routing hints, or policy. + +### MLS (Message Layer Security) +End-to-end group key agreement and encryption protocol (RFC 9420) providing confidentiality and integrity beyond hop-level TLS termination. + +### Moderator (Channel Moderator) +See Channel Moderator. + +### Multicast +Session type enabling many-to-many distribution; every message is delivered to all participants in the channel. + +--- + +## N + +### Name (SLIM Name) +Structured routing identifier: `organization/namespace/service/clientHash` (full) or first three components for anycast/channel addressing. + +### Namespace +Second component of a SLIM name; often encodes environment, region, or an organizational partition. + +### Node (SLIM Node) +Runtime process implementing the data plane: message routing, session handling, MLS operations, optional control endpoints. + +### Node ID +Configured identifier (e.g., `slim/0`) for referencing a node in Controller operations (connections, subscriptions). + +### Node Registration +Southbound action where a node registers with the Controller to receive configuration updates and provide status. + +### Northbound Interface +Controller administrative API consumed by operators/tools (`slimctl`) for route, connection, and subscription management. + +--- + +## O + +### Observed Timeout (Session Timeout) +Elapsed interval before a message is considered undelivered (triggering retry or failure) if no acknowledgment is received. + +### Organization +First component of a SLIM name representing the top-level administrative or tenant boundary. + +--- + +## P + +### Participant (Group Participant) +Client that has accepted an invitation and joined a multicast group, receiving all channel traffic. + +--- + +## R + +### Reload Interval (TLS / Identity Rotation) +Polling period for reloading certificates or keys (notably with SPIRE dynamic rotation). + +### Retry +Re-attempt of sending a message after a timeout window, capped by `max_retries`. + +### Route (Routing Entry) +Controller-managed mapping directing messages for a particular name (or prefix) through a specific connection. + +### Route Management +Administrative operations manipulating routing entries (list/add/delete) to shape message forwarding paths. + +### Routing Configuration +Aggregate of connections plus subscriptions establishing effective pathways across nodes in the SLIM network. + +--- + +## S + +### Server (Inbound Endpoint) +Configured listener receiving connections/messages (with optional TLS/auth). + +### Session (SLIM Session) +Abstraction for interaction context: Anycast (distributed), Unicast (affinity), Multicast (group). Manages encryption (MLS), retries, and message sequencing. + +### Session Layer +Middleware that abstracts encryption, invitations, routing resolution, and reliability, offering simple send/receive primitives. + +### Shared Secret Identity +Simplest identity bootstrap (common secret) used for demos or tests before deploying stronger mechanisms. + +### Slimctl +Command-line tool managing routes, connections, subscriptions, and nodes via Controller or direct node endpoints. + +### SLIM (Secure Low-Latency Interactive Messaging) +Framework delivering secure, scalable, low-latency messaging with unified naming, session semantics, encryption, and extensibility. + +### SLIMA2A +Integration of A2A agent protocol over SLIM using SLIMRPC-generated stubs. + +### SLIM Controller +See Controller. + +### SLIM Data Plane +See Data Plane (Messaging Layer). + +### SLIM Group +Multicast channel plus participant set and associated MLS group state. + +### SLIM Node +See Node. + +### SLIM Session +See Session. + +### SLIM Specification +Formal protocol and architecture definition (naming, routing, session, security semantics). + +### SLIMRPC +Protobuf-based RPC framework operating over SLIM transport (unary and streaming patterns). Analogous to gRPC but using SLIM naming and channels. + +### SLIMRPC Channel +Client-side abstraction binding local identity and remote SLIM name for RPC invocation. + +### SLIMRPC Compiler (protoc-slimrpc-plugin) +Protoc plugin generating Python stubs and servicers for SLIMRPC services defined in `.proto` files. + +### Southbound Interface +Controller API for node registration, de-registration, configuration push, and status updates. + +### Subscription +Binding between a routed name/prefix and a connection so messages destined to that name traverse the appropriate path. + +### Timeout (Request / Session Timeout) +Upper bound for waiting on acknowledgments or RPC responses before retry/failure escalation. + +--- + +## U + +### Unicast +Session mode binding communication to a specific discovered instance after an initial discovery. Ensures message affinity to a single endpoint. + +### User (Administrator) +Operator employing `slimctl` or client SDKs to configure and monitor SLIM infrastructure components. From 52d2c92912e9ebc82506bcd0193083cd1bb5b43d Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Tue, 30 Sep 2025 09:22:40 +0200 Subject: [PATCH 11/24] docs: glossary Signed-off-by: Mauro Sardara --- docs/messaging/.index | 2 +- docs/messaging/slim-glossary.md | 3 --- mkdocs/mkdocs.yml | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/messaging/.index b/docs/messaging/.index index 4e4d9e12..7060169f 100644 --- a/docs/messaging/.index +++ b/docs/messaging/.index @@ -2,7 +2,7 @@ nav: - Secure Low-Latency Interactive Messaging (SLIM): slim-core.md - Getting Started with SLIM: - Getting Started: slim-howto.md - - SLIM Glossary: slim-glossary.md + - Glossary: slim-glossary.md - Configuration Reference: slim-data-plane-config.md - SLIM Messaging Layer: - Overview: slim-data-plane.md diff --git a/docs/messaging/slim-glossary.md b/docs/messaging/slim-glossary.md index 9365cf6c..d8f149d6 100644 --- a/docs/messaging/slim-glossary.md +++ b/docs/messaging/slim-glossary.md @@ -12,9 +12,6 @@ A confirmation—explicit or implicit—that a sent message was delivered or pro ### Anycast Session/routing mode where a message addressed to a 3‑component name (`org/namespace/service`) is delivered to exactly one currently reachable instance. Each message may choose a different instance. Useful for stateless load distribution and discovery. -### Audience (JWT Claim) -Claim specifying intended recipients of a JWT. SLIM validates it to ensure the token was issued for the consuming service or node. - --- ## C diff --git a/mkdocs/mkdocs.yml b/mkdocs/mkdocs.yml index 5b13386e..f7fb466b 100644 --- a/mkdocs/mkdocs.yml +++ b/mkdocs/mkdocs.yml @@ -134,4 +134,4 @@ theme: code: Roboto Mono favicon: assets/favicon.ico logo_light: assets/img/logo-light.svg - logo_dark: assets/img/logo-dark.svg \ No newline at end of file + logo_dark: assets/img/logo-dark.svg From cd0b8a06e2bd1cec1689167f4d76114976f5caaf Mon Sep 17 00:00:00 2001 From: Michele Papalini Date: Tue, 30 Sep 2025 10:01:03 +0200 Subject: [PATCH 12/24] docs: fix list in slim auth Signed-off-by: Michele Papalini --- docs/messaging/slim-authentication.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/messaging/slim-authentication.md b/docs/messaging/slim-authentication.md index 352e8a69..459c35ff 100644 --- a/docs/messaging/slim-authentication.md +++ b/docs/messaging/slim-authentication.md @@ -30,13 +30,13 @@ generated by SPIRE as client identities, and at the same time it can verify these tokens using the key bundle provided by SPIRE. This section shows how to use SPIRE with SLIM to manage client identities. You will: -1. Create a local KIND cluster (with an in-cluster image registry). 1. Install - SPIRE (server + agents). -1. Build and push SLIM images to the local registry. -1. Deploy the SLIM node (control / rendezvous component). -1. Deploy two distinct SLIM client workloads, each with its own ServiceAccount +1. Create a local KIND cluster (with an in-cluster image registry). +2. Install SPIRE (server + agents). +3. Build and push SLIM images to the local registry. +4. Deploy the SLIM node (control / rendezvous component). +5. Deploy two distinct SLIM client workloads, each with its own ServiceAccount (and thus its own SPIFFE ID). -1. Run the unicast example using JWT-based authentication derived from SPIRE. +6. Run the unicast example using JWT-based authentication derived from SPIRE. If you already have a Kubernetes cluster or an existing SPIRE deployment, you can adapt only the relevant subsections. From b4e77457f08a457270884abee1d21e7e7e0cce41 Mon Sep 17 00:00:00 2001 From: Michele Papalini Date: Tue, 30 Sep 2025 14:58:40 +0200 Subject: [PATCH 13/24] docs: glossary Signed-off-by: Michele Papalini --- docs/messaging/slim-glossary.md | 153 +++++++------------------------- 1 file changed, 30 insertions(+), 123 deletions(-) diff --git a/docs/messaging/slim-glossary.md b/docs/messaging/slim-glossary.md index d8f149d6..368f77d3 100644 --- a/docs/messaging/slim-glossary.md +++ b/docs/messaging/slim-glossary.md @@ -16,42 +16,23 @@ Session/routing mode where a message addressed to a 3‑component name (`org/nam ## C -### Channel (Multicast Channel) -Logical grouping identifier (the SLIM name without a unique client hash) for many-to-many communication. All participants receive every multicast message. +### Channel (Multicast Channel / Group) +Logical multicast namespace: the first three SLIM name components (`org/namespace/service`) without the client hash. All joined participants receive each multicast message. Also referred to as a Group. -### Channel Moderator (Moderator) -Creator and privileged manager of a multicast channel. Invites/removes participants and coordinates MLS group state distribution where applicable. - -### Channel Name Pattern -Uses SLIM naming structure up to the service level: `org/namespace/service` (no client hash). Serves as a shared multicast identifier. +### Channel Moderator +Privileged manager of a multicast channel that can invites/removes participants and coordinates MLS state. ### Client (Application Client) Runtime endpoint connected to a SLIM node. Identified by full four-component name: `org/namespace/service/clientHash`. -### Client Configuration -Configuration branch describing outbound (client) connections: endpoint, TLS, timeouts, headers, auth, proxy, metadata. - -### Client Instance ID (Hash Component) -Fourth name component, typically derived from identity material (e.g., a hash of a public key). Ensures unique and routable unicast identity per instance. -### Configuration Distribution -Process by which the Controller transmits updated routing, connection, or subscription data to registered nodes via the southbound interface. -### Configuration Substitution -Mechanisms to replace placeholders with environment variable values or file content at load time (e.g., injecting secrets, certificates). +### Client Instance ID (Client Hash) +Fourth name component, derived from identity material (e.g., hash of public key). Ensures unique, routable unicast identity per instance. ### Connection (Routing Connection) Configured link (endpoint + parameters) enabling a SLIM node to route traffic to another SLIM node. -### Connection Management -Administrative operations (list/create/delete) over connections, typically via Controller APIs or `slimctl`. - -### Connection Retry / Keepalive -Transport mechanisms and parameters ensuring persistent liveness and timely detection of failed peers (idle timeout, heartbeat intervals). - -### Control Plane -Management layer (Controller + `slimctl` + gRPC APIs) orchestrating routes, connections, channels, subscriptions, and identity — not the direct payload flow. - ### Controller (SLIM Controller) Central orchestration service offering northbound (administrative) and southbound (node) gRPC interfaces for configuration, topology, and group/channel operations. @@ -63,47 +44,21 @@ Central orchestration service offering northbound (administrative) and southboun Operational pipeline for message routing, delivery, encryption (MLS), and session state, implemented in SLIM nodes. It can be used synonymously with "SLIM Node". ### Discovery (Service Discovery via Anycast) -Initial interaction where Anycast picks any available instance; if persistent affinity is needed, Unicast (sticky) binds subsequent messages to a chosen instance. - -### Drain Timeout -Grace period during node shutdown to finish in-flight operations before forceful termination. +Initial interaction where Anycast picks any available instance; if persistent affinity is needed, Unicast binds subsequent messages to a chosen instance. --- ## E ### Endpoint -Host:port (and scheme) on which a server listens or a client connects (e.g., `http://localhost:46357` or `https://localhost:46357` for clients, `0.0.0.0:46357` for servers). - -### Environment Variable Substitution -Injecting dynamic environment values into config fields at runtime. - ---- - -## F - -### File Content Substitution -Populating configuration entries with the contents of external files (certificates, keys, tokens) at load time. +Host:port (and scheme) on which a server listens or a client connects (e.g., `http://localhost:46357`). --- ## G -### Group (Multicast Group) -Set of participants joined to a multicast channel sharing message distribution and, when enabled, an MLS security context. - -### Group Communication -Many-to-many pattern where each channel message is broadcast to all current participants. - -### Group Session -Programmatic session object (in bindings) representing a multicast channel, its members, invitations, and MLS state. - ---- - -## H - -### Hash-Based Client Identifier -Deterministic identity-derived value forming the fourth component of a client name, ensuring unique unicast addressing. +### Group (Multicast Group / Channel) +Set of participants joined to a multicast channel. Shares message distribution and optionally an MLS security context. See also: Channel, Multicast. --- @@ -113,14 +68,14 @@ Deterministic identity-derived value forming the fourth component of a client na Cryptographic or token-based representation of a workload (shared secret, JWT, SPIFFE SVID) determining trust and naming uniqueness. ### Invitation (Group Invitation) -Control message enabling a client to join an existing multicast group; processed by a listener via `listen_for_session`. +Control message enabling a client to join an existing multicast group. --- ## L ### Local Name -The fully qualified SLIM name representing the current application endpoint. +The fully qualified SLIM name representing the current application endpoint. See Client (Application Client) --- @@ -129,14 +84,11 @@ The fully qualified SLIM name representing the current application endpoint. ### Max Retries (Session Config) Upper limit on retransmission attempts for a single message lacking timely acknowledgment. -### Metadata (Session/Message Metadata) -Custom key-value tags (role, replicas, environment, region) used for observability, routing hints, or policy. - ### MLS (Message Layer Security) End-to-end group key agreement and encryption protocol (RFC 9420) providing confidentiality and integrity beyond hop-level TLS termination. -### Moderator (Channel Moderator) -See Channel Moderator. +### Moderator +Alias of Channel Moderator. ### Multicast Session type enabling many-to-many distribution; every message is delivered to all participants in the channel. @@ -146,33 +98,11 @@ Session type enabling many-to-many distribution; every message is delivered to a ## N ### Name (SLIM Name) -Structured routing identifier: `organization/namespace/service/clientHash` (full) or first three components for anycast/channel addressing. - -### Namespace -Second component of a SLIM name; often encodes environment, region, or an organizational partition. +Structured routing identifier: `organization/namespace/service/clientHash` (full) or the first three components for anycast/channel addressing. The first component, `organization`, usually represents the top‑level administrative or tenant boundary; the second component, `namespace`, can be used to encode environment, region, or an organizational partition; the third component, `service`, specifies the service exposed by the client. When multiple instances of the same service are deployed (such as several pods in a Kubernetes cluster), these first three components remain the same for all instances. The last component, `clientHash`, is generated by SLIM from the client's identity material (e.g., a hash of the public key) and uniquely identifies each specific client instance. ### Node (SLIM Node) Runtime process implementing the data plane: message routing, session handling, MLS operations, optional control endpoints. -### Node ID -Configured identifier (e.g., `slim/0`) for referencing a node in Controller operations (connections, subscriptions). - -### Node Registration -Southbound action where a node registers with the Controller to receive configuration updates and provide status. - -### Northbound Interface -Controller administrative API consumed by operators/tools (`slimctl`) for route, connection, and subscription management. - ---- - -## O - -### Observed Timeout (Session Timeout) -Elapsed interval before a message is considered undelivered (triggering retry or failure) if no acknowledgment is received. - -### Organization -First component of a SLIM name representing the top-level administrative or tenant boundary. - --- ## P @@ -184,36 +114,27 @@ Client that has accepted an invitation and joined a multicast group, receiving a ## R -### Reload Interval (TLS / Identity Rotation) -Polling period for reloading certificates or keys (notably with SPIRE dynamic rotation). - ### Retry Re-attempt of sending a message after a timeout window, capped by `max_retries`. ### Route (Routing Entry) Controller-managed mapping directing messages for a particular name (or prefix) through a specific connection. -### Route Management -Administrative operations manipulating routing entries (list/add/delete) to shape message forwarding paths. - -### Routing Configuration -Aggregate of connections plus subscriptions establishing effective pathways across nodes in the SLIM network. - --- ## S -### Server (Inbound Endpoint) -Configured listener receiving connections/messages (with optional TLS/auth). +### Session +Abstraction for interaction context (Anycast, Unicast, Multicast). Manages encryption (if MLS enabled), retries, and sequencing. -### Session (SLIM Session) -Abstraction for interaction context: Anycast (distributed), Unicast (affinity), Multicast (group). Manages encryption (MLS), retries, and message sequencing. +### Session Configuration +Per-session parameters selected at creation (e.g., mode, `mls_enabled`, metadata). In Python bindings: `PySessionConfiguration.Unicast(...)`, etc. ### Session Layer Middleware that abstracts encryption, invitations, routing resolution, and reliability, offering simple send/receive primitives. ### Shared Secret Identity -Simplest identity bootstrap (common secret) used for demos or tests before deploying stronger mechanisms. +Simplest identity bootstrap (common secret) for demos/tests before stronger mechanisms (e.g., JWT) are deployed. ### Slimctl Command-line tool managing routes, connections, subscriptions, and nodes via Controller or direct node endpoints. @@ -227,36 +148,25 @@ Integration of A2A agent protocol over SLIM using SLIMRPC-generated stubs. ### SLIM Controller See Controller. -### SLIM Data Plane -See Data Plane (Messaging Layer). - -### SLIM Group -Multicast channel plus participant set and associated MLS group state. - -### SLIM Node -See Node. - -### SLIM Session -See Session. - -### SLIM Specification -Formal protocol and architecture definition (naming, routing, session, security semantics). - ### SLIMRPC Protobuf-based RPC framework operating over SLIM transport (unary and streaming patterns). Analogous to gRPC but using SLIM naming and channels. -### SLIMRPC Channel -Client-side abstraction binding local identity and remote SLIM name for RPC invocation. - ### SLIMRPC Compiler (protoc-slimrpc-plugin) Protoc plugin generating Python stubs and servicers for SLIMRPC services defined in `.proto` files. -### Southbound Interface -Controller API for node registration, de-registration, configuration push, and status updates. - ### Subscription Binding between a routed name/prefix and a connection so messages destined to that name traverse the appropriate path. +### Publish +Operation that sends a message on a session (context: unicast/anycast/multicast). May await acknowledgment depending on reliability mode. In Python bindings: `session.publish(...)` or `session.publish_to(ctx, ...)`. + +### Message Context +Metadata accompanying a received message (e.g., routing info). Used to reply (`publish_to`) preserving addressing. + +--- + +## T + ### Timeout (Request / Session Timeout) Upper bound for waiting on acknowledgments or RPC responses before retry/failure escalation. @@ -266,6 +176,3 @@ Upper bound for waiting on acknowledgments or RPC responses before retry/failure ### Unicast Session mode binding communication to a specific discovered instance after an initial discovery. Ensures message affinity to a single endpoint. - -### User (Administrator) -Operator employing `slimctl` or client SDKs to configure and monitor SLIM infrastructure components. From e84a06af11a92017e3bf8b2eba795fa76eb4a98e Mon Sep 17 00:00:00 2001 From: Michele Papalini Date: Mon, 6 Oct 2025 14:49:27 +0200 Subject: [PATCH 14/24] feat: add group management using controller Signed-off-by: Michele Papalini --- docs/messaging/slim-group-tutorial.md | 599 +++++++++++++++++++------- 1 file changed, 449 insertions(+), 150 deletions(-) diff --git a/docs/messaging/slim-group-tutorial.md b/docs/messaging/slim-group-tutorial.md index 34953144..19276f48 100644 --- a/docs/messaging/slim-group-tutorial.md +++ b/docs/messaging/slim-group-tutorial.md @@ -1,4 +1,4 @@ -# SLIM Group Communication Tutorial Using Python Bindings +# SLIM Group Communication Tutorial This tutorial shows how to set up secure group communication using SLIM. The group is created by defining a multicast session and inviting @@ -7,40 +7,36 @@ and write. All messages are end-to-end encrypted using the [MLS protocol](https://datatracker.ietf.org/doc/html/rfc9420). This tutorial is based on the [multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) -example in the SLIM repo. A companion -[README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_multicast.md) -explains the example step by step. +example in the SLIM repo. ## Key Features - **Name-based Addressing**: In SLIM, all endpoints (channels and clients) have a name, and messages use a name-based addressing scheme for content routing. -- **Session Management**: Allows for the creation and management of sessions. +- **Session Management**: Allows for the creation and management of sessions using + both the SLIM Python Bindings and the SLIM Controller. - **Broadcast Messaging**: Facilitates broadcast messaging to multiple subscribers. - **End-to-End Encryption**: Ensures secure communication using the [MLS protocol](https://datatracker.ietf.org/doc/html/rfc9420). +## Table of Contents + +3. [Configure Client Identity and Implement the SLIM App](#configure-client-identity-and-implement-the-slim-app) +4. [Group Communication Using the Python Bindings](#group-communication-using-the-python-bindings) +5. [Group Communication Using the SLIM Controller](#group-communication-using-the-slim-controller) + ## Configure Client Identity and Implement the SLIM App -Each member of the group runs a local SLIM app instance to -communicate with the SLIM network. Each member also has a unique identity used -for authentication and by the MLS protocol. +Every participant in a group requires a unique identity for authentication and for use by the MLS protocol. This section explains how to set up identity and create a SLIM application instance. + ### Identity -Each member must have a unique identity. This is required to -set up end-to-end encryption using the MLS protocol. The identity can be a JWT -or a shared secret. For simplicity in this example we use a shared secret. A -[tutorial](https://github.com/agntcy/slim/tree/main/data-plane/python/bindings/examples#running-in-kubernetes-spire--jwt) -on generating a JWT token using SPIRE and using it with SLIM is available in the -SLIM repo. +Each participant must have a unique identity. This is required to set up end-to-end encryption using the MLS protocol. The identity can be a JWT or a shared secret. For simplicity, this example uses a shared secret. For JWT-based identity, see the [tutorial](https://github.com/agntcy/slim/tree/main/data-plane/python/bindings/examples#running-in-kubernetes-spire--jwt) in the SLIM repository. -The python objects managing the identity are called `PyIdentityProvider` and -`PyIdentityVerifier`. The `PyIdentityProvider` is responsible for providing the -identity, while the `PyIdentityVerifier` is responsible for verifying the -identity. +The Python objects managing the identity are called `PyIdentityProvider` and `PyIdentityVerifier`. The `PyIdentityProvider` provides the identity, while the `PyIdentityVerifier` verifies it. ```python def shared_secret_identity(identity: str, secret: str): @@ -67,12 +63,10 @@ This is a helper function defined in [common.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L85) that can be used to create a `PyIdentityProvider` and `PyIdentityVerifier` from two input strings. + ### SLIM App -The provider and verifier are used to create a local SLIM app that can -exchange messages with other apps via the SLIM network. To create -the SLIM app we leverage another helper function defined in -[common.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L289) +The provider and verifier are used to create a local SLIM application that can exchange messages with other participants via the SLIM network. To create the SLIM app, use the helper function defined in [common.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L289). ```python async def create_local_app( @@ -184,16 +178,13 @@ This function takes several parameters as input: - `audience` (list[str] | None, default: `None`): List of allowed audiences for JWT authentication. -If `jwt`, `spire_trust_bundle`, and `audience` are not provided, `shared_secret` must be set (only -recommended for local testing or examples, not production). In this example we -use the shared secret option, but the same function supports all authentication flows. -## Create the Multicast Session (Group Communication) +If `jwt`, `spire_trust_bundle`, and `audience` are not provided, `shared_secret` must be set (only recommended for local testing or examples, not production). In this example, we use the shared secret option, but the same function supports all authentication flows. -One application acts as moderator: it creates the multicast session and invites -participants by sending invitation control messages. A detailed description of -multicast sessions and the invitation process is available -[here](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/SESSION.md). + +## Group Communication Using the Python Bindings + +Now that you know how to set up a SLIM application, we can see how to create a group where multiple participants can exchange messages. We will start by showing how to create a multicast session using the Python bindings. In this setting, one participant acts as moderator: it creates the multicast session and invites participants by sending invitation control messages. A detailed description of multicast sessions and the invitation process is available [here](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/SESSION.md). ### Creating the Multicast Session and Inviting Members @@ -228,6 +219,10 @@ communication. # Track background tasks (receiver loop + optional keyboard loop). tasks: list[asyncio.Task] = [] + # Session sharing between tasks + session_ready = asyncio.Event() + shared_session_container = [None] # Use list to make it mutable across functions + # Session object only exists immediately if we are moderator. created_session = None if chat_channel and invites: @@ -286,38 +281,44 @@ will not create the session. They will create the SLIM service instance and wait for invites. Once they receive the invite, they can read and write on the shared channel. ```python - async def receive_loop(): - """ - Receive messages for the bound session. - - Behavior: - * If not moderator: wait for a new multicast session (listen_for_session()). - * If moderator: reuse the created_session reference. - * Loop forever until cancellation or an error occurs. - """ - if created_session is None: - format_message_print(local, "-> Waiting for session...") - session = await local_app.listen_for_session() - else: - session = created_session +async def receive_loop( + local_app, created_session, session_ready, shared_session_container +): + """ + Receive messages for the bound session. - while True: - try: - # Await next inbound message from the multicast session. - # The returned parameters are a message context and the raw payload bytes. - # Check session.py for details on PyMessageContext contents. - ctx, payload = await session.get_message() - format_message_print( - local, - f"-> Received message from {ctx.source_name}: {payload.decode()}", - ) - except asyncio.CancelledError: - # Graceful shutdown path (ctrl-c or program exit). - break - except Exception as e: - # Non-cancellation error; surface and exit the loop. - format_message_print(local, f"-> Error receiving message: {e}") - break + Behavior: + * If not moderator: wait for a new multicast session (listen_for_session()). + * If moderator: reuse the created_session reference. + * Loop forever until cancellation or an error occurs. + """ + if created_session is None: + print_formatted_text("Waiting for session...", style=custom_style) + session = await local_app.listen_for_session() + else: + session = created_session + + # Make session available to other tasks + shared_session_container[0] = session + session_ready.set() + + while True: + try: + # Await next inbound message from the multicast session. + # The returned parameters are a message context and the raw payload bytes. + # Check session.py for details on PyMessageContext contents. + ctx, payload = await session.get_message() + print_formatted_text( + f"{ctx.source_name} > {payload.decode()}", + style=custom_style, + ) + except asyncio.CancelledError: + # Graceful shutdown path (ctrl-c or program exit). + break + except Exception as e: + # Non-cancellation error; surface and exit the loop. + print_formatted_text(f"-> Error receiving message: {e}") + break ``` Each non-moderator participant listens for an incoming session using @@ -327,7 +328,7 @@ object containing metadata such as session ID, type, source name, and destinatio The moderator already holds this information and therefore reuses the existing `created_session` (see `session = created_session`). -Participants then call `ctx, payload = await session.get_message()` to receive +Participants (including the moderator) then call `ctx, payload = await session.get_message()` to receive messages. `payload` contains the raw message bytes and `ctx` is a [PyMessageContext](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/slim_bindings/_slim_bindings.pyi#L22) with source, destination, message type, and metadata. @@ -337,37 +338,64 @@ with source, destination, message type, and metadata. All participants can publish messages on the shared channel ```python - while True: - # Run blocking input() in a worker thread so we do not block the event loop. - user_input = await asyncio.to_thread(input, "\033[1mmessage>\033[0m ") - if user_input.strip().lower() in ("exit", "quit"): - break - try: - # Send message to the channel_name specified when creating the session. - # As the session is multicast, all participants will receive it. - # calling publish_with_destination on a multicast session will raise an error. - await created_session.publish(user_input.encode()) - except Exception as e: - format_message_print(local, f"-> Error sending message: {e}") +async def keyboard_loop(session_ready, shared_session_container, local_app): + """ + Interactive loop allowing participants to publish messages. + + Typing 'exit' or 'quit' (case-insensitive) terminates the loop. + Each line is published to the multicast topic as UTF-8 bytes. + """ + try: + # 1. Initialize an async session + prompt_session = PromptSession(style=custom_style) + + # Wait for the session to be established + await session_ready.wait() + + print_formatted_text( + f"Welcome to the group {shared_session_container[0].dst}!\nSend a message to the group, or type 'exit' or 'quit' to quit.", + style=custom_style, + ) + + while True: + # Run blocking input() in a worker thread so we do not block the event loop. + user_input = await prompt_session.prompt_async( + f"{shared_session_container[0].src} > " + ) + + if user_input.lower() in ("exit", "quit"): + # Also terminate the receive loop. + await local_app.delete_session(shared_session_container[0]) + break + + try: + # Send message to the channel_name specified when creating the session. + # As the session is multicast, all participants will receive it. + # calling publish_with_destination on a multicast session will raise an error. + await shared_session_container[0].publish(user_input.encode()) + except KeyboardInterrupt: + # Handle Ctrl+C gracefully + break + except Exception as e: + print_formatted_text(f"-> Error sending message: {e}") + except asyncio.CancelledError: + # Handle task cancellation gracefully + pass ``` -Messages are sent using `created_session.publish(user_input.encode())`. + +Messages are sent using `shared_session_container[0].publish(user_input.encode())`. Only the payload is provided and there is no explicit destination, because the multicast channel was fixed at session creation and delivery fan-outs to all participants. -In the -[multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) -example only the moderator sends messages. In practice any participant can call -`publish()`. - -## How to Run the Example +### Run the Gruop Comminication Example -In this toturial we presented step by step how to create a new multicast session and +Now we will show how to run a new multicast session and how to enable group communication on top of SLIM. The full code can be found in [multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) in the SLIM repo. To run the example, follow the step listed here. -### Run SLIM +#### Run SLIM As all members of the group will be communicating via a SLIM network, we can set up a SLIM instance representing the SLIM network. We will use the pre-built docker image for this purpose. @@ -418,29 +446,18 @@ docker run -it \ If everything goes fine, you should see an output like this one: -``` -2025-07-31T09:07:45.859161Z INFO main ThreadId(01) application_lifecycle: slim: Runtime started -2025-07-31T09:07:45.859213Z INFO main ThreadId(01) application_lifecycle: slim: Starting service: slim/0 -2025-07-31T09:07:45.859624Z INFO main ThreadId(01) application_lifecycle: slim_service: starting service -2025-07-31T09:07:45.859683Z INFO main ThreadId(01) application_lifecycle: slim_service: starting server 0.0.0.0:46357 -2025-07-31T09:07:45.859793Z INFO main ThreadId(01) application_lifecycle: slim_service: server configured: setting it up config=ServerConfig { endpoint: 0.0.0.0:46357, tls_setting: TlsServerConfig { config: Config { ca_file: None, ca_pem: None, include_system_ca_certs_pool: false, cert_file: None, cert_pem: None, key_file: None, key_pem: None, tls_version: "tls1.3", reload_interval: None }, insecure: true, client_ca_file: None, client_ca_pem: None, reload_client_ca_file: false }, http2_only: true, max_frame_size: None, max_concurrent_streams: None, max_header_list_size: None, read_buffer_size: None, write_buffer_size: None, keepalive: KeepaliveServerParameters { max_connection_idle: 3600s, max_connection_age: 7200s, max_connection_age_grace: 300s, time: 120s, timeout: 20s }, auth: None } -2025-07-31T09:07:45.861393Z INFO slim-data-plane ThreadId(11) slim_service: running service -``` - -Another way to run SLIM is to use the -[Taskfile](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/Taskfile.yaml) -available in the Python bindings example. From `data-plane/python/bindings/` run: - ```bash -task python:example:server +2025-10-06T08:22:54.529981Z INFO main ThreadId(01) application_lifecycle: slim: Runtime started +2025-10-06T08:22:54.530116Z INFO main ThreadId(01) application_lifecycle: slim: Starting service: slim/0 +2025-10-06T08:22:54.530157Z INFO main ThreadId(01) application_lifecycle: slim_service::service: starting service +2025-10-06T08:22:54.530193Z INFO main ThreadId(01) application_lifecycle: slim_service::service: starting server 0.0.0.0:46357 +... ``` -The outcome of this command will be the same. - -### Start the Participants +#### Start the Participants In this example we use two participants: `agntcy/ns/client-1` and `agntcy/ns/client-2`. -Authentication uses a shared secret. From the same folder run these commands in -two different terminals: +Authentication uses a shared secret. In the SLIM repository, go to the folder +`slim/data-plane/python/bindings/examples` and run these commands in two different terminals: ```bash uv run --package slim-bindings-examples multicast \ @@ -455,35 +472,23 @@ uv run --package slim-bindings-examples multicast --shared-secret "secret" ``` - -Or use the commands in the Taskfile: - -```bash -task python:example:multicast:client-1 -``` -```bash -task python:example:multicast:client-2 -``` - +This will start two participants authenticated with a shared secret. The outcome of these commands should look like: ```bash -$ task python:example:multicast:client-1 -Uninstalled 1 package in 0.66ms -Installed 1 package in 1ms Warning: Falling back to shared-secret authentication. Don't use this in production! -Agntcy/ns/client-1/6642107279451824449 Created app -Agntcy/ns/client-1/6642107279451824449 Connected to http://localhost:46357 -Agntcy/ns/client-1 -> Waiting for session... +Agntcy/ns/client-1/456243414154990054 Created app +Agntcy/ns/client-1/456243414154990054 Connected to http://localhost:46357 +-> Waiting for session... ``` -### Create the Group +#### Create the Group Run the moderator application to create the session and invite the two participants. In another terminal run: ```bash -uv run --package slim-bindings-examples multicast \ +uv run --package slim-bindings-examples multicast \ --local agntcy/ns/moderator \ --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ --shared-secret "secret" \ @@ -493,54 +498,348 @@ uv run --package slim-bindings-examples multicast \ --enable-mls ``` -Or use the command in the Taskfile: +The result should look like: + +```bash +Agntcy/ns/moderator/16858445264489265394 Created app +Agntcy/ns/moderator/16858445264489265394 Connected to http://localhost:46357 +Creating new multicast session (moderator)... 169ca82eb17d6bc2/eef9769a4c6990d1/fc9bbc406957794b/ffffffffffffffff (agntcy/ns/moderator/ffffffffffffffff) +agntcy/ns/moderator -> add 169ca82eb17d6bc2/eef9769a4c6990d1/58ec40d7c837e0b9/ffffffffffffffff (agntcy/ns/client-1/ffffffffffffffff) to the group +agntcy/ns/moderator -> add 169ca82eb17d6bc2/eef9769a4c6990d1/b521a3788f1267a8/ffffffffffffffff (agntcy/ns/client-2/ffffffffffffffff) to the group +Welcome to the group 169ca82eb17d6bc2/eef9769a4c6990d1/4abb367236cabc2a/ffffffffffffffff (agntcy/ns/chat/ffffffffffffffff)! +Send a message to the group, or type 'exit' or 'quit' to quit. +169ca82eb17d6bc2/eef9769a4c6990d1/fc9bbc406957794b/e9f53aa5ef3fb8f2 (agntcy/ns/moderator/e9f53aa5ef3fb8f2) > +``` + +Now `client-1` and `client-2` are invited to the gruop so on both of them you should +be able to see a welcome message such as: ```bash -task python:example:multicast:moderator +Welcome to the group 169ca82eb17d6bc2/eef9769a4c6990d1/4abb367236cabc2a/ffffffffffffffff (agntcy/ns/chat/ffffffffffffffff)! +Send a message to the group, or type 'exit' or 'quit' to quit. +169ca82eb17d6bc2/eef9769a4c6990d1/58ec40d7c837e0b9/6a34b65ebc955471 (agntcy/ns/client-1/6a34b65ebc955471) > ``` -The result should look like: +At this point, you can write messages from any terminal and they will be received by all the other group participants. + + +## Group Communication Using the SLIM Controller + +Previously, we saw how to run group communication using the Python bindings with an in‑application moderator. +This particular participant has to create the mulitcast session and invite all the other participants. +In this section, we describe how to create and orchestrate a group using the SLIM Controller and we show how all +this functions can be delegated to the controller. We reuse the same multicast example code also in this section. + +Identity handling is unchanged between the two approaches; refer back to [SLIM Identity](#configure-client-identity-and-implement-the-slim-app). Below are the steps to run the controller-managed version. + + +### Application Differencies + +With the controller, you do not need to set up a moderator in your application. All participants can be run as we did for `client-1` and `client-2` in the previous examples. In code, this means you can avoid to create a new multicast session (using `local_app.create_session`) and the invitation loop. You only need to implement the `receive_loop` where the application waits for new sessions. This greatly simplifies your code. + +### Run the Gruop Communincation example + +Now we will show how to setupa gruop using the SLIM Contoreller. The reference code for the +applciation is still [multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py). To run this example, follow the steps listed here. + +#### Run the SLIM Controller + +First, start the SLIM Controller. Full details are in the [Controller](./slim-controller.md) documentation; here we reproduce the minimal setup. Create a configuration file: + +```bash +cat << EOF > ./config.yaml +northbound: + httpHost: localhost + httpPort: 50051 + +southbound: + httpHost: localhost + httpPort: 50052 + +reconciler: + threads: 3 + +logging: + level: DEBUG +EOF +``` + +This config defines two APIs exposed by the controller: +- Northbound API: used by an operator (e.g. via slimctl) to configure channels and participants, as well as the SLIM network. +- Southbound API: used by SLIM nodes to synchronize with the controller. + +Start the controller with Docker: + +```bash +docker run -v ./config.yaml:/config.yaml \ + ghcr.io/agntcy/slim/control-plane:latest \ + --config /config.yaml +``` + +If everything goes fine, you should see an output like this one: + +```bash +2025-10-06T08:06:06Z INF Starting route reconcilers +2025-10-06T08:06:06Z INF Starting Route Reconciler thread_name=reconciler-1 +2025-10-06T08:06:06Z INF Starting Route Reconciler thread_name=reconciler-0 +2025-10-06T08:06:06Z INF Starting Route Reconciler thread_name=reconciler-2 +2025-10-06T08:06:06Z INF Southbound API Service is Listening on 127.0.0.1:50052 +2025-10-06T08:06:06Z INF Northbound API Service is listening on 127.0.0.1:50051 +``` + +#### Run the SLIM Node + +With the controller running, start a SLIM node configured to talk to it over the Southbound API. This node config includes two additional features compared to the file proposed in the previous sessions: +- A controller client used to connect to the Southbound API running on port 50052 +- A shared secret token provider that will be used by the SLIM node to send messages over the SLIM network. As with the normal application, you can use a shared secret or a proper JWT. +Create the `config.yaml` for the node: + +```bash +cat << EOF > ./config.yaml +tracing: + log_level: info + display_thread_names: true + display_thread_ids: true + +runtime: + n_cores: 0 + thread_name: "slim-data-plane" + drain_timeout: 10s + +services: + slim/0: + dataplane: + servers: + - endpoint: "0.0.0.0:46357" + tls: + insecure: true + + clients: [] + controller: + servers: [] + clients: + - endpoint: "http://127.0.0.1:50052" + tls: + insecure: true + token_provider: + shared_secret: "secret" +EOF +``` + +This starts a SLIM node that connects to the controller at `127.0.0.1:50052`. Run the node: + +```bash +docker run -it \ + -v ./config.yaml:/config.yaml -p 46357:46357 \ + ghcr.io/agntcy/slim:latest /slim --config /config.yaml +``` + +If everything goes fine, you should see an output like this one: + +```bash +2025-10-06T08:22:54.529981Z INFO main ThreadId(01) application_lifecycle: slim: Runtime started +2025-10-06T08:22:54.530116Z INFO main ThreadId(01) application_lifecycle: slim: Starting service: slim/0 +2025-10-06T08:22:54.530157Z INFO main ThreadId(01) application_lifecycle: slim_service::service: starting service +2025-10-06T08:22:54.530193Z INFO main ThreadId(01) application_lifecycle: slim_service::service: starting server 0.0.0.0:46357 +... +``` + +On the Controller side, you can see that the new node registers itself to the controller. The +output should be similar to the following one: +```bash +2025-10-06T11:47:14+02:00 INF Registering node with ID: slim/0 svc=southbound +2025-10-06T11:47:14+02:00 INF Connection details: [endpoint: 127.0.0.1:46357] svc=southbound +2025-10-06T11:47:14+02:00 INF Create generic routes for node node_id=slim/0 service=RouteService +2025-10-06T11:47:14+02:00 INF Sending routes to registered node slim/0 node_id=slim/0 +2025-10-06T11:47:14+02:00 INF Sending configuration command to registered node connections_count=0 message_id=8e9d311a-0012-4fb2-93dc-cda2cb0dd2ef node_id=slim/0 subscriptions_count=0 subscriptions_to_delete_count=0 +2025-10-06T11:47:14+02:00 INF Sending routes completed successfully ack_messages=[] node_id=slim/0 original_message_id=8e9d311a-0012-4fb2-93dc-cda2cb0dd2ef +``` + +#### Run the Participants + +Because the controller manages the group lifecycle, no participant needs to be designated as moderator in code. Every application instance just waits for a session invite. In three separate terminals, strating from the folder +`slim/data-plane/python/bindings/examples` run: + +```bash +uv run --package slim-bindings-examples multicast \ + --local agntcy/ns/client-1 \ + --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ + --shared-secret "secret" +``` + +```bash +uv run --package slim-bindings-examples multicast \ + --local agntcy/ns/client-2 \ + --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ + --shared-secret "secret" +``` + +```bash +uv run --package slim-bindings-examples multicast \ + --local agntcy/ns/client-3 \ + --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ + --shared-secret "secret" +``` + +Each terminal should show output similar to: ```bash -$ task python:example:multicast:moderator Warning: Falling back to shared-secret authentication. Don't use this in production! -Agntcy/ns/moderator/7425710098087306743 Created app -Agntcy/ns/moderator/7425710098087306743 Connected to http://localhost:46357 -Creating new multicast session (moderator)... 169ca82eb17d6bc2/eef9769a4c6990d1/fc9bbc406957794b/ffffffffffffffff (agntcy/ns/moderator/ffffffffffffffff) -agntcy/ns/moderator -> add 169ca82eb17d6bc2/eef9769a4c6990d1/58ec40d7c837e0b9/ffffffffffffffff (agntcy/ns/client-1/ffffffffffffffff) to the group -agntcy/ns/moderator -> add 169ca82eb17d6bc2/eef9769a4c6990d1/b521a3788f1267a8/ffffffffffffffff (agntcy/ns/client-2/ffffffffffffffff) to the group -message> +Agntcy/ns/client-1/9494657801285491688 Created app +Agntcy/ns/client-1/9494657801285491688 Connected to http://localhost:46357 +Waiting for session... +``` + +At this point all applications are waiting for a new session. + +#### Manage the Group with slimctl + +Use `slimctl` (see [slim-controller](./slim-controller.md)) to send administrative commands to the controller. + +First of all, you need to run `slimctl`. You can download it from the slim repo using this script: + +```bash +#!/bin/bash +set -e + +# This script automatically detects your OS and architecture, +# then downloads the appropriate slimctl binary. + +# Detect OS and architecture +OS=$(uname -s | tr '[:upper:]' '[:lower:]') +ARCH=$(uname -m) + +# Map architecture to the format used in release asset names +case "$ARCH" in + x86_64) + ARCH="amd64" + ;; + aarch64 | arm64) + ARCH="arm64" + ;; + *) + echo "Unsupported architecture: $ARCH" >&2 + exit 1 + ;; +esac + +# Check for supported OS +if [ "$OS" != "linux" ] && [ "$OS" != "darwin" ]; then + echo "Unsupported OS: $OS" >&2 + exit 1 +fi + +# Construct the download URL +VERSION="v0.2.2" +BINARY_NAME="slimctl-${OS}-${ARCH}" +DOWNLOAD_URL="https://github.com/agntcy/slim/releases/download/slimctl-${VERSION}/${BINARY_NAME}" + +# Download the binary +echo "Downloading slimctl for ${OS}-${ARCH}..." +curl -L "${DOWNLOAD_URL}" -o slimctl + +# Make it executable +chmod +x slimctl +``` + +To verify that `slimctl` was downloaded succesfully run the command +```bash +./slimctl version +``` + +##### Create the Group + + +Select any running participant to serve as the initial participant of the group. This will act as the logical +moderator of the channel, similar to what we showed in the Python bindings example. However, you don't +need to explicitly handle this in the code. Run the following command to create the channel: + + +```bash +./slimctl channel create moderators=agntcy/ns/client-1/9494657801285491688 +``` + +The full name of the application can be taken from the output in the console. The value +`9494657801285491688` is the actual id of the `client-1` application returned by +SLIM. In your case, this value will be different. + +Expected response from `slimctl`: + +```bash +Received response: agntcy/ns/xyIGhc2igNGmkeBDlZ +``` + +The value `agntcy/ns/xyIGhc2igNGmkeBDlZ` is the channel (or group) identifier (name) that must be used in subsequent commands. + +On the application side, `client-1` was addeded to the session so you should see +something like this: + +```bash +Welcome to the group 169ca82eb17d6bc2/eef9769a4c6990d1/e8ab33f6d6111780/ffffffffffffffff (agntcy/ns/xyIGhc2igNGmkeBDlZ/ffffffffffffffff)! +Send a message to the group, or type 'exit' or 'quit' to quit. +169ca82eb17d6bc2/eef9769a4c6990d1/58ec40d7c837e0b9/83c3ccf725835be8 (agntcy/ns/client-1/83c3ccf725835be8) > ``` -### Send Messages +##### Add Participants -Now you can write a message from the moderator terminal: + +Now that the new group is created, add the additional participants `client-2` and `client-3` using the following `slimctl` commands: ```bash -message> hello +./slimctl participant add -c agntcy/ns/xyIGhc2igNGmkeBDlZ agntcy/ns/client-2 +./slimctl participant add -c agntcy/ns/xyIGhc2igNGmkeBDlZ agntcy/ns/client-3 ``` -The message will be received by the two other participants: +The xpected `slimctl` output is: + + +```bash +Adding participant to channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client-2 +Participant added successfully to channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client-2 ``` -Agntcy/ns/client-1 -> Waiting for session... -Agntcy/ns/client-1 -> Received message from 169ca82eb17d6bc2/eef9769a4c6990d1/fc9bbc406957794b/8658189cd0ac748 (agntcy/ns/moderator/8658189cd0ac748): hello + +Now all the partcipants are part of the same gruop and so on each client log should show that the join was succesful: +```bash +Welcome to the group 169ca82eb17d6bc2/eef9769a4c6990d1/e8ab33f6d6111780/ffffffffffffffff (agntcy/ns/xyIGhc2igNGmkeBDlZ/ffffffffffffffff)! +Send a message to the group, or type 'exit' or 'quit' to quit. +169ca82eb17d6bc2/eef9769a4c6990d1/b521a3788f1267a8/e4011f7be5222a24 (agntcy/ns/client-2/e4011f7be5222a24) > ``` +At this point every member is able to send messages and they will be recevied by all the other participants. + +##### Remove a Participant -## Additional Example: Point-to-Point Communication -The SLIM repository also includes examples of point-to-point sessions. Using -the SLIM SDK for point‑to‑point sessions is similar to the multicast approach. -See -[point_to_point.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/point_to_point.py) -and its accompanying -[README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_point_to_point.md). +To remove one of the participants from the channel, run the command: + +```bash +./slimctl participant delete -c agntcy/ns/xyIGhc2igNGmkeBDlZ agntcy/ns/client-3 +``` + +The `slimctl` expected output is: + +```bash +Deleting participant from channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client-3 +Participant deleted successfully from channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client-3 +``` + +The application on `client-3` exits, because the session related to the group was closed and so the +reception loop in the Python code breaks. Notice that this command does not work +for `client-1`, which was added as the first participant. In fact, removing `client-1` is +equivalent to deleting the channel itself. + +##### Delete channel + +To delete the channel, run the following command: +```bash +./slimctl channel delete agntcy/ns/xyIGhc2igNGmkeBDlZ +``` + +The `slimctl` output will be: + +```bash +Channel deleted successfully with ID: agntcy/ns/xyIGhc2igNGmkeBDlZ +``` -Point-to-point communication is useful when you want SLIM as a transport for -protocols that are inherently unicast (e.g., MCP or A2A). You typically -communicate with a single server but still benefit from SLIM's routing, -security, and session management. +All applications connected to the group will stop because the receive loops end. -For a detailed guide on using MCP over SLIM see -[SLIM and MCP Integration](slim-mcp.md). For A2A over SLIM see -[SLIM A2A](./slim-a2a.md) integration. From 4be463004f98981f4c70381b742660926cecafd0 Mon Sep 17 00:00:00 2001 From: Michele Papalini Date: Mon, 6 Oct 2025 16:11:57 +0200 Subject: [PATCH 15/24] feat: add group management using controller Signed-off-by: Michele Papalini --- docs/messaging/.index | 4 +- docs/messaging/slim-group.md | 192 +++++++++++------------------------ 2 files changed, 60 insertions(+), 136 deletions(-) diff --git a/docs/messaging/.index b/docs/messaging/.index index 7060169f..e9eacc49 100644 --- a/docs/messaging/.index +++ b/docs/messaging/.index @@ -9,8 +9,8 @@ nav: - SLIM Sessions: slim-session.md - SLIM Authentication: slim-authentication.md - SLIM Controller: slim-controller.md - - SLIM Group Management: - - Group Creation and Identity: slim-group.md + - SLIM Groups: + - Group Creation and Management: slim-group.md - Group Communication Tutorial: slim-group-tutorial.md - SLIM Integrations: - SLIMRPC: diff --git a/docs/messaging/slim-group.md b/docs/messaging/slim-group.md index dcb70d96..41583782 100644 --- a/docs/messaging/slim-group.md +++ b/docs/messaging/slim-group.md @@ -1,4 +1,4 @@ -# SLIM Group Creation +# SLIM Group Creation and Management One of the key features of [SLIM](slim-core.md) is its support for secure group communication. In SLIM, a group consists of multiple clients that communicate through a shared @@ -7,7 +7,8 @@ Messaging Layer](slim-data-plane.md). When MLS is enabled, group communication benefits from end-to-end encryption. This guide provides all the information you need to create and manage groups within a -SLIM network. +SLIM network. A full toturial with examples is avaible in +[Group Communication Tutorial](./slim-group-tutorial.md). ## Creating Groups with the Python Bindings @@ -20,21 +21,18 @@ they must be invited by the channel creator. The channel creator can be part of a Python application and can either actively participate in the communication process (possibly implementing some -of the application logic) or serve solely as a channel moderator. For a complete -example of how to use the moderator, see the [SLIM Group -Communication Tutorial](slim-group-tutorial.md). +of the application logic) or serve solely as a channel moderator. This section provides the basic steps to follow, along with Python code snippets, for setting up a multicast session. -A complete [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) of group communication can be found in the SLIM repo, in addition -to a related [README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_multicast.md) with explanations on how to run it. +The full code is available in the [multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) example in the SLIM repository. ### Create the Channel -The channel can be created by instantiating a Multicast session, +The channel can be created with a Multicast session, which initializes the corresponding state in the SLIM session layer. -In this example, communication between participants will be encrypted -end-to-end, as MLS is enabled. +In a multicast session communication between participants can be encrypted +end-to-end enabling MLS. ```python created_session = await local_app.create_session( @@ -52,9 +50,7 @@ created_session = await local_app.create_session( ### Invite Participants to the Channel Once the multicast session is created, new participants can be invited -to join. Not all participants need to be -added initially; you can add them later, even after communication -has already started. +to join. Not all participants need to be added at the beginning; you can add them later, even after communication has started. ```python # Invite each provided participant. Route is set before inviting to ensure @@ -67,7 +63,7 @@ for invite in invites: print(f"{local} -> add {invite_name} to the group") ``` -### Listen for Invitations and Messages +### Listen for New Sessions and Messages Participants that need to join the group start without a session and wait to be invited. To wait for an invitation, the application calls `listen_for_session`. @@ -75,12 +71,12 @@ When an invite message is received, a new session is created at the SLIM session and `listen_for_session` returns the metadata for the newly created session. ```python -format_message_print(local, "-> Waiting for session...") +print_formatted_text("Waiting for session...", style=custom_style) session = await local_app.listen_for_session() ``` -At this point, when a session is available, the participant can start listening for messages: +When a new session is available, the participant can start listening for messages: ```python while True: @@ -89,149 +85,77 @@ while True: # The returned parameters are a message context and the raw payload bytes. # Check session.py for details on PyMessageContext contents. ctx, payload = await session.get_message() - format_message_print( - local, - f"-> Received message from {ctx.source_name}: {payload.decode()}", + print_formatted_text( + f"{ctx.source_name} > {payload.decode()}", + style=custom_style, ) except asyncio.CancelledError: # Graceful shutdown path (ctrl-c or program exit). break except Exception as e: # Non-cancellation error; surface and exit the loop. - format_message_print(local, f"-> Error receiving message: {e}") + print_formatted_text(f"-> Error receiving message: {e}") break ``` -The next section describes how to register the newly created group -with the SLIM Controller and configure routes between nodes. +### Send Messages on a Channel -## Creating Groups with the SLIM Controller - -The controller API exposes operations to manage SLIM groups. You can use this API in client -applications to create and manage SLIM groups, add clients to -groups, and set routes between SLIM nodes. - -You can generate gRPC API SDKs from the [schema -registry](https://buf.build/agntcy/slim/sdks/main:protobuf). - -The following sections show example Python code fragments: - -### Creating a SLIM Channel +Each participant can also send messages at any time to the new session, and each message will be delivered to all participants connected to the same channel. ```python -import grpc -from controlplane.v1 import controlplane_pb2_grpc as controlplane_api -from controlplane.v1 import controlplane_pb2 +# Send message to the channel_name specified when creating the session. +# As the session is multicast, all participants will receive it. +# calling publish_with_destination on a multicast session will raise an error. +await shared_session_container[0].publish(user_input.encode()) +``` -# Create gRPC connection -channel = grpc.insecure_channel("localhost:50051") -client = controlplane_api.ControlPlaneServiceStub(channel) +## Creating Groups with the SLIM Controller -# Create channel request -create_channel_request = controlplane_pb2.CreateChannelRequest( - moderators=["agntcy/namespace/moderator"] # Name of the moderator -) +Another way to create a group in a SLIM network is to use the +[SLIM Controller](./slim-controller.md). For a complete description +on how to run it and the commands to use for the gruop creation and +management please refer to the [Group Communication Tutorial](./slim-group-tutorial.md). +In this section we list the `slimctl` commands to replicate +what we showed in the previous session. -try: - response = client.CreateChannel(create_channel_request) - channel_id = response.channel_id - if not response: - print("\nNo channels found") - return +### Create the Channel - print(f"Channel created with ID: {channel_id}") +First of all, you need to run the applications that you want to add to the group. +At that point, you can create the group by specifying the first participant in the +group. This will assign the role of moderator (like in the Python bindings examples), +but all the invites/removals will be done using the Controller and no action needs to be +performed in the application. -except grpc.RpcError as e: - print(f"Request failed: {e}") -finally: - channel.close() +To create the group, run: +```bash +./slimctl channel create moderators=agntcy/ns/client-1/9494657801285491688 ``` -### Adding Participants to a SLIM Group - -```python -import grpc -from controlplane.v1 import controlplane_pb2_grpc as controlplane_api -from controlplane.v1 import controlplane_pb2 - -# Create gRPC connection -channel = grpc.insecure_channel("localhost:50051") -client = controlplane_api.ControlPlaneServiceStub(channel) - -# Add participant request -add_participant_request = controlplane_pb2.AddParticipantRequest( - participant_id="agntcy/namespace/participant_1", - channel_id="agntcy/namespace/group_channel" -) - -try: - ack = client.AddParticipant(add_participant_request) - - print(f"ACK received for {ack.original_message_id}: success={ack.success}") - -except grpc.RpcError as e: - print(f"Request failed: {e}") -finally: - channel.close() +The outcome will be something similar to this: +```bash +Received response: agntcy/ns/xyIGhc2igNGmkeBDlZ ``` -### Setting Routes Between SLIM Nodes +The name in the response is the name of the new channel created, with only one participant +added (e.g. `moderators=agntcy/ns/client-1/9494657801285491688`). -```python -import grpc -from controlplane.v1 import controlplane_pb2_grpc as controlplane_api -from controlplane.v1 import controlplane_pb2 -from grpc_api import grpc_api_pb2 as grpcapi - -# Create gRPC connection -channel = grpc.insecure_channel("localhost:50051") -client = controlplane_api.ControlPlaneServiceStub(channel) - -try: - # Create connection to the target node - connection = grpcapi.Connection( - connection_id="http://127.0.0.1:46357", - config_data='{"endpoint": "http://127.0.0.1:46357"}' - ) - - create_connection_request = controlplane_pb2.CreateConnectionRequest( - connection=connection, - node_id="slim/0" - ) - - create_connection_response = client.CreateConnection(create_connection_request) - - if not create_connection_response.success: - raise Exception("Failed to create connection") - - connection_id = create_connection_response.connection_id - print(f"Connection created successfully with ID: {connection_id}") - - # Add subscription for a group to a SLIM node - subscription = grpcapi.Subscription( - component_0="agntcy", - component_1="namespace", - component_2="group_channel", - connection_id=connection_id - ) - - create_subscription_request = controlplane_pb2.CreateSubscriptionRequest( - node_id="slim/0", - subscription=subscription - ) +### Invite Participants to the Channel - create_subscription_response = client.CreateSubscription(create_subscription_request) +Now that the channel is created, you can start to invite new participants. To do so, you can use +the following command: - if not create_subscription_response.success: - raise Exception("Failed to create subscription") +```bash +./slimctl participant add -c agntcy/ns/xyIGhc2igNGmkeBDlZ agntcy/ns/client-2 +``` - print(f"Subscription created successfully with ID: {create_subscription_response.subscription_id}") +The reply to the command will be similar to this: -except grpc.RpcError as e: - print(f"gRPC error: {e}") -except Exception as e: - print(f"Error: {e}") -finally: - channel.close() +```bash +Adding participant to channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client-2 +Participant added successfully to channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client-2 ``` + +Now the channel has two participants that can start to communicate +over the shared channel `agntcy/ns/xyIGhc2igNGmkeBDlZ`. Message reception and publishing +must be done within the application in the same way as shown in the previous section. From 12e82abba11e87eec7a2d42c6f35899e96c4ae21 Mon Sep 17 00:00:00 2001 From: Michele Papalini Date: Mon, 6 Oct 2025 18:40:57 +0200 Subject: [PATCH 16/24] fix: PR comments Signed-off-by: Michele Papalini --- docs/messaging/slim-glossary.md | 2 +- docs/messaging/slim-group-tutorial.md | 68 +++++++++++++-------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/messaging/slim-glossary.md b/docs/messaging/slim-glossary.md index 368f77d3..4f081a56 100644 --- a/docs/messaging/slim-glossary.md +++ b/docs/messaging/slim-glossary.md @@ -51,7 +51,7 @@ Initial interaction where Anycast picks any available instance; if persistent af ## E ### Endpoint -Host:port (and scheme) on which a server listens or a client connects (e.g., `http://localhost:46357`). +Host:port (and scheme) on which a server listens or a client connects. Note that in the configuration the client needs to specify the protocol (e.g. http://localhost:46357), but not the server (e.g. localhost:46357) --- diff --git a/docs/messaging/slim-group-tutorial.md b/docs/messaging/slim-group-tutorial.md index 19276f48..9c399918 100644 --- a/docs/messaging/slim-group-tutorial.md +++ b/docs/messaging/slim-group-tutorial.md @@ -22,9 +22,9 @@ example in the SLIM repo. ## Table of Contents -3. [Configure Client Identity and Implement the SLIM App](#configure-client-identity-and-implement-the-slim-app) -4. [Group Communication Using the Python Bindings](#group-communication-using-the-python-bindings) -5. [Group Communication Using the SLIM Controller](#group-communication-using-the-slim-controller) +1. [Configure Client Identity and Implement the SLIM App](#configure-client-identity-and-implement-the-slim-app) +2. [Group Communication Using the Python Bindings](#group-communication-using-the-python-bindings) +3. [Group Communication Using the SLIM Controller](#group-communication-using-the-slim-controller) ## Configure Client Identity and Implement the SLIM App @@ -167,7 +167,7 @@ This function takes several parameters as input: - `jwt` (str | None, default: `None`): JWT token for identity. Used with `spire_trust_bundle` and `audience` for JWT-based authentication. - `spire_trust_bundle` (str | None, default: `None`): JWT trust bundle - (list of JWKs, one for each trust domain). It is expected in JSON format such as + (list of JWKs, one for each trust domain). It is expected in JSON format such as: ```json { "trust-domain-1.org": "base-64-encoded-jwks", @@ -388,12 +388,12 @@ Only the payload is provided and there is no explicit destination, because the multicast channel was fixed at session creation and delivery fan-outs to all participants. -### Run the Gruop Comminication Example +### Run the Group Communication Example Now we will show how to run a new multicast session and how to enable group communication on top of SLIM. The full code can be found in [multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) -in the SLIM repo. To run the example, follow the step listed here. +in the SLIM repo. To run the example, follow the steps listed here. #### Run SLIM As all members of the group will be communicating via a SLIM network, we can set @@ -473,13 +473,13 @@ uv run --package slim-bindings-examples multicast ``` This will start two participants authenticated with a shared secret. -The outcome of these commands should look like: +The output of these commands should look like: ```bash Warning: Falling back to shared-secret authentication. Don't use this in production! Agntcy/ns/client-1/456243414154990054 Created app Agntcy/ns/client-1/456243414154990054 Connected to http://localhost:46357 --> Waiting for session... +Waiting for session... ``` #### Create the Group @@ -511,7 +511,7 @@ Send a message to the group, or type 'exit' or 'quit' to quit. 169ca82eb17d6bc2/eef9769a4c6990d1/fc9bbc406957794b/e9f53aa5ef3fb8f2 (agntcy/ns/moderator/e9f53aa5ef3fb8f2) > ``` -Now `client-1` and `client-2` are invited to the gruop so on both of them you should +Now `client-1` and `client-2` are invited to the group, so on both of their terminals you should be able to see a welcome message such as: ```bash @@ -520,27 +520,27 @@ Send a message to the group, or type 'exit' or 'quit' to quit. 169ca82eb17d6bc2/eef9769a4c6990d1/58ec40d7c837e0b9/6a34b65ebc955471 (agntcy/ns/client-1/6a34b65ebc955471) > ``` -At this point, you can write messages from any terminal and they will be received by all the other group participants. +At this point, you can write messages from any terminal and they will be received by all other group participants. ## Group Communication Using the SLIM Controller -Previously, we saw how to run group communication using the Python bindings with an in‑application moderator. -This particular participant has to create the mulitcast session and invite all the other participants. -In this section, we describe how to create and orchestrate a group using the SLIM Controller and we show how all -this functions can be delegated to the controller. We reuse the same multicast example code also in this section. +Previously, we saw how to run group communication using the Python bindings with an in-application moderator. +This participant creates the multicast session and invites all other participants. +In this section, we describe how to create and orchestrate a group using the SLIM Controller, and we show how all +these functions can be delegated to the controller. We reuse the same multicast example code in this section as well. Identity handling is unchanged between the two approaches; refer back to [SLIM Identity](#configure-client-identity-and-implement-the-slim-app). Below are the steps to run the controller-managed version. -### Application Differencies +### Application Differences -With the controller, you do not need to set up a moderator in your application. All participants can be run as we did for `client-1` and `client-2` in the previous examples. In code, this means you can avoid to create a new multicast session (using `local_app.create_session`) and the invitation loop. You only need to implement the `receive_loop` where the application waits for new sessions. This greatly simplifies your code. +With the controller, you do not need to set up a moderator in your application. All participants can be run as we did for `client-1` and `client-2` in the previous examples. In code, this means you can avoid creating a new multicast session (using `local_app.create_session`) and the invitation loop. You only need to implement the `receive_loop` where the application waits for new sessions. This greatly simplifies your code. -### Run the Gruop Communincation example +### Run the Group Communication example -Now we will show how to setupa gruop using the SLIM Contoreller. The reference code for the -applciation is still [multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py). To run this example, follow the steps listed here. +Now we will show how to set up a group using the SLIM Controller. The reference code for the +application is still [multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py). To run this example, follow the steps listed here. #### Run the SLIM Controller @@ -589,7 +589,7 @@ If everything goes fine, you should see an output like this one: #### Run the SLIM Node -With the controller running, start a SLIM node configured to talk to it over the Southbound API. This node config includes two additional features compared to the file proposed in the previous sessions: +With the controller running, start a SLIM node configured to talk to it over the Southbound API. This node config includes two additional settings compared to the file from the previous section: - A controller client used to connect to the Southbound API running on port 50052 - A shared secret token provider that will be used by the SLIM node to send messages over the SLIM network. As with the normal application, you can use a shared secret or a proper JWT. Create the `config.yaml` for the node: @@ -644,8 +644,8 @@ If everything goes fine, you should see an output like this one: ... ``` -On the Controller side, you can see that the new node registers itself to the controller. The -output should be similar to the following one: +On the Controller side, you can see that the new node registers with the controller. The +output should be similar to the following: ```bash 2025-10-06T11:47:14+02:00 INF Registering node with ID: slim/0 svc=southbound 2025-10-06T11:47:14+02:00 INF Connection details: [endpoint: 127.0.0.1:46357] svc=southbound @@ -657,7 +657,7 @@ output should be similar to the following one: #### Run the Participants -Because the controller manages the group lifecycle, no participant needs to be designated as moderator in code. Every application instance just waits for a session invite. In three separate terminals, strating from the folder +Because the controller manages the group lifecycle, no participant needs to be designated as moderator in code. Every application instance just waits for a session invite. In three separate terminals, from the folder `slim/data-plane/python/bindings/examples` run: ```bash @@ -696,7 +696,7 @@ At this point all applications are waiting for a new session. Use `slimctl` (see [slim-controller](./slim-controller.md)) to send administrative commands to the controller. -First of all, you need to run `slimctl`. You can download it from the slim repo using this script: +First, you need to run `slimctl`. You can download it from the slim repo using this script: ```bash #!/bin/bash @@ -742,7 +742,7 @@ curl -L "${DOWNLOAD_URL}" -o slimctl chmod +x slimctl ``` -To verify that `slimctl` was downloaded succesfully run the command +To verify that `slimctl` was downloaded successfully, run the command ```bash ./slimctl version ``` @@ -750,9 +750,9 @@ To verify that `slimctl` was downloaded succesfully run the command ##### Create the Group -Select any running participant to serve as the initial participant of the group. This will act as the logical -moderator of the channel, similar to what we showed in the Python bindings example. However, you don't -need to explicitly handle this in the code. Run the following command to create the channel: +Select any running participant to be the initial member of the group. This participant will act as the logical +moderator of the channel, similar to the Python bindings example. However, you don't +need to handle this explicitly in the code. Run the following command to create the channel: ```bash @@ -771,7 +771,7 @@ Received response: agntcy/ns/xyIGhc2igNGmkeBDlZ The value `agntcy/ns/xyIGhc2igNGmkeBDlZ` is the channel (or group) identifier (name) that must be used in subsequent commands. -On the application side, `client-1` was addeded to the session so you should see +On the application side, `client-1` was added to the session, so you should see something like this: ```bash @@ -790,7 +790,7 @@ Now that the new group is created, add the additional participants `client-2` an ./slimctl participant add -c agntcy/ns/xyIGhc2igNGmkeBDlZ agntcy/ns/client-3 ``` -The xpected `slimctl` output is: +The expected `slimctl` output is: ```bash @@ -798,14 +798,14 @@ Adding participant to channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client- Participant added successfully to channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client-2 ``` -Now all the partcipants are part of the same gruop and so on each client log should show that the join was succesful: +Now all the participants are part of the same group, and so each client log should show that the join was successful: ```bash Welcome to the group 169ca82eb17d6bc2/eef9769a4c6990d1/e8ab33f6d6111780/ffffffffffffffff (agntcy/ns/xyIGhc2igNGmkeBDlZ/ffffffffffffffff)! Send a message to the group, or type 'exit' or 'quit' to quit. 169ca82eb17d6bc2/eef9769a4c6990d1/b521a3788f1267a8/e4011f7be5222a24 (agntcy/ns/client-2/e4011f7be5222a24) > ``` -At this point every member is able to send messages and they will be recevied by all the other participants. +At this point, every member can send messages, and they will be received by all the other participants. ##### Remove a Participant @@ -823,8 +823,8 @@ Deleting participant from channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/cli Participant deleted successfully from channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client-3 ``` -The application on `client-3` exits, because the session related to the group was closed and so the -reception loop in the Python code breaks. Notice that this command does not work +The application on `client-3` exits because the session related to the group was closed, which breaks the +reception loop in the Python code. Notice that this command does not work for `client-1`, which was added as the first participant. In fact, removing `client-1` is equivalent to deleting the channel itself. From 7487216674aab9446303477ad37cc2612414b868 Mon Sep 17 00:00:00 2001 From: Magyari Sandor Szilard Date: Wed, 8 Oct 2025 12:26:47 +0200 Subject: [PATCH 17/24] feat: update controller docs Signed-off-by: Magyari Sandor Szilard --- docs/messaging/slim-controller.md | 76 +++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/docs/messaging/slim-controller.md b/docs/messaging/slim-controller.md index b35d326a..918be479 100644 --- a/docs/messaging/slim-controller.md +++ b/docs/messaging/slim-controller.md @@ -148,7 +148,8 @@ sequenceDiagram ### Configuring the SLIM Controller -The Controller can be configured through the `config.yaml` file. An example configuration: +The Controller can be configured through the `config.yaml` file. +An example of minimal configuration: ```yaml northbound: @@ -160,8 +161,40 @@ northbound: southbound: httpHost: localhost httpPort: 50052 + # number of node reconciler thread + reconciler: + threads: 3 + +logging: + level: DEBUG +``` + +Example config to enable MTLS on Southbound endpoint using [Spire](https://spiffe.io/docs/latest/spire-about/spire-concepts/). + +```yaml + northbound: + httpHost: 0.0.0.0 + httpPort: 50051 + + southbound: + httpHost: 0.0.0.0 + httpPort: 50052 + tls: + useSpiffe: true + spire: + socketPath: "unix:///run/spire/agent-sockets/api.sock" + logging: level: DEBUG + reconciler: + threads: 3 + + spire: + enabled: false + # Slim Controller SVIDs will be federated with these trust domains + trustedDomains: [] + # - cluster-a.example.org + # - cluster-b.example.org ``` ## Usage @@ -235,7 +268,11 @@ To enable self-registration, configure the nodes with the Controller address: insecure: true ``` -Nodes can be managed through slimctl. For more information, see the [slimctl](#slimctl). +Routes between SLIM nodes are automatically created by Controller upon receiving new subscriptions from clients. + +Nodes can be managed through slimctl. Although routes are automatically created for client subscription you can still add/remove routes manually. + +For more information, see the [slimctl](#slimctl). ## slimctl @@ -263,6 +300,10 @@ The `server` endpoint should point to a [SLIM Control](https://github.com/agntcy ### Commands +List nodes: + +`slimctl node list` + List connection on a SLIM instance: `slimctl connection list --node-id=` @@ -273,11 +314,11 @@ List routes on a SLIM instance: Add a route to the SLIM instance: -`slimctl route add via --node-id=` +`slimctl route add via --node-id=` Delete a route from the SLIM instance: -`slimctl route del via --node-id=` +`slimctl route del via --node-id=` Print version information: @@ -285,7 +326,32 @@ Print version information: Run `slimctl --help` for more details on flags and usage. -### Example: Create, Delete Route +### Example 1: Create, Delete Route using node-id + +Add route for node `slim/a` to forward messages for `org/default/alice/0` to node `slim/b`. +```bash +slimctl node list + +Node ID: slim/b status: CONNECTED + Connection details: + - Endpoint: 127.0.0.1:46457 + MtlsRequired: false + ExternalEndpoint: test-slim.default.svc.cluster.local:46457 +Node ID: slim/a status: CONNECTED + Connection details: + - Endpoint: 127.0.0.1:46357 + MtlsRequired: false + ExternalEndpoint: test-slim.default.svc.cluster.local:46357 + +slimctl route add org/default/alice/0 via slim/b --node-id slim/a + + +# Delete an existing route +slimctl route del org/default/alice/0 via slim/b --node-id slim/a +``` + +### Example 2: Create, Delete Route using `connection_config.json` + ```bash # Add a new route From 4f12b148b084a6e3c84b5219ccfb2bf437bf029a Mon Sep 17 00:00:00 2001 From: Michele Papalini Date: Wed, 8 Oct 2025 13:11:10 +0200 Subject: [PATCH 18/24] feat: rename session APIs Signed-off-by: Michele Papalini --- docs/messaging/slim-authentication.md | 8 +- docs/messaging/slim-data-plane.md | 74 ++------- docs/messaging/slim-glossary.md | 34 ++-- docs/messaging/slim-group-tutorial.md | 66 ++++---- docs/messaging/slim-group.md | 32 ++-- docs/messaging/slim-session.md | 223 ++++++-------------------- 6 files changed, 132 insertions(+), 305 deletions(-) diff --git a/docs/messaging/slim-authentication.md b/docs/messaging/slim-authentication.md index 459c35ff..34c345bd 100644 --- a/docs/messaging/slim-authentication.md +++ b/docs/messaging/slim-authentication.md @@ -36,7 +36,7 @@ use SPIRE with SLIM to manage client identities. You will: 4. Deploy the SLIM node (control / rendezvous component). 5. Deploy two distinct SLIM client workloads, each with its own ServiceAccount (and thus its own SPIFFE ID). -6. Run the unicast example using JWT-based authentication derived from SPIRE. +6. Run the point-to-point example using JWT-based authentication derived from SPIRE. If you already have a Kubernetes cluster or an existing SPIRE deployment, you can adapt only the relevant subsections. @@ -337,7 +337,7 @@ POD_NAME=$(kubectl get pods -l app.kubernetes.io/component=client-a -o jsonpath= kubectl exec -c slim-client -it ${POD_NAME} -- ls -l /svids ``` -### Run the unicast example (inside the cluster) +### Run the point-to-point example (inside the cluster) Enter the first client pod (receiver): @@ -354,7 +354,7 @@ ls -l /svids Run the receiver: ```bash -/app/bin/unicast --slim '{"endpoint": "http://slim.slim:46357", "tls": {"insecure": true}}' \ +/app/bin/p2p --slim '{"endpoint": "http://slim.slim:46357", "tls": {"insecure": true}}' \ --jwt /svids/jwt_svid.token \ --spire-trust-bundle /svids/key.jwt \ --local agntcy/example/receiver \ @@ -370,7 +370,7 @@ kubectl exec -c slim-client -it $(kubectl get pods -l app.kubernetes.io/componen Run the sender: ```bash -/app/bin/unicast --slim '{"endpoint": "http://slim.slim:46357", "tls": {"insecure": true}}' \ +/app/bin/p2p --slim '{"endpoint": "http://slim.slim:46357", "tls": {"insecure": true}}' \ --jwt /svids/jwt_svid.token \ --spire-trust-bundle /svids/key.jwt \ --audience slim-demo \ diff --git a/docs/messaging/slim-data-plane.md b/docs/messaging/slim-data-plane.md index 371a0a78..25eaa38a 100644 --- a/docs/messaging/slim-data-plane.md +++ b/docs/messaging/slim-data-plane.md @@ -23,8 +23,8 @@ org/namespace/service/client Kubernetes cluster), the organization, namespace, and service components remain the same for all instances. - **Client**: The final component is generated by SLIM and is a hash of the - client's identity (e.g., a hash of the public key). This uniquely identifies - each specific client instance. + client's identity (e.g., a hash of its public key). This uniquely identifies + each client instance. This naming structure supports both Anycast and Unicast message delivery: @@ -33,9 +33,9 @@ This naming structure supports both Anycast and Unicast message delivery: - **Unicast**: By including the fourth component, the message is delivered directly to the specified client instance. -This approach enables efficient client discovery in fact the message will be +This approach enables efficient client discovery. In fact, the message will be delivered by the SLIM network to a client that is able to process it, even if the -real name of the client is unknown. The anycast forwarding is mostly used in +real name of the client is unknown. Anycast forwarding is primarily used in this discovery phase. In addition to client endpoints, SLIM allows messages to be sent to Channels. A @@ -69,69 +69,15 @@ The session layer offers several functionalities: and receive primitives to applications. -The session layer offers three primary APIs for establishing new sessions: +The session layer offers two primary APIs for establishing new sessions: -- **Anycast**: Enables point-to-point communication where each message sent -to a service is delivered to only one of its available instances. The -destination instance is selected for each message individually, so different -messages within the same session may be routed to different endpoints. +- **Point-to-Point**: Facilitates point-to-point communication with a specific service + instance. This session performs a discovery phase to bind the session + to a single instance; all subsequent messages in the session are sent to that + same endpoint. -- **Unicast**: Facilitates point-to-point communication with a specific service -instance. Unlike Anycast, Unicast performs a discovery phase to bind the session -to a single instance; all subsequent messages in the session are sent to that -same endpoint. - -- **Multicast**: Supports many-to-many communication over a named channel. +- **Group**: Supports many-to-many communication over a named channel. Every message sent to the channel is delivered to all current participants. For more information about each session type, see the [SLIM session](./slim-session.md) documentation. - - diff --git a/docs/messaging/slim-glossary.md b/docs/messaging/slim-glossary.md index 4f081a56..74f71666 100644 --- a/docs/messaging/slim-glossary.md +++ b/docs/messaging/slim-glossary.md @@ -10,17 +10,17 @@ This glossary defines technical terms referenced across the SLIM messaging docum A confirmation—explicit or implicit—that a sent message was delivered or processed. In reliable modes, missing acks trigger retries until `max_retries` is reached or a timeout fires. ### Anycast -Session/routing mode where a message addressed to a 3‑component name (`org/namespace/service`) is delivered to exactly one currently reachable instance. Each message may choose a different instance. Useful for stateless load distribution and discovery. +Routing mode where a message addressed to a 3-component name (`org/namespace/service`) is delivered to exactly one currently reachable instance. Each message may choose a different instance. Used in the discovery phase of point-to-point and group sessions. --- ## C -### Channel (Multicast Channel / Group) -Logical multicast namespace: the first three SLIM name components (`org/namespace/service`) without the client hash. All joined participants receive each multicast message. Also referred to as a Group. +### Channel (Group Channel) +Logical group namespace: the first three SLIM name components (`org/namespace/service`) without the client hash. All joined participants receive each message. Also referred to as a Group. ### Channel Moderator -Privileged manager of a multicast channel that can invites/removes participants and coordinates MLS state. +Manager of a group channel that can invites/removes participants and coordinates MLS state. ### Client (Application Client) Runtime endpoint connected to a SLIM node. Identified by full four-component name: `org/namespace/service/clientHash`. @@ -43,8 +43,8 @@ Central orchestration service offering northbound (administrative) and southboun ### Data Plane (Messaging Layer) Operational pipeline for message routing, delivery, encryption (MLS), and session state, implemented in SLIM nodes. It can be used synonymously with "SLIM Node". -### Discovery (Service Discovery via Anycast) -Initial interaction where Anycast picks any available instance; if persistent affinity is needed, Unicast binds subsequent messages to a chosen instance. +### Discovery (Service Discovery) +Initial interaction where packets can be sent to any available instance. This is used at the beginning of point-to-point session and when a new invite is sent in a group session. --- @@ -57,8 +57,8 @@ Host:port (and scheme) on which a server listens or a client connects. Note that ## G -### Group (Multicast Group / Channel) -Set of participants joined to a multicast channel. Shares message distribution and optionally an MLS security context. See also: Channel, Multicast. +### Group +Set of participants joined to a channel. Shares message distribution and optionally an MLS security context. See also: Channel. --- @@ -68,7 +68,7 @@ Set of participants joined to a multicast channel. Shares message distribution a Cryptographic or token-based representation of a workload (shared secret, JWT, SPIFFE SVID) determining trust and naming uniqueness. ### Invitation (Group Invitation) -Control message enabling a client to join an existing multicast group. +Control message enabling a client to join an existing group. --- @@ -90,7 +90,7 @@ End-to-end group key agreement and encryption protocol (RFC 9420) providing conf ### Moderator Alias of Channel Moderator. -### Multicast +### Group Session Session type enabling many-to-many distribution; every message is delivered to all participants in the channel. --- @@ -98,7 +98,7 @@ Session type enabling many-to-many distribution; every message is delivered to a ## N ### Name (SLIM Name) -Structured routing identifier: `organization/namespace/service/clientHash` (full) or the first three components for anycast/channel addressing. The first component, `organization`, usually represents the top‑level administrative or tenant boundary; the second component, `namespace`, can be used to encode environment, region, or an organizational partition; the third component, `service`, specifies the service exposed by the client. When multiple instances of the same service are deployed (such as several pods in a Kubernetes cluster), these first three components remain the same for all instances. The last component, `clientHash`, is generated by SLIM from the client's identity material (e.g., a hash of the public key) and uniquely identifies each specific client instance. +Structured routing identifier: `organization/namespace/service/clientHash` (full) or the first three components for channel addressing. The first component, `organization`, usually represents the top-level administrative or tenant boundary; the second component, `namespace`, can be used to encode environment, region, or an organizational partition; the third component, `service`, specifies the service exposed by the client. When multiple instances of the same service are deployed (such as several pods in a Kubernetes cluster), these first three components remain the same for all instances. The last component, `clientHash`, is generated by SLIM from the client's identity material (e.g., a hash of the public key) and uniquely identifies each specific client instance. ### Node (SLIM Node) Runtime process implementing the data plane: message routing, session handling, MLS operations, optional control endpoints. @@ -108,7 +108,7 @@ Runtime process implementing the data plane: message routing, session handling, ## P ### Participant (Group Participant) -Client that has accepted an invitation and joined a multicast group, receiving all channel traffic. +Client that has accepted an invitation and joined a group, receiving all channel traffic. --- @@ -125,10 +125,10 @@ Controller-managed mapping directing messages for a particular name (or prefix) ## S ### Session -Abstraction for interaction context (Anycast, Unicast, Multicast). Manages encryption (if MLS enabled), retries, and sequencing. +Abstraction for interaction context (Point-to-Point, Group). Manages encryption (if MLS enabled), retries, and sequencing. ### Session Configuration -Per-session parameters selected at creation (e.g., mode, `mls_enabled`, metadata). In Python bindings: `PySessionConfiguration.Unicast(...)`, etc. +Per-session parameters selected at creation (e.g., mode, `mls_enabled`, metadata). In Python bindings: `PySessionConfiguration.PointToPoint(...)`, etc. ### Session Layer Middleware that abstracts encryption, invitations, routing resolution, and reliability, offering simple send/receive primitives. @@ -158,7 +158,7 @@ Protoc plugin generating Python stubs and servicers for SLIMRPC services defined Binding between a routed name/prefix and a connection so messages destined to that name traverse the appropriate path. ### Publish -Operation that sends a message on a session (context: unicast/anycast/multicast). May await acknowledgment depending on reliability mode. In Python bindings: `session.publish(...)` or `session.publish_to(ctx, ...)`. +Operation that sends a message on a session (context: point-to-point/group). May await acknowledgment depending on reliability mode. In Python bindings: `session.publish(...)` or `session.publish_to(ctx, ...)`. ### Message Context Metadata accompanying a received message (e.g., routing info). Used to reply (`publish_to`) preserving addressing. @@ -174,5 +174,5 @@ Upper bound for waiting on acknowledgments or RPC responses before retry/failure ## U -### Unicast -Session mode binding communication to a specific discovered instance after an initial discovery. Ensures message affinity to a single endpoint. +### Point-to-Point Session +Session mode for communication with a specific client instance. Ensures message affinity to a single endpoint. diff --git a/docs/messaging/slim-group-tutorial.md b/docs/messaging/slim-group-tutorial.md index 9c399918..9c8821b1 100644 --- a/docs/messaging/slim-group-tutorial.md +++ b/docs/messaging/slim-group-tutorial.md @@ -1,12 +1,12 @@ # SLIM Group Communication Tutorial This tutorial shows how to set up secure group communication using -SLIM. The group is created by defining a multicast session and inviting +SLIM. The group is created by defining a group session and inviting participants. Messages are sent to a shared channel where every member can read and write. All messages are end-to-end encrypted using the [MLS protocol](https://datatracker.ietf.org/doc/html/rfc9420). This tutorial is based on the -[multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) +[group.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) example in the SLIM repo. ## Key Features @@ -184,11 +184,11 @@ If `jwt`, `spire_trust_bundle`, and `audience` are not provided, `shared_secret` ## Group Communication Using the Python Bindings -Now that you know how to set up a SLIM application, we can see how to create a group where multiple participants can exchange messages. We will start by showing how to create a multicast session using the Python bindings. In this setting, one participant acts as moderator: it creates the multicast session and invites participants by sending invitation control messages. A detailed description of multicast sessions and the invitation process is available [here](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/SESSION.md). +Now that you know how to set up a SLIM application, we can see how to create a group where multiple participants can exchange messages. We will start by showing how to create a group session using the Python bindings. In this setting, one participant acts as moderator: it creates the group session and invites participants by sending invitation control messages. A detailed description of group sessions and the invitation process is available [here](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/SESSION.md). -### Creating the Multicast Session and Inviting Members +### Creating the Group Session and Inviting Members -The creator of the multicast session invites other members to join the group. The +The creator of the group session invites other members to join the group. The session will be identified by a unique session ID, and the group communication will take place over a specific channel name. The session creator is responsible for managing the session lifecycle, including creating, updating, and @@ -226,13 +226,13 @@ communication. # Session object only exists immediately if we are moderator. created_session = None if chat_channel and invites: - # We are the moderator; create the multicast session now. + # We are the moderator; create the group session now. format_message_print( - f"Creating new multicast session (moderator)... {split_id(local)}" + f"Creating new group session (moderator)... {split_id(local)}" ) created_session = await local_app.create_session( - slim_bindings.PySessionConfiguration.Multicast( # type: ignore # Build multicast session configuration - channel_name=chat_channel, # Logical multicast channel (PyName) all participants join; acts as group/topic identifier. + slim_bindings.PySessionConfiguration.Group( # type: ignore # Build group session configuration + channel_name=chat_channel, # Logical group channel (PyName) all participants join; acts as group/topic identifier. max_retries=5, # Max per-message resend attempts upon missing ack before reporting a delivery failure. timeout=datetime.timedelta( seconds=5 @@ -255,13 +255,13 @@ communication. ``` This code comes from the -[multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) +[group.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) example. The local application is created using the helper function shown earlier. -The channel name (the logical multicast topic) is produced via the +The channel name (the logical group topic) is produced via the [split_id](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L63) -helper by parsing the `remote` parameter. A new multicast session is then created +helper by parsing the `remote` parameter. A new group session is then created using `local_app.create_session(...)` with a -`slim_bindings.PySessionConfiguration.Multicast` configuration. The key parameters are: +`slim_bindings.PySessionConfiguration.Group` configuration. The key parameters are: - `channel_name`: Logical channel/topic used to exchange messages among participants. - `max_retries`: Maximum number of retransmission attempts (upon missing ack) before @@ -288,7 +288,7 @@ async def receive_loop( Receive messages for the bound session. Behavior: - * If not moderator: wait for a new multicast session (listen_for_session()). + * If not moderator: wait for a new group session (listen_for_session()). * If moderator: reuse the created_session reference. * Loop forever until cancellation or an error occurs. """ @@ -304,7 +304,7 @@ async def receive_loop( while True: try: - # Await next inbound message from the multicast session. + # Await next inbound message from the group session. # The returned parameters are a message context and the raw payload bytes. # Check session.py for details on PyMessageContext contents. ctx, payload = await session.get_message() @@ -343,7 +343,7 @@ async def keyboard_loop(session_ready, shared_session_container, local_app): Interactive loop allowing participants to publish messages. Typing 'exit' or 'quit' (case-insensitive) terminates the loop. - Each line is published to the multicast topic as UTF-8 bytes. + Each line is published to the group topic as UTF-8 bytes. """ try: # 1. Initialize an async session @@ -370,8 +370,8 @@ async def keyboard_loop(session_ready, shared_session_container, local_app): try: # Send message to the channel_name specified when creating the session. - # As the session is multicast, all participants will receive it. - # calling publish_with_destination on a multicast session will raise an error. + # As the session is group, all participants will receive it. + # calling publish_with_destination on a group session will raise an error. await shared_session_container[0].publish(user_input.encode()) except KeyboardInterrupt: # Handle Ctrl+C gracefully @@ -385,14 +385,14 @@ async def keyboard_loop(session_ready, shared_session_container, local_app): Messages are sent using `shared_session_container[0].publish(user_input.encode())`. Only the payload is provided and there is no explicit destination, because the -multicast channel was fixed at session creation and delivery fan-outs to all +group channel was fixed at session creation and delivery fan-outs to all participants. ### Run the Group Communication Example -Now we will show how to run a new multicast session and +Now we will show how to run a new group session and how to enable group communication on top of SLIM. The full code can be found in -[multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) +[group.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) in the SLIM repo. To run the example, follow the steps listed here. #### Run SLIM @@ -460,13 +460,13 @@ Authentication uses a shared secret. In the SLIM repository, go to the folder `slim/data-plane/python/bindings/examples` and run these commands in two different terminals: ```bash -uv run --package slim-bindings-examples multicast \ +uv run --package slim-bindings-examples group \ --local agntcy/ns/client-1 \ --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ --shared-secret "secret" ``` ```bash -uv run --package slim-bindings-examples multicast \ +uv run --package slim-bindings-examples group \ --local agntcy/ns/client-2 \ --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ --shared-secret "secret" @@ -488,7 +488,7 @@ Run the moderator application to create the session and invite the two participants. In another terminal run: ```bash -uv run --package slim-bindings-examples multicast \ +uv run --package slim-bindings-examples group \ --local agntcy/ns/moderator \ --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ --shared-secret "secret" \ @@ -503,7 +503,7 @@ The result should look like: ```bash Agntcy/ns/moderator/16858445264489265394 Created app Agntcy/ns/moderator/16858445264489265394 Connected to http://localhost:46357 -Creating new multicast session (moderator)... 169ca82eb17d6bc2/eef9769a4c6990d1/fc9bbc406957794b/ffffffffffffffff (agntcy/ns/moderator/ffffffffffffffff) +Creating new group session (moderator)... 169ca82eb17d6bc2/eef9769a4c6990d1/fc9bbc406957794b/ffffffffffffffff (agntcy/ns/moderator/ffffffffffffffff) agntcy/ns/moderator -> add 169ca82eb17d6bc2/eef9769a4c6990d1/58ec40d7c837e0b9/ffffffffffffffff (agntcy/ns/client-1/ffffffffffffffff) to the group agntcy/ns/moderator -> add 169ca82eb17d6bc2/eef9769a4c6990d1/b521a3788f1267a8/ffffffffffffffff (agntcy/ns/client-2/ffffffffffffffff) to the group Welcome to the group 169ca82eb17d6bc2/eef9769a4c6990d1/4abb367236cabc2a/ffffffffffffffff (agntcy/ns/chat/ffffffffffffffff)! @@ -526,21 +526,21 @@ At this point, you can write messages from any terminal and they will be receive ## Group Communication Using the SLIM Controller Previously, we saw how to run group communication using the Python bindings with an in-application moderator. -This participant creates the multicast session and invites all other participants. +This participant creates the group session and invites all other participants. In this section, we describe how to create and orchestrate a group using the SLIM Controller, and we show how all -these functions can be delegated to the controller. We reuse the same multicast example code in this section as well. +these functions can be delegated to the controller. We reuse the same group example code in this section as well. Identity handling is unchanged between the two approaches; refer back to [SLIM Identity](#configure-client-identity-and-implement-the-slim-app). Below are the steps to run the controller-managed version. ### Application Differences -With the controller, you do not need to set up a moderator in your application. All participants can be run as we did for `client-1` and `client-2` in the previous examples. In code, this means you can avoid creating a new multicast session (using `local_app.create_session`) and the invitation loop. You only need to implement the `receive_loop` where the application waits for new sessions. This greatly simplifies your code. +With the controller, you do not need to set up a moderator in your application. All participants can be run as we did for `client-1` and `client-2` in the previous examples. In code, this means you can avoid creating a new group session (using `local_app.create_session`) and the invitation loop. You only need to implement the `receive_loop` where the application waits for new sessions. This greatly simplifies your code. ### Run the Group Communication example Now we will show how to set up a group using the SLIM Controller. The reference code for the -application is still [multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py). To run this example, follow the steps listed here. +application is still [group.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py). To run this example, follow the steps listed here. #### Run the SLIM Controller @@ -661,21 +661,21 @@ Because the controller manages the group lifecycle, no participant needs to be d `slim/data-plane/python/bindings/examples` run: ```bash -uv run --package slim-bindings-examples multicast \ +uv run --package slim-bindings-examples group \ --local agntcy/ns/client-1 \ --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ --shared-secret "secret" ``` ```bash -uv run --package slim-bindings-examples multicast \ +uv run --package slim-bindings-examples group \ --local agntcy/ns/client-2 \ --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ --shared-secret "secret" ``` ```bash -uv run --package slim-bindings-examples multicast \ +uv run --package slim-bindings-examples group \ --local agntcy/ns/client-3 \ --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ --shared-secret "secret" @@ -824,7 +824,7 @@ Participant deleted successfully from channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: a ``` The application on `client-3` exits because the session related to the group was closed, which breaks the -reception loop in the Python code. Notice that this command does not work +receive loop in the Python code. Notice that this command does not work for `client-1`, which was added as the first participant. In fact, removing `client-1` is equivalent to deleting the channel itself. diff --git a/docs/messaging/slim-group.md b/docs/messaging/slim-group.md index 41583782..395c0ccc 100644 --- a/docs/messaging/slim-group.md +++ b/docs/messaging/slim-group.md @@ -7,14 +7,14 @@ Messaging Layer](slim-data-plane.md). When MLS is enabled, group communication benefits from end-to-end encryption. This guide provides all the information you need to create and manage groups within a -SLIM network. A full toturial with examples is avaible in +SLIM network. A full tutorial with examples is available in [Group Communication Tutorial](./slim-group-tutorial.md). ## Creating Groups with the Python Bindings This section shows how to use the SLIM Python bindings to create a group. -This requires a [multicast session](./slim-session.md#multicast). A multicast +This requires a [group session](./slim-session.md#group). A group session is a channel shared among multiple participants and used to send messages to everyone. When a new participant wants to join the channel, they must be invited by the channel creator. @@ -24,20 +24,20 @@ actively participate in the communication process (possibly implementing some of the application logic) or serve solely as a channel moderator. This section provides the basic -steps to follow, along with Python code snippets, for setting up a multicast session. -The full code is available in the [multicast.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) example in the SLIM repository. +steps to follow, along with Python code snippets, for setting up a group session. +The full code is available in the [group.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) example in the SLIM repository. ### Create the Channel -The channel can be created with a Multicast session, +The channel can be created with a group session, which initializes the corresponding state in the SLIM session layer. -In a multicast session communication between participants can be encrypted -end-to-end enabling MLS. +In a group session, communication between participants can be encrypted +end-to-end, enabling MLS. ```python created_session = await local_app.create_session( - slim_bindings.PySessionConfiguration.Multicast( # type: ignore # Build multicast session configuration - channel_name=chat_channel, # Logical multicast channel (PyName) all participants join; acts as group/topic identifier. + slim_bindings.PySessionConfiguration.Group( # type: ignore # Build group session configuration + channel_name=chat_channel, # Logical group channel (PyName) all participants join; acts as group/topic identifier. max_retries=5, # Max per-message resend attempts upon missing ack before reporting a delivery failure. timeout=datetime.timedelta( seconds=5 @@ -49,7 +49,7 @@ created_session = await local_app.create_session( ### Invite Participants to the Channel -Once the multicast session is created, new participants can be invited +Once the group session is created, new participants can be invited to join. Not all participants need to be added at the beginning; you can add them later, even after communication has started. ```python @@ -81,7 +81,7 @@ When a new session is available, the participant can start listening for message ```python while True: try: - # Await next inbound message from the multicast session. + # Await next inbound message from the group session. # The returned parameters are a message context and the raw payload bytes. # Check session.py for details on PyMessageContext contents. ctx, payload = await session.get_message() @@ -104,8 +104,8 @@ Each participant can also send messages at any time to the new session, and each ```python # Send message to the channel_name specified when creating the session. -# As the session is multicast, all participants will receive it. -# calling publish_with_destination on a multicast session will raise an error. +# As the session is group, all participants will receive it. +# calling publish_with_destination on a group session will raise an error. await shared_session_container[0].publish(user_input.encode()) ``` @@ -113,9 +113,9 @@ await shared_session_container[0].publish(user_input.encode()) Another way to create a group in a SLIM network is to use the [SLIM Controller](./slim-controller.md). For a complete description -on how to run it and the commands to use for the gruop creation and -management please refer to the [Group Communication Tutorial](./slim-group-tutorial.md). -In this section we list the `slimctl` commands to replicate +on how to run it and the commands to use for the group creation and +management, please refer to the [Group Communication Tutorial](./slim-group-tutorial.md). +In this section, we list the `slimctl` commands to replicate what we showed in the previous session. diff --git a/docs/messaging/slim-session.md b/docs/messaging/slim-session.md index ef18a588..ef6a6fb6 100644 --- a/docs/messaging/slim-session.md +++ b/docs/messaging/slim-session.md @@ -1,140 +1,22 @@ # SLIM Sessions -This document explains the SLIM session layer and the three supported session -types. It helps you pick the right pattern, understand reliability and security -trade‑offs, and shows concrete Python usage examples. +This document explains the SLIM session layer and the two supported session +types. It helps you understand the insights of the two session interfaces, +understand reliability and security trade‑offs, and shows concrete Python usage examples. -## Quick Reference +## Point-to-Point -| Type | Pattern | Reliability | MLS | Primary Uses | Avoid When | -|----------|----------------|------------------------|-----|----------------------------------------|--------------------------------------------| -| Anycast | 1:1 stateless | Best‑effort or retries | No | Load balance, idempotent RPC, fan‑out | Need per‑peer state or E2E encryption | -| Unicast | 1:1 stateful | Optional acks + retries| Yes | Stateful convo, sticky peer, secure P2P| Need broadcast / many recipients | -| Multicast| N:N channel | Optional acks + retries| Yes | Group chat, pub/sub, coordination | Need strict single recipient semantics | +The point-to-point session enables point-to-point communication with a specific +instance. This session +performs a discovery phase to bind to one instance and all subsequent traffic in +the session targets that same endpoint. With reliability enabled, each message in +the session must be acked. -Key takeaways: +If MLS is enabled, the point-to-point session establishes a two‑member MLS group after +discovery. This mirrors the Group flow but with only two participants +(see [Group](#group) session). -* Pick Anycast for simple stateless request distribution. -* Pick Unicast when you must bind to one specific instance and optionally - secure with MLS. -* Pick Multicast when many peers need to exchange messages over the same shared - channel. - -## Anycast - - -The anycast session enables point-to-point (1:1) communication where each -message sent to a service is delivered to only one of its available instances. -This pattern provides natural load balancing and redundancy for stateless -services. Anycast is best suited for distributing requests across multiple -instances without maintaining session state. - -Let's see an example of the communication pattern in the anycast session using -the sequence diagram below. The anycast session sends each message to a service -(e.g., App-B) and the message is delivered to only one of its available -instances (e.g., App-B/1 or App-B/2). The SLIM Node dynamically routes each -message to one of the running instances, so consecutive messages may be -delivered to different endpoints. - -If reliability is enabled, the sender expects an acknowledgment (Ack) for every -message sent. This confirms successful delivery, even though the specific -instance may vary per message. - -The diagram below illustrates two consecutive messages from App-A to the -service agntcy/ns/App-B. The first message is delivered to App-B/1, the second -to App-B/2. Each delivery is followed by an Ack: - -```mermaid -sequenceDiagram - autonumber - - participant App-A - participant SLIM Node - participant App-B/1 - participant App-B/2 - - App-A->>SLIM Node: Message to agntcy/ns/App-B - SLIM Node->>App-B/1: Message to agntcy/ns/App-B - App-B/1->>SLIM Node: Ack - SLIM Node->>App-A: Ack - - App-A->>SLIM Node: Message to agntcy/ns/App-B - SLIM Node->>App-B/2: Message to agntcy/ns/App-B - App-B/2->>SLIM Node: Ack - SLIM Node->>App-A: Ack -``` - -Note: Anycast sessions are stateless and do not allow persistent per‑recipient -state. Consequently, Messaging Layer Security (MLS) cannot be enabled. If MLS -is required for point‑to‑point communication, use a Unicast session instead. - - -### Create an Anycast Session - -Using the SLIM Python bindings, you can create an Anycast session as follows: - -```python -# Assume local_app is an initialized application instance -session = await local_app.create_session( - slim_bindings.PySessionConfiguration.Anycast( - max_retries=5, # Retries before giving up - timeout=datetime.timedelta(seconds=5), # Wait per attempt for Ack - # (omit for best-effort) - ) -) -``` - -Parameters: - -* `max_retries` (optional, int): Number of retry attempts if an Ack is not - received. -* `timeout` (optional, timedelta): How long to wait for an Ack before retrying. - If omitted the session is best‑effort - -If timeout is not provided the session is best‑effort (unreliable): lost messages -are not retransmitted. - -### Sending and Replying in Anycast -Anycast sessions are not pinned to a single remote instance. Each outgoing -message must therefore specify a destination application name. Use -`publish_with_destination` for sends. The plain `publish` API is only valid for -sessions that already have an implicit peer or channel (Unicast / Multicast). - -```python -remote_name = slim_bindings.PyName("agntcy", "ns", "app") -await session.publish_with_destination(b"hello", remote_name) - -# This would raise for Anycast (no implicit peer): -# await session.publish(b"hello") -``` - -To reply to a received message, use `publish_to`, which routes a response back -to the original sender using the message context acquired via `get_message`: - -```python -async def session_loop(session: slim_bindings.PySession): - while True: - try: - msg_ctx, payload = await session.get_message() - except Exception: - break # Session likely closed - text = payload.decode() - await session.publish_to(msg_ctx, f"Echo: {text}".encode()) -``` - -## Unicast - -The Unicast session enables point‑to‑point communication with a specific -instance. Unlike Anycast (which re‑selects an instance each message), Unicast -performs a discovery phase to bind to one instance; all subsequent traffic in -the session targets that same endpoint. This enables stateful interactions and -session continuity. With reliability enabled each message must be Acked. - -If MLS is enabled, the Unicast session establishes a two‑member MLS group after -discovery. This mirrors the Multicast flow but with only two participants -(see [Multicast](#multicast) session). - -The diagram below illustrates a unicast session from App-A to agntcy/ns/App-B. +The diagram below illustrates a point-to-point session from App-A to agntcy/ns/App-B. App-A first discovers an available instance (App-B/1), then performs the MLS setup, and finally sends multiple messages to that same instance, each followed by an Ack. If MLS is not enabled, the MLS setup is skipped. @@ -158,7 +40,7 @@ sequenceDiagram Note over App-A,App-B/2: Invite App-A->>SLIM Node: Invite agntcy/ns/App-B/1 SLIM Node->>App-B/1: Invite agntcy/ns/App-B/1 - App-B/1->>App-B/1: Create new Unicast Session + App-B/1->>App-B/1: Create new point-to-point Session App-B/1->>SLIM Node: Invite Reply (MLS key package) SLIM Node->>App-A: Invite Reply (MLS key package) App-A->>App-A: Update MLS state @@ -183,15 +65,15 @@ sequenceDiagram ``` -### Create a Unicast Session +### Create a Point-to-Point Session -Using the SLIM Python bindings, you can create a Unicast session as follows: +Using the SLIM Python bindings, you can create a point-to-point session as follows: ```python # Assume local_app is an initialized application instance session = await local_app.create_session( - slim_bindings.PySessionConfiguration.Unicast( - unicast_name=remote_name, + slim_bindings.PySessionConfiguration.PointToPoint( + peer_name=remote_name, max_retries=5, timeout=datetime.timedelta(seconds=5), mls_enabled=True, # Enable MLS for end-to-end security @@ -201,19 +83,17 @@ session = await local_app.create_session( Parameters: -* `unicast_name` (required, PyName): Identifier of the remote participant +* `peer_name` (required, PyName): Identifier of the remote participant instance. * `max_retries` (optional, int): Retry attempts per message if Ack missing. * `timeout` (optional, timedelta): Wait per attempt for an Ack before retry. If `timeout` is not set the session is best‑effort. * `mls_enabled` (optional, bool): Enable end‑to‑end encryption (MLS). -### Sending and Replying in Unicast -In Unicast the session is bound to a single remote instance after discovery, so +### Sending and Replying in a Point-to-Point Session +In the point-to-point session is bound to a single remote instance after discovery, so outbound messages use the implicit destination. Use `publish` for normal sends -and `publish_to` to reply using a previously received message context. Do not -use `publish_with_destination` (it will raise) because the peer is already -fixed. +and `publish_to` to reply using a previously received message context. ```python # Send a message using publish it will reach the endpoint @@ -229,9 +109,9 @@ print(payload.decode()) await session.publish_to(msg_ctx, payload) ``` -## Multicast +## Group -The Multicast session allows many-to-many communication on a named channel. Each +The Group session allows many-to-many communication on a named channel. Each message is delivered to all participants connected to the same session. The creator of the channel can act as a moderator, meaning that it can add or @@ -242,17 +122,17 @@ Below are examples using the latest Python bindings, along with explanations of what happens inside the session layer when a participant is added or removed from the channel (see [Group management](./slim-group.md)). -### Create a Multicast Session +### Create a Group Session -To create a multicast session, you need to configure the session with a topic +To create a group session, you need to configure the session with a topic name and specify reliability and security settings. Here is an example: ```python # Assume local_app is an initialized application instance session = await local_app.create_session( - slim_bindings.PySessionConfiguration.Multicast( - topic=chat_topic, + slim_bindings.PySessionConfiguration.Group( + channel_name=chat_topic, max_retries=5, timeout=datetime.timedelta(seconds=5), mls_enabled=True, @@ -269,10 +149,10 @@ Parameters: If `timeout` is not set the session is best‑effort. * `mls_enabled` (optional, bool): Enable secure group MLS messaging. -### Sending and Replying in Multicast -In Multicast the session targets a channel: all sends are deliverd to all the current -participants. Use `publish` to send. `publish_with_destination` cannot be used -in Multicast because the channel name is implicit in the session. +### Sending and Replying in a Group Session +In a Group the session targets a channel: all sends are deliverd to all the current +participants. Use `publish` to send to a message to all the participants in the +group. ```python # Broadcast to the channel @@ -303,19 +183,19 @@ This will instruct SLIM on how to forward a message with the specified name. This has to be done by the application for every invite. When a moderator wants to add a new participant (e.g., an instance of App-C) to -a multicast session, the following steps occur. All the steps are visualized in +a group session, the following steps occur. All the steps are visualized in the diagram below: 1. **Discovery Phase:** The moderator initiates a discovery request to find a running instance of the desired application (App-C). This request is sent to - the SLIM Node, which forwards it in anycast to one of the App-C instances. + the SLIM Node, which forwards it via anycast to one of the App-C instances. In the example, the message is forwarded to App-C/1 that replies with its full identifier. The SLIM Node relays this reply back to the moderator. 2. **Invitation:** The moderator sends an invite message for the discovered instance (App-C/1) to the SLIM Node, which forwards it to App-C/1. Upon - receiving the invite, App-C/1 creates a new multicast session, subscribes to + receiving the invite, App-C/1 creates a new group session, subscribes to the channel, and replies with its MLS (Messaging Layer Security) key package. This reply is routed back to the moderator. @@ -327,7 +207,7 @@ the diagram below: received, the moderator sends an MLS Welcome message to App-C/1. App-C/1 initializes its MLS state and acknowledges receipt. At the end of this process, all participants (including the new one) share a secure group state - and can exchange encrypted messages on the multicast channel. If MLS is + and can exchange encrypted messages on the group channel. If MLS is disabled, the MLS state update and welcome step are skipped. ```mermaid @@ -350,7 +230,7 @@ sequenceDiagram Note over Moderator,App-A/1: Invite Moderator->>SLIM Node: Invite agntcy/ns/App-C/1 SLIM Node->>App-C/1: Invite agntcy/ns/App-C/1 - App-C/1->>App-C/1: Create new Multicast session + App-C/1->>App-C/1: Create new Group session App-C/1->>SLIM Node: Subscribe to Channel App-C/1->>SLIM Node: Invite Reply (MLS key package) SLIM Node->>Moderator: Invite Reply (MLS key package) @@ -393,13 +273,13 @@ Parameter: * `remove_name` (PyName): Identifier of the participant to remove. -When a moderator wants to remove a participant (e.g., App-C/1) from a multicast +When a moderator wants to remove a participant (e.g., App-C/1) from a group session, the following steps occur. All the steps are visualized in the diagram below: 1. **MLS State Update:** The moderator creates an MLS commit to remove App-C/1 - from the secure group. This commit is sent to the multicast channel and the + from the secure group. This commit is sent to the group channel and the SLIM Node distributes it to all current participants (App-C/1, App-B/2, and App-A/1). Each participant updates its MLS state and acknowledges the commit. The moderator collects all acknowledgments. In case the MLS is @@ -407,9 +287,9 @@ below: 2. **Removal:** After the MLS state is updated, the moderator sends a remove message to App-C/1. Upon receiving the remove message, App-C/1 unsubscribes - from the channel, deletes its multicast session, and replies with a + from the channel, deletes its group session, and replies with a confirmation. The SLIM Node relays this confirmation back to the moderator. - At the end of this process, App-C/1 is no longer a member of the multicast + At the end of this process, App-C/1 is no longer a member of the group group and cannot send or receive messages on the channel. ```mermaid @@ -445,7 +325,7 @@ sequenceDiagram Moderator->>SLIM Node: Remove agntcy/ns/App-C/1 SLIM Node->>App-C/1: Remove agntcy/ns/App-C/1 App-C/1->>SLIM Node: Unsubscribe from Channel - App-C/1->>App-C/1: Remove Multicast session + App-C/1->>App-C/1: Remove Group session App-C/1->>SLIM Node: Remove Reply SLIM Node->>Moderator: Remove Reply ``` @@ -458,23 +338,24 @@ that demonstrate how to create sessions and exchange messages between applicatio Python bindings. -### Anycast & Unicast +### Point-to-Point This [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/point_to_point.py) -walks through creating both Anycast and Unicast sessions side by side. -You will see how Anycast distributes stateless requests across multiple instances, -while Unicast performs discovery and binds to a single peer. The example +walks through the creation of a point-to-point sessions. +You will see how running multiple times the point-to-point example the session will +bind to different running instances, while the message stream always sticks to the same endpoint. +The example demonstrates how to publish messages, enable reliability, and enable MLS -for end‑to‑end security in Unicast sessions. The associated +for end‑to‑end security. The associated [README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_point_to_point.md) shows more information and how to run the example using the Taskfile provided in the repo. -### Multicast -This [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/multicast.py) -demonstrates how to create a multicast session, invite participants, and +### Gruop +This [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) +demonstrates how to create a group session, invite participants, and (if enabled) establish an MLS group for end-to-end encryption. It also shows how to broadcast messages to all current members and handle inbound group messages. The associated -[README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_multicast.md) +[README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_group.md) shows more information and how to run the example using the Taskfile. From 33e615c7a9b6032652a4af274789b806f8cfdfae Mon Sep 17 00:00:00 2001 From: Michele Papalini Date: Fri, 10 Oct 2025 12:21:27 +0200 Subject: [PATCH 19/24] feat: update tutorial with new images Signed-off-by: Michele Papalini --- docs/messaging/slim-group-tutorial.md | 44 +++++++++++++++++---------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/docs/messaging/slim-group-tutorial.md b/docs/messaging/slim-group-tutorial.md index 9c8821b1..6e1c3b0d 100644 --- a/docs/messaging/slim-group-tutorial.md +++ b/docs/messaging/slim-group-tutorial.md @@ -441,7 +441,7 @@ You can run the SLIM instance using Docker: ```bash docker run -it \ -v ./config.yaml:/config.yaml -p 46357:46357 \ - ghcr.io/agntcy/slim:latest /slim --config /config.yaml + ghcr.io/agntcy/slim:0.6.0 /slim --config /config.yaml ``` If everything goes fine, you should see an output like this one: @@ -547,33 +547,37 @@ application is still [group.py](https://github.com/agntcy/slim/blob/main/data-pl First, start the SLIM Controller. Full details are in the [Controller](./slim-controller.md) documentation; here we reproduce the minimal setup. Create a configuration file: ```bash -cat << EOF > ./config.yaml +cat << EOF > ./config-controller.yaml northbound: - httpHost: localhost + httpHost: 0.0.0.0 httpPort: 50051 + logging: + level: DEBUG southbound: - httpHost: localhost + httpHost: 0.0.0.0 httpPort: 50052 +# number of node reconciler thread reconciler: - threads: 3 + threads: 3 logging: - level: DEBUG + level: INFO EOF ``` This config defines two APIs exposed by the controller: + - Northbound API: used by an operator (e.g. via slimctl) to configure channels and participants, as well as the SLIM network. - Southbound API: used by SLIM nodes to synchronize with the controller. Start the controller with Docker: ```bash -docker run -v ./config.yaml:/config.yaml \ - ghcr.io/agntcy/slim/control-plane:latest \ - --config /config.yaml +docker run -it \ + -v ./config-controller.yaml:/config.yaml -p 50051:50051 -p 50052:50052 \ + ghcr.io/agntcy/slim/control-plane:0.6.0 --config /config.yaml ``` If everything goes fine, you should see an output like this one: @@ -590,12 +594,20 @@ If everything goes fine, you should see an output like this one: #### Run the SLIM Node With the controller running, start a SLIM node configured to talk to it over the Southbound API. This node config includes two additional settings compared to the file from the previous section: + - A controller client used to connect to the Southbound API running on port 50052 - A shared secret token provider that will be used by the SLIM node to send messages over the SLIM network. As with the normal application, you can use a shared secret or a proper JWT. -Create the `config.yaml` for the node: + +Create the `config-slim.yaml` for the node using the command below. You will need to replace `` with your actual IP address. + +To find your local IP address, you can use one of the following commands: + +- **On macOS:** `ipconfig getifaddr en0` (for Wi-Fi) or `ipconfig getifaddr en1` (for Ethernet). +- **On Linux:** `hostname -I | awk '{print $1}'` + ```bash -cat << EOF > ./config.yaml +cat << EOF > ./config-slim.yaml tracing: log_level: info display_thread_names: true @@ -618,7 +630,7 @@ services: controller: servers: [] clients: - - endpoint: "http://127.0.0.1:50052" + - endpoint: "http://:50052" tls: insecure: true token_provider: @@ -626,12 +638,12 @@ services: EOF ``` -This starts a SLIM node that connects to the controller at `127.0.0.1:50052`. Run the node: +This starts a SLIM node that connects to the controller at `:50052`. Run the node: ```bash docker run -it \ - -v ./config.yaml:/config.yaml -p 46357:46357 \ - ghcr.io/agntcy/slim:latest /slim --config /config.yaml + -v ./config-slim.yaml:/config.yaml -p 46357:46357 \ + ghcr.io/agntcy/slim:0.6.0 /slim --config /config.yaml ``` If everything goes fine, you should see an output like this one: @@ -730,7 +742,7 @@ if [ "$OS" != "linux" ] && [ "$OS" != "darwin" ]; then fi # Construct the download URL -VERSION="v0.2.2" +VERSION="v0.6.0" BINARY_NAME="slimctl-${OS}-${ARCH}" DOWNLOAD_URL="https://github.com/agntcy/slim/releases/download/slimctl-${VERSION}/${BINARY_NAME}" From 5cc14dc19134227c809a0cb014ab4000eaf34d2a Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Fri, 10 Oct 2025 13:24:57 +0200 Subject: [PATCH 20/24] docs: improvements Signed-off-by: Mauro Sardara --- docs/messaging/slim-group-tutorial.md | 30 +++++++++++++-------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/docs/messaging/slim-group-tutorial.md b/docs/messaging/slim-group-tutorial.md index 6e1c3b0d..c47f3617 100644 --- a/docs/messaging/slim-group-tutorial.md +++ b/docs/messaging/slim-group-tutorial.md @@ -456,7 +456,7 @@ If everything goes fine, you should see an output like this one: #### Start the Participants In this example we use two participants: `agntcy/ns/client-1` and `agntcy/ns/client-2`. -Authentication uses a shared secret. In the SLIM repository, go to the folder +Authentication uses a shared secret. In the SLIM repository, go to the folder `slim/data-plane/python/bindings/examples` and run these commands in two different terminals: ```bash @@ -511,7 +511,7 @@ Send a message to the group, or type 'exit' or 'quit' to quit. 169ca82eb17d6bc2/eef9769a4c6990d1/fc9bbc406957794b/e9f53aa5ef3fb8f2 (agntcy/ns/moderator/e9f53aa5ef3fb8f2) > ``` -Now `client-1` and `client-2` are invited to the group, so on both of their terminals you should +Now `client-1` and `client-2` are invited to the group, so on both of their terminals you should be able to see a welcome message such as: ```bash @@ -525,7 +525,7 @@ At this point, you can write messages from any terminal and they will be receive ## Group Communication Using the SLIM Controller -Previously, we saw how to run group communication using the Python bindings with an in-application moderator. +Previously, we saw how to run group communication using the Python bindings with an in-application moderator. This participant creates the group session and invites all other participants. In this section, we describe how to create and orchestrate a group using the SLIM Controller, and we show how all these functions can be delegated to the controller. We reuse the same group example code in this section as well. @@ -539,7 +539,7 @@ With the controller, you do not need to set up a moderator in your application. ### Run the Group Communication example -Now we will show how to set up a group using the SLIM Controller. The reference code for the +Now we will show how to set up a group using the SLIM Controller. The reference code for the application is still [group.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py). To run this example, follow the steps listed here. #### Run the SLIM Controller @@ -560,7 +560,7 @@ southbound: # number of node reconciler thread reconciler: - threads: 3 + threads: 3 logging: level: INFO @@ -587,8 +587,8 @@ If everything goes fine, you should see an output like this one: 2025-10-06T08:06:06Z INF Starting Route Reconciler thread_name=reconciler-1 2025-10-06T08:06:06Z INF Starting Route Reconciler thread_name=reconciler-0 2025-10-06T08:06:06Z INF Starting Route Reconciler thread_name=reconciler-2 -2025-10-06T08:06:06Z INF Southbound API Service is Listening on 127.0.0.1:50052 -2025-10-06T08:06:06Z INF Northbound API Service is listening on 127.0.0.1:50051 +2025-10-06T08:06:06Z INF Southbound API Service is Listening on [::]:50052 +2025-10-06T08:06:06Z INF Northbound API Service is listening on [::]:50051 ``` #### Run the SLIM Node @@ -598,8 +598,7 @@ With the controller running, start a SLIM node configured to talk to it over the - A controller client used to connect to the Southbound API running on port 50052 - A shared secret token provider that will be used by the SLIM node to send messages over the SLIM network. As with the normal application, you can use a shared secret or a proper JWT. -Create the `config-slim.yaml` for the node using the command below. You will need to replace `` with your actual IP address. - +Create the `config-slim.yaml` for the node using the command below. We use the `host.docker.internal` endpoint to reach the controller from inside the Docker container via the host. To find your local IP address, you can use one of the following commands: - **On macOS:** `ipconfig getifaddr en0` (for Wi-Fi) or `ipconfig getifaddr en1` (for Ethernet). @@ -630,7 +629,7 @@ services: controller: servers: [] clients: - - endpoint: "http://:50052" + - endpoint: "http://host.docker.internal:50052" tls: insecure: true token_provider: @@ -638,7 +637,7 @@ services: EOF ``` -This starts a SLIM node that connects to the controller at `:50052`. Run the node: +This starts a SLIM node that connects to the controller: ```bash docker run -it \ @@ -669,7 +668,7 @@ output should be similar to the following: #### Run the Participants -Because the controller manages the group lifecycle, no participant needs to be designated as moderator in code. Every application instance just waits for a session invite. In three separate terminals, from the folder +Because the controller manages the group lifecycle, no participant needs to be designated as moderator in code. Every application instance just waits for a session invite. In three separate terminals, from the folder `slim/data-plane/python/bindings/examples` run: ```bash @@ -762,7 +761,7 @@ To verify that `slimctl` was downloaded successfully, run the command ##### Create the Group -Select any running participant to be the initial member of the group. This participant will act as the logical +Select any running participant to be the initial member of the group. This participant will act as the logical moderator of the channel, similar to the Python bindings example. However, you don't need to handle this explicitly in the code. Run the following command to create the channel: @@ -783,7 +782,7 @@ Received response: agntcy/ns/xyIGhc2igNGmkeBDlZ The value `agntcy/ns/xyIGhc2igNGmkeBDlZ` is the channel (or group) identifier (name) that must be used in subsequent commands. -On the application side, `client-1` was added to the session, so you should see +On the application side, `client-1` was added to the session, so you should see something like this: ```bash @@ -835,7 +834,7 @@ Deleting participant from channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/cli Participant deleted successfully from channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client-3 ``` -The application on `client-3` exits because the session related to the group was closed, which breaks the +The application on `client-3` exits because the session related to the group was closed, which breaks the receive loop in the Python code. Notice that this command does not work for `client-1`, which was added as the first participant. In fact, removing `client-1` is equivalent to deleting the channel itself. @@ -854,4 +853,3 @@ Channel deleted successfully with ID: agntcy/ns/xyIGhc2igNGmkeBDlZ ``` All applications connected to the group will stop because the receive loops end. - From 3da3d8545182b73d0554a84805909bc6fcef5e95 Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Fri, 10 Oct 2025 13:29:17 +0200 Subject: [PATCH 21/24] docs: improvements Signed-off-by: Mauro Sardara --- docs/messaging/slim-group-tutorial.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/messaging/slim-group-tutorial.md b/docs/messaging/slim-group-tutorial.md index c47f3617..58e78348 100644 --- a/docs/messaging/slim-group-tutorial.md +++ b/docs/messaging/slim-group-tutorial.md @@ -599,10 +599,6 @@ With the controller running, start a SLIM node configured to talk to it over the - A shared secret token provider that will be used by the SLIM node to send messages over the SLIM network. As with the normal application, you can use a shared secret or a proper JWT. Create the `config-slim.yaml` for the node using the command below. We use the `host.docker.internal` endpoint to reach the controller from inside the Docker container via the host. -To find your local IP address, you can use one of the following commands: - -- **On macOS:** `ipconfig getifaddr en0` (for Wi-Fi) or `ipconfig getifaddr en1` (for Ethernet). -- **On Linux:** `hostname -I | awk '{print $1}'` ```bash From 38b2d114bab7a2093d63b6c403189535005ea8bf Mon Sep 17 00:00:00 2001 From: Aron Kerekes Date: Fri, 10 Oct 2025 15:11:33 +0200 Subject: [PATCH 22/24] chore: editorial review Signed-off-by: Aron Kerekes --- docs/.index | 1 + docs/glossary.md | 349 ++++++++++++++++++++++++++ docs/messaging/.index | 1 - docs/messaging/slim-authentication.md | 71 +++--- docs/messaging/slim-controller.md | 11 +- docs/messaging/slim-glossary.md | 178 ------------- docs/messaging/slim-group-tutorial.md | 86 +++---- docs/messaging/slim-group.md | 23 +- docs/messaging/slim-rpc.md | 2 +- docs/messaging/slim-session.md | 84 +++---- mkdocs/mkdocs.yml | 3 + 11 files changed, 481 insertions(+), 328 deletions(-) create mode 100644 docs/glossary.md delete mode 100644 docs/messaging/slim-glossary.md diff --git a/docs/.index b/docs/.index index e355bfe1..03f3e36b 100644 --- a/docs/.index +++ b/docs/.index @@ -12,4 +12,5 @@ nav: - Agent Workflow Server: agws - Agent Manifest: manifest - How-To Guides: how-to-guides + - Glossary: glossary.md - How to Contribute: contributing.md diff --git a/docs/glossary.md b/docs/glossary.md new file mode 100644 index 00000000..404f95bd --- /dev/null +++ b/docs/glossary.md @@ -0,0 +1,349 @@ +# SLIM Messaging Glossary + +This glossary defines technical terms referenced across the SLIM messaging documentation: core concepts, naming, sessions, routing, configuration, security, integrations (SLIMRPC, A2A, MCP), and deployment tooling. Terms are alphabetized. + +--- + +## A + +
+ +- **Ack (Acknowledgment)** + + --- + + A confirmation—explicit or implicit—that a sent message was delivered or processed. In reliable modes, missing acks trigger retries until `max_retries` is reached or a timeout fires. + +- **Anycast** + + --- + + Routing mode where a message addressed to a 3-component name (`org/namespace/service`) is delivered to exactly one currently reachable instance. Each message may choose a different instance. Used in the discovery phase of point-to-point and group sessions. + +
+ +--- + +## C + +
+ +- **Channel (Group Channel)** + + --- + + Logical group namespace: the first three SLIM name components (`org/namespace/service`) without the client hash. All joined participants receive each message. Also referred to as a Group. + +- **Channel Moderator** + + --- + + Manager of a group channel that invites/removes participants and coordinates MLS state. + +- **Client (Application Client)** + + --- + + Runtime endpoint connected to a SLIM node. Identified by full four-component name: `org/namespace/service/clientHash`. + +- **Client Instance ID (Client Hash)** + + --- + + Fourth name component, derived from identity material (e.g., hash of public key). Ensures unique, routable unicast identity per instance. + +- **Connection (Routing Connection)** + + --- + + Configured link (endpoint + parameters) enabling a SLIM node to route traffic to another SLIM node. + +- **Controller (SLIM Controller)** + + --- + + Central orchestration service offering northbound (administrative) and southbound (node) gRPC interfaces for configuration, topology, and group/channel operations. + +
+ +--- + +## D + +
+ +- **Data Plane (Messaging Layer)** + + --- + + Operational pipeline for message routing, delivery, encryption (MLS), and session state, implemented in SLIM nodes. It can be used synonymously with "SLIM Node". + +- **Discovery (Service Discovery)** + + --- + + Initial interaction where packets can be sent to any available instance. This is used at the beginning of a point-to-point session and when a new invite is sent in a group session. + +
+ +--- + +## E + +
+ +- **Endpoint** + + --- + + Host:port (and scheme) on which a server listens or a client connects. Note that in the configuration the client needs to specify the protocol (e.g. http://localhost:46357), but not the server (e.g. localhost:46357) + +
+ +--- + +## G + +
+ +- **Group** + + --- + + Set of participants joined to a channel. Shares message distribution and optionally an MLS security context. See also: Channel. + +
+ +--- + +## I + +
+ +- **Identity** + + --- + + Cryptographic or token-based representation of a workload (shared secret, JWT, SPIFFE SVID) determining trust and naming uniqueness. + +- **Invitation (Group Invitation)** + + --- + + Control message enabling a client to join an existing group. + +
+ +--- + +## L + +
+ +- **Local Name** + + --- + + The fully qualified SLIM name representing the current application endpoint. See Client (Application Client) + +
+ +--- + +## M + +
+ +- **Max Retries (Session Config)** + + --- + + Upper limit on retransmission attempts for a single message lacking timely acknowledgment. + +- **MLS (Message Layer Security)** + + --- + + End-to-end group key agreement and encryption protocol (RFC 9420) providing confidentiality and integrity beyond hop-level TLS termination. + +- **Moderator** + + --- + + Alias of Channel Moderator. + +- **Group Session** + + --- + + Session type enabling many-to-many distribution; every message is delivered to all participants in the channel. + +
+ +--- + +## N + +
+ +- **Name (SLIM Name)** + + --- + + Structured routing identifier: `organization/namespace/service/clientHash` (full) or the first three components for channel addressing. The first component, `organization`, usually represents the top-level administrative or tenant boundary; the second component, `namespace`, can be used to encode environment, region, or an organizational partition; the third component, `service`, specifies the service exposed by the client. When multiple instances of the same service are deployed (such as several pods in a Kubernetes cluster), these first three components remain the same for all instances. The last component, `clientHash`, is generated by SLIM from the client's identity material (e.g., a hash of the public key) and uniquely identifies each specific client instance. + +- **Node (SLIM Node)** + + --- + + Runtime process implementing the data plane: message routing, session handling, MLS operations, optional control endpoints. + +
+ +--- + +## P + +
+ +- **Participant (Group Participant)** + + --- + + Client that has accepted an invitation and joined a group, receiving all channel traffic. + +
+ +--- + +## R + +
+ +- **Retry** + + --- + + Re-attempt of sending a message after a timeout window, capped by `max_retries`. + +- **Route (Routing Entry)** + + --- + + Controller-managed mapping directing messages for a particular name (or prefix) through a specific connection. + +
+ +--- + +## S + +
+ +- **Session** + + --- + + Abstraction for interaction context (Point-to-Point, Group). Manages encryption (if MLS enabled), retries, and sequencing. + +- **Session Configuration** + + --- + + Per-session parameters selected at creation (e.g., mode, `mls_enabled`, metadata). In Python bindings: `PySessionConfiguration.PointToPoint(...)`, etc. + +- **Session Layer** + + --- + + Middleware that abstracts encryption, invitations, routing resolution, and reliability, offering simple send/receive primitives. + +- **Shared Secret Identity** + + --- + + Simplest identity bootstrap (common secret) for demos/tests before stronger mechanisms (e.g., JWT) are deployed. + +- **Slimctl** + + --- + + Command-line tool managing routes, connections, subscriptions, and nodes via Controller or direct node endpoints. + +- **SLIM (Secure Low-Latency Interactive Messaging)** + + --- + + Framework delivering secure, scalable, low-latency messaging with unified naming, session semantics, encryption, and extensibility. + +- **SLIMA2A** + + --- + + Integration of A2A agent protocol over SLIM using SLIMRPC-generated stubs. + +- **SLIM Controller** + + --- + + See Controller. + +- **SLIMRPC** + + --- + + Protobuf-based RPC framework operating over SLIM transport (unary and streaming patterns). Analogous to gRPC but using SLIM naming and channels. + +- **SLIMRPC Compiler (protoc-slimrpc-plugin)** + + --- + + Protoc plugin generating Python stubs and servicers for SLIMRPC services defined in `.proto` files. + +- **Subscription** + + --- + + Binding between a routed name/prefix and a connection so messages destined to that name traverse the appropriate path. + +- **Publish** + + --- + + Operation that sends a message on a session (context: point-to-point/group). May await acknowledgment depending on reliability mode. In Python bindings: `session.publish(...)` or `session.publish_to(ctx, ...)`. + +- **Message Context** + + --- + + Metadata accompanying a received message (e.g., routing info). Used to reply (`publish_to`) preserving addressing. + +
+ +--- + +## T + +
+ +- **Timeout (Request / Session Timeout)** + + --- + + Upper bound for waiting on acknowledgments or RPC responses before retry/failure escalation. + +
+ +--- + +## U + +
+ +- **Point-to-Point Session** + + --- + + Session mode for communication with a specific client instance. Ensures message affinity to a single endpoint. + +
diff --git a/docs/messaging/.index b/docs/messaging/.index index e9eacc49..1923892d 100644 --- a/docs/messaging/.index +++ b/docs/messaging/.index @@ -2,7 +2,6 @@ nav: - Secure Low-Latency Interactive Messaging (SLIM): slim-core.md - Getting Started with SLIM: - Getting Started: slim-howto.md - - Glossary: slim-glossary.md - Configuration Reference: slim-data-plane-config.md - SLIM Messaging Layer: - Overview: slim-data-plane.md diff --git a/docs/messaging/slim-authentication.md b/docs/messaging/slim-authentication.md index 34c345bd..d5ad0458 100644 --- a/docs/messaging/slim-authentication.md +++ b/docs/messaging/slim-authentication.md @@ -15,10 +15,10 @@ public key for verification. Check the [Identity Test](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/tests/test_identity.py) for an example of how to use JWT tokens with SLIM if you have your own keys. -If you are running your SLIM clients in a Kubernetes environment, a very common -approach to give an identity to each client is to use SPIRE -(https://spiffe.io/). SPIRE provides a way to issue [SPIFFE -IDs](https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/#spiffe-id) to +If you are running your SLIM clients in a Kubernetes environment, using +[SPIRE](https://spiffe.io/) is a very common approach to give an identity +to each client. SPIRE provides a way to issue +[SPIFFE IDs](https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/#spiffe-id) to workloads, in the form of JWT tokens, which SLIM can then use to authenticate clients. This allows for secure and scalable identity management in distributed systems. @@ -27,16 +27,16 @@ systems. SLIM integrates well with SPIRE, as it allows you to use the JWT tokens generated by SPIRE as client identities, and at the same time it can verify -these tokens using the key bundle provided by SPIRE. This section shows how to -use SPIRE with SLIM to manage client identities. You will: +these tokens using the key bundle provided by SPIRE. -1. Create a local KIND cluster (with an in-cluster image registry). -2. Install SPIRE (server + agents). -3. Build and push SLIM images to the local registry. -4. Deploy the SLIM node (control / rendezvous component). -5. Deploy two distinct SLIM client workloads, each with its own ServiceAccount - (and thus its own SPIFFE ID). -6. Run the point-to-point example using JWT-based authentication derived from SPIRE. +This section shows how to use SPIRE with SLIM to manage client identities. The following topics are covered: + +* Creating a local KIND cluster (with an in-cluster image registry). +* Installing SPIRE (server and agents). +* Building and pushing SLIM images to the local registry. +* Deploying the SLIM node (control and rendezvous components). +* Deploying two distinct SLIM client workloads, each with its own ServiceAccount (and thus its own SPIFFE ID). +* Running the point-to-point example using JWT-based authentication derived from SPIRE. If you already have a Kubernetes cluster or an existing SPIRE deployment, you can adapt only the relevant subsections. @@ -45,12 +45,13 @@ This tutorial is based on the [SLIM examples](https://github.com/agntcy/slim/blo ### Prerequisites -- [Docker](https://docs.docker.com/get-docker/) installed and running. -- [kubectl](https://kubernetes.io/docs/tasks/tools/) installed and configured. -- [Helm](https://helm.sh/docs/intro/install/) installed. -- [KIND](https://kind.sigs.k8s.io/docs/user/quick-start/) installed. +The following prerequisites are required: + +- [Docker](https://docs.docker.com/get-docker/) +- [kubectl](https://kubernetes.io/docs/tasks/tools/) +- [Helm](https://helm.sh/docs/intro/install/) +- [KIND](https://kind.sigs.k8s.io/docs/user/quick-start/) - [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) - installed. Clone the SLIM repository if you haven't already: @@ -58,7 +59,7 @@ Clone the SLIM repository if you haven't already: git clone https://github.com/agntcy/slim.git && cd slim/data-plane/python/bindings/examples ``` -### Create a KIND cluster with a local image registry +### Creating a KIND Cluster with a Local Image Registry The helper script below provisions a KIND cluster and configures a local registry (localhost:5001) that the cluster’s container runtime can pull from: @@ -67,7 +68,9 @@ registry (localhost:5001) that the cluster’s container runtime can pull from: curl -L https://kind.sigs.k8s.io/examples/kind-with-registry.sh | sh ``` -### Install SPIRE (server + CRDs + agents) +### Installing SPIRE + +To install SPIRE, you need to install the server, CRDs, and agents: ```bash helm upgrade --install \ @@ -90,7 +93,7 @@ kubectl get pods -n spire-server All pods should reach Running/READY status before proceeding. -### SPIFFE ID strategy +### SPIFFE ID Strategy The default SPIRE server Helm chart installs a Cluster SPIFFE ID controller object (`spire-server-spire-default`) that issues workload identities following @@ -98,11 +101,11 @@ the pattern: `spiffe://domain.test/ns//sa/` -We will rely on that default. If you need more granular issuance (specific label +We rely on this object by default. If you need more granular issuance (specific label selectors, different trust domain, etc.), consult the [ClusterSPIFFEID documentation](https://github.com/spiffe/spire-controller-manager/blob/main/docs/clusterspiffeid-crd.md). -### Build SLIM images (node + examples) +### Building SLIM Images (node and examples) You can use pre-built images if available; here we build and push fresh ones to the local registry: @@ -115,7 +118,7 @@ IMAGE_REPO=localhost:5001 docker bake bindings-examples && docker push localhost popd ``` -### Deploy the SLIM node +### Deploying the SLIM Node ```bash REPO_ROOT=$(git rev-parse --show-toplevel) @@ -134,15 +137,15 @@ Confirm the pod is running: kubectl get pods -n slim ``` -### Deploy client configuration (ConfigMap) +### Deploying Client Configuration (ConfigMap) -We first provide a config for `spiffe-helper`, which retrieves SVIDs/JWTs from -the SPIRE agent and writes them to disk. Key fields: +We first provide a config for `spiffe-helper`, which retrieves SVIDs or JWTs from +the SPIRE agent and writes them to disk. The key fields are: - `agent_address`: Path to the SPIRE agent API socket. -- `cert_dir`: Where artifacts (cert/key/bundles/JWTs) are written. -- `jwt_svids`: Audience + output filename for requested JWT SVIDs. -- `daemon_mode = true`: Run continuously to renew material. +- `cert_dir`: Where artifacts (cert, key, bundles, or JWTs) are written. +- `jwt_svids`: Audience and output filename for requested JWT SVIDs. +- `daemon_mode = true`: Run continuously to renew materials. ```bash kubectl apply -f - <` @@ -399,7 +400,7 @@ To enable this, configure the node to host a server allowing the client to conne clients: [] ``` -List connection on a SLIM instance: +List connections on a SLIM instance: `slimctl node-connect connection list --server=` List routes on a SLIM instance: diff --git a/docs/messaging/slim-glossary.md b/docs/messaging/slim-glossary.md deleted file mode 100644 index 74f71666..00000000 --- a/docs/messaging/slim-glossary.md +++ /dev/null @@ -1,178 +0,0 @@ -# SLIM Messaging Glossary - -This glossary defines technical terms referenced across the SLIM messaging documentation: core concepts, naming, sessions, routing, configuration, security, integrations (SLIMRPC, A2A, MCP), and deployment tooling. Terms are alphabetized. - ---- - -## A - -### Ack (Acknowledgment) -A confirmation—explicit or implicit—that a sent message was delivered or processed. In reliable modes, missing acks trigger retries until `max_retries` is reached or a timeout fires. - -### Anycast -Routing mode where a message addressed to a 3-component name (`org/namespace/service`) is delivered to exactly one currently reachable instance. Each message may choose a different instance. Used in the discovery phase of point-to-point and group sessions. - ---- - -## C - -### Channel (Group Channel) -Logical group namespace: the first three SLIM name components (`org/namespace/service`) without the client hash. All joined participants receive each message. Also referred to as a Group. - -### Channel Moderator -Manager of a group channel that can invites/removes participants and coordinates MLS state. - -### Client (Application Client) -Runtime endpoint connected to a SLIM node. Identified by full four-component name: `org/namespace/service/clientHash`. - - - -### Client Instance ID (Client Hash) -Fourth name component, derived from identity material (e.g., hash of public key). Ensures unique, routable unicast identity per instance. - -### Connection (Routing Connection) -Configured link (endpoint + parameters) enabling a SLIM node to route traffic to another SLIM node. - -### Controller (SLIM Controller) -Central orchestration service offering northbound (administrative) and southbound (node) gRPC interfaces for configuration, topology, and group/channel operations. - ---- - -## D - -### Data Plane (Messaging Layer) -Operational pipeline for message routing, delivery, encryption (MLS), and session state, implemented in SLIM nodes. It can be used synonymously with "SLIM Node". - -### Discovery (Service Discovery) -Initial interaction where packets can be sent to any available instance. This is used at the beginning of point-to-point session and when a new invite is sent in a group session. - ---- - -## E - -### Endpoint -Host:port (and scheme) on which a server listens or a client connects. Note that in the configuration the client needs to specify the protocol (e.g. http://localhost:46357), but not the server (e.g. localhost:46357) - ---- - -## G - -### Group -Set of participants joined to a channel. Shares message distribution and optionally an MLS security context. See also: Channel. - ---- - -## I - -### Identity -Cryptographic or token-based representation of a workload (shared secret, JWT, SPIFFE SVID) determining trust and naming uniqueness. - -### Invitation (Group Invitation) -Control message enabling a client to join an existing group. - ---- - -## L - -### Local Name -The fully qualified SLIM name representing the current application endpoint. See Client (Application Client) - ---- - -## M - -### Max Retries (Session Config) -Upper limit on retransmission attempts for a single message lacking timely acknowledgment. - -### MLS (Message Layer Security) -End-to-end group key agreement and encryption protocol (RFC 9420) providing confidentiality and integrity beyond hop-level TLS termination. - -### Moderator -Alias of Channel Moderator. - -### Group Session -Session type enabling many-to-many distribution; every message is delivered to all participants in the channel. - ---- - -## N - -### Name (SLIM Name) -Structured routing identifier: `organization/namespace/service/clientHash` (full) or the first three components for channel addressing. The first component, `organization`, usually represents the top-level administrative or tenant boundary; the second component, `namespace`, can be used to encode environment, region, or an organizational partition; the third component, `service`, specifies the service exposed by the client. When multiple instances of the same service are deployed (such as several pods in a Kubernetes cluster), these first three components remain the same for all instances. The last component, `clientHash`, is generated by SLIM from the client's identity material (e.g., a hash of the public key) and uniquely identifies each specific client instance. - -### Node (SLIM Node) -Runtime process implementing the data plane: message routing, session handling, MLS operations, optional control endpoints. - ---- - -## P - -### Participant (Group Participant) -Client that has accepted an invitation and joined a group, receiving all channel traffic. - ---- - -## R - -### Retry -Re-attempt of sending a message after a timeout window, capped by `max_retries`. - -### Route (Routing Entry) -Controller-managed mapping directing messages for a particular name (or prefix) through a specific connection. - ---- - -## S - -### Session -Abstraction for interaction context (Point-to-Point, Group). Manages encryption (if MLS enabled), retries, and sequencing. - -### Session Configuration -Per-session parameters selected at creation (e.g., mode, `mls_enabled`, metadata). In Python bindings: `PySessionConfiguration.PointToPoint(...)`, etc. - -### Session Layer -Middleware that abstracts encryption, invitations, routing resolution, and reliability, offering simple send/receive primitives. - -### Shared Secret Identity -Simplest identity bootstrap (common secret) for demos/tests before stronger mechanisms (e.g., JWT) are deployed. - -### Slimctl -Command-line tool managing routes, connections, subscriptions, and nodes via Controller or direct node endpoints. - -### SLIM (Secure Low-Latency Interactive Messaging) -Framework delivering secure, scalable, low-latency messaging with unified naming, session semantics, encryption, and extensibility. - -### SLIMA2A -Integration of A2A agent protocol over SLIM using SLIMRPC-generated stubs. - -### SLIM Controller -See Controller. - -### SLIMRPC -Protobuf-based RPC framework operating over SLIM transport (unary and streaming patterns). Analogous to gRPC but using SLIM naming and channels. - -### SLIMRPC Compiler (protoc-slimrpc-plugin) -Protoc plugin generating Python stubs and servicers for SLIMRPC services defined in `.proto` files. - -### Subscription -Binding between a routed name/prefix and a connection so messages destined to that name traverse the appropriate path. - -### Publish -Operation that sends a message on a session (context: point-to-point/group). May await acknowledgment depending on reliability mode. In Python bindings: `session.publish(...)` or `session.publish_to(ctx, ...)`. - -### Message Context -Metadata accompanying a received message (e.g., routing info). Used to reply (`publish_to`) preserving addressing. - ---- - -## T - -### Timeout (Request / Session Timeout) -Upper bound for waiting on acknowledgments or RPC responses before retry/failure escalation. - ---- - -## U - -### Point-to-Point Session -Session mode for communication with a specific client instance. Ensures message affinity to a single endpoint. diff --git a/docs/messaging/slim-group-tutorial.md b/docs/messaging/slim-group-tutorial.md index 58e78348..b04bb915 100644 --- a/docs/messaging/slim-group-tutorial.md +++ b/docs/messaging/slim-group-tutorial.md @@ -20,23 +20,15 @@ example in the SLIM repo. - **End-to-End Encryption**: Ensures secure communication using the [MLS protocol](https://datatracker.ietf.org/doc/html/rfc9420). -## Table of Contents - -1. [Configure Client Identity and Implement the SLIM App](#configure-client-identity-and-implement-the-slim-app) -2. [Group Communication Using the Python Bindings](#group-communication-using-the-python-bindings) -3. [Group Communication Using the SLIM Controller](#group-communication-using-the-slim-controller) - - ## Configure Client Identity and Implement the SLIM App Every participant in a group requires a unique identity for authentication and for use by the MLS protocol. This section explains how to set up identity and create a SLIM application instance. - ### Identity Each participant must have a unique identity. This is required to set up end-to-end encryption using the MLS protocol. The identity can be a JWT or a shared secret. For simplicity, this example uses a shared secret. For JWT-based identity, see the [tutorial](https://github.com/agntcy/slim/tree/main/data-plane/python/bindings/examples#running-in-kubernetes-spire--jwt) in the SLIM repository. -The Python objects managing the identity are called `PyIdentityProvider` and `PyIdentityVerifier`. The `PyIdentityProvider` provides the identity, while the `PyIdentityVerifier` verifies it. +The Python objects managing the identity are called `PyIdentityProvider` and `PyIdentityVerifier`. The `PyIdentityProvider` provides the identity, while the `PyIdentityVerifier` verifies it: ```python def shared_secret_identity(identity: str, secret: str): @@ -63,10 +55,9 @@ This is a helper function defined in [common.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L85) that can be used to create a `PyIdentityProvider` and `PyIdentityVerifier` from two input strings. - ### SLIM App -The provider and verifier are used to create a local SLIM application that can exchange messages with other participants via the SLIM network. To create the SLIM app, use the helper function defined in [common.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L289). +The provider and verifier are used to create a local SLIM application that can exchange messages with other participants via the SLIM network. To create the SLIM app, use the helper function defined in [common.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L289): ```python async def create_local_app( @@ -150,16 +141,17 @@ async def create_local_app( This function takes several parameters as input: -- `local` (str): The SLIM name of the local application in the form - `org/ns/service` (required). -- `slim` (dict): Configuration to connect to the remote SLIM node. Example: +- `local` (required, str): The SLIM name of the local application in the form + `org/ns/service`. +- `slim` (required, dict): Configuration to connect to the remote SLIM node. For example: + ```python { "endpoint": "http://127.0.0.1:46357", "tls": {"insecure": True}, } ``` - (required) + - `enable_opentelemetry` (bool, default: `False`): Enable OpenTelemetry tracing. If `True`, traces are sent to `http://localhost:4317` by default. - `shared_secret` (str | None, default: `None`): Shared secret for identity and @@ -168,6 +160,7 @@ This function takes several parameters as input: `spire_trust_bundle` and `audience` for JWT-based authentication. - `spire_trust_bundle` (str | None, default: `None`): JWT trust bundle (list of JWKs, one for each trust domain). It is expected in JSON format such as: + ```json { "trust-domain-1.org": "base-64-encoded-jwks", @@ -175,16 +168,17 @@ This function takes several parameters as input: ... } ``` + - `audience` (list[str] | None, default: `None`): List of allowed audiences for JWT authentication. - If `jwt`, `spire_trust_bundle`, and `audience` are not provided, `shared_secret` must be set (only recommended for local testing or examples, not production). In this example, we use the shared secret option, but the same function supports all authentication flows. - ## Group Communication Using the Python Bindings -Now that you know how to set up a SLIM application, we can see how to create a group where multiple participants can exchange messages. We will start by showing how to create a group session using the Python bindings. In this setting, one participant acts as moderator: it creates the group session and invites participants by sending invitation control messages. A detailed description of group sessions and the invitation process is available [here](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/SESSION.md). +Now that you know how to set up a SLIM application, we can see how to create a group where multiple participants can exchange messages. We start by showing how to create a group session using the Python bindings. + +In this setting, one participant acts as moderator: it creates the group session and invites participants by sending invitation control messages. A detailed description of group sessions and the invitation process is available [here](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/SESSION.md). ### Creating the Group Session and Inviting Members @@ -261,7 +255,7 @@ The channel name (the logical group topic) is produced via the [split_id](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L63) helper by parsing the `remote` parameter. A new group session is then created using `local_app.create_session(...)` with a -`slim_bindings.PySessionConfiguration.Group` configuration. The key parameters are: +`slim_bindings.PySessionConfiguration.Group` configuration. The key parameters are the following: - `channel_name`: Logical channel/topic used to exchange messages among participants. - `max_retries`: Maximum number of retransmission attempts (upon missing ack) before @@ -276,8 +270,8 @@ SLIM knows how to deliver the control messages. ### Implement Participants and Receive Messages -The group participants will be implemented in a similar way, but they -will not create the session. They will create the SLIM service instance and wait +The group participants are implemented in a similar way, but they +do not create the session. They create the SLIM service instance and wait for invites. Once they receive the invite, they can read and write on the shared channel. ```python @@ -335,7 +329,7 @@ with source, destination, message type, and metadata. ### Publish Messages to the Session -All participants can publish messages on the shared channel +All participants can publish messages on the shared channel: ```python async def keyboard_loop(session_ready, shared_session_container, local_app): @@ -393,11 +387,12 @@ participants. Now we will show how to run a new group session and how to enable group communication on top of SLIM. The full code can be found in [group.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) -in the SLIM repo. To run the example, follow the steps listed here. +in the SLIM repo. To run the example, follow the steps listed here: #### Run SLIM -As all members of the group will be communicating via a SLIM network, we can set -up a SLIM instance representing the SLIM network. We will use the pre-built + +As all members of the group are communicating via a SLIM network, we can set +up a SLIM instance representing the SLIM network. We use the pre-built docker image for this purpose. First execute this command to create the SLIM configuration file. Details about @@ -430,7 +425,7 @@ services: EOF ``` -This configuration will start a SLIM instance with a server listening on port +This configuration starts a SLIM instance with a server listening on port 46357, without TLS encryption for simplicity. Messages are still encrypted using the MLS protocol, but the connections between SLIM nodes do not use TLS. In a production environment, it is recommended to always use TLS and configure @@ -455,6 +450,7 @@ If everything goes fine, you should see an output like this one: ``` #### Start the Participants + In this example we use two participants: `agntcy/ns/client-1` and `agntcy/ns/client-2`. Authentication uses a shared secret. In the SLIM repository, go to the folder `slim/data-plane/python/bindings/examples` and run these commands in two different terminals: @@ -465,6 +461,7 @@ uv run --package slim-bindings-examples group \ --slim '{"endpoint": "http://localhost:46357", "tls": {"insecure": true}}' \ --shared-secret "secret" ``` + ```bash uv run --package slim-bindings-examples group \ --local agntcy/ns/client-2 \ @@ -472,8 +469,9 @@ uv run --package slim-bindings-examples group \ --shared-secret "secret" ``` -This will start two participants authenticated with a shared secret. -The output of these commands should look like: + +This start two participants authenticated with a shared secret. +The output of these commands should look like this: ```bash Warning: Falling back to shared-secret authentication. Don't use this in production! @@ -522,7 +520,6 @@ Send a message to the group, or type 'exit' or 'quit' to quit. At this point, you can write messages from any terminal and they will be received by all other group participants. - ## Group Communication Using the SLIM Controller Previously, we saw how to run group communication using the Python bindings with an in-application moderator. @@ -532,7 +529,6 @@ these functions can be delegated to the controller. We reuse the same group exam Identity handling is unchanged between the two approaches; refer back to [SLIM Identity](#configure-client-identity-and-implement-the-slim-app). Below are the steps to run the controller-managed version. - ### Application Differences With the controller, you do not need to set up a moderator in your application. All participants can be run as we did for `client-1` and `client-2` in the previous examples. In code, this means you can avoid creating a new group session (using `local_app.create_session`) and the invitation loop. You only need to implement the `receive_loop` where the application waits for new sessions. This greatly simplifies your code. @@ -558,7 +554,7 @@ southbound: httpHost: 0.0.0.0 httpPort: 50052 -# number of node reconciler thread +# number of node reconciler threads reconciler: threads: 3 @@ -580,7 +576,7 @@ docker run -it \ ghcr.io/agntcy/slim/control-plane:0.6.0 --config /config.yaml ``` -If everything goes fine, you should see an output like this one: +If everything goes fine, you should see an output like this: ```bash 2025-10-06T08:06:06Z INF Starting route reconcilers @@ -595,12 +591,11 @@ If everything goes fine, you should see an output like this one: With the controller running, start a SLIM node configured to talk to it over the Southbound API. This node config includes two additional settings compared to the file from the previous section: -- A controller client used to connect to the Southbound API running on port 50052 +- A controller client used to connect to the Southbound API running on port 50052. - A shared secret token provider that will be used by the SLIM node to send messages over the SLIM network. As with the normal application, you can use a shared secret or a proper JWT. Create the `config-slim.yaml` for the node using the command below. We use the `host.docker.internal` endpoint to reach the controller from inside the Docker container via the host. - ```bash cat << EOF > ./config-slim.yaml tracing: @@ -652,7 +647,8 @@ If everything goes fine, you should see an output like this one: ``` On the Controller side, you can see that the new node registers with the controller. The -output should be similar to the following: +output should be similar to this: + ```bash 2025-10-06T11:47:14+02:00 INF Registering node with ID: slim/0 svc=southbound 2025-10-06T11:47:14+02:00 INF Connection details: [endpoint: 127.0.0.1:46357] svc=southbound @@ -749,19 +745,18 @@ curl -L "${DOWNLOAD_URL}" -o slimctl chmod +x slimctl ``` -To verify that `slimctl` was downloaded successfully, run the command +To verify that `slimctl` was downloaded successfully, run the following command: + ```bash ./slimctl version ``` ##### Create the Group - -Select any running participant to be the initial member of the group. This participant will act as the logical +Select any running participant to be the initial member of the group. This participant acts as the logical moderator of the channel, similar to the Python bindings example. However, you don't need to handle this explicitly in the code. Run the following command to create the channel: - ```bash ./slimctl channel create moderators=agntcy/ns/client-1/9494657801285491688 ``` @@ -789,7 +784,6 @@ Send a message to the group, or type 'exit' or 'quit' to quit. ##### Add Participants - Now that the new group is created, add the additional participants `client-2` and `client-3` using the following `slimctl` commands: ```bash @@ -799,13 +793,13 @@ Now that the new group is created, add the additional participants `client-2` an The expected `slimctl` output is: - ```bash Adding participant to channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client-2 Participant added successfully to channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client-2 ``` Now all the participants are part of the same group, and so each client log should show that the join was successful: + ```bash Welcome to the group 169ca82eb17d6bc2/eef9769a4c6990d1/e8ab33f6d6111780/ffffffffffffffff (agntcy/ns/xyIGhc2igNGmkeBDlZ/ffffffffffffffff)! Send a message to the group, or type 'exit' or 'quit' to quit. @@ -816,14 +810,13 @@ At this point, every member can send messages, and they will be received by all ##### Remove a Participant - -To remove one of the participants from the channel, run the command: +To remove one of the participants from the channel, run the following command: ```bash ./slimctl participant delete -c agntcy/ns/xyIGhc2igNGmkeBDlZ agntcy/ns/client-3 ``` -The `slimctl` expected output is: +The `slimctl` expected output is this: ```bash Deleting participant from channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client-3 @@ -838,14 +831,15 @@ equivalent to deleting the channel itself. ##### Delete channel To delete the channel, run the following command: + ```bash ./slimctl channel delete agntcy/ns/xyIGhc2igNGmkeBDlZ ``` -The `slimctl` output will be: +The `slimctl` output is this: ```bash Channel deleted successfully with ID: agntcy/ns/xyIGhc2igNGmkeBDlZ ``` -All applications connected to the group will stop because the receive loops end. +All applications connected to the group stop because the receive loops end. diff --git a/docs/messaging/slim-group.md b/docs/messaging/slim-group.md index 395c0ccc..99155d18 100644 --- a/docs/messaging/slim-group.md +++ b/docs/messaging/slim-group.md @@ -7,14 +7,13 @@ Messaging Layer](slim-data-plane.md). When MLS is enabled, group communication benefits from end-to-end encryption. This guide provides all the information you need to create and manage groups within a -SLIM network. A full tutorial with examples is available in +SLIM network. A full tutorial with examples is available in [Group Communication Tutorial](./slim-group-tutorial.md). ## Creating Groups with the Python Bindings - This section shows how to use the SLIM Python bindings to create a group. -This requires a [group session](./slim-session.md#group). A group +This requires a [group session](./slim-session.md#group-session). A group session is a channel shared among multiple participants and used to send messages to everyone. When a new participant wants to join the channel, they must be invited by the channel creator. @@ -75,7 +74,6 @@ print_formatted_text("Waiting for session...", style=custom_style) session = await local_app.listen_for_session() ``` - When a new session is available, the participant can start listening for messages: ```python @@ -112,12 +110,11 @@ await shared_session_container[0].publish(user_input.encode()) ## Creating Groups with the SLIM Controller Another way to create a group in a SLIM network is to use the -[SLIM Controller](./slim-controller.md). For a complete description -on how to run it and the commands to use for the group creation and +[SLIM Controller](./slim-controller.md). For a complete description +on how to run it and the commands to use for the group creation and management, please refer to the [Group Communication Tutorial](./slim-group-tutorial.md). -In this section, we list the `slimctl` commands to replicate -what we showed in the previous session. - +In this section, we list the `slimctl` commands to replicate +what we showed in the previous section. ### Create the Channel @@ -128,11 +125,13 @@ but all the invites/removals will be done using the Controller and no action nee performed in the application. To create the group, run: + ```bash ./slimctl channel create moderators=agntcy/ns/client-1/9494657801285491688 ``` -The outcome will be something similar to this: +The outcome should be something similar to this: + ```bash Received response: agntcy/ns/xyIGhc2igNGmkeBDlZ ``` @@ -142,14 +141,14 @@ added (e.g. `moderators=agntcy/ns/client-1/9494657801285491688`). ### Invite Participants to the Channel -Now that the channel is created, you can start to invite new participants. To do so, you can use +Now that the channel is created, you can start to invite new participants. To do so, you can use the following command: ```bash ./slimctl participant add -c agntcy/ns/xyIGhc2igNGmkeBDlZ agntcy/ns/client-2 ``` -The reply to the command will be similar to this: +The reply to the command should be similar to this: ```bash Adding participant to channel ID agntcy/ns/xyIGhc2igNGmkeBDlZ: agntcy/ns/client-2 diff --git a/docs/messaging/slim-rpc.md b/docs/messaging/slim-rpc.md index 7549d2e8..50b45975 100644 --- a/docs/messaging/slim-rpc.md +++ b/docs/messaging/slim-rpc.md @@ -287,7 +287,7 @@ disables TLS for simplicity in this example. The `shared_secret` parameter is used for initializing the Message Layer Security (MLS) protocol. Note that using a hardcoded shared_secret like "my_shared_secret" is not recommended, please refer to [the documentation for proper MLS -configuration](./slim-group.md#identity-management). +configuration](./slim-group.md). Finally, the add_TestServicer_to_server function is called to register the implemented TestService with the SLIMRPC server, making its RPC methods diff --git a/docs/messaging/slim-session.md b/docs/messaging/slim-session.md index ef6a6fb6..028a0760 100644 --- a/docs/messaging/slim-session.md +++ b/docs/messaging/slim-session.md @@ -1,20 +1,21 @@ # SLIM Sessions This document explains the SLIM session layer and the two supported session -types. It helps you understand the insights of the two session interfaces, -understand reliability and security trade‑offs, and shows concrete Python usage examples. +types. It helps you understand the two session interfaces, reliability, and security trade‑offs. -## Point-to-Point +The SLIM repository ships with practical, runnable [examples](https://github.com/agntcy/slim/tree/main/data-plane/python/bindings/examples) that demonstrate how to create sessions and exchange messages between applications using the Python bindings. + +## Point-to-Point Session The point-to-point session enables point-to-point communication with a specific instance. This session performs a discovery phase to bind to one instance and all subsequent traffic in -the session targets that same endpoint. With reliability enabled, each message in +the session targets that same endpoint. With reliability enabled, each message in the session must be acked. If MLS is enabled, the point-to-point session establishes a two‑member MLS group after -discovery. This mirrors the Group flow but with only two participants -(see [Group](#group) session). +discovery. This mirrors the Group flow but with only two participants +(see [Group Session](#group-session)). The diagram below illustrates a point-to-point session from App-A to agntcy/ns/App-B. App-A first discovers an available instance (App-B/1), then performs the MLS @@ -64,7 +65,6 @@ sequenceDiagram SLIM Node->>App-A: Ack ``` - ### Create a Point-to-Point Session Using the SLIM Python bindings, you can create a point-to-point session as follows: @@ -87,13 +87,16 @@ Parameters: instance. * `max_retries` (optional, int): Retry attempts per message if Ack missing. * `timeout` (optional, timedelta): Wait per attempt for an Ack before retry. - If `timeout` is not set the session is best‑effort. + If `timeout` is not set, the session is best‑effort. * `mls_enabled` (optional, bool): Enable end‑to‑end encryption (MLS). ### Sending and Replying in a Point-to-Point Session -In the point-to-point session is bound to a single remote instance after discovery, so + +As the point-to-point session is bound to a single remote instance after discovery, outbound messages use the implicit destination. Use `publish` for normal sends -and `publish_to` to reply using a previously received message context. +and `publish_to` to reply using a previously received message context. + +This example shows how to send and reply in a point-to-point session: ```python # Send a message using publish it will reach the endpoint @@ -109,12 +112,18 @@ print(payload.decode()) await session.publish_to(msg_ctx, payload) ``` -## Group +### Point-to-Point Example + +This [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/point_to_point.py) walks through the creation of a point-to-point session. When running the point-to-point example multiple times, the session binds to different running instances, while the message stream always sticks to the same endpoint. + +The example demonstrates how to publish messages, enable reliability, and enable MLS for end‑to‑end security. The associated [README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_point_to_point.md) shows more information and how to run the example using the Taskfile provided in the repository. + +## Group Session The Group session allows many-to-many communication on a named channel. Each message is delivered to all participants connected to the same session. -The creator of the channel can act as a moderator, meaning that it can add or +The creator of the channel can act as a moderator, meaning that it can add or remove participants from the session. Moderation can be built into your application or delegated to a separate control service or the SLIM control plane. @@ -150,9 +159,9 @@ Parameters: * `mls_enabled` (optional, bool): Enable secure group MLS messaging. ### Sending and Replying in a Group Session -In a Group the session targets a channel: all sends are deliverd to all the current -participants. Use `publish` to send to a message to all the participants in the -group. + +In a Group, the session targets a channel: all sends are delivered to all the current +participants. Use `publish` to send a message to all the participants in the group. ```python # Broadcast to the channel @@ -176,17 +185,17 @@ await session.invite(invite_name) ``` Parameters: + * `invite_name` (PyName): Identifier of the participant to add. Notice the `await local_app.set_route(invite_name)` command before the invite. -This will instruct SLIM on how to forward a message with the specified name. -This has to be done by the application for every invite. +This instructs SLIM on how to forward a message with the specified name. +This has to be done by the application for every invite. When a moderator wants to add a new participant (e.g., an instance of App-C) to a group session, the following steps occur. All the steps are visualized in the diagram below: - 1. **Discovery Phase:** The moderator initiates a discovery request to find a running instance of the desired application (App-C). This request is sent to the SLIM Node, which forwards it via anycast to one of the App-C instances. @@ -258,26 +267,25 @@ sequenceDiagram ### Remove a Participant - A moderator can remove a participant from the channel using the `remove` method after creating the session. +This example shows how to remove a participant from a group session: + ```python # To remove a participant from the session: remove_name = slim_bindings.PyName("agntcy", "ns", "participant") await session.remove(remove_name) ``` - Parameter: -* `remove_name` (PyName): Identifier of the participant to remove. +* `remove_name` (PyName): Identifier of the participant to remove. When a moderator wants to remove a participant (e.g., App-C/1) from a group session, the following steps occur. All the steps are visualized in the diagram below: - 1. **MLS State Update:** The moderator creates an MLS commit to remove App-C/1 from the secure group. This commit is sent to the group channel and the SLIM Node distributes it to all current participants (App-C/1, App-B/2, and @@ -290,7 +298,7 @@ below: from the channel, deletes its group session, and replies with a confirmation. The SLIM Node relays this confirmation back to the moderator. At the end of this process, App-C/1 is no longer a member of the group - group and cannot send or receive messages on the channel. + and cannot send or receive messages on the channel. ```mermaid sequenceDiagram @@ -330,32 +338,6 @@ sequenceDiagram SLIM Node->>Moderator: Remove Reply ``` -## Examples - - -The SLIM repository ships with practical, runnable [examples](https://github.com/agntcy/slim/tree/main/data-plane/python/bindings/examples) -that demonstrate how to create sessions and exchange messages between applications using the -Python bindings. - - -### Point-to-Point -This [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/point_to_point.py) -walks through the creation of a point-to-point sessions. -You will see how running multiple times the point-to-point example the session will -bind to different running instances, while the message stream always sticks to the same endpoint. -The example -demonstrates how to publish messages, enable reliability, and enable MLS -for end‑to‑end security. The associated -[README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_point_to_point.md) shows more information and how to run the example using the Taskfile -provided in the repo. - - -### Gruop -This [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) -demonstrates how to create a group session, invite participants, and -(if enabled) establish an MLS group for end-to-end encryption. It also shows -how to broadcast messages to all current members and handle inbound group -messages. The associated -[README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_group.md) -shows more information and how to run the example using the Taskfile. +### Group Example +This [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) demonstrates how to create a group session, invite participants, and (if enabled) establish an MLS group for end-to-end encryption. It also shows how to broadcast messages to all current members and handle inbound group messages. The associated [README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_group.md) shows more information and how to run the example using the Taskfile. diff --git a/mkdocs/mkdocs.yml b/mkdocs/mkdocs.yml index f7fb466b..c46c62cc 100644 --- a/mkdocs/mkdocs.yml +++ b/mkdocs/mkdocs.yml @@ -14,6 +14,9 @@ extra_css: markdown_extensions: - admonition + - attr_list + - def_list + - md_in_html - pymdownx.details - pymdownx.superfences - pymdownx.tabbed: From f4e89f02dddf12824f7f0fd825d9f4bba851a49e Mon Sep 17 00:00:00 2001 From: Michele Papalini Date: Fri, 10 Oct 2025 17:42:01 +0200 Subject: [PATCH 23/24] fix: fix links Signed-off-by: Michele Papalini --- docs/messaging/slim-group.md | 4 ++-- docs/messaging/slim-howto.md | 8 ++++---- docs/messaging/slim-mcp.md | 4 ++-- docs/messaging/slim-rpc.md | 14 +++++++------- docs/messaging/slim-session.md | 8 ++++---- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/messaging/slim-group.md b/docs/messaging/slim-group.md index 99155d18..9b7d716d 100644 --- a/docs/messaging/slim-group.md +++ b/docs/messaging/slim-group.md @@ -24,7 +24,7 @@ of the application logic) or serve solely as a channel moderator. This section provides the basic steps to follow, along with Python code snippets, for setting up a group session. -The full code is available in the [group.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) example in the SLIM repository. +The full code is available in the [group.py](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) example in the SLIM repository. ### Create the Channel @@ -54,7 +54,7 @@ to join. Not all participants need to be added at the beginning; you can add the ```python # Invite each provided participant. Route is set before inviting to ensure # outbound control messages can reach them. For more info see -# https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/SESSION.md#invite-a-new-participant +# https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/SESSION.md#invite-a-new-participant for invite in invites: invite_name = split_id(invite) await local_app.set_route(invite_name) diff --git a/docs/messaging/slim-howto.md b/docs/messaging/slim-howto.md index 6b6eb0dc..8c554233 100644 --- a/docs/messaging/slim-howto.md +++ b/docs/messaging/slim-howto.md @@ -147,13 +147,13 @@ dependencies = ["slim-bindings>=0.5.0"] A tutorial on how to use the bindings in an application can be found in the [messaging layer documentation](./slim-data-plane.md). Otherwise examples are available in the -[SLIM Repository](https://github.com/agntcy/slim/tree/slim-v0.5.0/data-plane/python/bindings/examples/src/slim_bindings_examples). +[SLIM Repository](https://github.com/agntcy/slim/tree/slim-v0.6.0/data-plane/python/bindings/examples/src/slim_bindings_examples). ### Slimctl `slimctl` is a command-line tool for managing SLIM Nodes and Controllers. It can be downloaded from the [releases -page](https://github.com/agntcy/slim/releases/tag/slimctl-v0.2.1) in the SLIM repo. +page](https://github.com/agntcy/slim/releases/tag/slimctl-v0.6.0) in the SLIM repo. #### Installation @@ -162,7 +162,7 @@ Choose the appropriate installation method for your operating system: === "macOS (Apple Silicon)" ```bash - curl -LO https://github.com/agntcy/slim/releases/download/slimctl-v0.2.1/slimctl-darwin-arm64 + curl -LO https://github.com/agntcy/slim/releases/download/slimctl-v0.6.0/slimctl-darwin-arm64 sudo mv slimctl-darwin-arm64 /usr/local/bin/slimctl sudo chmod +x /usr/local/bin/slimctl ``` @@ -179,7 +179,7 @@ Choose the appropriate installation method for your operating system: === "Linux (AMD64)" ```bash - curl -LO https://github.com/agntcy/slim/releases/download/slimctl-v0.2.1/slimctl-linux-amd64 + curl -LO https://github.com/agntcy/slim/releases/download/slimctl-v0.6.0/slimctl-linux-amd64 sudo mv slimctl-linux-amd64 /usr/local/bin/slimctl sudo chmod +x /usr/local/bin/slimctl ``` diff --git a/docs/messaging/slim-mcp.md b/docs/messaging/slim-mcp.md index fddb8160..790ac6ef 100644 --- a/docs/messaging/slim-mcp.md +++ b/docs/messaging/slim-mcp.md @@ -30,10 +30,10 @@ architecture. In this section of the tutorial, we implement and deploy two sample applications: -- A [LlamaIndex agent](https://github.com/agntcy/slim/tree/main/data-plane/python/integrations/slim-mcp/slim_mcp/examples/llamaindex_time_agent) +- A [LlamaIndex agent](https://github.com/agntcy/slim/tree/slim-v0.6.0/data-plane/python/integrations/slim-mcp/slim_mcp/examples/llamaindex_time_agent) that communicates with an MCP server over SLIM to perform time queries and timezone conversions. - An [MCP time - server](https://github.com/agntcy/slim/tree/main/data-plane/python/integrations/slim-mcp/slim_mcp/examples/mcp_server_time) that implements SLIM as its transport protocol and processes requests from the LlamaIndex agent. + server](https://github.com/agntcy/slim/tree/slim-v0.6.0/data-plane/python/integrations/slim-mcp/slim_mcp/examples/mcp_server_time) that implements SLIM as its transport protocol and processes requests from the LlamaIndex agent. ### Prerequisites diff --git a/docs/messaging/slim-rpc.md b/docs/messaging/slim-rpc.md index 50b45975..f4e99b32 100644 --- a/docs/messaging/slim-rpc.md +++ b/docs/messaging/slim-rpc.md @@ -24,7 +24,7 @@ documentation](./slim-slimrpc-compiler.md). In SLIMRPC, each service and its individual RPC handlers are assigned a SLIM name, facilitating efficient message routing and processing. Consider the [example -protobuf](https://github.com/agntcy/slim/blob/main/data-plane/python/integrations/slimrpc/slimrpc/examples/simple/example.proto) +protobuf](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/integrations/slimrpc/slimrpc/examples/simple/example.proto) definition, which defines four distinct services: ```proto @@ -95,7 +95,7 @@ standard gRPC. This section provides a detailed walkthrough of a basic SLIMRPC client-server interaction, leveraging the simple example provided in -[example](https://github.com/agntcy/slim/tree/main/data-plane/python/integrations/slimrpc/slimrpc/examples/simple) +[example](https://github.com/agntcy/slim/tree/slim-v0.6.0/data-plane/python/integrations/slimrpc/slimrpc/examples/simple) folder. ### Generated Code @@ -104,9 +104,9 @@ The foundation of this example is the `example.proto` file, which is a standard Protocol Buffers definition file. This file is compiled using the [SLIMRPC compiler](./slim-slimrpc-compiler.md) to generate the necessary Python stub code. The generated code is available in two files: -[example_pb2.py](https://github.com/agntcy/slim/blob/main/data-plane/python/integrations/slimrpc/slimrpc/examples/simple/types/example_pb2.py) +[example_pb2.py](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/integrations/slimrpc/slimrpc/examples/simple/types/example_pb2.py) and -[example_pb2_slimrpc.py](https://github.com/agntcy/slim/blob/main/data-plane/python/integrations/slimrpc/slimrpc/examples/simple/types/example_pb2_slimrpc.py). +[example_pb2_slimrpc.py](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/integrations/slimrpc/slimrpc/examples/simple/types/example_pb2_slimrpc.py). Specifically, `example_pb2_slimrpc.py` contains the SLIMRPC-specific stubs for both client and server implementations. Below are the key classes and functions generated by the compiler: @@ -216,7 +216,7 @@ def add_TestServicer_to_server(servicer, server: slimrpc.Server): ### Server implementation The server-side logic is defined in -[server.py](https://github.com/agntcy/slim/blob/main/data-plane/python/integrations/slimrpc/slimrpc/examples/simple/server.py). +[server.py](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/integrations/slimrpc/slimrpc/examples/simple/server.py). Similar to standard gRPC implementations, the core service functionality is provided by the TestService class, which inherits from TestServicer (as introduced in the previous section). This class contains the concrete @@ -304,7 +304,7 @@ available. ### Client implementation The client-side implementation, found in -[client.py](https://github.com/agntcy/slim/blob/main/data-plane/python/integrations/slimrpc/slimrpc/examples/simple/client.py), +[client.py](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/integrations/slimrpc/slimrpc/examples/simple/client.py), largely mirrors the structure of a standard gRPC client. The primary distinction and SLIM-specific aspect lies in the creation of the SLIMRPC channel: @@ -355,7 +355,7 @@ details, as these aspects are handled automatically by SLIMRPC and SLIM. All RPC services underneath utilize a sticky point-to-point session. The SLIM session creation is implemented in inside SLIMRPC in -[channel.py](https://github.com/agntcy/slim/blob/main/data-plane/python/integrations/slimrpc/slimrpc/channel.py): +[channel.py]https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/integrations/slimrpc/slimrpc/channel.py): ```python # Create a session diff --git a/docs/messaging/slim-session.md b/docs/messaging/slim-session.md index 028a0760..45498ffb 100644 --- a/docs/messaging/slim-session.md +++ b/docs/messaging/slim-session.md @@ -3,7 +3,7 @@ This document explains the SLIM session layer and the two supported session types. It helps you understand the two session interfaces, reliability, and security trade‑offs. -The SLIM repository ships with practical, runnable [examples](https://github.com/agntcy/slim/tree/main/data-plane/python/bindings/examples) that demonstrate how to create sessions and exchange messages between applications using the Python bindings. +The SLIM repository ships with practical, runnable [examples](https://github.com/agntcy/slim/tree/slim-v0.6.0/data-plane/python/bindings/examples) that demonstrate how to create sessions and exchange messages between applications using the Python bindings. ## Point-to-Point Session @@ -114,9 +114,9 @@ await session.publish_to(msg_ctx, payload) ### Point-to-Point Example -This [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/point_to_point.py) walks through the creation of a point-to-point session. When running the point-to-point example multiple times, the session binds to different running instances, while the message stream always sticks to the same endpoint. +This [example](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/examples/src/slim_bindings_examples/point_to_point.py) walks through the creation of a point-to-point session. When running the point-to-point example multiple times, the session binds to different running instances, while the message stream always sticks to the same endpoint. -The example demonstrates how to publish messages, enable reliability, and enable MLS for end‑to‑end security. The associated [README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_point_to_point.md) shows more information and how to run the example using the Taskfile provided in the repository. +The example demonstrates how to publish messages, enable reliability, and enable MLS for end‑to‑end security. The associated [README](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/examples/src/slim_bindings_examples/README_point_to_point.md) shows more information and how to run the example using the Taskfile provided in the repository. ## Group Session @@ -340,4 +340,4 @@ sequenceDiagram ### Group Example -This [example](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) demonstrates how to create a group session, invite participants, and (if enabled) establish an MLS group for end-to-end encryption. It also shows how to broadcast messages to all current members and handle inbound group messages. The associated [README](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/README_group.md) shows more information and how to run the example using the Taskfile. +This [example](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) demonstrates how to create a group session, invite participants, and (if enabled) establish an MLS group for end-to-end encryption. It also shows how to broadcast messages to all current members and handle inbound group messages. The associated [README](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/examples/src/slim_bindings_examples/README_group.md) shows more information and how to run the example using the Taskfile. From 7ddb840c3ae756a9234c77f1c61ecfe201ef0991 Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Fri, 10 Oct 2025 17:42:50 +0200 Subject: [PATCH 24/24] docs: links Signed-off-by: Mauro Sardara --- docs/messaging/slim-a2a.md | 8 ++++---- docs/messaging/slim-authentication.md | 4 ++-- docs/messaging/slim-controller.md | 8 ++++---- docs/messaging/slim-group-tutorial.md | 26 +++++++++++++------------- docs/messaging/slim-howto.md | 4 ++-- docs/messaging/slim-mcp.md | 8 ++++---- docs/messaging/slim-rpc.md | 2 +- docs/messaging/slim-session.md | 8 ++++---- 8 files changed, 34 insertions(+), 34 deletions(-) diff --git a/docs/messaging/slim-a2a.md b/docs/messaging/slim-a2a.md index 3b6beb6a..db9feb01 100644 --- a/docs/messaging/slim-a2a.md +++ b/docs/messaging/slim-a2a.md @@ -8,15 +8,15 @@ SLIMRPC is a framework that enables Protocol Buffers (protobuf) Remote Procedure To compile a protobuf file and generate the clients and service stub you can use the [SLIMRPC compiler](./slim-slimrpc-compiler.md). This works in a similar way to the protoc compiler. -For SLIM A2A we compiled the [a2a.proto](https://github.com/a2aproject/A2A/blob/main/specification/grpc/a2a.proto) file using the SLIM RPC compiler. The generated code is in [a2a_pb2_slimrpc.py](https://github.com/agntcy/slim/blob/main/data-plane/python/integrations/slima2a/slima2a/types/a2a_pb2_slimrpc.py). +For SLIM A2A we compiled the [a2a.proto](https://github.com/a2aproject/A2A/blob/main/specification/grpc/a2a.proto) file using the SLIM RPC compiler. The generated code is in [a2a_pb2_slimrpc.py](https://github.com/agntcy/slim/tree/slim-v0.6.0/data-plane/python/integrations/slima2a/examples/travel_planner_agent). ## How to use SLIMA2A -Using SLIMA2A is very similar to using the standard A2A implementation. As a reference example here we use the [travel planner agent](https://github.com/a2aproject/a2a-samples/tree/main/samples/python/agents/travel_planner_agent) available on the A2A samples repository. The version adapted to use SLIM A2A can be found in [travel_planner_agent](https://github.com/agntcy/slim/tree/main/data-plane/python/integrations/slima2a/examples/travel_planner_agent) folder. In the following section, we highlight and explain the key difference between the standard and SLIM A2A implementations. +Using SLIMA2A is very similar to using the standard A2A implementation. As a reference example here we use the [travel planner agent](https://github.com/a2aproject/a2a-samples/tree/main/samples/python/agents/travel_planner_agent) available on the A2A samples repository. The version adapted to use SLIM A2A can be found in [travel_planner_agent](https://github.com/agntcy/slim/tree/slim-v0.6.0/data-plane/python/integrations/slima2a/examples/travel_planner_agent) folder. In the following section, we highlight and explain the key difference between the standard and SLIM A2A implementations. ### Travel Planner: Server -In this section we highlight the main differences between the SLIM A2A [server](https://github.com/agntcy/slim/blob/main/data-plane/python/integrations/slima2a/examples/travel_planner_agent/server.py) implementation with respect to the original implementation in the A2A repository. +In this section we highlight the main differences between the SLIM A2A [server](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/integrations/slima2a/examples/travel_planner_agent/server.py) implementation with respect to the original implementation in the A2A repository. 1. Import the SLIMRPC package. ```python @@ -76,7 +76,7 @@ Your A2A server is now ready to run on SLIM. ### Travel Planner: Client -These are the main differences between the [client](https://github.com/agntcy/slim/blob/main/data-plane/python/integrations/slima2a/examples/travel_planner_agent/client.py) using SLIM A2A and the standard one. +These are the main differences between the [client](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/integrations/slima2a/examples/travel_planner_agent/client.py) using SLIM A2A and the standard one. 1. Create a channel. This requires a configuration that is similar to the server ```python diff --git a/docs/messaging/slim-authentication.md b/docs/messaging/slim-authentication.md index d5ad0458..f4dd90a6 100644 --- a/docs/messaging/slim-authentication.md +++ b/docs/messaging/slim-authentication.md @@ -12,7 +12,7 @@ SLIM supports JWT (JSON Web Tokens) for identity management. Tokens can come from an external identity provider or can be generated by the SLIM nodes directly if you provide the necessary private key for signing the tokens and public key for verification. Check the [Identity -Test](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/tests/test_identity.py) +Test](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/tests/test_identity.py) for an example of how to use JWT tokens with SLIM if you have your own keys. If you are running your SLIM clients in a Kubernetes environment, using @@ -41,7 +41,7 @@ This section shows how to use SPIRE with SLIM to manage client identities. The f If you already have a Kubernetes cluster or an existing SPIRE deployment, you can adapt only the relevant subsections. -This tutorial is based on the [SLIM examples](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples). +This tutorial is based on the [SLIM examples](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/examples). ### Prerequisites diff --git a/docs/messaging/slim-controller.md b/docs/messaging/slim-controller.md index 3524e3f9..bd605d03 100644 --- a/docs/messaging/slim-controller.md +++ b/docs/messaging/slim-controller.md @@ -164,7 +164,7 @@ southbound: httpPort: 50052 # number of node reconciler threads reconciler: - threads: 3 + threads: 3 logging: level: DEBUG @@ -179,7 +179,7 @@ Example config to enable MTLS on Southbound endpoint using [Spire](https://spiff southbound: httpHost: 0.0.0.0 - httpPort: 50052 + httpPort: 50052 tls: useSpiffe: true spire: @@ -297,7 +297,7 @@ tls: key_file: "/path/to/client.key" ``` -The `server` endpoint should point to a [SLIM Control](https://github.com/agntcy/slim/tree/main/control-plane/control-plane) endpoint which is a central service managing SLIM node configurations. +The `server` endpoint should point to a [SLIM Control](https://github.com/agntcy/slim/tree/slim-v0.6.0/control-plane/control-plane) endpoint which is a central service managing SLIM node configurations. ### Commands @@ -368,7 +368,7 @@ slimctl route add org/default/alice/0 via connection_config.json slimctl route del org/default/alice/0 via http://localhost:46367 ``` -For full reference of connection_config.json, see the [client-config-schema.json](https://github.com/agntcy/slim/blob/main/data-plane/core/config/src/grpc/schema/client-config.schema.json). +For full reference of connection_config.json, see the [client-config-schema.json](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/core/config/src/grpc/schema/client-config.schema.json). ### Managing SLIM Nodes Directly diff --git a/docs/messaging/slim-group-tutorial.md b/docs/messaging/slim-group-tutorial.md index b04bb915..af900c5f 100644 --- a/docs/messaging/slim-group-tutorial.md +++ b/docs/messaging/slim-group-tutorial.md @@ -6,7 +6,7 @@ participants. Messages are sent to a shared channel where every member can read and write. All messages are end-to-end encrypted using the [MLS protocol](https://datatracker.ietf.org/doc/html/rfc9420). This tutorial is based on the -[group.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) +[group.py](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) example in the SLIM repo. ## Key Features @@ -26,7 +26,7 @@ Every participant in a group requires a unique identity for authentication and f ### Identity -Each participant must have a unique identity. This is required to set up end-to-end encryption using the MLS protocol. The identity can be a JWT or a shared secret. For simplicity, this example uses a shared secret. For JWT-based identity, see the [tutorial](https://github.com/agntcy/slim/tree/main/data-plane/python/bindings/examples#running-in-kubernetes-spire--jwt) in the SLIM repository. +Each participant must have a unique identity. This is required to set up end-to-end encryption using the MLS protocol. The identity can be a JWT or a shared secret. For simplicity, this example uses a shared secret. For JWT-based identity, see the [tutorial](https://github.com/agntcy/slim/tree/slim-v0.6.0/data-plane/python/bindings/examples#running-in-kubernetes-spire--jwt) in the SLIM repository. The Python objects managing the identity are called `PyIdentityProvider` and `PyIdentityVerifier`. The `PyIdentityProvider` provides the identity, while the `PyIdentityVerifier` verifies it: @@ -52,12 +52,12 @@ def shared_secret_identity(identity: str, secret: str): ``` This is a helper function defined in -[common.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L85) +[common.py](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L85) that can be used to create a `PyIdentityProvider` and `PyIdentityVerifier` from two input strings. ### SLIM App -The provider and verifier are used to create a local SLIM application that can exchange messages with other participants via the SLIM network. To create the SLIM app, use the helper function defined in [common.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L289): +The provider and verifier are used to create a local SLIM application that can exchange messages with other participants via the SLIM network. To create the SLIM app, use the helper function defined in [common.py](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L289): ```python async def create_local_app( @@ -178,7 +178,7 @@ If `jwt`, `spire_trust_bundle`, and `audience` are not provided, `shared_secret` Now that you know how to set up a SLIM application, we can see how to create a group where multiple participants can exchange messages. We start by showing how to create a group session using the Python bindings. -In this setting, one participant acts as moderator: it creates the group session and invites participants by sending invitation control messages. A detailed description of group sessions and the invitation process is available [here](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/SESSION.md). +In this setting, one participant acts as moderator: it creates the group session and invites participants by sending invitation control messages. A detailed description of group sessions and the invitation process is available [here](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/SESSION.md). ### Creating the Group Session and Inviting Members @@ -240,7 +240,7 @@ communication. # Invite each provided participant. Route is set before inviting to ensure # outbound control messages can reach them. For more info see - # https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/SESSION.md#invite-a-new-participant + # https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/SESSION.md#invite-a-new-participant for invite in invites: invite_name = split_id(invite) await local_app.set_route(invite_name) @@ -249,10 +249,10 @@ communication. ``` This code comes from the -[group.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) +[group.py](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) example. The local application is created using the helper function shown earlier. The channel name (the logical group topic) is produced via the -[split_id](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L63) +[split_id](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/examples/src/slim_bindings_examples/common.py#L63) helper by parsing the `remote` parameter. A new group session is then created using `local_app.create_session(...)` with a `slim_bindings.PySessionConfiguration.Group` configuration. The key parameters are the following: @@ -317,14 +317,14 @@ async def receive_loop( Each non-moderator participant listens for an incoming session using `local_app.listen_for_session()`. This returns a -[PySession](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/slim_bindings/session.py) +[PySession](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/slim_bindings/session.py) object containing metadata such as session ID, type, source name, and destination name. The moderator already holds this information and therefore reuses the existing `created_session` (see `session = created_session`). Participants (including the moderator) then call `ctx, payload = await session.get_message()` to receive messages. `payload` contains the raw message bytes and `ctx` is a -[PyMessageContext](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/slim_bindings/_slim_bindings.pyi#L22) +[PyMessageContext](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/slim_bindings/_slim_bindings.pyi#L22) with source, destination, message type, and metadata. ### Publish Messages to the Session @@ -386,7 +386,7 @@ participants. Now we will show how to run a new group session and how to enable group communication on top of SLIM. The full code can be found in -[group.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) +[group.py](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py) in the SLIM repo. To run the example, follow the steps listed here: #### Run SLIM @@ -396,7 +396,7 @@ up a SLIM instance representing the SLIM network. We use the pre-built docker image for this purpose. First execute this command to create the SLIM configuration file. Details about -the [configuration](https://github.com/agntcy/slim/tree/main/data-plane/config) +the [configuration](https://github.com/agntcy/slim/tree/slim-v0.6.0/data-plane/config) can be found in the SLIM repo. ```bash @@ -536,7 +536,7 @@ With the controller, you do not need to set up a moderator in your application. ### Run the Group Communication example Now we will show how to set up a group using the SLIM Controller. The reference code for the -application is still [group.py](https://github.com/agntcy/slim/blob/main/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py). To run this example, follow the steps listed here. +application is still [group.py](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/bindings/examples/src/slim_bindings_examples/group.py). To run this example, follow the steps listed here. #### Run the SLIM Controller diff --git a/docs/messaging/slim-howto.md b/docs/messaging/slim-howto.md index 8c554233..a469b3ba 100644 --- a/docs/messaging/slim-howto.md +++ b/docs/messaging/slim-howto.md @@ -89,7 +89,7 @@ helm pull oci://ghcr.io/agntcy/slim/helm/slim --version v0.2.0 ``` For information about how to use the Helm chart, see the -[values.yaml](https://github.com/agntcy/slim/blob/main/charts/slim/values.yaml) +[values.yaml](https://github.com/agntcy/slim/blob/slim-v0.6.0/charts/slim/values.yaml) ### SLIM Controller @@ -142,7 +142,7 @@ pip install slim-bindings ```toml [project] ... -dependencies = ["slim-bindings>=0.5.0"] +dependencies = ["slim-bindings>=0.6.0"] ``` A tutorial on how to use the bindings in an application can be found in the [messaging layer diff --git a/docs/messaging/slim-mcp.md b/docs/messaging/slim-mcp.md index 790ac6ef..1ea3a7dc 100644 --- a/docs/messaging/slim-mcp.md +++ b/docs/messaging/slim-mcp.md @@ -30,7 +30,7 @@ architecture. In this section of the tutorial, we implement and deploy two sample applications: -- A [LlamaIndex agent](https://github.com/agntcy/slim/tree/slim-v0.6.0/data-plane/python/integrations/slim-mcp/slim_mcp/examples/llamaindex_time_agent) +- A [LlamaIndex agent](https://github.com/agntcy/slim/tree/slim-v0.6.0/data-plane/python/integrations/slim-mcp/slim_mcp/examples/llamaindex_time_agent) that communicates with an MCP server over SLIM to perform time queries and timezone conversions. - An [MCP time server](https://github.com/agntcy/slim/tree/slim-v0.6.0/data-plane/python/integrations/slim-mcp/slim_mcp/examples/mcp_server_time) that implements SLIM as its transport protocol and processes requests from the LlamaIndex agent. @@ -1041,19 +1041,19 @@ local proxy instance: ```bash cat << EOF > ./config-proxy.yaml # SLIM-MCP Proxy Configuration - + # Tracing settings for log visibility tracing: log_level: info display_thread_names: true display_thread_ids: true - + # Runtime configuration runtime: n_cores: 0 thread_name: "slim-data-plane" drain_timeout: 10s - + # Service configuration for connecting to the SLIM node services: slim/0: diff --git a/docs/messaging/slim-rpc.md b/docs/messaging/slim-rpc.md index f4e99b32..546dd922 100644 --- a/docs/messaging/slim-rpc.md +++ b/docs/messaging/slim-rpc.md @@ -355,7 +355,7 @@ details, as these aspects are handled automatically by SLIMRPC and SLIM. All RPC services underneath utilize a sticky point-to-point session. The SLIM session creation is implemented in inside SLIMRPC in -[channel.py]https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/integrations/slimrpc/slimrpc/channel.py): +[channel.py](https://github.com/agntcy/slim/blob/slim-v0.6.0/data-plane/python/integrations/slimrpc/slimrpc/channel.py): ```python # Create a session diff --git a/docs/messaging/slim-session.md b/docs/messaging/slim-session.md index 45498ffb..49d03be1 100644 --- a/docs/messaging/slim-session.md +++ b/docs/messaging/slim-session.md @@ -237,7 +237,7 @@ sequenceDiagram SLIM Node->>Moderator: Discover Reply from agntcy/ns/App-C/1 Note over Moderator,App-A/1: Invite - Moderator->>SLIM Node: Invite agntcy/ns/App-C/1 + Moderator->>SLIM Node: Invite agntcy/ns/App-C/1 SLIM Node->>App-C/1: Invite agntcy/ns/App-C/1 App-C/1->>App-C/1: Create new Group session App-C/1->>SLIM Node: Subscribe to Channel @@ -328,10 +328,10 @@ sequenceDiagram App-A/1->>SLIM Node: Ack(MLS Commit) SLIM Node->>Moderator: Ack(MLS Commit) end - + Note over Moderator,App-A/1: Remove - Moderator->>SLIM Node: Remove agntcy/ns/App-C/1 - SLIM Node->>App-C/1: Remove agntcy/ns/App-C/1 + Moderator->>SLIM Node: Remove agntcy/ns/App-C/1 + SLIM Node->>App-C/1: Remove agntcy/ns/App-C/1 App-C/1->>SLIM Node: Unsubscribe from Channel App-C/1->>App-C/1: Remove Group session App-C/1->>SLIM Node: Remove Reply