Skip to content

Reference implementation

The canonical reference Adapter is pack-hello-world/adapter.py in the platform repo: the smallest possible complete Adapter, Python stdlib only, used by the platform’s smoke tests. Read it top to bottom: it is about 200 lines and exercises every part of the contract:

  • Handshake: hello with mpp = 2, the Pack ID, a manifest_hash computed at startup by shelling out to mobrule pack print-hash (never hand-pinned), and a bridge_token that authenticates the connection. The Adapter reads MOBRULE_ADAPTER_TOKEN from its environment and sends that value as the hello frame’s bridge_token; the bridge hashes it against the Adapter-token hash it minted and rejects a mismatch.
  • Credit priming: one pull per declared queue after hello_ack.
  • Per-queue dispatch table: invocation.queue selects a handler, so a multi-queue Pack adds an entry instead of restructuring the loop.
  • Lifecycle replies: ackapplied (with a result) → done, then a fresh pull on the same queue; failed with a reason for unknown events.
  • Pack state: a running counter published via state_write after each applied Event, feeding the overlay’s counter widget.
  • Heartbeat thread: a heartbeat frame every 15 s.

The reference Adapter reads its connection parameters from the environment:

VariableDefaultMeaning
BRIDGE_HOST127.0.0.1Bridge MPP host.
BRIDGE_PORT7777Bridge MPP port.
MOBRULE_ADAPTER_TOKEN(required)Adapter auth token, sent as the hello bridge_token.

There is one token. When the bridge launches the Adapter itself (adapter.launch), it injects the token into the child process as MOBRULE_ADAPTER_TOKEN, and the Adapter reads exactly that variable. A hand-launched dev Adapter must set MOBRULE_ADAPTER_TOKEN itself. The Adapter reads it with no fallback: if the variable is absent the process exits with a KeyError before connecting.

There is no SDK to link: MPP is newline-delimited JSON over a TCP socket, so the reference Adapter ports almost mechanically to any language. Keep these invariants:

  1. One JSON object per line; read line-by-line, never by fixed buffer.
  2. hello must be your first frame; wait for hello_ack.ok before anything else, and apply hello_ack.persisted[] before your first state_write.
  3. Never assume push without credit: no pull, no Invocations.
  4. Treat config frames as latched values and apply them idempotently.
  5. On protocol_error, log the message and exit non-zero; it is always a bug on your side or a stale manifest, never a transient condition.