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

> ## Agent Instructions
> These docs target Mesh SDK v0.27.0. Match the installed package and binding before generating code. Start at /getting-started/agents for task-specific reading paths.
> Call the company and product Offline Protocol, never Offline alone. Current packages: @offline-protocol/mesh-sdk 0.27.0 (React Native), @offline-protocol/id-react 0.2.0, @offline-protocol/id-react-native 0.3.3, @offline-protocol/pol 0.1.2 and @offline-protocol/cli 0.2.6. Canonical docs URLs start with https://www.offlineprotocol.com/docs.
> The Mesh SDK runs in a native app or gateway. A browser OfflineID SDK integration does not provide browser mesh transport. Local mesh operation does not require a portal API key.
> Service RPC is signed plaintext in v0.27.0. Message delivery, durable local acceptance and backend commit are distinct outcomes. Use the workflow guide for the required application logic.
> Offline Protocol CLI 0.2.6 is on npm (@offline-protocol/cli, command offline). Its local MCP server runs with offline mcp serve and requires no login or key. Hosted MCP is at https://mcp.offlineprotocol.com/mcp with an application API key in Authorization: Bearer and a matching x-app-id; organization keys are rejected. Follow /tools/overview for setup and do not invent commands beyond it. MCP provides integration context and planning, not mesh execution; file-writing tools are local only.
> Phone Wi-Fi Direct and MultipeerConnectivity carry no data in v0.27.0. Use BLE or a provisioned relay. The receiver core ACKs before application persistence; use application acceptance for durable workflows.
> Proof of Location is Sepolia testnet witness evidence, not zero-knowledge proof or proof of presence. The geohash is public onchain. Read /proof-of-location/security before integration.

# Groups and membership

> Mesh SDK v0.27.0 group methods: create MLS groups, invite and remove members, manage roles and send group messages.

Import `OfflineProtocol` from `@offline-protocol/mesh-sdk`. These signatures match **v0.27.0**. Read [the integration guide](/docs/guides/shared-state) for prerequisites and complete usage.

## Methods on this page

* [`meshCreateGroup`](#meshcreategroup)
* [`meshInviteToGroup`](#meshinvitetogroup)
* [`meshSendGroupMessage`](#meshsendgroupmessage)
* [`meshForwardMessageToGroup`](#meshforwardmessagetogroup)
* [`meshRemoveFromGroup`](#meshremovefromgroup)
* [`meshLeaveGroup`](#meshleavegroup)
* [`meshListGroups`](#meshlistgroups)
* [`meshGetGroupInfo`](#meshgetgroupinfo)
* [`meshGroupRichReadiness`](#meshgrouprichreadiness)
* [`groupRelaySyncState`](#grouprelaysyncstate)
* [`requestGroupRelayRegistration`](#requestgrouprelayregistration)
* [`ensureGroupRegistered`](#ensuregroupregistered)
* [`meshSetMemberRole`](#meshsetmemberrole)
* [`meshGetMemberRole`](#meshgetmemberrole)
* [`meshGetGroupRoles`](#meshgetgrouproles)
* [`meshRenameGroup`](#meshrenamegroup)

## meshCreateGroup

Creates a new MLS group with full protocol integration.
Emits GroupCreated event. Use inviteToGroup() to add members.

**returns:** Group info

```typescript theme={null}
meshCreateGroup(groupName: string): Promise<MlsGroupInfo>
```

## meshInviteToGroup

Invites a user to an MLS group.
Sends MLS Welcome to invitee and Commit to existing members.
Emits GroupMemberAdded event on all participants.

```typescript theme={null}
meshInviteToGroup(groupId: string, inviteeUserId: string): Promise<void>
```

## meshSendGroupMessage

Sends an MLS-encrypted message to all group members via mesh transport.
Handles encryption and fan-out to each member automatically.

**returns:** Array of per-member message IDs

```typescript theme={null}
meshSendGroupMessage(groupId: string, content: string, priority?: string | null, replyToMsg?: string | null): Promise<string[]>
```

## meshForwardMessageToGroup

Forwards a message to all members of a group with forwarding attribution.

The message content is encrypted via MLS for the group and fan-out follows
the same path as regular group messages.

**returns:** Array of per-member message IDs

```typescript theme={null}
meshForwardMessageToGroup(params: ForwardMessageToGroupParams): Promise<string[]>
```

## meshRemoveFromGroup

Removes a member from an MLS group.
Sends removal notification to all members.

```typescript theme={null}
meshRemoveFromGroup(groupId: string, memberId: string): Promise<void>
```

## meshLeaveGroup

Leaves an MLS group with notification to other members.

```typescript theme={null}
meshLeaveGroup(groupId: string): Promise<void>
```

## meshListGroups

Lists all MLS groups (excluding 1:1 sessions).

**returns:** Array of group IDs

```typescript theme={null}
meshListGroups(): Promise<string[]>
```

## meshGetGroupInfo

Gets information about an MLS group.

**returns:** Group info or null if not found

```typescript theme={null}
meshGetGroupInfo(groupId: string): Promise<MlsGroupInfo | null>
```

## meshGroupRichReadiness

Whether a rich group send right now would seal its extras, and which
members hold the gate closed. Point-in-time and advisory: the send path
re-evaluates the gate itself: use this to warn before sending instead
of learning from a GroupRichExtrasDropped event after the drop.

**returns:** Readiness snapshot `({ ready, unknownMembers })`

```typescript theme={null}
meshGroupRichReadiness(groupId: string): Promise<GroupRichReadiness>
```

## groupRelaySyncState

The relay-side registration state of a group. Point-in-time:
transitions arrive as `group_relay_sync_changed` events.

`'synced'` means the relay positively acknowledged the group's
registration on the current connection: relay-dependent server
commands for it (`CreateGroupInviteLink` & co. via
`sendRawServerCommand`) can be issued. `'pending'` means a
registration is in flight; `'unsynced'` means none is (Internet down,
relay grouping disabled, or a prior attempt errored / timed out).

```typescript theme={null}
groupRelaySyncState(groupId: string): Promise<RelaySyncState>
```

## requestGroupRelayRegistration

Registers (or re-registers) a group with the relay server on demand: the supported path for making a mesh-created group known to the relay
before issuing relay-dependent server commands for it. Never raw-send
`CreateGroup`: it desyncs the SDK's registration tracking.

Fire-and-event: the outcome arrives as `group_relay_sync_changed`
(`ensureGroupRegistered` wraps the wait). Resolves true when the
registration frame was queued (or the group is already synced), false
when relay grouping is disabled or the Internet transport is
unavailable; rejects when the group is unknown locally.

```typescript theme={null}
requestGroupRelayRegistration(groupId: string): Promise<boolean>
```

## ensureGroupRegistered

Resolves once the relay holds a positively acknowledged registration
for the group: the gate to await before `CreateGroupInviteLink` and
other relay-dependent raw server commands for a mesh-created group.

Resolves immediately when the group is already synced; otherwise kicks
a registration (when none is in flight) and waits for the
`group_relay_sync_changed` outcome. Rejects on a negative outcome
(`reason: 'error' | 'ack_timeout' | …`), when the registration cannot
be sent (Internet down / relay grouping disabled / unknown group), or
on timeout.

The SDK re-sends an unanswered registration every 30s up to 3 attempts
before giving up with `ack_timeout` (\~90s worst case): the default
timeout covers that full cycle. A shorter timeout is fine for UI
purposes: the SDK keeps retrying in the background and a later
`group_relay_sync_changed` still fires on success.

```typescript theme={null}
ensureGroupRegistered(groupId: string, options?: { timeoutMs?: number }): Promise<void>
```

## meshSetMemberRole

Sets a member's role in an MLS group (admin only).
Broadcasts role change to all group members.

```typescript theme={null}
meshSetMemberRole(groupId: string, userId: string, role: string): Promise<void>
```

## meshGetMemberRole

Gets a member's role in an MLS group.

**returns:** Role string ("admin" or "member")

```typescript theme={null}
meshGetMemberRole(groupId: string, userId: string): Promise<string>
```

## meshGetGroupRoles

Gets all member roles in an MLS group.

**returns:** Map of user\_id -> role

```typescript theme={null}
meshGetGroupRoles(groupId: string): Promise<Record<string, string>>
```

## meshRenameGroup

Renames an MLS group (admin only).
Broadcasts the rename to all group members.

**throws:** Error if not admin or group not found

```typescript theme={null}
meshRenameGroup(groupId: string, newName: string): Promise<void>
```

## Parameter and result types

Import these types from the same SDK package. Event payloads and configuration types are linked below.

### MlsGroupInfo

```typescript theme={null}
export interface MlsGroupInfo {
  groupId: string;
  groupName: string;
  memberIds: string[];
  epoch: number;
  createdAt: number;
}
```

### ForwardMessageToGroupParams

```typescript theme={null}
export interface ForwardMessageToGroupParams {
  originalMessageJson: string;
  groupId: string;
  priority?: MessagePriority;
}
```

### MessagePriority

```typescript theme={null}
export enum MessagePriority {
  Low = 0,
  Medium = 1,
  High = 2,
  Critical = 3,
}
```

### GroupRichReadiness

```typescript theme={null}
export interface GroupRichReadiness {
  ready: boolean;
  unknownMembers: string[];
}
```

### RelaySyncState

```typescript theme={null}
export type RelaySyncState = 'synced' | 'pending' | 'unsynced';
```

## Related references

* [Event payloads](/docs/mesh-sdk/events)
* [Configuration types](/docs/mesh-sdk/configuration-types)
* [All public types](/docs/mesh-sdk/public-types)
* [Error codes](/docs/mesh-sdk/errors)
* [All API tasks](/docs/mesh-sdk/reference)
