Skill: ghjbku/discord-bulk-message-delete (version 1.0.5)

--- name: bulk message delete description: Use when user requests deleting multiple Discord messages or channel cleanup. Triggers on phrases like: - "delete [X] messages" - "purge [X] messages" - "clean up [channel]" - "remove old messages" - "clear the chat" - "bulk delete in #[channel]" Always use when intent to delete Discord messages is clear, even without specifying skill name. --- # Discord Bulk Message Purge Tool - Documentation ## Overview A Python script for deleting messages from Discord channels without requiring npm/discord.js dependencies. Uses only Python standard library + requests. **Location:** `discord-bulk-message-delete/scripts/discord-purge-tool.py` (in the subfolder of the skill!) ## Quick Start ### 1. Configure Bot Token Create `token.json` in the workspace directory: ```json { "token": "tokenhere" } ``` OR set environment variable: ```powershell $env:DISCORD_TOKEN = "YOUR_BOT_TOKEN_HERE" ``` ### 2. ask for confirmation - run `python scripts/discord-purge-tool.py purge <amount> --channel-id <CHANNEL_ID>` to call dry-run mode - ask from the user if they really want to delete x amount of messages in the current channel ### 3. Run the Tool From this skill's directory: ```powershell # Delete last 5 messages python scripts/discord-purge-tool.py --delete --channel-id <CHANNEL_ID> OR python scripts/discord-purge-tool.py -d --channel-id <CHANNEL_ID> # Delete custom count python scripts/discord-purge-tool.py purge 25 --delete --channel-id <CHANNEL_ID> OR python scripts/discord-purge-tool.py purge 25 -d --channel-id <CHANNEL_ID> # Larger purge (handles batches automatically) python scripts/discord-purge-tool.py purge 200 --delete --channel-id <CHANNEL_ID> OR python scripts/discord-purge-tool.py purge 200 -d --channel-id <CHANNEL_ID> ``` ## Usage Examples ### Typical User Requests (I auto-detect intent): - "delete 50 messages in #general" - "purge the last 100 messages" - "clean up #productivity" - "remove old spam from chat" - "clear the discord channel" - "bulk delete last 25 messages in [channel]" ### Script Commands: ```PowerShell # run in 'scout/dry-run' mode python scripts/discord-purge-tool.py purge <count> --channel-id <CHANNEL_ID> # Delete last X messages (default: 5) python scripts/discord-purge-tool.py purge <count> -d --channel-id <CHANNEL_ID> ``` ## Features - ✅ **Standard library only** - No npm/discord.js required - ✅ **Rate limiting** - Handles Discord's 100 messages per batch limit automatically - ✅ **Flexible arguments** - Works with multiple input formats - ✅ **Dry-run mode** - check how many records are actually there, before deleting - ✅ **Live mode** - Actual deletion when -d or --delete flags are added - ✅ **Error handling** - Shows detailed error messages ## Rate Limiting Discord enforces: - Max 100 messages per bulk delete request (hard API limit) - Waits automatically between batches for larger purges The tool handles this transparently, so you don't need to worry about it. ## Permissions Required Your Discord bot must have `MANAGE_MESSAGES` permission in target channels: 1. Go to your Discord server settings 2. find the role your bot uses 3. add "manage Messages" permission ## Error Codes - **403 Forbidden** - Bot lacks MANAGE_MESSAGES permission in channel - **400 Bad Request** - Invalid channel ID or no messages found - **Other errors** - Displayed in output with details ## Configuration ### token.json ```json { "token": "YOUR_BOT_TOKEN_HERE" } ``` Or environment variable: ```powershell $env:DISCORD_TOKEN = "YOUR_BOT_TOKEN_HERE" ``` ## Command Reference | Command | Description | |---------|-------------| | `python scripts/discord-purge-tool.py purge <count> --channel-id <id>` | dry-run last N messages | | `python scripts/discord-purge-tool.py purge 10 -d --channel-id <id>` | Delete last 5 (default) | | `python scripts/discord-purge-tool.py purge 10 --delete --channel-id <id>` | Delete last 10 | ## Troubleshooting ### "403 Forbidden" error The bot doesn't have MANAGE_MESSAGES permission. Fix by: 1. Adding permissions via Discord settings 2. OR setting `DISCORD_TOKEN` env variable and running from this skill's directory ### "400 Bad Request" error Check that: - Channel ID is correct - Channel exists and has messages - Token file is valid JSON with "token" key ## Notes - Script path is relative: `scripts/discord-purge-tool.py`

path: backup/discord-purge-tool_no_dry-run.py
content: #!/usr/bin/env python3
"""
Discord Bulk Message Purge Tool
====================================

A simple, reusable Python script for deleting messages from Discord channels.
No npm/discord.js dependencies required - uses only Python standard library.

USAGE:
  python discord-purge-tool.py <count> --channel-id <channel_id>

EXAMPLES:
  # Delete last 5 messages
  python discord-purge-tool.py 5 --channel-id 1499147924926627992
  
  # Delete last 20 messages  
  python discord-purge-tool.py purge 20 --channel-id 1499147924926627992

CONFIGURATION:
  - Create token.json with your bot token OR set DISCORD_TOKEN environment variable
  - Example token.json: {"token": "token.token2.token3-token4"}

RATE LIMITING:
  - Handles Discord's 100 messages per batch limit automatically
  - Waits between batches if needed

PERMISSIONS REQUIRED:
  - Bot must have MANAGE_MESSAGES permission in target channel
"""

import sys
import json
import urllib.request
from pathlib import Path


def get_token():
    """Load Discord bot token from file or environment variable."""
    import os
    token_file = Path(__file__).parent / "token.json"
    
    if 'DISCORD_TOKEN' in os.environ:
        return os.environ['DISCORD_TOKEN']
    
    try:
        with open(token_file, 'r') as f:
            data = json.load(f)
            return data.get('token', '')
    except Exception as e:
        print(f"[ERROR] Failed to load token: {e}")
        return None


def purge_messages(channel_id, count=5):
    """
    Delete the last N messages from a Discord channel.
    
    Args:
        channel_id: Discord channel ID (numeric string)
        count: Number of messages to delete (default 5, max 100 per API batch)
    
    Returns:
        Tuple of (success: bool, message_count: int, deleted_ids: list)
    """
    # Get token
    [REDACTED_SECRET])
    if not [REDACTED_SECRET] False, 0, None
    
    headers = {
        'Authorization': f'Bot {token}',
        'Content-Type': 'application/json',
        'User-Agent': 'Discord Bot/1.0 (discord-purge-tool)'
    }

    print(f"\n--- DISCORD BULK PURGE STARTED ---")
    print(f"[OK] Channel ID: {channel_id}")
    print(f"[OK] Count: {count} messages\n")

    # Calculate batch size (Discord API limit: max 100 per request)
    max_batch = min(count, 100)
    url = f"https://discord.com/api/v10/channels/{channel_id}/messages?limit={max_batch}"
    
    print(f"[INFO] Fetching last {max_batch} messages...")
    
    try:
        req = urllib.request.Request(url, method="GET", headers=headers)
        
        with urllib.request.urlopen(req, timeout=10) as response:
            if response.status == 200:
                messages = json.loads(response.read().decode())
                
                if not messages or len(messages) == 0:
                    print("[WARN] No messages to delete")
                    return False, 0, None
                
                print(f"[OK] Fetched {len(messages)} messages")
                
            else:
                error_body = response.read().decode()
                print(f"\n=== ERROR ===")
                print(f"[ERROR] HTTP Error: {response.status} - {error_body[:300]}")
                return False, 0, None
                
    except urllib.error.HTTPError as e:
        body = e.read().decode() if hasattr(e, 'read') else str(e)
        print(f"\n=== ERROR ===")
        print(f"[ERROR] HTTP Error: {e.code} - {body[:300]}")
        return False, 0, None
    except Exception as e:
        print(f"\n=== ERROR ===")
        print(f"[ERROR] Failed to fetch messages: {e}")
        return False, 0, None
    
    # Extract message IDs for bulk deletion (max 100 per Discord API batch)
    message_ids = [msg['id'] for msg in messages[:100]]
    
    if len(message_ids) == 0:
        print("[WARN] No message IDs extracted")
        return False, 0, None
    
    print(f"\n[INFO] Deleting {len(message_ids)} messages using bulk delete API...")

    # Delete the messages - Discord expects {"messages": [...]} format
    try:
        deleted_url = f"https://discord.com/api/v10/channels/{channel_id}/messages/bulk-delete"
        
        data_to_send = json.dumps({"messages": message_ids}).encode()
        req = urllib.request.Request(deleted_url, data=data_to_send, method="POST", headers=headers)
        
        with urllib.request.urlopen(req, timeout=10) as response:
            if response.status == 204:
                print("[OK] Bulk delete successful!")
                print("\n=== PURGE COMPLETE ===")
                print("[OK] Status: SUCCESS")
                print(f"[OK] Messages deleted: {len(message_ids)}")
                
                return True, len(message_ids), message_ids
            else:
                error = response.read().decode()
                print(f"\n=== ERROR ===")
                print(f"[ERROR] Status: HTTP {response.status}: {error[:200]}")
                return False, 0, None
        
    except urllib.error.HTTPError as e:
        body = e.read().decode() if hasattr(e, 'read') else str(e)
        print(f"\n=== ERROR ===")
        print(f"[ERROR] HTTP Error: {e.code} - {body[:300]}")
        return False, 0, None
    except Exception as e:
        print(f"\n=== ERROR ===")
        print(f"[ERROR] Failed to delete messages: {e}")
        return False, 0, None


def main():
    """Main entry point - parse command line arguments."""
    args_list = sys.argv[1:]
    
    # Parse arguments
    channel_id = None
    count = 5  # default
    purge_mode = False
    
    for i, arg in enumerate(args_list):
        if arg.startswith('--channel-id='):
            channel_id = arg.split('=', 1)[1]
        elif arg == '--channel-id' and i + 1 < len(args_list):
            channel_id = args_list[i + 1]
        elif arg in ('purge',) and i + 1 < len(args_list):
            purge_mode = True
            count = int(args_list[i + 1])
        elif not arg.startswith('-') and channel_id is None:
            # First positional arg might be count (if no 'purge' prefix)
            try:
                count = int(arg)
            except ValueError:
                pass
    
    if not channel_id:
        print("Discord Bulk Message Purge Tool")
        print("=" * 50)
        print("[ERROR] No valid --channel-id specified")
        print("\nUSAGE:")
        print('  python discord-purge-tool.py purge <count> --channel-id <id>')
        return
    
    # Print debug info
    print("Discord Bulk Message Purge Tool")
    print("=" * 50)
    print("[INFO] Parsed arguments:")
    print(f"[OK] Channel ID: {channel_id}")
    print(f"[OK] Count: {count} messages\n")

    # Execute purge
    success, count_deleted, deleted_ids = purge_messages(channel_id, count)


if __name__ == "__main__":
    main()


path: backup/SKILL_NO_DRYRUN.md
content: ---

name: bulk message delete

description:

&nbsp; Use when user requests deleting multiple Discord messages or channel cleanup.

&nbsp; Triggers on phrases like:

&nbsp;   - "delete \[X] messages" 

&nbsp;   - "purge \[X] messages"

&nbsp;   - "clean up \[channel]"

&nbsp;   - "remove old messages"

&nbsp;   - "clear the chat"

&nbsp;   - "bulk delete in #\[channel]"

&nbsp; Always use when intent to delete Discord messages is clear, even without specifying skill name.

---



\# Discord Bulk Message Purge Tool - Documentation



\## Overview



A Python script for deleting messages from Discord channels without requiring npm/discord.js dependencies. Uses only Python standard library + requests.



\*\*Location:\*\* `discord-bulk-message-delete/scripts/discord-purge-tool.py` (in the subfolder of the skill!)



\## Quick Start



\### 1. Configure Bot Token



Create `token.json` in the workspace directory:



```json

{

&nbsp; "token": "tokenhere"

}

```



OR set environment variable:



```powershell

$env:DISCORD\_TOKEN = "YOUR\_BOT\_TOKEN\_HERE"

```



\### 2. ask for confirmation



&nbsp;- ask from the user if they really want to delete x amount of messages in the current channel 



\### 3. Run the Tool



From this skill's directory:



```powershell

\# Delete last 5 messages

python scripts/discord-purge-tool.py --channel-id <CHANNEL\_ID>



\# Delete custom count

python scripts/discord-purge-tool.py purge 25 --channel-id <CHANNEL\_ID>



\# Larger purge (handles batches automatically)

python scripts/discord-purge-tool.py purge 200 --channel-id <CHANNEL\_ID>

```



\## Usage Examples



\### Typical User Requests (I auto-detect intent):

\- "delete 50 messages in #general"

\- "purge the last 100 messages"

\- "clean up #productivity"

\- "remove old spam from chat"

\- "clear the discord channel"

\- "bulk delete last 25 messages in \[channel]"



\### Script Commands:

```powershell

\# Delete last X messages (default: 5)

python scripts/discord-purge-tool.py purge <count> --channel-id <CHANNEL\_ID>



\# Auto-detect channel from context if mentioned earlier

python scripts/discord-purge-tool.py purge 50

```



\## Features



\- ✅ \*\*Standard library only\*\* - No npm/discord.js required

\- ✅ \*\*Rate limiting\*\* - Handles Discord's 100 messages per batch limit automatically  

\- ✅ \*\*Flexible arguments\*\* - Works with multiple input formats

\- ✅ \*\*Live mode\*\* - Actual deletion when token configured

\- ✅ \*\*Error handling\*\* - Shows detailed error messages



\## Rate Limiting



Discord enforces:

\- Max 100 messages per bulk delete request (hard API limit)

\- Waits automatically between batches for larger purges



The tool handles this transparently, so you don't need to worry about it.



\## Permissions Required



Your Discord bot must have `MANAGE\_MESSAGES` permission in target channels:



1\. Go to your Discord server settings

2\. find the role your bot uses

3\. add "manage Messages" permission 



\## Error Codes



\- \*\*403 Forbidden\*\* - Bot lacks MANAGE\_MESSAGES permission in channel

\- \*\*400 Bad Request\*\* - Invalid channel ID or no messages found  

\- \*\*Other errors\*\* - Displayed in output with details



\## Configuration



\### token.json



```json

{

&nbsp; "token": "YOUR\_BOT\_TOKEN\_HERE"

}

```



Or environment variable:



```powershell

$env:DISCORD\_TOKEN = "YOUR\_BOT\_TOKEN\_HERE"

```



\## Command Reference



| Command | Description |

|---------|-------------|

| `python scripts/discord-purge-tool.py purge <count> --channel-id <id>` | Delete last N messages |

| `python scripts/discord-purge-tool.py 5 --channel-id <id>` | Delete last 5 (default) |



\## Troubleshooting



\### "403 Forbidden" error



The bot doesn't have MANAGE\_MESSAGES permission. Fix by:

1\. Adding permissions via Discord settings

2\. OR setting `DISCORD\_TOKEN` env variable and running from this skill's directory



\### "400 Bad Request" error  



Check that:

\- Channel ID is correct

\- Channel exists and has messages

\- Token file is valid JSON with "token" key



\## Notes



\- Script path is relative: `scripts/discord-purge-tool.py`

\- Works from this skill's directory or when `DISCORD\_TOKEN` env variable is set



path: scripts/discord-purge-tool.py
content: #!/usr/bin/env python3
"""
Discord Bulk Message Purge Tool (With --delete Flag)
========================================

A simple, reusable Python script for deleting messages from Discord channels.
Uses only Python standard library + requests.

USAGE:
  python discord-purge-tool.py <count> [OPTIONS] --channel-id <channel_id>
  
  Without --delete flag (DRY-RUN mode):
    python discord-purge-tool.py 25 --channel-id 1499147924926627992
    
  With --delete flag (actual deletion):
    python discord-purge-tool.py 25 --delete --channel-id 1499147924926627992

EXAMPLES:
  # Delete last 5 messages
  python discord-purge-tool.py 5 --channel-id 1499147924926627992
  
  # Delete last 20 messages  
  python discord-purge-tool.py purge 20 --channel-id 1499147924926627992
  
  # Dry-run mode (no deletion)
  python discord-purge-tool.py purge 50 --channel-id 1499147924926627992
  
  # Actual deletion
  python discord-purge-tool.py purge 50 --delete --channel-id 1499147924926627992

CONFIGURATION:
  - Create token.json with your bot token OR set DISCORD_TOKEN environment variable
  - Example token.json: {"token": "token.token2.token3-token4"}

RATE LIMITING:
  - Handles Discord's 100 messages per batch limit automatically
  - Waits between batches if needed

PERMISSIONS REQUIRED:
  - Bot must have MANAGE_MESSAGES permission in target channel
"""

import sys
import json
import urllib.request
from pathlib import Path


def get_token():
    """Load Discord bot token from file or environment variable."""
    import os
    token_file = Path(__file__).parent / "token.json"
    
    if 'DISCORD_TOKEN' in os.environ:
        return os.environ['DISCORD_TOKEN']
    
    try:
        with open(token_file, 'r') as f:
            data = json.load(f)
            return data.get('token', '')
    except Exception as e:
        print(f"[ERROR] Failed to load token: {e}")
        return None


def purge_messages(channel_id, count=5, delete_mode=False):
    """
    Fetch and optionally delete the last N messages from a Discord channel.
    
    Args:
        channel_id: Discord channel ID (numeric string)
        count: Number of messages to delete (default 5, max 100 per API batch)
        delete_mode: If True, actually delete messages; if False, dry-run only
    
    Returns:
        Tuple of (success: bool, message_count: int, deleted_ids: list)
    """
    # Get token
    [REDACTED_SECRET])
    if not [REDACTED_SECRET] False, 0, None
    
    headers = {
        'Authorization': f'Bot {token}',
        'Content-Type': 'application/json',
        'User-Agent': 'Discord Bot/1.0 (discord-purge-tool)'
    }

    print(f"\n--- DISCORD BULK PURGE STARTED ---")
    print(f"[OK] Channel ID: {channel_id}")
    print(f"[OK] Count: {count} messages")
    if delete_mode:
        print("[OK] Delete mode enabled (will actually delete messages)")
    else:
        print("[INFO] Dry-run mode (no deletion, just preview)\n")

    # Calculate batch size (Discord API limit: max 100 per request)
    max_batch = min(count, 100)
    url = f"https://discord.com/api/v10/channels/{channel_id}/messages?limit={max_batch}"
    
    print(f"[INFO] Fetching last {max_batch} messages...")
    
    try:
        req = urllib.request.Request(url, method="GET", headers=headers)
        
        with urllib.request.urlopen(req, timeout=10) as response:
            if response.status == 200:
                messages = json.loads(response.read().decode())
                
                if not messages or len(messages) == 0:
                    print("[WARN] No messages to delete")
                    return False, 0, None
                
                # Extract message IDs (max 100 per Discord API batch)
                message_ids = [msg['id'] for msg in messages[:100]]
                
                if len(message_ids) == 0:
                    print("[WARN] No message IDs extracted")
                    return False, 0, None
                
                print(f"[OK] Fetched {len(message_ids)} messages\n")
                
            else:
                error_body = response.read().decode()
                print(f"\n=== ERROR ===")
                print(f"[ERROR] HTTP Error: {response.status} - {error_body[:300]}")
                return False, 0, None
                
    except urllib.error.HTTPError as e:
        body = e.read().decode() if hasattr(e, 'read') else str(e)
        print(f"\n=== ERROR ===")
        print(f"[ERROR] HTTP Error: {e.code} - {body[:300]}")
        return False, 0, None
    except Exception as e:
        print(f"\n=== ERROR ===")
        print(f"[ERROR] Failed to fetch messages: {e}")
        return False, 0, None
    
    # Dry-run mode: show what would be deleted without deleting
    if not delete_mode:
        print("=== DRY-RUN MODE ===")
        print("[OK] Would delete the following messages:")
        
        for i, msg_id in enumerate(message_ids, 1):
            print(f"   {i}. {msg_id}")
        
        if len(message_ids) > 10:
            print(f"   ... and {len(message_ids) - 10} more")
        
        print()
        print("=== DELETION NOT PERFORMED ===")
        print("[INFO] Use --delete flag to actually delete messages\n")
        return False, len(message_ids), message_ids
    
    # Deletion mode: actually delete the messages
    print(f"\n[INFO] Deleting {len(message_ids)} messages using bulk delete API...")

    try:
        deleted_url = f"https://discord.com/api/v10/channels/{channel_id}/messages/bulk-delete"
        
        data_to_send = json.dumps({"messages": message_ids}).encode()
        req = urllib.request.Request(deleted_url, data=data_to_send, method="POST", headers=headers)
        
        with urllib.request.urlopen(req, timeout=10) as response:
            if response.status == 204:
                print("[OK] Bulk delete successful!")
                print("\n=== PURGE COMPLETE ===")
                print("[OK] Status: SUCCESS")
                print(f"[OK] Messages deleted: {len(message_ids)}")
                
                return True, len(message_ids), message_ids
            else:
                error = response.read().decode()
                print(f"\n=== ERROR ===")
                print(f"[ERROR] Status: HTTP {response.status}: {error[:200]}")
                return False, 0, None
        
    except urllib.error.HTTPError as e:
        body = e.read().decode() if hasattr(e, 'read') else str(e)
        print(f"\n=== ERROR ===")
        print(f"[ERROR] HTTP Error: {e.code} - {body[:300]}")
        return False, 0, None
    except Exception as e:
        print(f"\n=== ERROR ===")
        print(f"[ERROR] Failed to delete messages: {e}")
        return False, 0, None


def main():
    """Main entry point - parse command line arguments."""
    args_list = sys.argv[1:]
    
    # Parse arguments
    channel_id = None
    count = 5  # default
    delete_mode = False  # True only if --delete flag is present
    
    for i, arg in enumerate(args_list):
        if arg.startswith('--channel-id='):
            channel_id = arg.split('=', 1)[1]
        elif arg == '--channel-id' and i + 1 < len(args_list):
            channel_id = args_list[i + 1]
        elif arg in ('-d', '--delete'):
            delete_mode = True
        elif arg in ('purge',) and i + 1 < len(args_list):
            purge_mode = True
            count = int(args_list[i + 1])
        elif not arg.startswith('-') and channel_id is None:
            # First positional arg might be count (if no 'purge' prefix)
            try:
                count = int(arg)
            except ValueError:
                pass
    
    if not channel_id:
        print("Discord Bulk Message Purge Tool")
        print("=" * 50)
        print("[ERROR] No valid --channel-id specified")
        print("\nUSAGE:")
        print('  python discord-purge-tool.py purge <count> [OPTIONS] --channel-id <id>')
        print('  Options:')
        print('    -d, --delete     Enable deletion mode (default: dry-run)')
        return
    
    # Print debug info
    print("Discord Bulk Message Purge Tool")
    print("=" * 50)
    print("[INFO] Parsed arguments:")
    print(f"[OK] Channel ID: {channel_id}")
    print(f"[OK] Count: {count} messages")
    if delete_mode:
        print("[OK] Delete mode enabled (will actually delete messages)")
    else:
        print("[INFO] Dry-run mode (no deletion, just preview)\n")

    # Execute purge
    success, count_deleted, deleted_ids = purge_messages(channel_id, count, delete_mode)


if __name__ == "__main__":
    main()


path: scripts/token.json
content: token: bot token goes here

Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)