Skip to content

Reviewed native bulk guild-ban workflow

Bulk guild bans use Discord's native one-request batch endpoint and have no immediate-call path. They are independent of ordinary member moderation and ban audit. Set capabilities.bulkBanAudit: true to permit planning, set capabilities.bulkBans: true only to permit execution, list every eligible guild in scopes.bulkBanGuildIds, list every operator, service account, break-glass identity, or other ineligible target in scopes.protectedUserIds, and select the bulk-bans toolset. Execution depends on audit, the exact bulk-ban guild allowlist must remain inside readScope.guildIds when that outer allowlist exists, and no legacy environment variable can grant or alter this authority.

The relevant schema-v2 policy fragment is:

{
"capabilities": {
"bulkBanAudit": true,
"bulkBans": true
},
"scopes": {
"bulkBanGuildIds": ["YOUR_GUILD_ID"],
"protectedUserIds": ["INELIGIBLE_USER_ID"]
},
"tools": {
"toolsets": ["bulk-bans", "connector"]
}
}

Merge that fragment into a complete strict policy rather than using it as a standalone file. Run config validate, offline or online doctor, and smoke against the selected file. Doctor reports planning and execution gates separately, and setup warns when enabled bulk-ban policy is omitted from the bulk-bans surface. The bot requires both BAN_MEMBERS and MANAGE_GUILD for this endpoint unless it is the guild owner; ownership and ADMINISTRATOR are accepted by Discord's permission model but remain visible warnings rather than recommended grants.

Each request accepts one exact guild ID, 2 through 200 unique exact user IDs, one non-blank audit-log reason, one unique one-shot operation key, and an optional batch-wide deleteMessageSeconds from 0 through 604800 that defaults to 0. IDs are normalized into numeric snowflake order, so caller ordering has no semantic effect. Duplicate, zero, noncanonical, out-of-range, undersized, oversized, unknown-field, invalid-reason, or invalid-deletion-window input is rejected before Discord access. The target-set digest binds the normalized complete set independently of its presentation order.

  1. Choose a new one-shot operation key and call plan_bulk_guild_ban with the exact complete target set, guild, audit reason, and optional deletion window.
  2. Review the pinned application and bot IDs, every exact target in numeric order, transient untrusted username, global name, and nickname, membership and current ban state, role evidence, protected-user boundary, complete bot permission proof, request estimates, privacy projection, risks, warnings, operation-key hash, target-set digest, verification boundary, and keyed plan digest.
  3. Call execute_bulk_guild_ban with semantically identical inputs and the digest. Reordering the same target set is equivalent; adding, removing, or replacing any target is not.
  4. Approve the signed MCP confirmation only if every target, the deletion window, audit reason, permission and hierarchy boundary, operation-key hash, target-set digest, and plan digest remain intended.
  5. Review every requested, response-banned, response-failed, observed-banned, and observed-not-banned ID partition before any follow-up. Never reuse the reserved key or retry a subset automatically.

Planning verifies the pinned current application and bot, exact guild and owner, bot membership, a complete bounded guild role inventory, and complete effective BAN_MEMBERS plus MANAGE_GUILD permission evidence. For each target it first proves no exact guild ban exists, then reads the exact member or falls back to one exact user lookup only for a non-member. It rejects the connector bot, guild owner, configured protected users, bot accounts, existing bans, malformed or mismatched identity evidence, unknown target roles, administrators that cannot be safely bounded, and any member whose highest role is equal to or above the connector's highest role unless the connector is the guild owner. It never enumerates guild members and does not require the Guild Members privileged intent.

The process-keyed plan digest covers stable identity, guild owner, complete role and bot-member evidence, full permission state, every target's exact membership and role evidence, batch parameters, audit reason, operation-key hash, target-set digest, privacy boundary, risk set, warnings, and verification contract. Mutable display names are shown for review but deliberately excluded from freshness so harmless profile edits do not invalidate the plan. Any authority, membership, role, ban-state, target-set, or request drift does invalidate it, and a process restart invalidates every outstanding digest.

Execution rebuilds the complete plan and requires the same digest before reservation. The production facade acquires one durable coordination claim containing every exact member target in numeric order, so overlapping single-member or bulk-member writes across connector processes sharing the same local activity-state root cannot race past review. The operation store then reserves the one-shot key and the activity log records a pending content-free entry before the connector sends exactly one POST /guilds/{guild.id}/bulk-ban. Automatic rate-limit retry is disabled. The connector never issues per-target fallback bans, retries a failed subset, or performs automatic rollback.

A successful Discord response must contain exactly the requested users partitioned once between banned_users and failed_users, with no duplicates, omissions, overlap, extra IDs, unknown keys, or malformed snowflakes. The connector then queries the exact ban state for every requested target in bounded batches after every dispatch outcome, including a response error or transport ambiguity. A matching all-banned response and readback is completed; matching mixed state is partial; matching none-banned state is failed. An all-banned readback that disagrees with the response is completed-with-drift; a mixed disagreeing readback is partial-with-drift. A known non-rate-limit client refusal with no observed bans is failed. Any ambiguous dispatch with one or more unbanned targets, or any incomplete readback, is uncertain. Successful bans are never misrepresented as rolled back, and every ambiguous complete-set claim remains quarantined for exact operator review.

Terminal completed, drifted, partial, and failed records contain only exact requested and observed ID partitions, the deletion window, guild ID, digests, activity ID, timestamps, fixed outcome and verification values, and a sanitized error category. They never contain target profiles, names, audit reasons, raw operation keys, Discord bodies, attachment or message data, or transport causes. Partial and failed terminal receipts release the durable target claim because exact readback settled every target, but the one-shot key remains spent. Uncertain results, unreadable evidence, malformed evidence, or receipt-finalization failure retain the entire claim. Inspect every exact ban state and the Discord audit log before resolving quarantine or forming a newly reviewed action with a new key.

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.