Reviewed bounded guild-prune workflow
Guild pruning uses Discord's native count and begin-prune endpoints and has no immediate-call path. Unlike exact member moderation and native bulk bans, Discord selects the inactive cohort and does not expose either candidate or removed member IDs. The connector therefore treats pruning as a separate non-exact authority. Set capabilities.guildPruneAudit: true to permit planning, set capabilities.guildPrunes: true only to permit execution, list every eligible guild in scopes.guildPruneGuildIds, set an operator ceiling in limits.guildPruneMaxMembers, keep every ineligible identity in scopes.protectedUserIds, and select the guild-prunes toolset. Execution depends on audit, the prune guild allowlist must remain inside readScope.guildIds when that outer allowlist exists, and no legacy environment variable, alias, fallback parser, or migration mode can grant or alter this authority.
The relevant schema-v2 policy fragment is:
{ "capabilities": { "guildPruneAudit": true, "guildPrunes": true }, "limits": { "guildPruneMaxMembers": 12 }, "scopes": { "guildPruneGuildIds": ["YOUR_GUILD_ID"], "guildPruneIncludeRoleIds": [], "protectedUserIds": ["INELIGIBLE_USER_ID"] }, "tools": { "toolsets": ["connector", "guild-prunes"] }}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 prune policy is omitted from the guild-prunes surface. The bot requires both KICK_MEMBERS and MANAGE_GUILD unless it is the guild owner. Ownership and ADMINISTRATOR satisfy Discord's permission model but remain visible warnings rather than recommended grants.
Each request accepts one exact guild ID, an inactivity window from 1 through 30 days, a literal acknowledgeNonExactMemberSet: true, one non-blank audit-log reason, one unique one-shot operation key, a request-specific maximumEstimatedMemberCount, and up to five unique exact includeRoleIds. The request ceiling may not exceed the configured ceiling, and both have a hard connector maximum of 250. Include-role IDs are normalized into numeric snowflake order, so caller ordering has no semantic effect. Unknown fields, a false or missing acknowledgement, invalid snowflakes, duplicate or excessive roles, an invalid day window, an invalid count ceiling, audit-reason violations, or an invalid operation key are rejected before destructive access.
By default, Discord considers inactive members with no assigned roles. Supplying include roles widens the cohort to inactive members whose complete assigned-role set is contained in the supplied role set; members with any additional assigned role remain outside it. The connector rejects an explicit @everyone include, every managed role, every role at or above the connector's highest role, unknown permission bits, and roles carrying administrative, moderation, role-management, channel-management, message-management, webhook-management, event-management, guild-expression-management, nickname-management, voice-moderation, or audit-log authority. The @everyone role must also be free of those hazardous permissions because roleless members are always in the cohort.
The connector bot and every configured protected user who is present must hold at least one assigned role outside the selected include-role set, forming a fresh role shield. A configured protected user absent from the guild is safely outside the cohort. The owner is protected by Discord's ownership and hierarchy rules, which the plan labels explicitly without claiming candidate-member evidence. Every protected member reference must be exact and every referenced role must exist in the complete fresh guild role inventory.
- Choose a new one-shot operation key and call
plan_guild_prunewith the exact guild, acknowledgement, inactivity window, optional include roles, request ceiling, and audit reason. - Review the pinned application and bot IDs, Discord-defined cohort semantics, fresh estimated count, request and policy ceilings, complete bot permission and hierarchy evidence, each include role, every protected identity and its outside-cohort role shield, privacy boundary, risks, warnings, request estimates, operation-key hash, verification boundary, and keyed plan digest.
- Call
execute_guild_prunewith semantically identical inputs and the digest. Reordering the same include-role set is equivalent; changing a role, day window, ceiling, acknowledgement, reason, guild, or operation key is not. - Approve the signed MCP confirmation only if the non-exact cohort, both pre-dispatch ceilings, protected identities, included roles, operation-key hash, and plan digest remain intended.
- Review the returned actual count and status. Never infer exact removed members, reuse a reserved key, or retry after an ambiguous result.
Planning verifies the pinned current application and bot, exact guild and owner, bot membership, complete bounded guild roles, effective KICK_MEMBERS plus MANAGE_GUILD, include-role safety, and every protected-identity shield before requesting Discord's fresh prune count. The estimate must be a non-negative safe integer no greater than both ceilings. A zero estimate returns a plan with writeRequired: false; execution of that unchanged plan is a record-free noop that creates no coordination claim, receipt, activity record, rate-budget consumption, or Discord write.
The process-keyed plan digest covers stable identity, guild owner, complete role and bot-member evidence, full permission state, every protected user's exact membership and role evidence, cohort semantics, include roles, inactivity window, fresh estimated count, both ceilings, acknowledgement, audit reason, operation-key hash, privacy boundary, risk set, warnings, and verification contract. Any authority, role, membership, protection, estimate, request, or policy drift invalidates 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 a durable claim over the guild member collection, @everyone, and every exact included role. Member and bulk-ban workflows share the member collection, role workflows touching those exact roles share the role targets, and integration or role deletion also shares the member collection, so those overlapping operations cannot race across connector processes using the same activity-state root. The operation store then reserves the one-shot key and the activity log records a pending content-free entry before exactly one POST /guilds/{guild.id}/prune whose strict body enables count computation. Automatic rate-limit retry is disabled, and no per-member fallback, automatic retry, or rollback exists.
A successful Discord response must contain only one non-negative safe integer pruned count. A count equal to the reviewed estimate is completed; a different returned count is completed-with-drift because external activity, membership, or roles can change between the final estimate and dispatch and Discord does not enforce either ceiling during mutation. A definite non-timeout, non-rate-limit client refusal is failed. A rate limit, request timeout, server error, transport failure, malformed response, or other dispatch ambiguity is uncertain because exact-member readback is impossible. Uncertain results retain the guild member collection and exact-role claim for operator review.
Pending and terminal evidence contains only the guild ID, exact include-role IDs, inactivity days, request and policy ceilings, reviewed and returned counts, plan digest, operation-key hash, activity ID, timestamps, fixed status and verification values, and a sanitized error category. It never contains candidate or removed member IDs, profiles, names, audit reasons, raw operation keys, Discord bodies, message data, or transport causes. Inspect Discord's member state and audit log before resolving a quarantined claim; never treat the reviewed estimate as proof of which members were removed.
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.