#23850·forem

Agent session embeds: transcript table-of-contents fragment links are dead (headings render without ids)

Author: seppegadeyneCreated Sep 18, 2026Updated Sep 29, 2026

Describe the bug

Agent session embeds render transcript headings without id attributes, so fragment links inside the embed are dead. Coding agents (Claude Code, Codex, Gemini CLI, ...) frequently emit a table of contents in their transcripts, e.g.:

markdown
## Intro

- [Astro vs WordPress: the practical comparison](#astro-vs-wordpress-the-practical-comparison)
- [Test editing before choosing the stack](#test-editing-before-choosing-the-stack)

Inside an {% agent_session %} embed every one of those links points at #<slug>, but no element in the page carries that id — the headings render as bare <h2>...</h2>. Clicking does nothing (or jumps the page). In a real writing-session transcript I embedded, 9 of 9 table-of-contents links were dead.

To Reproduce

  1. Upload an agent session whose assistant message contains a markdown table of contents with #slug fragment links plus matching ## headings (the format agents commonly generate).
  2. Embed it in an article: {% agent_session <id> %}.
  3. Open the article preview.
  4. Inspect the embed: the <h2> elements have no id and no anchor child; the TOC <a href="#..."> targets do not exist in the DOM.
  5. Click a TOC link: nothing navigates to the intended section.

Expected behavior

Either headings in agent session embeds get (scoped) ids so fragment links resolve within the embed, or links without a resolvable target degrade visibly. Ideally a click also expands collapsed long text (agent-session-text-collapse) and scrolls the embed's own .agent-session-scroll container instead of jumping the page.

Root cause

AgentSessionRenderers::MarkdownRenderer (app/services/agent_session_renderers/markdown_renderer.rb) uses Redcarpet::Render::HTML without heading ids, and the sanitizer whitelist (ALLOWED_ATTRS = %w[class href target rel]) would strip id even if the renderer emitted one. By contrast, article markdown goes through Redcarpet::Render::HTMLRouge#header which does slugify headings. Note the slug conventions differ: agent transcripts follow the GitHub convention (hyphens preserved, e.g. #work-through-a-small-business-example), while HTMLRouge's slugify strips punctuation including hyphens — so a fix should slug headings GitHub-style to match what agents actually generate.

Two additional considerations for a fix:

  • ids must be scoped per embed (e.g. agent-session-<id>-<slug>) so they cannot collide with article headings or with a second session embed on the same page;
  • the same heading text may repeat across messages of one session, which needs GitHub-style dedup suffixes (-2, -3).

Screenshots

Not applicable — pure DOM/behaviour issue, fully described above.

Desktop (please complete the following information):

  • OS, version: Arch Linux
  • Browser, version: Chrome 144

Smartphone (please complete the following information):

  • Device: n/a
  • OS, version: n/a
  • Browser, version: n/a

Additional context

Verified against current main (Forem revision with AgentSessionTag + MarkdownRenderer as shipped in the Agent Sessions feature, #22854). Related but different: #22703 covers cross-page anchor links; #4922 covers duplicate heading anchors in articles. Neither covers fragment links inside ltag-agent-session embeds.