What is CyberPUP?
CyberPUP is Frisky Dev's Telegram group protection stack — two complementary bots that together handle automated moderation, ML-based content screening, reputation tracking, and community management for the Haus of Howl community and partner groups.
/setlog log channel. Think of it as the tool belt that Security's log channel receives events into.64.23.130.34) inside separate Docker containers: cyberpup-security and cyberpup-core.
Architecture
Two independent processes, one droplet, shared logging destination.
DB: SQLite (aiosqlite) / PostgreSQL via DB_URL
ML: Image classifier (NSFW), text spam model
Config:
config.toml + environment variablesDeployment: Docker,
/opt/cyberpup-securityHealth: HTTP healthcheck on port 8080
DB: MongoDB (
claw-mongo motor async)Modules: ~50 auto-discovered Python modules
Config: Environment variables + MongoDB
Deployment: Docker,
/opt/cyberpup-coreHot-patch:
docker cp + restart (no rebuild)
Reputation System
CyberPUP Security tracks every member's message count and reputation points. Clean messages earn points; violations cost them. Thresholds gate which actions the bot applies to each user.
Member Levels
Level is determined by total message count. Admins and the group owner are always exempt from automated restrictions regardless of level.
Reputation Thresholds
These rep-point thresholds control which automatic restrictions apply. All values are configurable in config.toml under [spam].
Reputation Labels
Rep Changes
-20Link spam:
-10Forward violation:
-10Cross-chat reply:
-10Location blocked:
-10Voice messages:
-10Invisible spacing:
-10Single emoji:
-5CJK spam:
-5ML spam:
-5Promo violation:
-5
Spam Detections
Security's message pipeline runs a cascade of checks in order. Admins and group owners bypass every check. Trusted users (100+ clean messages, high rep) skip the expensive ML check.
Active Content Checks
| Check | Condition | Action | Rep Penalty |
|---|---|---|---|
| CJK Spam | Message contains Chinese characters (CJK Unified Ideographs) | Delete, log to channel | -5 |
| Invisible Spacing | Hangul filler chars (U+115F, U+1160, U+3164, U+FFA0) present; user rep < 50 | Delete, log to channel | -10 |
| Profanity | Built-in bad-word list matches any member regardless of rep | Delete, log to channel | -20 |
| Single Emoji | Message is exactly one emoji; user rep < 30 | Delete, log to channel | -5 |
| Link Spam | Message has URL or text_link entity; user rep < 50; not a promo slot | Delete, log to channel | -10 |
| ML Spam Model | Text classified as spam; user not trusted; low message count or low rep | Delete (no log entry by itself) | -5 |
Message Type Checks
| Content Type | Rule | Action |
|---|---|---|
| Media (photos, videos, documents, audio, video notes, animations) | User rep < 20 | Delete silently |
| Forwards (external, non-auto-forward) | User rep < 30 AND not a channel forward | Delete, log Forward Filter, -10 |
| Channel Forwards (external channels) | Counted as promo — see Promo Guard section | Promo Guard flow |
| Cross-chat replies ("Reply in Another Chat") | User rep < 50 | Delete, log Cross-Chat Reply Filter, -10 |
| Voice messages | 75% probability trigger (all users) | Reply discouraging message, -10 |
| Contacts | Sender is not admin | Delete silently |
| Locations | Sender rep < 50 | Delete, log Location Filter, -10 |
| Early comments | Reply to linked channel post within 30s; user rep < 50 | Delete, log Early Comment Filter |
| Join notifications | All NEW_CHAT_MEMBERS service messages | Delete; log member joined |
NSFW Detection
CyberPUP Security runs an ML image classifier on photos from low-rep users. Both in-chat images and profile photos are checked. Results are cached to avoid re-downloading the same file.
Classification Categories
What Gets Checked
file_unique_id to avoid repeated downloads. If NSFW: message deleted, review sent to log channel with action buttons.Log Channel Review
When NSFW is detected, two action buttons appear in the log channel:
Promo Guard
Each user gets one promotional post per 24-hour rolling window per group. Admins and owners are always exempt. Reposts of the same content (same URL or same channel) reuse the existing slot without consuming a new one.
What Counts as a Promo?
Regular messages, stickers, voice notes, photos without links, and forwards from linked channels are not counted as promos.
How the Limit Works
wbb.promo_limits collection). If MongoDB is unavailable, an in-memory fallback is used (lost on restart). The limit defaults to 1/day and is configurable via PROMO_LIMIT_PER_DAY or config.toml [promo].
Configuration
| Key | Default | Description |
|---|---|---|
PROMO_ENABLED | true | Enable/disable promo guard entirely |
PROMO_LIMIT_PER_DAY | 1 | Max promo slots per user per group per 24h |
Auto-Ban
When a user accumulates enough spam violations while maintaining low reputation, CyberPUP Security automatically bans them without waiting for manual action.
Both conditions must be true simultaneously. A user with 200 violations but high reputation won't be auto-banned. A user with 50 violations and low rep also won't. Only when violations cross 100 AND rep is below 100 does the ban fire.
violations_count_spam.
autoban_enabled = false in [spam] in config.toml, or set AUTOBAN_ENABLED=false env var.
Security Commands
CyberPUP Security uses a ! prefix for owner commands and / prefix for member commands. All owner commands require the sender to be configured as an owner in config.toml or BOT_OWNER env var.
Member Commands (in main groups)
| Command | Description |
|---|---|
/me /info /я /лвл /whoami /neofetch /fastfetch | Show your member signal snapshot — level, reputation, message count. Reply to another member to see their info. Throttled: once per minute per user per group. |
/rules /правила | Show the group rules message. Throttled: once per minute per group (all aliases share the throttle). |
!бу /бу | Fun command — the bot pretends to be startled. Random response from the bot's "bu-responses" string set. |
Owner Commands (in main groups)
| Command | Usage | Description |
|---|---|---|
!spam | Reply to a message | Flag message as spam. Deletes it (if user isn't admin), creates DB record, sends to log channel with ban / mark-safe / cleanup buttons. |
!setlvl | !setlvl 500 (reply) | Override a member's message count and boost their reputation by the same value. Useful for manually promoting trusted members. |
!reward | !reward 100 (reply) | Award N reputation points to the replied member. Max 100 000 per call. |
!punish | !punish 50 (reply) | Remove N reputation points from the replied member. Max 100 000 per call. |
!rreset | Reply to a message | Reset a member's reputation to equal their message count (clean slate). |
Owner System Commands
| Command | Usage | Description |
|---|---|---|
!setmain | !setmain -100xxxx | Set authorized main group(s) — comma-separated IDs. Only groups in this list will be moderated. |
!setreports | !setreports -100xxxx | Set the channel where reported messages are sent. |
!setlogs | !setlogs -100xxxx | Set the channel where moderation events are logged. |
!ping | In any authorized group | Confirm the bot is monitoring this group. |
!menu | DM or any group | Open the inline navigation menu (Status / Moderation / Reports / Help / Configure). |
Auto-Activation
groups.main, persisted to MongoDB, and a confirmation panel is posted. No !setmain needed. If added by anyone else, the bot stays silent and posts a message explaining how the owner can activate it.
Admin Commands (Core)
CyberPUP Core provides the full moderation toolkit. Commands require the calling user to have the relevant admin permission in the group (e.g., can_restrict_members for bans). The Sudoers list can bypass permission checks.
Ban & Kick
| Command | Description |
|---|---|
/ban | Remove a user from the chat permanently. |
/dban | Delete the replied message and ban its sender. |
/tban | Ban a user for a limited time (e.g., /tban 2h). |
/unban | Restore a banned user's access. |
/listban | Ban a user across all chats listed in a replied message. |
/listunban | Remove a cross-chat ban applied by /listban. |
/kick | Remove a user and allow them to rejoin. |
/dkick | Delete the replied message and kick its sender. |
/ban_ghosts | Remove all deleted Telegram accounts from the chat. |
Warn System
| Command | Description |
|---|---|
/warn | Add a warning to a user. Reply to their message. |
/dwarn | Delete the replied message and warn its sender. |
/warns | Show a user's current warning count. |
/rmwarns | Clear all warnings for a user. |
Mute
| Command | Description |
|---|---|
/mute | Put a user in read-only mode. |
/tmute | Mute a user for a limited time (e.g., /tmute 30m). |
/unmute | Restore sending access to a muted user. |
Messages & Promotion
| Command | Description |
|---|---|
/del | Delete the replied message. |
/purge | Clear messages from the replied point upward. |
/purge N | Clear exactly N messages from the replied point. |
/promote | Promote a member to admin with standard rights. |
/fullpromote | Promote a member with every available admin right. |
/demote | Remove admin rights from a member. |
/pin | Pin or unpin the replied message. |
/invite | Share the group or supergroup invite link. |
/report @admins @admin | Signal a message to the admin team. |
Blacklist & Filters
CyberPUP Core separates two concepts: the Blacklist (explicit phrases that trigger enforcement) and Filters (keyword-triggered bot responses). Both are per-chat.
/blacklist are enforced. General cursing passes freely.
Blacklist Commands
| Command | Description |
|---|---|
/blacklist [WORD|PHRASE] | Add a phrase to this chat's blacklist. Requires can_change_info admin right. |
/whitelist [WORD|PHRASE] | Remove a phrase from the blacklist. |
/blacklisted | List all blacklisted phrases. Large lists are paginated; very large lists sent as a text file to avoid flooding. |
8581086019 is hard-coded as a never-restrict user — the blacklist enforcer will never delete their messages regardless of content.
Filters Commands
Filters let you save a Telegram message (text, photo, video, audio, animation, etc.) as a trigger. When any member sends a message matching the filter name, the bot responds with the saved content.
| Command | Description |
|---|---|
/filter [NAME] | Save a filter, replying to the message you want as the response. Use underscores for multi-word names: /filter Hey_there. |
/stop [NAME] | Remove one filter. |
/stopall | Permanently remove all filters in this chat. |
/filters | List all saved filters in this chat. |
Federations
Federations let you synchronize bans across multiple groups. A spammer banned in one group can be auto-banned in all others in the same federation. Federation admins can ban across all member groups without being an admin in each one individually.
/feds help. Creating a federation, inviting groups, and designating fed admins requires the Sudoers list or fed ownership. Support channel: Frisky Signal.
/setlog — Log Channel
The /setlog command in CyberPUP Core sets the Telegram channel where moderation events are posted. Three privilege tiers can run it, each with different scope.
Access Tiers
off, no-arg status, @handle, numeric ID), any context (DM, group, inside channel)./setlog -100xxxx or /setlog @handle only when the command is sent from within a group they administer. Cannot use off (global disable) or query the current setting (no-arg). Cannot run it in a group where they are not an admin — no cross-group leakage.Usage Reference
| Syntax | Who | Description |
|---|---|---|
/setlog (bare, in DM) ★ primary | Owner / Sudoer only | Activates forward mode (5 min TTL). Bot replies "Forward me any post from your log channel." On receiving a forwarded channel post, automatically reads forward_from_chat and sets it. No ID lookup required. Also writes to Security's MongoDB — Security applies within ~30 s, no restart needed. |
/setlog -100xxxx | Owner / Sudoer / Group Admin | Set by numeric ID (explicit fallback). Group admins must send from within their group. |
/setlog @channelname | Owner / Sudoer / Group Admin | Set by @username. Bot must already be a member of the target channel. |
/setlog (inside channel) | Owner / Sudoer only | Auto-register this channel as the log destination. Bot probes and sets immediately. |
/setlog off | Owner / Sudoer only | Disable logging for both Core and Security. Group admins cannot do this. |
/logstatus | Owner / Sudoer / Group Admin | Probes Core's in-memory channel AND reads Security's MongoDB value. Reports both in one reply — shows whether they are in sync and each is reachable. |
/setlog (any path) writes the channel ID to security_settings.groups_logs in MongoDB. Security's background task polls this field every 30 s and hot-applies it to config.groups.logs — no Security restart needed. Run /logstatus to confirm both bots are pointed at the same channel.
How it Works
/setlog in DM. Bot enters forward mode (5 min window, stored in _pending_setlog[user_id]). User forwards any post from their log channel. Bot reads message.forward_from_chat, verifies it is a channel type, sends a probe, and on success calls _apply_log_channel()./setlog -100xxxx or /setlog @handle. Bot checks privilege tier, resolves the channel, probes it.core_settings._id="global", field log_group_id). Security's value is written simultaneously to security_settings.groups_logs. Both survive restarts.sys.modules iteration — modules that did from wbb import LOG_GROUP_ID at load time all see the new value immediately without restarting.@@channelname → @channelname, and a bare channelname (no @) → @channelname. Double-@ typos (a known UX trap when copy-pasting) no longer cause "Can't find @@…" errors. Error messages now distinguish two failure modes: "username doesn't exist" (UsernameNotOccupied) vs. "bot is not yet a member" (PeerIdInvalid).
Sudoers (Global Ops)
The Sudoers list in CyberPUP Core is the highest privilege tier. Sudoers can execute global operations across all groups the bot serves.
| Command | Description |
|---|---|
/gban [user] [reason] | Ban a user across every served group. Requires a reason. Sends the user a DM explaining the ban. |
/gunban [user] | Reverse a global ban, removing the ban across all served groups. |
/stats | Live system stats: uptime, CPU, RAM, disk, bot process memory. |
/gstats | Network-wide stats: total served chats, served users, global ban count. |
/broadcast | Send a replied message to all served groups. |
/ubroadcast | Send a replied message to all served users. |
/setlogs [id] | Set the primary log group ID (Sudoers version — integer-only). |
/setgbanlogs [id] | Set the global ban log group. |
/setdump [id] | Set the message dump chat. |
/eval | Execute Python code in the bot's process. |
/sh | Execute shell commands on the host. |
/update | Pull latest changes and restart. |
/restart | Restart the bot. |
/clean_db | Remove stale served-chat records from the database. |
/servedchats | List every group and channel the bot is serving, with chat IDs and type. Sent as a .txt file if > 60 lines. Sudoers + owner only. |
Initial Setup
Both bots run as Docker containers on a DigitalOcean droplet. Here's how each is brought live for a new group.
CyberPUP Security — New Group
!setmain.!ping in the group to confirm monitoring is active.!setreports -100xxxx and !setlogs -100xxxx to point the reports and log channels.CyberPUP Core — New Group
/setlog (no args). Core enters forward mode — forward any post from your log channel and it is set automatically for both Core and Security (~30 s sync). Alternatively use /setlog -100xxxx by ID. Run /logstatus to confirm both bots are pointed at the same channel./blacklist WORD and filters with /filter NAME as needed.Configuration
CyberPUP Security is configured via config.toml and environment variables. Environment variables take precedence over the file.
Key Environment Variables
| Variable | Description |
|---|---|
BOT_TOKEN | Telegram bot token (required) |
BOT_OWNER | Primary owner Telegram ID |
BOT_OWNERS | Comma-separated additional owner IDs |
GROUPS_MAIN | Comma-separated main group IDs to moderate |
GROUPS_REPORTS | Reports channel ID |
GROUPS_LOGS | Log channel ID |
LINKED_CHANNELS | Comma-separated linked channel IDs (forwards allowed) |
DB_URL | Database URL (default: SQLite) |
PROMO_ENABLED | true/false — enable promo guard |
PROMO_LIMIT_PER_DAY | Promo slots per user per 24h (default: 1) |
LOG_LEVEL | Python logging level (default: INFO) |
HONEYBADGER_API_KEY | Optional: Honeybadger error reporting |
config.toml Sections
owner, owners, token, version, version_codenamemain, reports, logs, linked_channels, new_users_nomediaenabled, limit_per_daydata/bootstrap-state.json) stores the owner_id, group_id, reports_id, and logs_id from the web activation portal. This file is loaded on startup and fills in any config values that weren't explicitly set.
Troubleshooting
Common issues and their resolutions.
2. Confirm the group ID is in
GROUPS_MAIN (or was auto-activated).3. Check the bot has admin rights (Delete + Ban).
4. Run
!ping in the group to confirm the bot responds.
docker logs cyberpup-core --tail 50 on the droplet. Confirm the module table shows the relevant module (e.g., admin, blacklist). If the container crashed, docker start cyberpup-core.
parse_mode="html" string instead of ParseMode.HTML enum). Fixed in v2+. If you still see it, verify the deployed setlog.py contains from pyrogram.enums import … ParseMode and uses parse_mode=ParseMode.HTML.
filters.command() already rejects commands addressed to another bot — /ban@OtherBot won't trigger the ban handler. The one gap is the keyword filter engine (filters_re): if a saved filter word matches a command name (e.g., a saved filter "ban"), it would fire on /ban@OtherBot because filters_re scans raw text. Fix deployed in v4: filters_re now skips any message that starts with a slash command whose @mention targets a different bot's username.
/opt/cyberpup-core/wbb/modules/<module>.py (host source — survives rebuild).2.
docker cp /opt/cyberpup-core/wbb/modules/<module>.py cyberpup-core:/wbb/wbb/modules/<module>.py3.
docker restart cyberpup-core
claw-mem Docker network. If the claw-mongo container is down: docker start claw-mongo. The promo guard falls back to in-memory (lost on restart). The log channel setting also persists in MongoDB — run /setlog again after recovery.
ssh -o ControlMaster=auto -o ControlPath=/tmp/cyberpup-ssh root@64.23.130.34.
from wbb import LOG_GROUP_ID creates a local copy at import time. v2 of setlog.py uses sys.modules iteration to patch every loaded wbb submodule. If you're still seeing old behavior, verify you have the updated setlog.py deployed (check for the _patch_all_modules function).
FAQ
Can group admins use /setlog?
/setlog -100xxxx or /setlog @handle from within a group they administer. The bot verifies their admin status via get_chat_member() at command time. They cannot run /setlog off (global disable), query the current setting with no-arg, or run it from a group where they are not an admin. Sudoers and the owner have full unrestricted access. Non-authorized users are silently ignored.Why does the Security bot delete Chinese text even from trusted members?
A user says they're getting their messages deleted unfairly. How do I check?
/me as a reply to one of their messages in the group (Security bot). This shows their rep, level, and message count. If rep is very low, the appropriate thresholds are active. The owner can use !reward to boost rep or !setlvl to raise their level if they're a trusted member who joined recently.What is the difference between the reports channel and the log channel?
/report, @admins, or @admin — user-initiated. Log channel receives automatic moderation events (bans, NSFW detections, spam removals, member joins, global bans, etc.) — bot-initiated. Set them separately with !setreports and !setlogs in Security, or /setlog in Core.Does CyberPUP Core automatically block profanity like Security does?
AUTO_PROFANITY_FILTER = False). Core ships with no built-in wordlist. The blacklist only enforces words you explicitly add with /blacklist WORD. General cursing passes freely in Core. CyberPUP Security has its own built-in profanity detection which is separate.How do I add a second owner to CyberPUP Security?
BOT_OWNERS=id1,id2 in the environment or add owners = [id1, id2] to [bot] in config.toml. Settings loaded from MongoDB at startup merge with these — Mongo's list is never allowed to replace the env/config list to prevent a stale Mongo doc from locking out configured owners.What happens if MongoDB is down?
/setlog channel config also lives in Mongo — if Mongo was down when you ran /setlog, the in-memory patch still works for the current session but won't survive a restart. Security uses SQLite by default so isn't affected.The NSFW filter flagged a clean anime image. What do I do?
[nsfw] can be raised.