# NousResearch/hermes-agent · Config option for reasoning output display format

## Open now

- Nothing open on GitHub.

These members add a configurable option to control how reasoning output is displayed, with at least one implementation rendering it as subtext in Discord. The work covers both the config option design and specific rendering style variants.

## TL;DR

- 3 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 1 PR(s) closed without merging.
- A fix was merged to main in PR #51168. Verify it addresses your case.
- **Recommended:** read PR #51168 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `unresolved`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.67`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #25574: Add display.reasoning_format config option (code vs quote)

## Prior & competing PRs

- **#51168: feat(discord): render reasoning as -# subtext via display.reasoning_style**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `gateway/display_config.py`, `gateway/run.py`, `hermes_cli/config.py`, `tests/gateway/test_display_config.py`
  - fix hunks:
  - `gateway/display_config.py`

    ```diff
    @@ -34,6 +34,12 @@
         "tool_progress": "all",
         "tool_progress_grouping": "accumulate",  # "accumulate" = edit one bubble; "separate" = one msg per tool
         "show_reasoning": False,
    +    # How a reasoning/thinking summary is rendered when show_reasoning is on.
    +    #   "code"      -> 💭 **Reasoning:** + fenced code block (legacy default)
    +    #   "blockquote"-> each line prefixed with "> "
    +    #   "subtext"   -> each line prefixed with "-# " (Discord small grey subtext)
    +    # Discord defaults to "subtext"; everywhere else defaults to "code".
    +    "reasoning_style": "code",
         "tool_preview_length": 0,
         "streaming": None,  # None = follow top-level streaming config
         # Gateway-only assistant/status chatter controls. These default on for
    ```

    ```diff
    @@ -111,7 +117,10 @@
             "tool_progress": "off",
             "busy_ack_detail": False,
         },
    -    "discord":     _TIER_HIGH,
    +    # Discord has a native "subtext" primitive (-# small grey text) that reads
    +    # as metadata rather than content, so reasoning summaries default to it
    +    # here instead of the fenced code block used elsewhere.
    +    "discord":     {**_TIER_HIGH, "reasoning_style": "subtext"},
     
         # Tier 2 — edit support, often customer/workspace channels
         # Slack: tool_progress off by default — Bolt posts cannot be edited like CLI;
    ```

    ```diff
    @@ -242,6 +251,9 @@ def _normalise(setting: str, value: Any) -> Any:
         if setting == "tool_progress_grouping":
             val = str(value).lower()
             return val if val in ("accumulate", "separate") else "accumulate"
    +    if setting == "reasoning_style":
    +        val = str(value).lower()
    +        return val if val in ("code", "blockquote", "subtext") else "code"
         if setting == "tool_preview_length":
             try:
                 return int(value)
    ```
  - `gateway/run.py`

    ```diff
    @@ -9727,7 +9727,31 @@ async def _handle_message_with_agent(self, event, source, _quick_key: str, run_g
                             display_reasoning += f"\n_... ({len(lines) - 15} more lines)_"
                         else:
                             display_reasoning = last_reasoning.strip()
    -                    response = f"💭 **Reasoning:**\n```\n{display_reasoning}\n```\n\n{response}"
    +                    # Render style is per-platform: Discord defaults to "-# "
    +                    # subtext (native small grey metadata text); other
    +                    # platforms keep the fenced code block.
    +                    try:
    +                        from gateway.display_config import resolve_display_setting
    +                        _reasoning_style = resolve_display_setting(
    +                            _load_gateway_config(),
    +                            _platform_config_key(source.platform),
    +                            "reasoning_style",
    +                            "code",
    +                        )
    +                    except Exception:
    +                        _reasoning_style = "code"
    +                    if _reasoning_style == "subtext":
    +                        _quoted = "\n".join(
    +                            f"-# {ln}" if ln else "-#" for ln in display_reasoning.splitlines()
    +                        )
    +                        response = f"-# 💭 Reasoning\n{_quoted}\n\n{response}"
    +                    elif _reasoning_style == "blockquote":
    +                        _quoted = "\n".join(
    +                            f"> {ln}" if ln else ">" for ln in display_reasoning.splitlines()
    +                        )
    +                        response = f"> 💭 **Reasoning:**\n{_quoted}\n\n{response}"
    +                    else:
    +                        response = f"💭 **Reasoning:**\n```\n{display_reasoning}\n```\n\n{response}"
     
                 # Runtime-metadata footer — only on the FINAL message of the turn.
                 # Off by default (display.runtime_footer.enabled=false).  When
    ```
  - `hermes_cli/config.py`

    ```diff
    @@ -1667,6 +1667,12 @@ def _ensure_hermes_home_managed(home: Path):
             # applies where tool_progress is already enabled. Per-platform override
             # via display.platforms.<platform>.tool_progress_grouping.
             "tool_progress_grouping": "accumulate",
    +        # How a reasoning/thinking summary renders when show_reasoning is on.
    +        # "code" (default) = 💭 fenced code block; "blockquote" = "> " lines;
    +        # "subtext" = "-# " lines (Discord small grey metadata text). Discord
    +        # defaults to "subtext"; override per-platform via
    +        # display.platforms.<platform>.reasoning_style.
    +        "reasoning_style": "code",
             # Auto-delete system-notice replies (e.g. "✨ New session started!",
             # "♻ Restarting gateway…", "⚡ Stopped…") after N seconds on platforms
             # that support message deletion (currently Telegram; other platforms
    ```
  - `tests/gateway/test_display_config.py`

    ```diff
    @@ -510,3 +510,48 @@ def test_case_insensitive(self):
                 resolve_display_setting(config, "telegram", "tool_progress_grouping")
                 == "separate"
             )
    +
    +
    +class TestReasoningStyle:
    +    """Per-platform reasoning render style (code | blockquote | subtext)."""
    +
    +    def test_discord_defaults_to_subtext(self):
    +        from gateway.display_config import resolve_display_setting
    +
    +        assert resolve_display_setting({}, "discord", "reasoning_style") == "subtext"
    +
    +    def test_other_platforms_default_to_code(self):
    +        from gateway.display_config import resolve_display_setting
    +
    +        for plat in ("telegram", "slack", "matrix", "api_server"):
    +            assert (
    +                resolve_display_setting({}, plat, "reasoning_style") == "code"
    +            ), plat
    +
    +    def test_platform_override_wins(self):
    +        from gateway.display_config import resolve_display_setting
    +
    +        config = {"display": {"platforms": {"discord": {"reasoning_style": "blockquote"}}}}
    +        assert (
    +            resolve_display_setting(config, "discord", "reasoning_style") == "blockquote"
    +        )
    +
    +    def test_global_override(self):
    +        from gateway.display_config import resolve_display_setting
    +
    +        config = {"display": {"reasoning_style": "subtext"}}
    +        assert (
    +            resolve_display_setting(config, "telegram", "reasoning_style") == "subtext"
    +        )
    +
    +    def test_invalid_value_falls_back_to_code(self):
    +        from gateway.display_config import resolve_display_setting
    +
    +        config = {"display": {"reasoning_style": "bogus"}}
    +        assert resolve_display_setting(config, "telegram", "reasoning_style") == "code"
    +
    +    def test_case_insensitive(self):
    +        from gateway.display_config import resolve_display_setting
    +
    +        config = {"display": {"reasoning_style": "SUBTEXT"}}
    +        assert resolve_display_setting(config, "telegram", "reasoning_style") == "subtext"
    ```
- **#25933: feat(display): add reasoning_format config option for reasoning output style (#25574)**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `6cc07b6cd0344e63340aa003a5e90a5bdefe14c0`, `#51168`, `#25574`

## Fix status

- Merged to main in PR #51168 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-06-23`.
- Subsystem: `gateway`
