I ran into this while building a chat UI against Hermes Agent, Nous Research’s self-hosted agent gateway. Replies over its HTTP API came back as plain text with bare URLs – no **bold**, no ## headings, no [label](url) – even though my UI renders Markdown. The same agent formats answers with Markdown when used from Slack.

The reason why is that Hermes injects a per-platform hint into the system prompt depending on which platform adapter you connect through. Here is a short snippet from agent/system_prompt.py that quotes the code in question directly:

python
platform_key = (agent.platform or "").lower().strip()
if platform_key in PLATFORM_HINTS:
    stable_parts.append(PLATFORM_HINTS[platform_key])

The hint for the api_server platform – the HTTP API – explicitly tells the model not to use Markdown. From PLATFORM_HINTS in agent/prompt_builder.py:

You’re responding through an API server. The rendering layer is unknown — assume plain text. No markdown formatting (no asterisks, bullets, headers, code fences). Treat this like a conversation, not a document. Keep responses brief and natural.

The slack hint carries no such restriction (Slack renders its own markup and auto-links URLs), and the webui hint is the opposite:

Full Markdown rendering is supported – headings, bold, italic, code blocks, tables, math (LaTeX), and Mermaid diagrams all render natively.

So the platform you connect as changes the model’s output. Same model, same prompt, same question – but Slack, the web UI, and the HTTP API each get a different formatting contract injected into the system prompt, so they answer in different shapes. The flat prose, the bare URLs, and the brevity I was seeing were all the gateway doing what the api_server hint told it to do.

Getting Markdown back#

Making the API respond with Markdown ended being pretty simple in the end – all that was needed was to pass an instructions (or system_message) field in the chat request, which is then added to the prompt in a later block than the platform hint. From gateway/platforms/api_server.py:

python
system_prompt = body.get("system_message") or body.get("instructions")

Here is what I ended up sending alongside the question:

Your reply is rendered as GitHub-Flavored Markdown – use bold, ## headings, tables, and [label](url) links (never bare URLs). Disregard any earlier instruction to assume a plain-text renderer.

That field lands after the api_server “no markdown” hint, and the model honours the later instruction: a test query came back as a Markdown table with bold text and [label](url) links. Whether a later instruction wins over the earlier “no markdown” directive is a model-precedence question that you can’t settle by reading the source, so I confirmed it with one live request rather than guessing.

Notes#

  • The HTTP API gets the most conservative formatting defaults, by design: the gateway can’t see your client, so it assumes the rendering layer is unknown. On the raw API you are effectively the platform adapter, and declaring your client’s capabilities through instructions is the supported way to do it – the same thing the built-in Slack and Discord adapters do internally.
  • In the chat body, body.get("message") or body.get("input") is the user message, and body.get("system_message") or body.get("instructions") is the system overlay. Session creation (POST /api/sessions) separately accepts system_prompt and model.

Further reading#