🤖 feat: sticky table of contents next to plans in chat transcript#3380
Conversation
Adds a sticky 'Contents' navigation alongside propose_plan tool cards in the chat transcript when the chat pane has enough horizontal room. Click any entry to jump to that section in the plan; the TOC follows the user while the plan is on screen and scrolls away naturally once the plan exits the viewport. Visibility is CSS-only (a container query on the transcript scrollport plus an opt-in class), so toggling the plan tool expanded/collapsed never produces a layout flash. The transcript scroll container is a named CSS container, so the gate tracks actual chat-pane width and stays correct when sidebars open or close.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2d410d17b2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- Promote the plan title to be the TOC's heading instead of a static "CONTENTS" label plus a separate h1 list entry. Saves vertical space and tightens the visual hierarchy: the title sits at column 0, h2 entries align flush with it, and h3+ get a small indent step per level. - Filter h1 entries out of the navigation list since they're represented by the heading. h1 still consumes a renderIndex so DOM lookups stay aligned. - When the plan markdown contains an h1, the TOC heading becomes a button that scrolls to that h1 (the natural "top of plan" target). With no h1, the heading is a static label. - Reduce indent steps from 10/20/30px to 6/12/18px to keep the TOC usable in the narrow left-gutter column. - Drop the uppercase/letter-spaced eyebrow styling on the heading since real plan titles are sentences, not labels.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9b70cd43d2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Updated the plan TOC layout and fixed the indented ATX heading renderIndex drift from the previous review. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 42205bce7c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Updated the TOC to stay in the existing gutter without shifting the plan, widened/wrapped the nav to avoid unnecessary ellipses, and addressed the extractor comments for indented ATX headings plus ordered-list/setext drift. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0817d55127
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Updated TOC gutter layout per latest design feedback (no plan displacement, centered gutter nav, thinner hint) and fixed container-prefixed heading index alignment. |
|
@codex review Addressed the latest extractor feedback: setext underlines now preserve indentation so four-space code lines do not create phantom headings, and container-prefixed/blockquoted headings are counted for renderIndex alignment. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f54f01bb48
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Addressed the HTML edge cases: raw HTML block lines are excluded from setext detection, and empty raw HTML headings now still consume renderIndex for navigation alignment. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ebfda4820d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Pushed the final visual update: the full TOC stays centered in the gutter and the constrained-width indicator is now plain informational text instead of button-like chrome. |
|
@codex review Addressed the raw HTML block feedback: extraction now tracks CommonMark-style raw HTML block context and skips markdown-looking headings inside those blocks while still counting standalone raw h1-h6 headings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7286841a5d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Addressed nested raw HTML headings as well: standalone h1-h6 tags are counted even while inside raw HTML block context, so later renderIndex values stay aligned. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a9206c1f5b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Addressed script/style raw HTML handling: nested h1-h6 tags are counted only for raw HTML blocks whose rendered content can contribute headings, while script/style/pre/comment-like blocks continue to suppress heading counting. |
|
@codex review No unresolved Codex threads remain; pushed an empty commit to rerun the failing Codex Comments check after resolving the stale parser-review threads. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0d97834972
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Addressed raw HTML allowlist parity: raw HTML heading extraction now uses the same rawHtmlUsesOnlyAllowedTags guard as MarkdownCore, so unsupported raw blocks are treated as text and do not affect TOC entries or renderIndex. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d803b2ef94
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Addressed inline-token raw HTML headings: inline token children are reconstructed when they contain raw HTML so paragraph/list inline |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1ab11202cc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Addressed both findings: inline reconstruction now ignores code_inline/non-HTML content while preserving text inside actual HTML tags, and the full TOC breakpoint now waits until the gutter can contain the 13rem rail without clipping. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a04e419d36
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Addressed both latest findings: the full TOC now reveals at 82rem so the 13rem gutter rail fits, and inline HTML reconstruction tracks nested tags so text after inner tags remains in the TOC label. |
|
Codex Review: Didn't find any major issues. Delightful! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review Polished the TOC reveal threshold, compact hint spacing, and title tint per design feedback. |
|
Codex Review: Didn't find any major issues. Keep it up! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review Adjusted the ToC breakpoint/gutter so the full ToC is visible in the 1600px wide Storybook story, and fixed the story copy to say left gutter. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f8a2acccea
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Fixed the Storybook/Chromatic mismatch: the ToC story now pins an explicit wide Chromatic viewport, asserts the full ToC is visible under Chromatic/wide runtime, and has a unit contract so future responsive snapshot stories do not silently capture the wrong UI. |
|
@codex review Addressed the raw HTML |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ae88d5e31e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Addressed the implicit-close raw HTML heading comment by scanning opening h1-h6 tags and stopping at explicit closes, block boundaries, or the next heading tag. Added regression coverage for unclosed headings and adjacent raw HTML headings. |
Summary
Renders a sticky "Contents" navigation alongside
propose_plantool cards in the chat transcript when the chat pane has enough horizontal room. Clicking an entry jumps to the matching plan heading; the TOC follows the user while the plan is on screen, then scrolls away once the plan exits the viewport. Visibility is gated by a CSS container query on the transcript scrollport, so opening/closing sidebars and expanding/collapsing the plan tool never produce layout flash.Background
Long propose_plan outputs (multi-section refactor plans, rollout designs, etc.) can be hundreds of lines tall. Users had no way to jump between sections short of scrolling, and the centered
max-w-4xltranscript column wastes a large strip of horizontal space on wide monitors. This PR puts that unused right gutter to work as a navigation aid for the plan currently in view, without touching the markdown rendering of any other transcript content.Implementation
Heading source of truth: plan markdown, not the rendered DOM. A new
extractPlanHeadingshelper walks the plan source and emits one entry per heading (ATX, setext, or block-level raw HTML), skipping fenced code blocks so example markdown inside code samples never shows up in the TOC. Each entry stores arenderIndex— its position across all rendered<h1>..<h6>elements — so click handlers can locate the matching DOM node viacontainer.querySelectorAll("h1..h6")[renderIndex].scrollIntoView({ block: "start" })without forcing the shared Streamdown rehype pipeline to assign IDs to every heading in the chat.Layout: absolute aside + sticky inner nav. The plan card is wrapped in a
plan-toc-layoutpositioning context. The TOC<aside>is absolutely positioned to the right of that wrapper (inset: 0 auto 0 100%), so it breaks out of the centeredmax-w-4xlcolumn into the transcript's right gutter without changing the plan's own bounding box. Inside the aside, the<nav>isposition: stickyand bounded to the aside's vertical extent — that's what lets the TOC follow the user while the plan is on screen and then scroll away naturally with the plan.Visibility: CSS container query, no JS. The transcript scroll container becomes a named CSS container (
@container/transcript). The visibility rule fires only above78.5remof content-box width, which works out to roughly a 1440px viewport with mux's standard sidebars open. Container queries (rather than viewportmin-width) let the gate track actual chat-pane width, so opening or closing the project sidebar or right sidebar correctly hides or reveals the TOC. Theplan-toc-awareopt-in class is only set on the centered transcript column — full-width transcript mode is excluded so the TOC never gets clipped by the scroller'soverflow-x-hidden.Self-containment. The TOC only renders when the plan is in normal markdown mode (not annotate, raw-text, or error). Plans with fewer than two visible (h1–h4) headings render nothing. Deep h5/h6 headings are filtered from display but still consume
renderIndex, so DOM lookups stay aligned regardless of which levels we show.Validation
make static-check— clean (ESLint, both TypeScript projects, Prettier, docs links).extractPlanHeadings.test.ts— ATX / setext / raw HTML headings, fenced-code-block skipping, thematic-break disambiguation, inline-formatting stripping, mixed-contentrenderIndexalignment.PlanTableOfContents.test.tsx— short-list hiding, deep-heading filtering, click →scrollIntoViewwiring against a hand-rolled DOM (the dedicated component test is needed because sibling test files mockMarkdownCoreat file scope), and level normalization.ProposePlanToolCall.test.tsx— TOC content presence, hidden for short plans, hidden during annotate mode.ProposePlanWithTableOfContentsStorybook story:display: none, plan renders identically to before.Risks
Scoped to plan rendering and a single CSS container declaration on the chat scrollport. Risk surface:
showToc(markdown mode + ≥2 headings + non-error) and only renders insideProposePlanToolCall. Other tool calls and message types are unaffected.@container/transcriptto the scrollport is the only change visible outside the plan tool. There are no existing@container transcript (...)queries in the codebase that would unexpectedly match. The new visibility gate only matches the.plan-toc-aware .plan-toc-asideselector pair, which exists nowhere else.left: 100%would be clipped by the scroller'soverflow-x-hiddenand could create invisible focusable controls.Generated with
mux• Model:anthropic:claude-opus-4-7• Thinking:max• Cost:$29.54