Groups & Collaboration
Groups are real-time, multi-peer communication channels. They enable features like multiplayer games, live quizzes, collaborative editing, group chat, file sharing, and distributed compute.
How groups work
Groups use a host-relayed model. The peer that creates a group acts as the hub. Every member opens a long-lived bidirectional stream to the host, and the host relays messages between members.
graph LR
A["Member A"] <-->|stream| H["Host"]
H <-->|stream| B["Member B"]
H <-->|stream| C["Member C"]
This model works naturally because the host already serves the site, stores data, and knows its visitors. All group events flow through the unified MQ bus.
Group types
| Type | App type | Lifecycle | Use case |
|---|---|---|---|
| Ephemeral | varies | Auto-dissolves when activity ends | Games, quizzes |
| Persistent | varies | Exists until explicitly closed | Study groups, teams |
| Open | varies | Any peer can join | Community chat |
| Invite-only | varies | Requires invitation | Private projects |
| Files | files |
Persistent | Shared file storage |
| Cluster | cluster |
Volatile | Distributed compute |
| Listen | listen |
Varies | Audio listening sessions |
Creating a group
Groups are created by the host peer through the viewer's Groups page or programmatically through the API. The group is stored in the host's SQLite database and made available to visitors.
Joining a group
Members join by sending a join message to the host over the MQ bus. The join flow is:
- Member sends a
joinmessage via MQ to the host (group:{groupID}:join). - Host validates and adds the member.
- Host sends a
welcomemessage with the current member list and state. - Host broadcasts an updated
memberslist to all other members.
Message types
| Type | Direction | Purpose |
|---|---|---|
join |
Member to Host | Request to join a group |
welcome |
Host to Member | Confirmation with current state |
members |
Host to Members | Updated member list |
msg |
Both directions | Application message (chat, game move) |
meta |
Host to Members | Group metadata update |
ping / pong |
Both directions | Keep-alive |
leave |
Member to Host | Member leaving |
close |
Host to Members | Group is being closed |
All group events are published on the MQ bus under the topic group:{groupID}:{type}. Group invites use group.invite.
File sharing
File groups let peers share documents within a group. Any member can upload files and browse or download files shared by other members.
Creating a file group
Create a group with app type files from the Groups page. File groups are persistent by default.
Uploading files
Upload files through the viewer's file sharing UI or via the API:
POST /api/docs/upload-- Multipart upload (max 50 MB per file)POST /api/docs/upload-local-- Upload from a local filesystem path
Browsing and downloading
GET /api/docs/browse-- Aggregates file lists from all group members (parallel query, 8s timeout per peer)GET /api/docs/download-- Download a file from any member (local or proxied from remote peer)GET /api/docs/my-- List your own shared files in a group
Files are stored on each member's disk. When you browse, the viewer queries all online members and merges their file lists. Downloads are streamed directly from the owning peer.
Cluster compute
Cluster groups enable distributed computation across peers. One peer acts as the host (dispatcher) and others join as workers. The host dispatches jobs to workers, which execute them using a configured executor binary.
Roles
| Role | Responsibility |
|---|---|
| Host | Creates the cluster, dispatches jobs, collects results |
| Worker | Joins a cluster, executes jobs using an executor binary |
Setting up a worker
Configure the executor binary in your goop.json:
{
"viewer": {
"cluster_binary_path": "/path/to/my-executor",
"cluster_binary_mode": "daemon"
}
}
Binary modes:
- oneshot -- Started per job, exits after producing a result.
- daemon -- Started once, handles multiple jobs via stdin/stdout JSON.
See the Executor Protocol page for the full binary contract and code examples.
Submitting jobs
The host submits jobs via the API or UI. Jobs have a type, payload, optional priority, timeout, and retry policy. The dispatcher assigns jobs to available workers and streams output back to the host.
JavaScript API
Templates interact with groups through the Goop.group API:
// List available groups
const groups = await Goop.data.query("_groups");
// Join a group
Goop.group.join("chess-42", function(msg) {
console.log("Received:", msg);
});
// Send a message
Goop.group.send({ move: "e2e4" });
// Leave the group
Goop.group.leave();
Use cases
Multiplayer game
- Host creates an ephemeral group for a chess match.
- Opponent joins via the game UI.
- Moves are exchanged in real time through the group channel.
- Move history is stored in the host's database.
- When the game ends, the group dissolves but the history persists.
File sharing workspace
- Host creates a file group for a project.
- Team members join and upload documents.
- Everyone can browse and download files from any member.
- Files live on each member's machine -- no central storage.
Distributed processing
- Host creates a cluster and submits computation jobs.
- Workers join and execute jobs using their local executor binary.
- Results stream back to the host in real time.
- Workers can join and leave dynamically; the dispatcher handles reassignment.
Interaction with other protocols
| Task | Protocol |
|---|---|
| Serve the UI | /goop/site/1.0.0 |
| Store persistent data | /goop/data/1.0.0 |
| Real-time messaging | MQ bus (/goop/mq/1.0.0) |
| Discover groups | Query _groups via /goop/data/1.0.0 |
| Event delivery | MQ topics (group:{groupID}:{type}) |