hermes - ✅(Solved) Fix Markdown tables rendered via display.final_response_markdown: render lack cell borders [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#28714Fetched 2026-05-20 04:02:21
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Author
Participants
Timeline (top)
labeled ×3cross-referenced ×1

With display.final_response_markdown: render and display.streaming: false configured, markdown tables are rendered via rich.markdown.Markdown instead of showing raw source code. However, the rendered tables have NO vertical cell borders — only a single horizontal line under the header. This makes tables hard to read.

Root Cause

Hermes delegates table rendering to rich.markdown.Markdown. Inside Rich's TableElement.__rich_console__() (in markdown.py), the table is created with box=box.SIMPLE, which draws only horizontal lines ─ without any vertical column dividers (│, ┼, etc.).

The relevant code in Rich:

table = Table(
    box=box.SIMPLE,       # <-- no vertical cell borders
    pad_edge=False,
    ...
)

Fix Action

Workaround

Manually patch the Rich library inside Hermes' venv:

# File: ~/.hermes/hermes-agent/venv/lib/python3.11/site-packages/rich/markdown.py
# Change:
#   box=box.SIMPLE,
# To:
#   box=box.HEAVY,

With box.HEAVY, tables render with full borders (┏━┳━┓ / ┃ ┃ / ┣━╋━┫ / ┗━┻━┛). But this workaround is fragile — it gets lost on Hermes update or venv rebuild, and users shouldn't have to hack third-party library code.

PR fix notes

PR #28735: fix(cli): render markdown tables with visible column borders (#28714)

Description (problem / solution / changelog)

What does this PR do?

Upstream rich.markdown.Markdown (v14.x) hard-codes box=box.SIMPLE inside TableElement.__rich_console__, so when display.final_response_markdown: render is enabled, Hermes draws markdown tables with only a header underline — no vertical column dividers. On any multi-column data this collapses into an unreadable wall of text, forcing users to hand-edit the vendored Rich source inside ~/.hermes/.../venv/lib/python3.11/site-packages/rich/markdown.py to recover sane output (a hack that gets blown away on every upgrade or venv rebuild).

This PR fixes that without touching the third-party library:

  • Subclass rich.markdown.Markdown with a TableElement whose box= argument is resolved from display.markdown_table_box_style at render time (so /reload-config and tests pick up changes without rebuilding the class).
  • Default to heavy_head — heavy header rule + light cell borders. This adds the missing vertical dividers while preserving the visual hierarchy of the old SIMPLE style.
  • Accept any Rich box constant name (case-insensitive, whitespace-tolerated). Unknown / blank / non-string values fall back to the default rather than silently regressing to borderless output.
  • Setting markdown_table_box_style: simple restores the pre-PR borderless behaviour for operators who prefer it.

Related Issue

Fixes #28714

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • cli.py — Introduce _resolve_markdown_table_box(), _get_hermes_bordered_markdown_cls() (lazy, cached), and a _HermesBorderedTableElement / _HermesBorderedMarkdown pair that mirror upstream Rich line-for-line except for the configurable box= argument. Switch _render_final_assistant_content() to use the new class.
  • hermes_cli/config.py — Register display.markdown_table_box_style: heavy_head as the new default.
  • cli-config.yaml.example — Document the new key (and the long-undocumented final_response_markdown neighbour) so operators find it via the canonical commented example.
  • website/docs/user-guide/cli.md — Add a one-paragraph user-guide note next to the existing "markdown stripping" guidance.
  • tests/cli/test_cli_markdown_rendering.py — 18 new tests covering: default-bordered rendering, the simple opt-out, unknown-value fallback, empty/None values, case-insensitive box name lookup, the documented bordered-style allowlist (heavy, heavy_head, square, rounded, double), Markdown subclass identity, lazy caching, and the contract that only table_open is overridden (so future Rich element additions aren't silently shadowed).

How to Test

  1. Set in ~/.hermes/config.yaml:
    display:
      streaming: false
      final_response_markdown: render
  2. Restart Hermes CLI.
  3. Ask the agent to output a markdown table, e.g. "Show me a table with columns Module/Status/Priority".
  4. Observe vertical column dividers between every cell ( under the header, elsewhere). Previously this would render as a single header rule with no column dividers.
  5. To verify the opt-out: add display.markdown_table_box_style: simple, restart, repeat — the legacy borderless layout returns.
  6. To verify unknown-value safety: set display.markdown_table_box_style: not-a-real-style — the CLI must not crash, and tables must still render with dividers.

Automated coverage:

scripts/run_tests.sh tests/cli/test_cli_markdown_rendering.py -q
# 32 passed (14 existing + 18 new) in 1.5s

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(cli):, test(cli):, docs(cli):, docs(config):)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix (no unrelated commits)
  • I've run the relevant test suite locally and it passes
  • I've added tests for my changes (18 new regression tests)
  • Tested on my platform: macOS 15.2 (Darwin 24.6.0)

Documentation & Housekeeping

  • I've updated relevant documentation (website/docs/user-guide/cli.md)
  • I've updated cli-config.yaml.example with the new config key
  • N/A — no architecture or workflow changes
  • N/A — pure terminal-output change, identical on every platform
  • N/A — no tool descriptions / schemas changed

Screenshots / Logs

Before (default config, final_response_markdown: render):

           ──────────────────────
   Module     Status     Priority
           ──────────────────────
  User Mgmt    Done        P0
  Role Mgmt    Done        P0

After (default config, same input):

┏━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┓
┃ Module    ┃ Status ┃ Priority ┃
┡━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━┩
│ User Mgmt │ Done   │ P0       │
│ Role Mgmt │ Done   │ P0       │
└───────────┴────────┴──────────┘

Opt out (display.markdown_table_box_style: simple) — legacy behaviour preserved verbatim.

Changed files

  • cli-config.yaml.example (modified, +20/-0)
  • cli.py (modified, +96/-2)
  • hermes_cli/config.py (modified, +9/-0)
  • tests/cli/test_cli_markdown_rendering.py (modified, +210/-3)
  • website/docs/user-guide/cli.md (modified, +2/-0)

Code Example

display:
     streaming: false
     final_response_markdown: render

---

──────────────────────
   Module     Status     Priority
           ──────────────────────
  User Mgmt    Done        P0
  Role Mgmt    Done        P0

---

table = Table(
    box=box.SIMPLE,       # <-- no vertical cell borders
    pad_edge=False,
    ...
)

---

# File: ~/.hermes/hermes-agent/venv/lib/python3.11/site-packages/rich/markdown.py
# Change:
#   box=box.SIMPLE,
# To:
#   box=box.HEAVY,
RAW_BUFFERClick to expand / collapse

Description

With display.final_response_markdown: render and display.streaming: false configured, markdown tables are rendered via rich.markdown.Markdown instead of showing raw source code. However, the rendered tables have NO vertical cell borders — only a single horizontal line under the header. This makes tables hard to read.

Steps to Reproduce

  1. Set in config.yaml:
    display:
      streaming: false
      final_response_markdown: render
  2. Restart Hermes CLI (or start a new session)
  3. Ask the agent to output a markdown table
  4. Observe: the table shows only a horizontal rule under the header, no column dividers

Actual Result

The table looks like this (conceptually):

           ──────────────────────
   Module     Status     Priority
           ──────────────────────
  User Mgmt    Done        P0
  Role Mgmt    Done        P0

No vertical separators between columns.

Root Cause

Hermes delegates table rendering to rich.markdown.Markdown. Inside Rich's TableElement.__rich_console__() (in markdown.py), the table is created with box=box.SIMPLE, which draws only horizontal lines ─ without any vertical column dividers (│, ┼, etc.).

The relevant code in Rich:

table = Table(
    box=box.SIMPLE,       # <-- no vertical cell borders
    pad_edge=False,
    ...
)

Workaround

Manually patch the Rich library inside Hermes' venv:

# File: ~/.hermes/hermes-agent/venv/lib/python3.11/site-packages/rich/markdown.py
# Change:
#   box=box.SIMPLE,
# To:
#   box=box.HEAVY,

With box.HEAVY, tables render with full borders (┏━┳━┓ / ┃ ┃ / ┣━╋━┫ / ┗━┻━┛). But this workaround is fragile — it gets lost on Hermes update or venv rebuild, and users shouldn't have to hack third-party library code.

Expected Behavior

Hermes should produce readable markdown tables without requiring users to patch Rich directly. Options include:

  1. Use a custom Markdown renderer or monkey-patch Rich's TableElement at Hermes startup to use a box style with column dividers (e.g. box.HEAVY or box.SQUARE)
  2. Add a config option like display.markdown_table_box_style to let users choose the border style
  3. At minimum, document that users need to patch Rich's markdown.py

Environment

  • Hermes Agent v0.14.0 (2026.5.19)
  • Python 3.11.15
  • WSL2 + Windows Terminal
  • Rich (version bundled in Hermes venv)

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix Markdown tables rendered via display.final_response_markdown: render lack cell borders [1 pull requests, 1 participants]