Changelog
Every release of cordless, newest first. Pre-release versions aren’t listed here.
2 September 2026
- The package now ships
py.typed, so type checkers (mypy, pyright) read cordless’s annotations when you depend on it. DiscordObject.to_dict()returns the raw Discord payload behind any wrapped response model (webhook, channel, message, and so on).
Changed
Section titled “Changed”- The entire codebase is now type-checked under pyright strict.
- An interaction that arrives without a request path is now ignored instead of being passed on to route matching.
Full Changelog: https://github.com/borhara/cordless/compare/v1.5.0...v1.5.1
31 August 2026
- Full REST API client. A complete async client for Discord’s bot-accessible REST API, exposed as flat
bot.<verb>()methods and as object-method sugar (channel.send(),message.edit(),member.add_role(),role.delete(), …). Covers channels, messages and reactions, polls, members and roles, guilds (bans, prune, widget, welcome screen, onboarding, incident actions), threads, webhooks, invites, emojis, stickers, soundboard, scheduled events, stage instances, auto-moderation, guild templates, audit log, users, voice state, entitlements, SKUs, subscriptions, the application object, and application commands - Typed
DiscordHTTPErrorhierarchy (BadRequest,Unauthorized,Forbidden,NotFound,ServerError) carrying.status,.body, and.headers;MissingTokenErrorwhen no bot token is configured - REST rate limiting keyed by Discord’s
X-RateLimit-Bucketid and shared across concurrent Lambda invocations via the existing DynamoDB table, with a warm-container HTTPS connection kept open between calls idempotent=on REST calls to override the default per-method safe-to-retry guess@bot.route(method, path)for raw HTTP handlers on the interaction Lambda, outside Discord’s signature-verified flow: incoming service webhooks, OAuth callbacks, health checks. Supports{name}path params and a trailing{name+}greedy segment (delivered onevent["pathParameters"]), coerces handler returns (string, dict/list as JSON, status int,(status, body)/(status, body, headers)tuple, or a full proxy dict), and works on either a Function URL or API Gatewaycordless deploysyncs@bot.routepaths onto API Gateway alongside the slash commands;cordless devserves them locally;cordless doctorreports whether they’re in sync- Per-option
name_localizations/description_localizations, plus localisation of auto-created subcommand groups, parent command names, and choices choice()helper for building localised choice dictsuser_installable="only"for commands that drop the guild install and are usable only by users who installed themdefault_member_permissionsandnsfwon@bot.user_commandand@bot.message_commandchannel_typeson channel options;group_descriptionfor a real description on an auto-created subcommand groupLabelcomponent for wrapping a select menu inside a modal;default_valueson entity select menusctx.entitlementson the interaction contextbot.execute_slack_webhook/bot.execute_github_webhook;bot.fetch_webhook_message,bot.fetch_webhook_with_token,bot.edit_webhook_with_tokenreason=(audit-log reason) onbot.add_role,bot.remove_role,bot.create_webhook, andbot.delete_webhook- Decoration-time validation of command and option shape (name pattern, 1–100 char descriptions, 25-option and 25-choice caps), with the offending command and option named in the error
- Discord’s Components v2 structural limits and per-message action-row limits are enforced at build time with a clear error
Guild, theDiscordHTTPErrorfamily,MissingTokenError,Label, andchoiceare exported from the top-levelcordlesspackage
Changed
Section titled “Changed”- REST and webhook calls that fail now raise
DiscordHTTPError(aCordlessErrorsubclass) instead ofRuntimeError pynaclis now a required runtime dependency and the pure-Python Ed25519 signature-verification fallback has been removed;cordless deployfails rather than shipping a function that can’t verify Discord’s requestsbot.send_messageandbot.edit_messagereturn the resultingMessage;send_message/edit_message/delete_message/add_role/remove_rolenow run through the shared async REST clientratelimit.wait_if_neededcan raiseDiscordHTTPError(429)without sending when a confirmed, shared rate-limit block has more time left than the retry budget allowsbot.<verb>()methods return_rest.modelsobjects (e.g.Webhook,Thread) that are not exported at the top level
- Autocomplete interactions no longer fall through to the shared error handler, which could return a message-type response Discord rejects
parse_webhook_urlno longer echoes the passed-in URL (which contains a live token) in its error message- Multipart uploads escape filenames and field values in
Content-Dispositionheaders - The rate limiter never retries a 429 before Discord’s own
retry_after, never sleeps past the retry deadline, keys shared state by major resource, tolerates an explicitnullretry_after, and warns once instead of silently when the shared DynamoDB table is unreachable - Non-idempotent requests (POST/PATCH) are no longer resent after a dropped connection or network error
- The persistent connection lock is held until the response body is read, fixing a race on the shared connection
DiscordObjectinstances are hashable againThreadandThreadMemberkeep fields cordless doesn’t explicitly declare instead of dropping thembot.execute_slack_webhookno longer crashes on the Slack endpoint’s plain-textwaitresponse- Forum thread creation no longer forces
rate_limit_per_user=0;start_thread_from_forum(files=...)nests the attachments descriptor undermessageso the files actually attach fetch_thread_memberssupportsafter/limitpagination- An interaction POST delivered on a non-root path is routed through the normal interaction handler
- API Gateway route sync no longer drops routes when the bot fails to load, and handles greedy route keys correctly
- A
@bot.routehandler that returns a value cordless can’t turn into a response now gets a clean 500 instead of an unhandled 502 - Webhook 429 retries no longer stack sleeps past a total time budget
- Editing or deleting a Nitro-pack sticker or default soundboard sound raises a clear error
- A token-authenticated webhook’s avatar can be cleared by passing
None
Full Changelog: https://github.com/borhara/cordless/compare/v1.4.7...v1.5.0
15 August 2026
Guildmodel withctx.guild, exposing icon, banner, and splash URLs from the interaction’s partial guild object- Command and subcommand name/description localisation support
cordless doctor: a new diagnostic command for checking your deploy setup, with streamed section-by-section output- Testing helpers:
invoke()and builders for slash/context menu commands, buttons, selects, modals, and autocomplete, plus support for dispatching deferred handlers in worker mode
- CloudWatch log groups now default to 30 day retention instead of never expiring, configurable via
log_retentionin[deploy] - Subcommands no longer leak
name_localizationsonto the parent command invoke()now correctly decodes file-attachment responses- Testing helpers default placeholder usernames to
test-user
Full Changelog: https://github.com/borhara/cordless/compare/v1.4.6...v1.4.7
26 July 2026
Permissionsbitfield object for reading and building Discord permission bits. Read named bits off an incoming member or role (ctx.member.permissions.manage_guild), or construct one to send (Permissions(manage_guild=True, kick_members=True)).Member.permissionsandRole.permissions, wrapping Discord’s raw bitfield string in aPermissionsobject.ctx.resolved_users,ctx.resolved_members,ctx.resolved_roles, andctx.resolved_channels: dicts of id to typedUser/Member/Role/Channel, resolvingUserSelect,RoleSelect,ChannelSelect, andMentionableSelectpicks instead of leaving callers to dig through rawresolvedpayloads.Rolemodel, with.mention(<@&id>) and.permissions.Channel.mention(<#id>).User.avatar_urlandUser.banner_url, andRole.icon_url: full Discord CDN URLs built from the raw asset hashes, including the default-avatar fallback for users without a custom avatar.
Changed
Section titled “Changed”- Outgoing message content is now validated against Discord’s 2000-character limit before sending, raising
MessageTooLongErrorinstead of letting the request fail invisibly on Discord’s end after we’ve already returned 200 to API Gateway. cordless dev’s tunnel output no longer blocks startup waiting for the cloudflared tunnel to answer; it now prints the public URL immediately (highlighted) with a note that it may take a few seconds to start working.cordless deploynow prints a hint to paste the returned URL into the app’s Interactions Endpoint URL setting.
default_member_permissionsis now coerced to an int before being stringified when registering commands, so passing aPermissionsobject works correctly.
Full Changelog: https://github.com/borhara/cordless/compare/v1.4.5...v1.4.6
20 July 2026
- User-installable commands: pass
user_installable=Trueto@bot.command,@bot.user_command, or@bot.message_commandto let users install the command as a personal app and run it in any DM, not just servers the bot is in cordless devrequest logs are now timestamped and colour-coded by status, with a--verbose/-vflag to print the full interaction payload under each line
Changed
Section titled “Changed”- Full docstring coverage across the public API, feeding cordless.dev’s generated reference
Full Changelog: https://github.com/borhara/cordless/compare/v1.4.4...v1.4.5
19 July 2026
Changed
Section titled “Changed”- The
deployextra is folded into cordless’s base dependencies:uv add cordlessis now enough, no separate extra needed - Docstring coverage extended across the public API, feeding cordless.dev’s generated reference
- CLI and deploy-only source are no longer bundled into the Lambda layer or function zip
Full Changelog: https://github.com/borhara/cordless/compare/v1.4.3...v1.4.4
19 July 2026
- Discord payloads (user, member, message, channel, attachment) are now wrapped in typed objects instead of raw dicts
- cordless now declares Python 3.14 support
- Rate-limit waits are now logged when they actually happen
Changed
Section titled “Changed”cordless deploynow falls back to the process environment for Discord credentials if not otherwise configured
cordless devnow waits for the cloudflared tunnel to actually route before printing its URL- The keep-warm deploy step is now correctly labelled as off when not opted into
Full Changelog: https://github.com/borhara/cordless/compare/v1.4.2...v1.4.3
19 July 2026
cordless deploynow runs a describe-only post-deploy health check, and prints the function’s runtime and signature-verification method after every deploy
Full Changelog: https://github.com/borhara/cordless/compare/v1.4.1...v1.4.2
19 July 2026
- Opt-in keep-warm cron that periodically invokes the main function to avoid cold starts
cordless initnow requires an explicit endpoint choice
Changed
Section titled “Changed”- New Lambda functions default to the
arm64architecture (existing deployments keep their current architecture on redeploy) - New projects default to the
us-east-1region, closest to Discord’s own API - HTTP connections are now reused across webhook, app, and deferred-followup requests instead of opening a new one per call, and the DynamoDB table handle is cached per table name
- Missing Function URL invoke permission is now healed automatically on existing deployments
- Duplicate file names in an upload zip no longer get written twice
- A
pynaclfetch failure is now surfaced clearly after the deploy spinner instead of being lost mid-spin, andpynaclis now bundled correctly forbundle_cordlessdeploys too
Full Changelog: https://github.com/borhara/cordless/compare/v1.4.0...v1.4.1
13 July 2026
- Optional cross-invocation rate-limit coordination via DynamoDB (
ratelimit = truein[deploy]), tracking Discord’s rate-limit headers locally and falling back to a shared table when needed
Changed
Section titled “Changed”- Outbound requests now retry a 429 on a time budget instead of a fixed 3-attempt cap, with jitter added to backoff waits
- Deferred followups (
post_followup,delete_original) and webhook calls (execute/edit/delete) now retry on 429 - Rate-limit state is now published proactively when remaining requests get low, not only after an actual 429
Full Changelog: https://github.com/borhara/cordless/compare/v1.3.0...v1.4.0
12 July 2026
--environment/-Eflag (and$ENV) ondeploy/dev/register/cron, with.env.<environment>overlay files merged over the base.env
- A command handler literally named
setupis no longer mistaken for thesetup(bot)extension hook files=onsend_message/edit_messagenow actually attaches files, via multipart encodingsend_message/edit_messagenow set the Components v2 flag when passed UI-Kit components.env.*overlay files are excluded from the deployment zip
Full Changelog: https://github.com/borhara/cordless/compare/v1.2.0...v1.3.0
12 July 2026
Changed
Section titled “Changed”guild_idis renamed toguild_idsacross@bot.command, Cog decorators, andsync_commands, and now accepts multiple guild ids to scope a command to more than one guild at once
cordless registerreports guild-scoped command counts
Full Changelog: https://github.com/borhara/cordless/compare/v1.1.3...v1.2.0
10 July 2026
--verboseflag on the CLI
- Lambda layer names now include the target architecture, so switching architecture forces a new layer build instead of reusing an incompatible one
- The layer is now published with the correct
CompatibleArchitectures
Full Changelog: https://github.com/borhara/cordless/compare/v1.1.2...v1.1.3
9 July 2026
cordless deploynow fails loudly instead of silently falling back when Lambda layer packaging errors- Layer wheel fetching now uses
uvinstead ofpip, and fails clearly ifuvis missing or the install fails uvitself is now bundled as a deploy dependency, using the interpreter-local copy when available
Full Changelog: https://github.com/borhara/cordless/compare/v1.1.0...v1.1.2
9 July 2026
- Webhook support:
execute_webhook,edit_webhook_message,delete_webhook_message,create_webhook,get_channel_webhooks, anddelete_webhookonCordless
- Webhook file uploads now declare attachment metadata, so uploaded files actually attach to the message
- Webhook calls now raise on a non-2xx response instead of silently swallowing the error
- CLI flag abbreviation is disabled, so
--bundlecan no longer silently match--bundle-cordless
Full Changelog: https://github.com/borhara/cordless/compare/v1.0.0...v1.1.0
8 July 2026
Cordlessapp with a Lambda-readyhandler(), Discord interaction routing, and@bot.command()slash command registrationContextobject wrapping an interaction’s data, with aResponder-based API for building replies- Ed25519 signature verification for incoming interaction requests
cordlessCLI for registering slash commands with Discord, including OAuth2 client-credentials supportcordless upload: deploy the framework itself as a Lambda layer
- Replaced the
pynaclsignature-verification dependency with a pure-Python Ed25519 implementation, sincepynacl’s native extension failed to load in AWS Lambda’s runtime
Full Changelog: https://github.com/borhara/cordless/commits/v1.0.0