Reference GUILD_SETTINGS.md and platform guild.update span metadata. Co-authored-by: Cursor <[email protected]>
pearcord-guild
Guild lifecycle, channel tree (including threads and forums), member joins, and the Hyperswarm gossip mesh for server-scoped realtime events.
Mission
Create and load guilds in local storage, join peers on pearcord:guild:{guildId} topics, fan out RPC gossip (messages, reactions, voice, roles, audit, …), and attach auxiliary protomux channels for attachments, voice media, and screen share.
When to use / not
Use when:
- Implementing server creation, invite joins, channel CRUD, or guild-scoped P2P replication.
- Extending gossip handlers (
_onGossip) or adding newRPC.*fanout methods.
Do not use when:
- You only need a thin channel CRUD helper without mesh — see
pearcord-channel(minimal; production path is this module). - You need DM conversations — use
pearcord-dm. - You need the full desktop API — use
pearcord-platform, which ownsPearcordGuildinstances.
Public API
| Export | Role |
|---|---|
PearcordGuild |
Main class (EventEmitter) |
PearcordGuild#create({ name, iconHash? }) |
New guild + owner member + general text + Voice Lobby; nsfwGateEnabled defaults true (v0.8.174) |
PearcordGuild#joinByInvite(invite, userId) |
Materialize guild/channels from invite; add member; bump invite uses |
PearcordGuild#setActiveGuild(guild) |
Set this.guild for list/create operations |
PearcordGuild#joinMesh(opts?) / #leaveMesh() |
Hyperswarm on topicToBuffer(guild.topic); bounded flush() via PEARCORD_GUILD_SWARM_FLUSH_MS (default 2.5s) |
PearcordGuild#listChannels() / #listMembers() |
DB queries with thread meta attached |
PearcordGuild#createChannel, #createCategory, #createThread, #createForumThread |
Channel tree |
PearcordGuild#reorderChannelsInParent |
Reassign position for siblings under one category/root |
PearcordGuild#moveChannelToParent |
Move channel into category (v0.8.168) |
PearcordGuild#reorderCategories |
Reassign position for category rows |
PearcordGuild#updateChannel, #ingestChannel |
Upsert + thread meta; voice/stage userLimit (0–99); nsfw flag (v0.8.173) |
PearcordGuild#setMessageHandler(fn) |
Inbound RPC.MESSAGE_CREATE persistence hook (platform sets this) |
PearcordGuild#gossip* / #sendVoiceMedia / #sendScreenMedia |
Outbound RPC (see index.js for full list) |
PearcordGuild#simulateGossip(method, payload) |
Bare smoke injection without live peers |
PearcordGuild#getStats() |
{ guildId, peers, openGossip, topic } |
PearcordGuild#fetchAttachmentFromPeers |
P2P attachment pull via pearcord-drive |
PearcordGuild#setVoiceMediaHub / #setScreenShareHub / #setAttachmentProvider |
Wire media meshes |
./mesh |
attachGossipMesh, broadcastGossip, GOSSIP_PROTOCOL |
P2P surface
| Protocol | Transport | Purpose |
|---|---|---|
pearcord-gossip-v1 |
Protomux on Hyperswarm connection | JSON payloads in encodeRpc frames; handler _onGossip |
| Drive attach mesh | pearcord-drive/attach-mesh |
Binary attachment fetch |
| Voice media | pearcord-voice-media |
Live audio frames |
| Screen share | pearcord-screen-share |
Display frames |
Topic: guildTopic(guildId) → topicToBuffer for swarm.join. Server and client mode enabled.
Inbound events emitted include: message, message-delete, presence, typing, reaction, channel, channel-update, member, guild-sync, voice-state, peer, and many feature-specific events (audit, bots, stickers, …).
Storage
Uses shared LocalDatabase (opts.db or opts.dbPath):
@pearcord/guilds,channels,members,messages,invites,thread-meta,bans, etc.
Guild rows include topic: pearcord:guild:{id} for swarm discovery.
Platform integration
const { PearcordGuild } = require('pearcord-guild')
// createGuild / loadGuild / joinInvite:
this.guild = new PearcordGuild({ ownerId, userId, db: this.db })
await this.guild.ready()
this.guild.setActiveGuild(guildRecord)
this._wireGuild(this.guild) // setMessageHandler + event bridges
await this.guild.joinMesh()
_wireGuild connects gossip to platform emit('message'), search indexing, bot fanout, and db.insert. Outbound sends use this.guild.gossipMessage(msg) from sendMessage / edits / deletes.
Channel creation in production uses guild.createChannel / createCategory, not pearcord-channel.
UI / IPC
Indirect only. IPC create-guild, select-guild, join-invite, send-message, voice join, etc. all route through platform methods that delegate to PearcordGuild.
Related docs
- GUILD_SYNC.md — history bundle on peer join
- VOICE.md —
RPC.VOICE_STATE - VOICE_MEDIA.md — media mesh
- ATTACH_MESH_LIVE.md — attachment gossip
- MESSAGE_THREADS.md — thread channels
- FORUM_CHANNELS.md — forum posts
- MODERATION.md — bans, kicks, audit RPC
- MODULES.md
- IPC.md
Tests
-
apps/pearcord:npm run test:guild-sync—smoke-guild-sync.cjs -
smoke-guild-settings.cjs,smoke-guild-deep-link.cjs -
Many mesh smokes call
platform.guild.simulateGossip(RPC.*, payload) -
v0.8.418 (Phase 455): Server settings UI uses
syncGuildSettingsPanelDuringGuildLoadingduring guild switch; platformguild.updatespan onupdateGuildSettingsgossip path. See GUILD_SETTINGS.md. -
v0.8.410 (Phase 447): Custom roles and channel overwrites are platform-owned (
pearcord-guild-roles+channelPermissions); gossip still fans outROLE_UPSERT/ channel overwrite RPC fromPearcordGuild. Regression bundle:npm run test:phase447-roles-permissions(see ROLES.md).
Code example
const { PearcordGuild } = require('pearcord-guild')
const { LocalDatabase } = require('pearcord-db')
const Hyperswarm = require('hyperswarm')
const db = new LocalDatabase('./pearcord-storage/db')
const guild = new PearcordGuild({ ownerId: 'user-1', userId: 'user-1', db })
await guild.ready()
const { guild: g, channels } = await guild.create({ name: 'My Server' })
guild.setMessageHandler(async (msg) => {
await db.insert(require('pearcord-shared').COLLECTIONS.MESSAGES, msg)
return msg
})
await guild.joinMesh()
guild.gossipTyping({ userId: 'user-1', channelId: channels[0].id, guildId: g.id, at: Date.now() })
Repository
Part of Pearcord.
- Org:
pearcord - Clone:
git clone https://git.ssh.surf/pearcord/pearcord-guild.git - Install:
npm install git+https://git.ssh.surf/pearcord/pearcord-guild.git#main