Releases: TheHolyOneZ/discord-bot-framework
discord-bot-framework (1.9.3.0)
[Feature] — 2026-03-27 v1.9.3.0
3 new framework cogs — infrastructure-level additions (no bot-feature commands)
cogs/db_migrations.py (NEW)
Database Migration System — versioned, sequential schema migrations for the framework.
- Migration files live in
./migrations/as numbered Python files (001_name.py,002_name.py, ...) - Each file defines
async def up(db)and adescriptionstring - Tracking table
_schema_migrationsin the main database records applied migrations - Migrations run automatically on startup in order; execution stops on first failure (sequential guarantee)
- Failed migrations are recorded with
success = 0so/fw_migratecan retry after a fix /fw_migrations— show migration status: applied, pending, failed counts with details/fw_migrate— manually re-run pending migrations (e.g. after fixing a failed one)- Ships with
migrations/001_add_scheduled_tasks.pywhich creates thescheduled_taskstable for the Task Scheduler
cogs/task_scheduler.py (NEW)
Persistent Task Scheduler — cron-like scheduling that survives bot restarts.
- Jobs stored in
scheduled_taskstable (created by migration 001) - Standard 5-field cron expressions:
minute hour day month weekday CronParserclass: validates, matches, calculates next run, and generates human-readable descriptions- Scheduler tick runs every 30 seconds, checks all enabled tasks against current time
- Deduplication: skips tasks already run within the same minute window
- Three task types:
message— send a message (with optional embed) to a target channelhook— emit a framework event hook viabot.emit_hook()log— write a log entry at a configurable level
max_runssupport: auto-disables task after N executions- Slash command group
/schedule:create— create a new task (with cron validation, channel picker, type selector)list— list all tasks for the current guilddelete— delete a task (creator or bot owner)toggle— enable/disable a taskinfo— detailed view of a single task
- Public Python API:
create_task_programmatic()for other cogs/extensions to register scheduled work - Permission: bot owner or guild owner can create; creators can manage their own tasks
cogs/config_validator.py (NEW)
Config Schema Validator — validates config.json against a defined schema on boot.
- Full schema definition covering all framework config keys:
prefix,status,database,logging,extensions,cooldowns,command_permissions,slash_limiter,framework - Validates: types, required keys, numeric min/max bounds, string length, enum choices, nested objects
- Unknown keys produce warnings (not errors) — user extension keys are allowed
- Keys starting with
_commentare silently skipped - Runs validation on
cog_loadand logs all errors/warnings at appropriate levels /fw_config_validate— run validation on-demand and see errors/warnings in an embed/fw_config_schema— show the full expected schema as a YAML-like referenceregister_extension_schema(name, schema)— extensions can register their own config keys for validationunregister_extension_schema(name)— remove an extension's schema on cog unload_get_merged_schema()merges framework + extension schemas;/fw_config_validateand/fw_config_schemause merged schema
Reusability fixes (Same Release)
cogs/db_migrations.py
- [FIX]
_failedlist was never cleared between/fw_migratecalls — old failures accumulated across re-runs. Addedself._failed.clear()at top of_run_pending_migrations - [API] Added
is_migration_applied(number)— extensions can check if a specific migration was applied before using its tables - [API] Added
applied_migrations/failed_migrationsread-only properties
cogs/task_scheduler.py
- [FIX]
_load_tasksonly loadedenabled = 1tasks from DB. After a restart, disabled tasks vanished from the cache —/schedule listwouldn't show them, and/schedule togglecouldn't re-enable them. Changed toSELECT * FROM scheduled_tasks(loads all tasks) - [FIX] SQLite returns
enabledas int1/0, but toggle logic used Pythonnoton it. Added bool normalization on load:task["enabled"] = bool(task.get("enabled", 1)) - [FIX] Removed unused
import re
cogs/config_validator.py
- [FIX] No way for extensions to register their own config keys — all extension keys flagged as "Unknown key" warnings. Added
register_extension_schema()/unregister_extension_schema()API. Extensions call these fromcog_load/cog_unload - [FIX]
/fw_config_validateand/fw_config_schemaused hardcodedCONFIG_SCHEMA— now use_get_merged_schema()which includes extension-registered keys
atomic_file_system.py
- Added
enable_db_migrations,enable_task_scheduler,enable_config_validatorto the default configframeworkblock
main.py
- Added
db_migrations,task_scheduler,config_validatortoload_order(loaded after shard_manager) - Added
fw_migrations,fw_migrate,fw_config_validate,fw_config_schematoBOT_OWNER_ONLY_COMMANDS
[KNOWN — UPCOMING v1.9.3.1]
- GeminiServiceHelper
collect_dashboard_data()security issue: still pending (tracked separately)
discord-bot-framework (1.9.2.0)
[Fix] — 2026-03-07 -> 2026-03-25 v1.9.1.0 → v1.9.2.0
41 confirmed bug fixes across 13 cogs
cogs/framework_diagnostics.py
- [FIX]
generate_diagnostics()accessedself.bot.bot_owner_id,self.bot.extension_load_times,self.bot.db.conn,self.bot.db.base_path, andself.bot.configwithout guards. Any one missing attribute raisedAttributeErrorcaught generically, returningNonewith no useful detail. All replaced withgetattr(...)guards. - [FIX]
loop_lag_monitorran every 1 second (86,400 scheduling events/day). Changed to@tasks.loop(seconds=5)andexpected_interval = 5.0. - [FIX]
_send_alertcalled.send()unconditionally on any channel type. If the configured channel was a voice, stage, or forum channel,send()raisedHTTPExceptioncaught generically. Addedisinstance(channel, discord.TextChannel)check. - [FIX] Write-failure alert in
generate_diagnostics()fired on every failure with no debounce. Added_last_write_alert_time— alert only fires if >300 seconds since last write alert.
cogs/shard_monitor.py
- [FIX]
save_metricsand_save_alert_configused synchronousopen()+json.dump()directly on the event loop, blocking all coroutines during disk writes. Both now useawait asyncio.to_thread(...)._save_alert_configis nowasync def. - [FIX]
ShardMetrics.is_healthy()hardcodedconsecutive_failures >= 3regardless of the configurablealert_thresholdonShardMonitor. Addedthreshold: int = 3parameter.health_checkand_build_health_embednow passself.alert_threshold.
cogs/shard_manager.py
- [FIX]
_seen_nonceswas asettrimmed viaset(list(...)[half:]—sethas no ordering so the "keep newest half" logic randomly discarded nonces, potentially re-allowing replay of recently seen ones. Replaced withcollections.deque(maxlen=10000)which auto-drops the oldest. - [FIX]
sync_statsloop had notry/except. An unhandled exception silently killed the task permanently with no alert. Wrapped body intry/except Exception as e: logger.error(...).
cogs/event_hooks.py
- [FIX] Queue-full fallback in
emit_hookcalledawait self._hook_queue.put(hook_data)with no timeout on a still-full queue, suspending the emitter indefinitely. Theexcept asyncio.QueueFullbelow it was dead code sincequeue.put()never raisesQueueFull. Replaced fallback withput_nowait()insidetry/except asyncio.QueueFull. - [FIX]
hook_idusedcallback.__name__— two callbacks in different cogs with the same function name shared onehook_id, causing one to overwrite the other. Changed tocallback.__module__.callback.__qualname__for guaranteed uniqueness. - [FIX]
disable_hook()checkedif hook_id not in self.hookswhereself.hooksis keyed by event_name (e.g."bot_ready"), not hook_id (e.g."bot_ready:module.func"). This check always evaluated True, makingdisable_hookalways returnFalse—/eh_disablewas completely broken (regression from v1.9.1.0). Now iterates hooks to find a matchinghook_id. - [FIX]
cog_unloadcalledself._worker_task.cancel()but did not await it, leaving cleanup fromCancelledErrorunguaranteed. Changedcog_unloadtoasync defand addedawait self._worker_taskintry/except asyncio.CancelledError.
cogs/plugin_registry.py
- [FIX]
PluginListViewhad noon_timeout— after the 120s timeout the cog reference stayed alive and buttons remained visually enabled. Addedasync def on_timeoutthat clearsself._cogand disables all buttons.
cogs/slash_command_limiter.py
- [FIX] Debug log used
logging.FileHandlerwith no rotation or size cap, growing indefinitely. Replaced withlogging.handlers.RotatingFileHandler(maxBytes=5MB, backupCount=2). - [FIX]
/slashlimithad no access control — any guild member could enumerate all blocked/converted command names. Added@commands.is_owner().
cogs/GeminiService.py
- [FIX] No
cog_loadvalidation forGEMINI_API_KEY— if the key was missing, the cog loaded silently and only failed at first invocation with a confusing error. Addedcog_loadthat logs CRITICAL if the key is absent. - [FIX] No
cog_unload— hot-reloading left_user_cooldownsand_ai_cachepopulated with stale state from the previous config. Addedcog_unloadthat clears both dicts.
cogs/GeminiServiceHelper.py
- [FIX] Sessions were only written to disk synchronously on each message send. A crash between sends lost the latest entry. Added a
@tasks.loop(seconds=60)auto-save task with a dirty flag — sessions are now also persisted periodically as a safety net.
cogs/live_monitor.py + ReUseInfos/live_monitor_helper.py
- [FIX]
_load_configcaught JSON parse errors with a bareexcept: passand returned defaults silently. Operators had no indication config was reset. Changed toexcept Exception as e: logger.error(...)including the config file path and exception detail.
cogs/EventHooksCreater.py
- [FIX]
_cooldownsdict accumulated one entry per (hook_id, user_id) pair seen and grew indefinitely. Added eviction in_check_cooldown— entries older thancooldown_seconds * 2are pruned on each cooldown check. - [FIX]
_user_message_countsgrew indefinitely (one entry per unique user ever seen). Added a cleanup step inanalytics_task(runs every 5 min) that caps the dict at 5,000 users by count. - [FIX]
_execute_webhookcreated a newaiohttp.ClientSessionper invocation, defeating connection pooling. Addedself._http_sessioncreated incog_loadand closed incog_unload._execute_webhooknow reuses the shared session. Changedcog_unloadtoasync def.
cogs/event_hooks.py
- [FIX]
_add_to_historyper-event pruning usedh not in events_to_removewhereevents_to_removeis a list of dicts — dict equality is O(n), making the pruning O(n²). Replaced with{id(h) for h in ...}set for O(n) membership checks.
cogs/shard_monitor.py
- [FIX]
is_bot_owner()returned False for the real bot owner whenBOT_OWNER_IDwas0(env var not set), locking the owner out of all commands. Updated predicate to tryBOT_OWNER_IDfirst, then fall back toapplication_info().owner.id.
cogs/shard_manager.py
- [FIX] Default
SHARD_IPC_SECRET = "change_me_please"only logged aWARNINGand continued loading, allowing IPC to run with a known-public secret. Escalated toCRITICALlog and earlyreturn— the cog will not load at all until a real secret is configured.
cogs/GeminiService.py (MEDIUM batch)
- [FIX] Cache lookup happened after
PluginRegistry.get_all_plugins(),generate_diagnostics(), etc. were already called — cache hits still paid the full I/O cost. Moved cache check to before context-gathering; a cache hit now skips all framework calls and returns immediately. - [FIX]
_user_cooldownsand_ai_cachegrew without bound. Added@tasks.loop(minutes=5)_cleanup_cache_taskthat evicts cooldown entries older thanCOOLDOWN_SECONDS * 2and cache entries older thanCACHE_TTL. - [FIX]
_active_requestswas an unprotected plain integer. Replaced withasyncio.Semaphore(_MAX_CONCURRENT). Guard usessemaphore.locked(), acquire/release infinally.
cogs/GeminiServiceHelper.py (MEDIUM batch)
- [FIX]
_save_sessionscalledPath.write_text()synchronously inside an async method, blocking the event loop on large session files. Wrapped withawait asyncio.to_thread(lambda: ...). - [FIX]
_gather_tool_contextstopped at the first matching cog name with abreak, silently ignoring further cog mentions in the same message. Removedbreak— all matching cog names are now collected.
cogs/EventHooksCreater.py (MEDIUM batch)
- [FIX]
_execute_webhookpassed any user-supplied URL directly toaiohttp.ClientSession.post()with no validation, enabling SSRF to internal services. Added URL prefix check — onlydiscord.com,discordapp.com,ptb.discord.com, andcanary.discord.comwebhook URLs are permitted.
cogs/plugin_registry.py (MEDIUM batch)
- [FIX]
check_dependenciesoperator extraction used">=" if ">=" in required_version else "==", silently mapping>1.0.0or<=2.0.0to==. Replaced withre.match(r'([><=!]+)', ...)for correct extraction of any operator. - [FIX]
save_registryfailures were logged but had no operator alert. Added_save_failure_countcounter — after 3 consecutive failures_send_alertfires a critical message warning that disk state is stale.
cogs/backup_restore.py (MEDIUM batch)
- [FIX]
_download_image_b64created a newaiohttp.ClientSessionper image. A backup with 50 emojis + stickers + icon + banner opened 57+ sessions sequentially.capture()now creates one shared session and passes it to all_download_image_b64calls via a newsessionparameter. - [FIX] Banner was captured as base64 during backup but
_do_restorenever applied it. Added banner restore after icon restore in theserver_settingsblock:await guild.edit(banner=banner_bytes, ...).
cogs/event_hooks.py (MEDIUM batch)
- [FIX]
alert_channel_idwas in-memory only — lost on every restart, leaving the alert system permanently silent after a reload. Added_load_config/_save_configbacked by./data/event_hooks_config.json;alert_channel_idis persisted on every/eh_alert_channelcall. - [FIX]
_worker_restart_countnever reset — a bot that crashed twice a year could permanently exhaust its 10-restart budget._restart_workernow resets the counter to 0 if the worker ran stably for >1 hour before the current crash.
cogs/Guild_settings.py (MEDIUM batch)
- [FIX]
get_guild_mention_prefix_enabled,get_guild_prefix, andset_guild_mention_prefix_enabledwere called withouttry/except. A DB failure propagated to the global error handler with no user-friendly context. All DB calls now ...
discord-bot-framework (1.9.1.0)
[Fix] — 2026-03-04 — v1.9.0.0 → v1.9.1.0
14 confirmed bug fixes across 11 cogs
cogs/GeminiService.py
- [FIX] Cooldown stamp
_user_cooldowns[user.id] = nowwas written before the_active_requests >= _MAX_CONCURRENTcheck — a user rejected for capacity silently consumed their 15-second cooldown slot. Stamp now written only after all guards pass.
cogs/GeminiServiceHelper.py
- [FIX]
_cmd_update_configguard wasif owner_id is not None and requester_id != owner_id— ifapplication_info()raised an exception,owner_idstayedNoneand the guard was vacuously false, allowing any caller to update config. Guard inverted toif owner_id is None or requester_id != owner_id(deny-by-default). - [KNOWN — UPCOMING] Security:
collect_dashboard_data()iterates all sessions and includes every user'saes_keyand full history in the polled JSON. Any authenticated dashboard user can currently read other users' encryption keys. Fix requires live_monitor to pass the authenticated dashboard user's Discord ID at data-collection time (currently hardcodedNone). Will be addressed in v1.9.2.0.
cogs/live_monitor.py
- [FIX]
on_commandlistener was defined twice in the same class. The duplicateon_command+on_command_errorpair caused every prefix/hybrid command to be double-counted in_command_usageand logged twice in the dashboard event log. Duplicate block removed from both files. - [FIX]
cog_unloadwas deletingplugin_registry.jsonon every hot-reload, destroying PluginRegistry's persisted data owned by another cog. Deletion removed from both files — Live Monitor only cleans up its own files. - [FIX]
asyncio.get_event_loop()(deprecated Python 3.10+) replaced withasyncio.get_running_loop()inlive_monitor_helper.py(_get_process,_collect_monitor_data).
cogs/EventHooksCreater.py
- [FIX]
or Trueon theimplementedstatus check made the"⚠️"branch permanently unreachable — all templates always showed"✅"regardless of implementation status. Removedor True.
cogs/plugin_registry.py
- [FIX]
self.bot.extension_load_times[name]was accessed without ahasattrguard — raisesAttributeErrorif the bot doesn't expose the attribute, silently abortingregister_plugin. Replaced withgetattr(self.bot, 'extension_load_times', {}).get(name, 0.0). - [FIX]
_auto_scan_extensiononly calledcog.get_commands(), missing all pure@app_commands.commandslash commands. Addedcog.get_app_commands()scan —/pr_infoand/pr_listnow report accurate command counts for GeminiService, EventHooksCreater, etc.
cogs/backup_restore.py
- [FIX]
BackupSnapshotversion string hardcoded as"2.1.0"while the cog is v2.2.0 — new snapshots were mis-tagged. Updated to"2.2.0".
cogs/framework_diagnostics.py
- [FIX]
on_app_command_errorlistener added — slash command errors (the majority of commands in this framework) were never tracked in_error_historyorhealth_metrics["last_error"]. Rolling error rate was systematically undercounted. - [FIX]
asyncio.get_event_loop()(deprecated Python 3.10+) replaced withasyncio.get_running_loop()in_get_processand_get_system_metrics.
cogs/event_hooks.py
- [FIX]
disable_hook()unconditionally added any string todisabled_hooksand returnedTrue— a typo in a hook ID silently "succeeded", making the "hook not found" branch in commands dead code. Now returnsFalsefor unknown hook IDs.
cogs/shard_monitor.py
- [FIX] Health alert had no debounce —
_send_health_alertfired on every 60-second tick while a shard stayed unhealthy, flooding the alert channel. Added_last_alert_timewith a 5-minute cooldown per alert.
cogs/shard_manager.py
- [FIX]
_heartbeat_loopcapturedguild_countatconnect()time and sent the stale frozen value on every heartbeat. Now readslen(self.bot.guilds)live on each tick.
cogs/Guild_settings.py
- [FIX]
actionparameter typed asstr— Discord showed a free-text field with no hints. Changed toLiteral["enable", "disable", "status"]so Discord renders a dropdown in slash mode.
discord-bot-framework (1.9.0.0)
[Add] — 2026-03-01 — v1.9.0.0
cogs/GeminiServiceHelper.py — Fully new cog
A dedicated AI assistant embedded directly inside the Live Monitor web dashboard. No slash commands — entirely dashboard-native, accessed from the new AI Assistant tab (tab 21).
Encryption
- [ADD] AES-256-CBC end-to-end encryption: server-side via Python
cryptographylibrary, client-side via native Web Crypto API (crypto.subtle) — no external CDN, no CSP issues - [ADD] Per-user AES keys stored server-side; new users bootstrap a key in
localStoragewhich is registered on first send - [ADD] Encrypted session history persisted to
./data/gemini_dashboard_sessions.json
Context tools (auto-injected based on message keywords)
- [ADD] Framework Info — live bot stats (version, guild count, loaded cogs)
- [ADD] Extension/Cog Info — docstring and slash commands for any loaded cog, detected by cog name appearing in the message
- [ADD] File Structure — lists root
.pyfiles,cogs/,data/, and notable project files - [ADD] README Search — full hierarchical breadcrumb parse of
README.md; up to 3,000 chars from the top 4 scoring sections - [ADD] Capabilities — triggered by "what can you do"-style queries; lists all tools and what the AI cannot do
- [ADD] File Reading — sandboxed reader; allowed: root
*.py,cogs/*.py,data/*(direct children only); always blocked:.env,gemini_dashboard_sessions.json, live monitor config JSON files
Attach File (Option C)
- [ADD] Attach File toolbar button opens an inline row with a live-filter autocomplete dropdown above the input
- [ADD] File list pre-fetched from Python on every data poll (
available_filesincollect_dashboard_data) — shows only allowed paths, no blocked files - [ADD] Multiple files: each confirmed file becomes a removable chip tag; up to 3 files read per message and injected as separate
[Tool Context — File: …]blocks - [ADD] Auto-detect fallback: if no explicit attachment, the message text is scanned for filenames with known extensions and the file is read automatically
Chat UX
- [ADD] Optimistic message bubbles — user message appears immediately; removed if a confirmed user message arrives from the server
- [ADD] Smart scroll — only auto-scrolls if user was within 120 px of the bottom; never interrupts reading older history
- [ADD] Typing indicator — persists until the AI response arrives in history (not just on POST ACK)
- [ADD] Lock + Cancel — send button and textarea disabled while waiting for response; Cancel button removes the optimistic bubble and unlocks input
- [ADD] Client-side 15-second rate limit gate with countdown feedback
- [ADD] Markdown rendering — fenced code blocks, headers, bold, italic, inline code, lists, HR — XSS-safe via
gaiEsc(), no external dependencies - [ADD] Capabilities popup — animated glassmorphism modal from a toolbar button listing what the AI can and cannot do
Configuration & permissions
- [ADD] Config drawer (owner-only): live model and system prompt override without restart; respects
GEMINI_MODELenv var (defaultgemini-2.5-flash-lite) - [ADD] 4 dashboard permission flags:
view_gemini_chat,action_gemini_send,action_gemini_clear_history,action_gemini_config - [ADD] Requires
pip install cryptography
cogs/live_monitor.py + ReUseInfos/live_monitor_helper.py — GeminiServiceHelper integration
- [ADD]
'gemini'added to$validPackagesin_generate_receive_php()— without thismonitor_data_gemini.jsonreturned 404 - [ADD]
GeminiServiceHelper.collect_dashboard_data(discord_id)called inside_collect_monitor_data()and merged under key"gemini"in the polled JSON - [ADD] AI Assistant tab (tab 21) injected into generated
index.phpviaLiveMonitor._get_gemini_tab_html()— HTML/CSS/JS fully embedded inlive_monitor_helper.pyfor self-contained CGI-bin deployment;GeminiServiceHelper.get_tab_html()removed (dead code) - [ADD]
geminiInit(monitorData, userId)wired into the dashboard's existing 2-second data-poll cycle - [ADD]
handle_command()dispatch registered forgemini_send_message,gemini_clear_history,gemini_update_config
[Update] — 2026-02-28 — v1.8.0.0 → v1.9.0.0
cogs/EventHooksCreater.py — Full overhaul
Missing template handlers implemented
- [ADD]
leveling_system— XP awarded per message with per-user cooldown, level calculation, level-up announcements to configured channel, role rewards at configured level thresholds; XP data persisted in memory and saved via the batch save task - [ADD]
scheduled_announcement— recurring message/embed sent to a configured channel at a configurable interval (hours); implemented as a per-hookasyncio.Taskstarted on registration and cancelled on unregister/delete/disable - [ADD]
ticket_system— creates a private text channel per user in a configured category when they react with a configured emoji on a configured message; support role granted access automatically; channel named via template; reaction removed after ticket creation to keep the message clean - [ADD]
voice_activity_tracker— logs join, leave, and mute/unmute events to a configured log channel with embed; each event type independently togglable - [ADD]
dynamic_voice_channels— creates a temporary voice channel in a configured category when a user joins a designated trigger channel, moves the user into it, and deletes it automatically when it becomes empty; channel named via template; active temp channels tracked in memory
Dead code wired in
- [FIX]
_execute_actionsis now called by all new template handlers — the generic action pipeline (send_message, add_role, remove_role, timeout, send_dm, webhook, create_role, delay, trigger_hook) is no longer dead code - [FIX]
AdvancedConditionEngine.evaluate()is now called at the top of every handler before executing — hooks with conditions configured (time_range, day_of_week, role_hierarchy, message_count, user_age, custom_variable) now actually respect them
Security
- [FIX]
eval()in_format_messagereplaced with a safe AST-based math evaluator — only numeric constants and basic operators (+, -, *, /) are permitted; no code execution possible
Reliability
- [FIX] Listener accumulation fixed —
_registered_hook_ids: settracks which hooks have active listeners;_register_hookskips registration if the hook is already registered, preventing duplicate listeners from piling up on restart or re-register - [FIX] I/O on every execution removed —
_save_created_hooks()is no longer called after every hook fires; execution_count and error_count are updated in memory and flushed by a new_auto_savebackground task (60-second interval, dirty flag); the analytics task already saves analytics every 5 minutes - [FIX] Channel and role ID validation at registration time — invalid IDs (non-integer, channel/role not found in guild) now return a clear error from
create_hook()instead of failing silently at runtime
New Discord commands (Bot Owner / Administrator)
- [ADD]
/hooks list [page]— paginated list of all hooks in the current guild with template name, status (enabled/disabled), execution count, error count - [ADD]
/hooks info <hook_id>— detailed embed showing all params, conditions, execution stats, and last execution time for a specific hook - [ADD]
/hooks delete <hook_id>— delete a hook with confirmation; owner-only - [ADD]
/hooks toggle <hook_id>— enable or disable a hook - [ADD]
/hooks create <template_id>— shows required and optional parameters for the template and creates the hook with provided params via command options
cogs/plugin_registry.py — Upgrade
Auto-scan completeness
- [ADD]
provides_hooksandlistens_to_hooksare now populated during auto-scan by reading__provides_hooks__and__listens_to_hooks__module-level attributes from extension modules
Persistence
- [FIX] Alert channel now persisted to
./data/plugin_registry_config.json— survives restarts - [FIX]
enforce_dependenciesandenforce_conflictsstates now persisted to the same config file — no longer reset toTrueon restart after being disabled via/pr_enforce
Real enforcement
- [FIX] Enforcement is no longer advisory only — when
enforce_dependencies=Trueand a plugin has missing or incompatible dependencies,register_plugin()now refuses to register it and returns an error; same for conflict enforcement
UX
- [FIX]
/pr_listnow uses paginated embeds (10 plugins per page with Prev/Next buttons) — no longer hits Discord's 25-field embed limit with large plugin sets
Resilience
- [FIX]
extension_loaded/extension_unloadedhook registration no longer depends on EventHooks being loaded — fallback uses directbot.add_listener()onon_readyif EventHooks is absent
discord-bot-framework (1.8.0.0)
[Update] — 2026-02-28 — v1.7.2.2 → v1.8.0.0
cogs/framework_diagnostics.py
Persistence
- [FIX] Alert channel now persisted to
./data/framework_diagnostics_config.json— survives bot restarts, no longer needs to be re-set every time
Reliability
- [FIX]
bot.metricsis no longer a hard dependency — all accesses wrapped withgetattrfallbacks; cog loads and runs without crashing even if the main bot doesn't implementbot.metrics - [FIX] Loop lag threshold is now configurable via
FW_LOOP_LAG_THRESHOLD_MSenv var (default: 500ms) — no longer hardcoded and no longer stored confusingly as seconds while being compared as ms
Accuracy
- [FIX] Loop lag now uses a rolling average of the last 10 readings instead of the raw instantaneous value — eliminates false alerts from single-tick jitter
- [FIX] Error rate now computed over a rolling 1-hour window (delta of 12 × 5-minute snapshots) instead of lifetime totals — an early error burst no longer permanently inflates the rate;
/fw_diagnosticsshows(rolling 1h)or(lifetime)to indicate which mode is active
History & Observability
- [ADD] Health check history: last 48 entries (4 hours) kept in memory and persisted to
./data/framework_health_history.jsonafter each health_monitor run - [ADD] Error history: last 20 command errors kept in a deque;
on_command_errornow appends each error with timestamp and command name instead of overwriting a single field - [ADD]
/fw_history [entries]command — shows last N (1–20) health check snapshots with timestamp, status, error rate, and loop lag per entry - [ADD]
/fw_errorscommand — shows the last 20 command errors with timestamp, command name, and error message
Embed improvements
- [CHG]
/fw_diagnosticshealth field now shows rolling window note, recent error count, and(avg 10s)annotation on loop lag
cogs/GeminiService.py
Security
- [FIX]
fileaction is now restricted to bot owner only — previously any Discord user could read.env,config.json, database files, and any other file in the bot's working directory - [FIX]
permissionaction now accurately describes the real access model (fileandpermission= bot owner only; all other actions = everyone) instead of incorrectly stating all actions are public
Fixes
- [FIX] Per-user cooldown (15 s) and global max concurrency (3) are now enforced via a manual
_user_cooldownsdict and_active_requestscounter —@commands.cooldown/@commands.max_concurrencyare silently ignored by discord.py for pure@app_commands.commandhandlers and have been removed; both limits now fire beforeinteraction.response.defer()so the response is immediate and ephemeral - [FIX] AI responses that exceed Discord's 4096-character embed limit now show a visible truncation notice (
Response truncated — ask a more specific question) instead of cutting off silently - [FIX] Context strings sent to Gemini are now capped at 8,000 characters — large plugin lists or database schemas no longer risk exceeding model token limits
- [FIX] Import coupling removed —
PluginRegistryandFrameworkDiagnosticsare no longer imported at module level; GeminiService loads gracefully even if those cogs are disabled
Additions
- [ADD] 60-second in-memory TTL cache for repeated identical queries on
diagnose,plugins,slash,hooks, andautomationsactions — cache hits are noted in the embed footer - [ADD] Gemini model is now configurable via
GEMINI_MODELenvironment variable (default:gemini-2.5-flash-lite)
cogs/backup_restore.py — Restore expanded to cover all captured data
Previously the backup captured forum channels, stage channels, emojis, stickers, and server settings but silently skipped all of them during restore. This update makes restore match what backup captures.
Backup (capture) changes
- [FIX] Emoji images are now downloaded and stored as base64 inside the backup JSON at capture time — CDN URLs alone are useless after an emoji is deleted
- [FIX] Sticker images are now downloaded and stored as base64 inside the backup JSON at capture time (also adds the missing
urlfield to sticker entries) - [FIX] Server icon and banner are now downloaded and stored as base64 (
icon_b64,banner_b64) inside the guild info block — restoring an icon no longer depends on the CDN URL remaining valid - [ADD] Added
_download_image_b64()async helper used by capture for all image downloads
Restore changes
- [ADD] Forum channels: restored via
guild.create_forum(), skips duplicates by name - [ADD] Stage channels: restored via
guild.create_stage_channel(), skips duplicates by name - [ADD] Emojis: restored from embedded base64 image data via
guild.create_custom_emoji()— managed emojis are skipped - [ADD] Stickers: restored from embedded base64 image data via
guild.create_sticker()— requires re-backup for entries captured before this update - [ADD] Server settings: restores name, verification level, default notifications, explicit content filter, AFK channel/timeout, premium progress bar via
guild.edit() - [ADD] Server icon: restored from embedded base64 data via
guild.edit(icon=bytes)
Discord UI (RestoreSelectView)
- [ADD] Three new toggle buttons: Emojis, Stickers, Server Settings
- [CHG] Bot Settings moved to row 1 alongside the new buttons
- [CHG] Select All now includes emojis, stickers, and server_settings in its selection set
- [CHG] Confirm Restore moved to its own row (row 3) for visual clarity
cogs/live_monitor.py — Dashboard restore parity
- [ADD]
_execute_dashboard_restore()updated with the same new restore blocks: forum channels, stage channels, emojis (base64), stickers (base64), server settings + icon (base64) - [ADD] PHP backup/restore UI: added Forum Channels and Stage Channels restore component checkboxes (Emojis, Stickers, Server Settings were already present in the UI but non-functional on the backend)
- [CHG] Default restore components in
_process_backup_actions()extended to includeemojis,stickers,server_settings
discord-bot-framework (1.7.2.2)
What's New in Version 1.7.2.2
[Patch] - 2026-02-25
Fixed
cogs/EventHooksCreater.py — Async I/O fix
_save_analytics()was a synchronous function called from an async background task (analytics_task, runs every 5 minutes). Usingopen()+json.dump()in a sync function inside an async context blocks the entire event loop until the write finishes — meaning the bot cannot process any messages, commands, or Discord heartbeats during that time._save_created_hooks()had the same problem and is called in over a dozen places across async event handlers and command callbacks.- Fix: Both functions converted to
async defusingaiofiles. All 13 call sites updated toawait self._save_created_hooks().analytics_taskupdated toawait self._save_analytics(). - Behaviour is identical — hooks and analytics are still saved to the same JSON files at the same times. Only the I/O is now non-blocking.
cogs/GeminiService.py — Path traversal fix
- The
/ask_zdbfcommand'sfileandextensionactions sanitized user-supplied file paths usingfile.lstrip("./\\").replace("..", ""). This was incorrect:lstripstrips individual characters from the left edge, not a literal prefix. A path likecogs/../config.jsonwould survive the sanitization and resolve tocogs/config.json, potentially exposing files outside the intended scope. - Fix: Replaced the string manipulation with
Path.resolve()+Path.relative_to(). The resolved absolute path is checked to be inside the allowed directory (bot root forfileaction,extensions/forextensionaction) before the file is opened. If the path escapes the boundary, the command returns a clear access denied message. - Behaviour for valid paths is identical. Paths that previously slipped through are now blocked.
discord-bot-framework (1.7.2.1)
- Added Action Permissions + Permission checks for the new Feature: Bot Status Configurator
discord-bot-framework (1.7.2.0)
What's New in Version 1.7.2.0
This update introduces a comprehensive Bot Status Configuration system, fully integrated into the Live Monitor web dashboard. This feature allows for dynamic, multi-status rotation with customizable variables, providing a more engaging and informative presence for your bot on Discord.
Bot Status Configuration — Now in the Dashboard
The new Bot Status Configuration card, located in the System tab of the Live Monitor dashboard, provides complete control over your bot's presence.
Key Features
- Multi-Status Rotator: Create a list of different statuses for your bot to cycle through. Each status can have its own text, type (playing, watching, listening), and presence (online, idle, dnd).
- Customizable Interval: Set the rotation interval in seconds to control how frequently the bot's status updates.
- Dynamic Variables: Use variables like
{guilds},{users}, and{commands}in your status text, which will be automatically replaced with real-time data. - Live Editing: Add, edit, and delete statuses directly from the dashboard. Changes are saved and applied instantly without needing to restart the bot.
- Log Toggling: A new toggle allows you to enable or disable logging for status updates, helping you monitor the rotator's activity in your bot's console.
- Intuitive UI: The interface provides clear input fields for status type, text, and presence, making it easy to configure complex rotations.
This new system replaces the previous static status configuration, offering a much more flexible and powerful way to manage your bot's presence.
discord-bot-framework (1.7.1.0)
What's New in Version 1.7.1.0
Two major systems that were previously only accessible through Discord commands are now fully integrated into the Live Monitor web dashboard: Backup & Restore and Shard Management. Everything you could do in Discord, you can now do from your browser — plus a few extras.
Backup & Restore — Now in the Dashboard
The Backup & Restore tab gives you a complete overview of every server snapshot across all your guilds, with full management capabilities built right in.
At a Glance
When you open the tab, you'll see global stats at the top — total backups, how many guilds have backups, total storage used, pinned count, cooldown timer, auto-backup interval, and retention policy. A storage utilization bar shows how much of your capacity is in use.
Guild Sidebar
On the left, every guild with backups is listed with its backup count, total size, and schedule status. Click any guild to open its backup viewer.
Backup Viewer
Once you select a guild, you'll see all its backups listed chronologically. Each entry shows the label, timestamp, role and channel counts, file size, and whether it was created manually or automatically. From here you can:
- Create a new backup directly from the dashboard with an optional custom label. The bot captures the full server snapshot — roles, channels, categories, emojis, stickers, member role assignments, and server settings — just like it would from a Discord command.
- Delete a backup you no longer need. Pinned backups are protected and must be unpinned first.
- Restore a backup using the restore modal, where you pick exactly which components to restore (roles, channels, categories, bot settings, member roles) and optionally enable full role sync mode.
- Pin or unpin backups with one click to protect important snapshots from automatic cleanup and deletion.
- View full details for any backup by expanding its detail panel, which shows everything — role count, category count, text/voice/forum/stage channel counts, emoji and sticker counts, member role assignments, total members at time of capture, file size, data integrity checksum, who created it, and any attached notes.
Per-Guild Scheduling
Each guild has its own configuration panel where you can enable or disable automatic scheduled backups, set the interval in hours, and configure retention (how many days to keep old backups before they're automatically cleaned up). Changes are saved instantly and take effect on the next bot cycle.
Restore Workflow
The restore process walks you through component selection, warns you about what will be affected, and shows a real-time log as the bot processes the operation. When it's done, you'll see a full results summary — how many items were created, skipped, or failed, how many members were processed, roles added or removed, duration, and any issues that came up. The button then changes to let you close the modal cleanly.
Shard Manager — Now in the Dashboard
If your bot runs across multiple shards or IPC clusters, the new Shard Manager tab gives you real-time visibility into every shard's health and performance without needing to run commands in Discord.
Overview
The top of the tab shows your total shard count, how many are healthy, how many have warnings, and your average latency across all shards. Below that, three info panels cover:
- IPC Status — your clustering mode, cluster name, and how many clients are connected to the IPC mesh.
- Health Summary — a breakdown of healthy, warning, and critical shards at a glance.
- Global Totals — total guilds, total users, and overall uptime across all shards.
Health Bar
A visual health bar shows every shard as a colored block — green for healthy, yellow for warning, red for critical. Hover over any block to see that shard's ID, current latency, and the reason for its health status.
Shard Detail Cards
Below the health bar, each shard gets its own detail card showing its current latency, guild count, health status and reason, connection/disconnection/reconnection history, error count, and event throughput. You can view detailed metrics and reset shard statistics from the dashboard.
Cluster Map
If you're running multiple IPC clusters, the cluster map visualizes which shards belong to which cluster, their connection status, and how they're distributed across your infrastructure.
Role-Based Access
Both tabs respect the dashboard's permission system. Server owners have full access by default, while custom roles can be granted granular permissions — separately controlling who can view backups, create them, delete them, restore them, edit scheduling configs, view shard details, or reset shard metrics.
Summary of What's New
| Feature | Before 1.7.1.0 | Now |
|---|---|---|
| Create backups | Discord command only | Dashboard + Discord |
| Delete backups | Discord command only | Dashboard + Discord |
| Restore backups | Discord command only | Dashboard + Discord |
| Pin/unpin backups | Discord command only | Dashboard + Discord |
| View backup details | Discord command only | Dashboard + Discord |
| Configure backup schedules | Discord command only | Dashboard + Discord |
| Monitor shard health | Discord command only | Dashboard + Discord |
| View shard latency & metrics | Discord command only | Dashboard + Discord |
| Reset shard statistics | Discord command only | Dashboard + Discord |
| IPC cluster visualization | Not available | Dashboard |
All existing Discord commands continue to work exactly as before. The dashboard simply gives you an additional way to manage everything from your browser.
discord-bot-framework (1.7.0.0)
📋 Changelog
All notable changes to the Zoryx Discord Bot Framework are documented in this file.
🚀 v1.7.0.0 — Advanced Shard System & Backup/Restore
Release Date: 2026-02-18
Previous Version: 1.6.1.0
✨ New Features
📊 Shard Monitor Cog (cogs/shard_monitor.py) — v2.0.0 (V1 = Private)
A complete real-time shard health monitoring system with an interactive dashboard.
- Interactive Dashboard (
/shardmonitor) with 4 button-navigated tabs:- 📊 Overview — Cluster-wide stats, per-shard summary, alert configuration
- 🏥 Health — Full health report with critical/warning/healthy breakdown
- 📡 Latency — Visual latency bars per shard with min/avg/max statistics
- 📈 Events — Per-shard counters (messages, commands, connects, disconnects, errors)
- 🔄 Refresh — Refresh active tab with latest data
- 5 Hybrid Commands (all Bot Owner Only):
/shardmonitor— Interactive dashboard/sharddetails <id>— Deep-dive metrics for a specific shard/shardhealth— Quick health report across all shards/shardalerts [#channel] [threshold]— Configure automatic health alerts/shardreset [shard_id]— Reset metrics for one or all shards
- Enhanced ShardMetrics Class:
- Latency history tracking (120 samples with rolling window)
- Per-shard event counters (messages, commands, guild joins/leaves)
- Uptime percentage calculation
- Connection/disconnection/reconnection tracking with timestamps
- Consecutive failure tracking with error details
- Three-Tier Health Check System:
- 🟢 Healthy — All metrics within normal range
- 🟡 Warning — Latency >1s, no activity for 5+ min, or 3+ consecutive failures
- 🔴 Critical — Latency >2s, 5+ consecutive failures, or currently disconnected
- Alert System:
- Configurable alert channel with persistent storage (
./data/shard_monitor/alert_config.json) - Configurable failure threshold (1–20, default: 3)
- Automatic alert embeds sent on unhealthy shard detection
- Configurable alert channel with persistent storage (
- Background Tasks:
collect_metrics— Records shard latency every 30 secondshealth_check— Evaluates shard health every 60 secondssave_metrics— Persists metrics to disk every 5 minutes
- Event Listeners:
on_message— Per-shard message counteron_command— Per-shard command counteron_shard_connect/on_shard_disconnect/on_shard_resumed/on_shard_readyon_guild_join/on_guild_remove
.envToggle:ENABLE_SHARD_MONITOR=true/false(default:true)
🌐 Shard Manager Cog (cogs/shard_manager.py) — v1.0.0
A new IPC (Inter-Process Communication) system for running shards across multiple processes or servers.
- TCP-Based IPC Protocol:
- Length-prefixed messages (4-byte header + JSON payload)
- 1MB max message size
- Nonce-based deduplication to prevent duplicate processing
- IPC Server Mode (primary cluster):
- Hosts TCP server, handles client authentication
- Tracks connected clients with heartbeat monitoring
- Routes messages between clusters
- Broadcasts cluster join/leave notifications
- IPC Client Mode (secondary clusters):
- Connects to primary cluster's IPC server
- Automatic reconnection with exponential backoff (5s → 120s max)
- Sends heartbeats every 30 seconds
- Message Types:
auth/auth_response— Shared secret authenticationheartbeat/heartbeat_ack— Keep-alive with guild countstats_broadcast— Cluster statistics exchange (every 60s)cluster_join/cluster_leave— Connection notificationsbroadcast_message— Owner-initiated text broadcast
- Security:
- Shared secret authentication (
SHARD_IPC_SECRET) - 10-second auth timeout for unauthenticated connections
- No arbitrary code execution — safe preset queries only
- Warning logged when using default secret
- Shared secret authentication (
- 3 Hybrid Commands (all Bot Owner Only):
/clusters— Show all connected clusters with stats, health, and global totals/ipcstatus— IPC system diagnostics (mode, host, port, clients, heartbeats)/broadcastmsg <message>— Broadcast text to all connected clusters
- Background Task:
sync_stats— Broadcasts cluster statistics every 60 seconds
.envToggle:ENABLE_SHARD_MANAGER=true/false(default:false)
💾 Backup & Restore System (cogs/backup_restore.py) — v2.1.0
A full guild configuration snapshot system for disaster recovery, server migrations, and auditing. Now with member role snapshots, selective restore, auto-backup scheduling, and a full audit trail.
- Full Guild Snapshots capturing:
- Roles (name, color, hoist, mentionable, permissions value, position)
- Categories (name, position, NSFW, permission overwrites with target/allow/deny)
- Text channels (name, topic, slowmode, NSFW, category, full permission overwrites)
- Voice channels (name, bitrate, user limit, RTC region, category, full permission overwrites)
- Forum channels and Stage channels (safe fallback if discord.py version lacks support)
- Emojis (name, animated, URL, managed status)
- Stickers (name, description, emoji)
- Server settings (verification level, notification level, content filter, AFK, system channel, locale, boost bar)
- Member role assignments — saves which non-bot members have which roles (requires Members Intent)
- Bot settings (custom prefix, mention prefix configuration)
- Interactive Dashboard (
/backup) with 5 button-navigated tabs:- 📊 Overview — Storage usage bar, latest backup, current guild stats, cooldown timer
- 📦 Backups — Paginated list with metadata (roles, channels, member snapshots, author, size)
- 🔍 Compare — Drift analysis: current state vs latest backup with change counts
- 📜 Audit Log — Every backup operation tracked (create, delete, restore, pin, verify, export)
- 📈 Analytics — Trends, top creators, backup frequency, member snapshot counts
- 🔄 Refresh + ◀ ▶ Pagination on all paginated tabs
- 🗑️ Delete — Quick-delete from dashboard via dropdown selector with pin protection
- 13 Hybrid Commands:
/backup— Interactive dashboard with 5 tabs/backupcreate [label]— Create a full guild snapshot/backuprestore <id>— Selective restore with component toggles (roles, categories, channels, member roles, bot settings)/backupview <id>— Detailed backup inspection/backupdelete <id>— Delete with two-step confirmation (respects pin protection)/backuplist— Paginated backup list/backuppin <id>— Pin/unpin to protect from deletion and cleanup/backupnote <id> <text>— Annotate backups with notes/backupverify <id>— SHA-256 checksum integrity verification/backupschedule <action> [hours]— Per-guild auto-backup schedule (enable/disable/status)/backupdiff <id_a> <id_b>— Compare any two backups (added/removed roles, channels, members)/backupexport <id>— Export as JSON (Bot Owner only)/backupstats— Global backup statistics (Bot Owner only)
- Selective Restore Engine:
- Toggle individual components: roles, categories, channels, member roles, bot settings
- Creates only missing roles, categories, and channels (skips existing by name)
- Recreates permission overwrites with old→new role ID mapping
- Reapplies member role assignments — gives members back the roles they had at backup time
- Role Sync mode (off by default) — when enabled, does a full rewind: adds missing roles AND removes roles that weren't in the backup, restoring each member's roles to the exact state at backup time
- Guild chunking ensures all members are loaded before processing
- Restores bot settings with cache invalidation
- Real-time progress updates and detailed results report
- Per-guild restore lock prevents concurrent operations
- Audit Log System:
- Tracks all operations with user ID, backup ID, and details
- Per-guild storage, keeps last 200 entries
- Auto-Backup Scheduler:
- Per-guild configurable interval (1–168 hours)
- Background loop checks hourly, auto-backups flagged with 🔁
- Requires
BACKUP_AUTO_INTERVAL> 0 in.env
- Retention Cleanup:
- Auto-deletion of old unpinned backups past threshold
- Pinned backups always protected
- Configurable via
BACKUP_RETENTION_DAYS
- Timezone-Aware Timestamps:
- All timestamps stored as UTC-aware ISO 8601 (
+00:00) - Discord
<t:epoch:R>formatting shows correct relative time in every user's local timezone - Backward-compatible with legacy naive timestamps
- All timestamps stored as UTC-aware ISO 8601 (
- Safety & Abuse Protection:
- 5-minute cooldown per guild (configurable, bot owner gets bypass notification instead of silent skip)
- Max 25 backups per guild (configurable)
- Two-step confirmation for restore and delete
- Interaction author verification on all buttons — only the invoker can interact
- SHA-256 checksums, pin protection, restore lock
- Permission System:
- Bot Owner: Full access + export + global stats
- Administrator: Guild-scoped access to all commands
- Delete protection: non-admin users can only delete their own backups
.envToggle:ENABLE_BACKUP_RESTORE=true/false(default:true)`
🔧 Modified Files
main.py
4 patches applied to integrate the new cogs:
-
Owner-Only Commands List (line ~103):
- Added 8 commands to
BOT_OWNER_ONLY_COMMANDS:
shardmonitor,sharddetails,shardhealth,shardalerts,shardreset,clusters,ipcstatus,broadcastmsg - Added
backupexportandbackupstatsto owner-only list (backup export and global stats restricted to bot owner) - Ensures all shard and backup-export commands are restricted to
BOT_OWNER_ID
- Added 8 commands to
-
Cog Load Order (line ~22...