Files
Project-Thoth/applications/chatgpt-capture/codex-work-orders/implementation/0004-markdown-normalizer.md
T

4.0 KiB

Implement Task 4 — Markdown Normalizer for the Project Thoth ChatGPT Capture Connector MVP.

Context:

  • Task 3 now returns a ChatGPT capture payload with:
    • sourcePlatform
    • title
    • url
    • capturedAt
    • messages[]
  • This task converts that extracted payload into canonical Project Thoth conversation.md format.
  • Capture Connectors still only capture and transmit source material.
  • Do not reason, summarize, classify, call LLMs, generate Project Thoth Source Metadata, generate Manifests, generate Harvests, or write to the vault.

Goal: Create a markdown normalization module that converts extracted ChatGPT messages into a single Markdown string.

Files to create or update:

  • src/markdownNormalizer.js
  • src/background.js only as needed to call the normalizer
  • README.md only if testing instructions need updating

Expected input shape:

{ sourcePlatform: "ChatGPT", title: "Detected conversation title", url: "https://chatgpt.com/...", capturedAt: "2026-07-08T...", messages: [ { role: "user", content: "..." }, { role: "assistant", content: "..." } ] }

Expected Markdown output format:

Conversation Title

Captured: 2026-07-08T15:30:00.000Z Source Platform: ChatGPT Source URL: https://chatgpt.com/...


User

Message content


Assistant

Message content


Requirements:

  1. Export a function named normalizeConversationToMarkdown(capturePayload).

  2. Preserve message order exactly as received in capturePayload.messages.

  3. Add a metadata header containing:

    • Title as H1
    • Captured timestamp
    • Source Platform
    • Source URL
  4. Use speaker boundaries:

    • role: "user" → ## User
    • role: "assistant" → ## Assistant
    • role: "system" → ## System
    • any unknown or missing role → ## Unknown
  5. Preserve message content as already extracted by the DOM extractor.

    • Do not summarize.
    • Do not rewrite.
    • Do not classify.
    • Do not run AI processing.
    • Do not alter code block contents.
  6. Normalize only structural Markdown concerns:

    • Trim leading/trailing whitespace from each message.
    • Ensure exactly one blank line after headings.
    • Ensure --- separators between messages.
    • Ensure final output ends with a newline.
    • Avoid excessive blank lines caused by extraction artifacts.
    • Do not collapse intentional line breaks inside code fences.
  7. Escape or sanitize the title only as needed for Markdown safety.

    • Remove excessive whitespace.
    • If no title exists, use "ChatGPT Conversation".
  8. If messages is empty or missing:

    • Still produce a valid Markdown file.

    • Include the metadata header.

    • Add:

      Capture Notice

      No conversation messages were detected.

  9. Include capture errors if present:

    • If capturePayload.error exists, include:

      Capture Error

  10. Keep the module generic enough that later connectors can reuse the same normalizer with other source platforms.

Suggested implementation:

export function normalizeConversationToMarkdown(capturePayload) { // validate payload // normalize title // write metadata header // write optional error // write messages in order // return markdown string }

Suggested helper functions:

  • normalizeTitle(title)
  • normalizeRoleHeading(role)
  • normalizeMessageContent(content)
  • collapseExcessBlankLinesOutsideCodeBlocks(text)

Integration:

  • In src/background.js, after receiving the capture payload from the content script, call normalizeConversationToMarkdown(payload).
  • For now, log the Markdown output or hold it for Task 5 download writing.
  • Do not implement the downloads API in this task unless it already exists from a previous step.

Acceptance criteria:

  • A valid Markdown string is produced from a normal ChatGPT capture payload.
  • Metadata header appears at the top.
  • Message order is preserved.
  • User and assistant sections are clearly separated.
  • Code blocks remain intact.
  • Empty captures produce a useful Markdown file with a Capture Notice.
  • No LLM calls.
  • No Project Thoth application dependency.
  • No vault writes.