Changelog

September 17, 2026 · View on GitHub

All notable changes to slackblocks are documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[2.4.0] — 2026-09-17

This coordinated release introduces the C# package, published to NuGet as Slackblocks, and moves all five packages onto one shared release number. The Python public API and wire format are unchanged.

Changed

  • Coordinated release validation now requires the Python, TypeScript, Java, and C# package manifests and all five language changelogs to agree before any tags are created.
  • Project documentation now includes the C# implementation alongside the existing Python, TypeScript, Go, and Java variants.

[2.3.0] — 2026-09-16

This coordinated release introduces the Java package while moving Python, TypeScript, Go, and Java onto one shared release number. The Python public API and wire format are unchanged.

Changed

  • Coordinated release validation now requires the Python, TypeScript, and Java package manifests and all four language changelogs to agree before any tags are created.
  • Project documentation now includes the Java implementation alongside the existing Python, TypeScript, and Go variants.

[2.2.0] — 2026-08-29

This coordinated release introduces the fluent TypeScript API while keeping the Python and TypeScript packages on one release number. Python constructor signatures are unchanged.

Changed

  • Complete message payloads now enforce Slack's 50-block and 100-attachment limits and require a non-empty channel.
  • Message, modal, and App Home block collections now reject blocks that Slack does not support on that surface.
  • Modals containing an input block now require submit text, matching Slack's view rules.
  • The shared cross-language conformance contract is now version 1.1.0 and covers these complete-payload rules in both implementations.

[2.1.1] — 2026-08-16

A documentation and packaging-metadata patch; no library behaviour changes.

Changed

  • The PyPI page now carries Homepage, Repository, Documentation, and Changelog links ([project.urls] was previously misplaced and silently dropped from the wheel metadata).
  • The README leads with the new language-neutral project logo, links to the current documentation site paths, and shows the quickstart's rendered message.
  • Wheels are built with current Hatchling again (Core Metadata 2.5), now that Twine 7 validates it; the temporary hatchling<1.28 pin is retired.

[2.1.0] — 2026-08-14

The 2.1 release adds the current generation of Block Kit blocks while keeping the Python and TypeScript packages on one coordinated release number.

Added

  • Support for AlertBlock, CardBlock, CarouselBlock, ContainerBlock, ContextActionsBlock, DataTableBlock, DataVisualizationBlock, TaskCardBlock, and PlanBlock, together with their supporting elements and composition objects.
  • Shared valid and invalid conformance cases for the new block families, with coverage checks that require both language implementations to handle every registered capability.

Changed

  • FileInput now emits "type": "file_input" in its JSON (the field was previously deliberately omitted from the rendered payload).
  • HeaderBlock now enforces the 150-character limit on pre-built Text objects (previously only plain strings were length-checked) and converts mrkdwn Text to plain_text, matching the Slack API's requirement that header text be plain text.
  • InputBlock now accepts FileInput elements.
  • block_id values longer than 255 characters now raise LengthError (previously they were accepted and passed through to the Slack API unchecked).
  • Documentation now covers the new blocks with Python, JSON, and rendered Slack previews.
  • The project is now a multi-package workspace with coordinated Python and TypeScript releases.

[2.0.0] — 2026-05-15

The 2.0 release. First final release of the modernised line.

slackblocks 2.x requires Python 3.10 or newer. Users on Python 3.8 or 3.9 should pin to the 1.x release line; see the Compatibility docs page for details.

Added

  • MarkdownBlock for Slack's 2024 GitHub-flavored Markdown block type (1-12000 character text field). Used for AI / agentic app outputs. (#198, #199)
  • VideoBlock for embedding video content with alt_text, thumbnail_url, title, video_url, plus six optional fields. (#200, #201)
  • PlainText and Markdown thin subclasses of Text that remove the boilerplate of constructing plain-text or mrkdwn-flavored text: PlainText("Hi", emoji=True) instead of Text("Hi", type_=TextType.PLAINTEXT, emoji=True). (#202, #203)
  • block_kit_builder_url(payload, team_id=None) utility that turns any block, list of blocks, message, view, or raw dict into a Block Kit Builder URL for browser-based preview. (#204, #205)
  • Workflow.from_url(url, **params) classmethod factory that collapses the four-deep nested workflow construction (Workflow -> Trigger -> customizable_input_parameters -> InputParameter) into a single call. (#206, #207)
  • from_dict() parsers for round-tripping Slack JSON back into slackblocks objects. Supported now: every composition object (Text, Option, OptionGroup, Confirm, ConversationFilter, DispatchActionConfiguration, InputParameter, SlackFile, Trigger, Workflow) and the basic blocks (DividerBlock, FileBlock, HeaderBlock, MarkdownBlock, ImageBlock, SectionBlock, ContextBlock, VideoBlock). Element-level and rich-text round-tripping is deferred to follow-up phases. (#208, #209)
  • Top-level Block.from_dict(data) dispatcher that reads data["type"] and routes to the right subclass. Block is now exported from the package root. (#208, #209)
  • Five new typed exception subclasses of InvalidUsageError so consumer code can except for specific failure categories instead of string-matching the message: LengthError, RangeError, TypeMismatchError, MutualExclusivityError, MissingRequiredError. Existing except InvalidUsageError blocks continue to catch every subclass unchanged. (#196, #197)
  • PEP 561 py.typed marker file so downstream type checkers honour slackblocks' inline annotations. (#164, #165)
  • Compatibility docs page (usage/compatibility.md) documenting which Python versions each release line supports. (#166, #167)
  • PEP 585 / PEP 604 annotation syntax across the codebase (list[X], X | Y) plus from __future__ import annotations in every module. (#170, #171)
  • PEP 613 TypeAlias declarations on the public type aliases: TextLike, ButtonStyleLike, ButtonStyleName, ColumnAlignment, ConversationType. (#194, #195)
  • Literal type narrowing for string-valued enums: Button.style: ButtonStyle | Literal["primary", "danger"] | None, ColumnSettings.align: Literal["left", "center", "right"] | None, ConversationFilter.include items typed as Literal["im", "mpim", "private", "public"]. mypy / pyright now reject misspellings at type-check time. (#190, #191)
  • @overload on Text.to_text so the return type narrows to Text when allow_none=False (the default), and to Text | None when allow_none=True. (#192, #193)
  • Internal slackblocks/_core.py module providing a shared Resolvable protocol, recursive resolve() walker, and omit_none() helper. The walker structurally eliminates the entire class of bugs that produced eight Phase 1 P0 fixes (forgotten ._resolve() calls on nested objects). (#174, #175)

Changed

  • Minimum Python version raised to 3.10 (was 3.8.1). Bump version to 2.0.0.dev0. (#168, #169)
  • Tooling migrated from black + flake8 + flake8-pyproject to ruff for both linting and formatting. Workflow files renamed (formatting.yml -> ruff-format.yml, linting.yml -> ruff-lint.yml); CI job names updated to Ruff Format and Ruff Lint. Branch protection required-status-check list updated correspondingly. (#162, #163)
  • Additional ruff rule families enabled: B (bugbear), I (isort), SIM (simplify), TC (type-checking), UP (pyupgrade) on top of the baseline E, F, W. (#172, #173)
  • _resolve() methods refactored across the entire library to use the central resolve() / omit_none() helpers from _core.py. The diff is internal — public API and JSON output are byte-identical — but the per-class boilerplate is dramatically reduced. (#176-#185)
  • Shared RenderableMixin factored out of the five abstract base classes (Block, Element, CompositionObject, RichTextElement, RichTextObject) which previously each defined their own copy of __repr__. (#188, #189)
  • _MessagePayloadMixin factored out of BaseMessage and WebhookMessage to dedupe the to_dict / json / __repr__ / __getitem__ / keys payload helpers. (#186, #187)
  • Rich-text style emission deduplicated via a private _style_dict() helper; the same 8-line block previously appeared in 5 classes. (#182, #183)
  • Renamed text_basic_file_block test (typo, never collected by pytest) to test_basic_file_block. (#156, #157)

Fixed

19 P0 correctness bugs found in the audit before 2.0 development began, each in its own focused PR. The most impactful:

  • Confirm.__init__ was brokensuper(*args, **kwargs) (missing parens) raised TypeError on every invocation. (#126, #127)
  • Eight _resolve() methods forgot to recurse into nested objects, causing json.dumps to raise TypeError for any caller exercising the affected fields: Image.slack_file (#130, #131), URLInput.placeholder (#132, #133), TimePicker.confirm (#134, #137), DatePicker (confirm + missing initial_date) (#135, #138), DateTimePicker (confirm + missing initial_datetime) (#136, #139), ConversationSelectMenu.filter (#140, #141), RichTextInput.dispatch_action_config and placeholder (#142, #143).
  • ConversationMultiSelectMenu typo'd JSON key "intial_conversations" (Slack silently ignored it). (#144, #145)
  • NumberInput dropped min_value=0 / max_value=0 via truthy checks, plus a typo'd error message that referenced min_value twice. (#146, #147)
  • StaticSelectMenu raised UnboundLocalError when neither options nor option_groups was provided. (#150, #151)
  • FileBlock required an explicit block_id instead of synthesising one. (#152, #153)
  • FileInput and SlackFile were missing from the top-level package exports. (#154, #155)
  • validate_int max-value error message said "less than the minimum" (copy-paste bug from the min-value branch). (#120, #121)
  • validate_string_nonnull truthy min_length / max_length checks silently dropped explicit 0 values. (#122, #123)
  • validate_string and validate_string_nonnull had inconsistent positional argument order. (#124, #125)
  • DispatchActionConfiguration.__init__ did not call super().__init__, so self.type was unset. (#128, #129)
  • option_groups flattening used quadratic sum([list], []) instead of itertools.chain.from_iterable. (#148, #149)
  • mypy was failing on master because DatePicker.initial_date was inferred as str (from the if branch) and conflicted with the None in the else branch. (#158, #160)
  • black was failing on master in test_elements.py after a multi-line Option(...) invocation. (#159, #161)

Removed

  • Removed black, flake8, flake8-pyproject dev dependencies (replaced by ruff). (#162, #163)
  • Removed Python 3.8 and 3.9 from the supported versions and the CI matrix. (#168, #169)
  • Removed Slack-API-URL # noqa: E501 comments inside docstrings (ruff correctly does not honour them since they are within string literals, not real code comments). (#162, #163)

[1.2.5] — 2026-05-10

Last release of the 1.x line. Patch release; no functional changes.

Earlier releases

For 1.x and 0.x release history, see the Git tag history.