Privacy-safe Stage instances and reviewed lifecycle
list_stage_instances returns one bounded configured inventory with an explicit active or inactive entry for every separately allowlisted Stage channel. get_stage_instance and discord://guilds/{guildId}/channels/{channelId}/stage-instance inspect one exact entry. Set capabilities.stageInstanceAudit: true and list every eligible Stage channel by its own exact ID in scopes.stageChannelIds. The Stage allowlist must be a subset of readScope.channelIds when the outer read allowlist exists; parent, thread, category, and guild scope never imply Stage scope.
Every read verifies the application and bot identity, exact guild and channel ownership, exact Stage channel type, connector membership, complete bounded roles and permission overwrites, and effective VIEW_CHANNEL. One inventory call shares a coherent guild, connector-member, and role snapshot across configured Stage channels in that guild while retaining an exact channel and instance read for every entry; no evidence cache survives the call. An active result contains only exact instance, guild, channel, optional scheduled-event identity, bounded topic, privacy level, schema-drift count, and permission evidence. An inactive result is explicit rather than a missing record. Speaker and audience identities, voice state, member objects, scheduled-event objects, raw Discord payloads, and unknown field values are never returned, cached, journaled, or persisted.
Changes have no immediate-call path. Set capabilities.stageInstanceChanges: true in addition to audit scope. The strict action union supports starting an inactive Stage, replacing the topic of an active Stage, and ending an active Stage. A start requires a topic and may explicitly request a guild-wide notification; an update requires only a topic; an end accepts neither field. Writes require guild-only privacy, no scheduled-event association, zero unknown fields, and complete VIEW_CHANNEL, CONNECT, MANAGE_CHANNELS, MUTE_MEMBERS, and MOVE_MEMBERS evidence. Deprecated public or scheduled-event-linked instances remain readable but fail closed for mutation.
Guild-wide start notification has a third independent gate, capabilities.stageStartNotifications: true. It requires fresh MENTION_EVERYONE evidence and consumes the same bounded interaction rate budget as message notifications. Topic updates and ends can never request notification. A start against an already active Stage is rejected unless its exact state is already satisfied without notification, an update against an inactive Stage is rejected, and an end against an inactive Stage returns a true no-op without approval, reservation, activity, or write.
- Call
plan_stage_instance_changewith the exact guild, Stage channel, action-specific fields, Discord audit-log reason, and unique one-shot operation key. - Review the verified application and bot IDs, exact guild and Stage channel, active or inactive current state, desired state, guild-only privacy, scheduled-event isolation, complete permissions, notification setting, warnings, operation-key hash, and keyed digest.
- If the plan reports
already-current, no confirmation, reservation, activity record, or Discord write is needed. - Call
execute_stage_instance_changewith identical inputs plus the digest. - Approve the signed MCP confirmation only if every exact identity, lifecycle state, topic, privacy boundary, permission, notification choice, warning, audit reason, operation-key hash, and digest remains intended.
- Review the returned exact active state or verified absence, activity ID, verification, and outcome before any follow-up.
The process-keyed HMAC digest binds the normalized request, verified identities, exact guild and Stage channel, complete roles and overwrites, effective permissions, current and desired privacy-safe state, notification choice, privacy projection, operation-key hash, and warnings. A connector restart invalidates the digest. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Any identity, instance, topic, privacy, scheduled-event linkage, schema, role, overwrite, or permission drift invalidates the reviewed plan. The shared interaction rate guard is checked immediately before any notification reservation or durable write state.
Execution atomically reserves the operation-key hash and appends pending content-free operation and activity records before one non-retried POST, PATCH, or DELETE. It then performs an exact Stage-instance GET and requires the reviewed active state after start or update, or exact absence after end. A full match is completed; valid server-adjusted state or a target that remains after end is completed-with-drift; a known pre-write Discord client error is failed; transport failure, Discord server error, malformed success, or failed readback is uncertain. The connector never retries, compensates, or rolls back automatically.
Changes to the same Stage channel serialize inside one process. The production facade additionally acquires a durable exact channel claim, so connector processes sharing the activity-state root exclude overlapping Stage changes. An uncertain result retains that claim for operator review before queued or later work can reserve another key. Activity and operation records contain only exact guild, channel, and optional Stage-instance IDs, action, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Topics, guild and channel names, speaker and audience identities, scheduled-event objects, role names, audit reasons, raw operation keys, permission evidence, and raw Discord responses never enter durable records, diagnostics, or telemetry. Scheduled-event association changes are intentionally unsupported because they require a separate cross-resource authority model. See Discord's Stage instance reference and permission flags.
Canonical source: docs/reference.md
Documentation generated for guildcontrol@0.0.0. Canonical source and edit history remain in the public repository. GuildControl is an independent project and is not affiliated with or endorsed by Discord Inc. Discord is used only to identify the platform that GuildControl connects to.