Matrix cron delivery missing HTML/markdown formatting
NousResearch/hermes-agent · cluster 5233 · cron
Data as of
Nothing open on GitHub. Fix merged in #38649. Check it covers your case.
The short answer
- Known?
- Yes. 5 related items grouped here, 2 issues already closed.
- Fix event
- A fix was merged to main in PR #38649. Check it covers your case. No release data is tracked.
- Tracker
- The maintainers' tracker marks this
partially resolved, deciding PR #38649. That is separate from the fix event. - Still open
- Nothing open on GitHub.
A cluster of bug reports and fixes addressing Matrix notifications sent as plain text without formatted_body or markdown rendering, traced to a missing markdown dependency in the default Docker image.
Open issues0
Open PRs0
Fixes on record
-
#38649 fix(deps): promote markdown to a core dependency so rich delivery works out of the box (#32486)
files:
gateway/platforms/matrix.py,pyproject.toml,tools/lazy_deps.pyShow the diff
-
gateway/platforms/matrix.py@@ -2799,11 +2799,11 @@ def _mxc_to_http(self, mxc_url: str) -> str: def _markdown_to_html(self, text: str) -> str: """Convert Markdown to Matrix-compatible HTML (org.matrix.custom.html). - Uses the ``markdown`` library when available (installed with the - ``matrix`` extra). Falls back to a comprehensive regex converter - that handles fenced code blocks, inline code, headers, bold, - italic, strikethrough, links, blockquotes, lists, and horizontal - rules — everything the Matrix HTML spec allows. + Uses the ``markdown`` library (a core dependency) when available. + Falls back to a comprehensive regex converter that handles fenced + code blocks, inline code, headers, bold, italic, strikethrough, + links, blockquotes, lists, and horizontal rules — everything the + Matrix HTML spec allows. """ try: import markdown as _md -
pyproject.toml@@ -61,6 +61,16 @@ dependencies = [ "prompt_toolkit==3.0.52", # Cron scheduler (built-in feature — scheduled cron/interval jobs use croniter). "croniter==6.0.0", + # Markdown -> HTML conversion for rich message delivery (Matrix + # `formatted_body`, and the `send_message` tool's HTML path). Now on the + # DEFAULT delivery path, not matrix-specific: without it both + # gateway/platforms/matrix.py and tools/send_message_tool.py silently fall + # back to plain text, so cron/agent deliveries render raw `##`/`**`/tables + # in clients like Element (see #32486). Pure-Python py3-none-any wheel + # (~108KB, no compiled extensions, no platform constraints), so unlike the + # matrix extra's `mautrix`/`python-olm` it's safe to ship everywhere — keeps + # it out of the lazy-install path that exists only for the heavy matrix deps. + "Markdown==3.10.2", # Skills Hub (GitHub App JWT auth — optional, only needed for bot identity) "PyJWT[crypto]==2.12.1", # CVE-2026-32597 # Windows has no IANA tzdata shipped with the OS, so Python's ``zoneinfo`` @@ -104,7 +114,7 @@ dev = ["debugpy==1.8.20", "pytest==9.0.2", "pytest-asyncio==1.3.0", "pytest-time messaging = ["python-telegram-bot[webhooks]==22.6", "discord.py[voice]==2.7.1", "aiohttp==3.13.3", "brotlicffi==1.2.0.1", "slack-bolt==1.27.0", "slack-sdk==3.40.1", "qrcode==7.4.2"] cron = [] # croniter is now a core dependency; this extra kept for back-compat slack = ["slack-bolt==1.27.0", "slack-sdk==3.40.1", "aiohttp==3.13.3"] -matrix = ["mautrix[encryption]==0.21.0", "Markdown==3.10.2", "aiosqlite==0.22.1", "asyncpg==0.31.0", "aiohttp-socks==0.11.0"] +matrix = ["mautrix[encryption]==0.21.0", "aiosqlite==0.22.1", "asyncpg==0.31.0", "aiohttp-socks==0.11.0"] # WeCom callback-mode adapter — parses untrusted XML POST bodies from # WeCom-controlled callback endpoints, so we use defusedxml (drop-in # replacement for stdlib xml.etree.ElementTree) to block billion-laughs -
tools/lazy_deps.py@@ -135,7 +135,6 @@ ), "platform.matrix": ( "mautrix[encryption]==0.21.0", - "Markdown==3.10.2", "aiosqlite==0.22.1", "asyncpg==0.31.0", "aiohttp-socks==0.11.0", -
uv.lock@@ -1398,6 +1398,7 @@ dependencies = [ { name = "fire" }, { name = "httpx", extra = ["socks"] }, { name = "jinja2" }, + { name = "markdown" }, { name = "openai" }, { name = "pathspec" }, { name = "prompt-toolkit" }, @@ -1509,7 +1510,6 @@ matrix = [ { name = "aiohttp-socks" }, { name = "aiosqlite" }, { name = "asyncpg" }, - { name = "markdown" }, { name = "mautrix", extra = ["encryption"] }, ] mcp = [ @@ -1647,7 +1647,7 @@ requires-dist = [ { name = "httpx", extras = ["socks"], specifier = "==0.28.1" }, { name = "jinja2", specifier = "==3.1.6" }, { name = "lark-oapi", marker = "extra == 'feishu'", specifier = "==1.5.3" }, - { name = "markdown", marker = "extra == 'matrix'", specifier = "==3.10.2" }, + { name = "markdown", specifier = "==3.10.2" }, { name = "mautrix", extras = ["encryption"], marker = "extra == 'matrix'", specifier = "==0.21.0" }, { name = "mcp", marker = "extra == 'computer-use'", specifier = "==1.26.0" }, { name = "mcp", marker = "extra == 'dev'", specifier = "==1.26.0" },
-
2 PRs closed without merging
From the close comments: stale or abandoned 1 · other 1
Closed issues · 2
How this cluster was grouped
-
Link evidence (
partly structural links): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text. - Members outside that structural core may belong to a different underlying problem.
-
Pairwise link density
0.34: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36.1.00means every pair is linked.
Pick up a Lab task
Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.
Open the LabAt a glance
- Subsystem
- cron
- Merged PRs
- #38649
- Closed issues
- 2
- Attempts
- 2 PRs closed without merging
- Fix link checked
- 4 Jun 2026