Protocol notation
Grammar for messages, choices, recursion, and parallel.
render prints a compact multiparty session-protocol notation.
Use notation as a review surface
The rendered form is short enough to paste into a design review or incident note. Python remains the editable form; the rendering is the view a reader can scan.
Notation ↔ API
| Notation | API / Construct | Meaning |
|---|---|---|
A -> B : M(type) | ap.send(A, B, M) | Send message M with payload type from A to B |
M(type) | message class | Message label and payload type, for example Ping(str) |
:: 'intent' | M.__intent__ / docstring | Human-readable purpose of the message |
A -> B \{ Branch: ... \} | ap.choose(A, B, \{Branch: ...\}) | Role A chooses a branch and sends it to B |
rec \<label\> | ap.loop(...) | Recursion binder declaring a loop scope, such as rec loop.0 |
\<label\> | ap.repeat() | Repeat the nearest enclosing loop, such as loop.0 |
end | [] continuation | Session branch terminates here |
par \{ / ` | /}` | ap.par(...) |
What render prints
import agentsparty as ap
A, B = ap.roles('A', 'B')
class Ping(ap.Message):
"""A ping."""
text: str
class Ok(ap.Message):
"""Accept."""
class No(ap.Message):
"""Refuse."""
print(
ap.render(
ap.Protocol(
ap.send(A, B, Ping),
ap.choose(B, A, {Ok: [], No: []}),
)
)
)A small reading example
The output is easiest to read from left to right. The sender appears before the
arrow, the receiver appears after it, and the message name appears after the
colon. A choice is a point where the role on the left owns the next branch. In
the example above, A -> B : Ping(str) happens first; only then does B select
either Ok or No and send that result to A.
That order is more than presentation. It is the order in which the runtime expects envelopes to become available. A local endpoint may wait for an incoming message, make a decision, or continue a loop, but it cannot silently skip a step just because the eventual branch looks obvious from the global conversation.
The notation is a view of a protocol, not a second input language. Authors
still construct protocols with Python, which means normal Python composition
and namespacing remain available. render is useful when reviewing a design,
writing a runbook, or comparing a journal with the protocol that produced it;
it is not intended to be edited and parsed back into a Protocol.
Reading the operators
| Operator | Question to ask while reviewing it |
|---|---|
A -> B : M(...) | Which role owns the payload and which role must receive it? |
A -> B \{ ... \} | Who chooses, and can every other role distinguish the selected branch? |
rec loop.N / loop.N | What state is revisited, and what event makes progress possible? |
par \{ | ... \} | Which independent conversations may make progress at the same time? |
Treat par as a concurrency claim, not as a formatting shortcut. If two
steps share a role, the participant still needs a deterministic way to decide
which envelope to handle first. If the order matters, keep the steps
sequential or make the synchronization message explicit. A compact rendering
should make that question visible during review rather than hide it.
Related
- Protocol explains the executable protocol value.
- Projection explains how the global view becomes endpoint views.
- Glossary distinguishes protocols, endpoints, transcripts, journals, and traces.
Where the notation comes from
The project takes its inspiration from
Multiparty Session Types (MPST),
where global types are written with mathematical symbols such as p→q:M for message
exchange, ⊕ for internal choice, μX for recursion binders, X for recursion variables,
and | for parallel composition. agentsparty adopts this model while printing an ASCII
form (->, \{ \}, rec, loop.0, par) directly readable in terminals and code reviews.
For related work on agent interaction protocols, see
Global Types for Agent Interaction Protocols.