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:
-
Export a function named normalizeConversationToMarkdown(capturePayload).
-
Preserve message order exactly as received in capturePayload.messages.
-
Add a metadata header containing:
- Title as H1
- Captured timestamp
- Source Platform
- Source URL
-
Use speaker boundaries:
- role: "user" → ## User
- role: "assistant" → ## Assistant
- role: "system" → ## System
- any unknown or missing role → ## Unknown
-
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.
-
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.
-
Escape or sanitize the title only as needed for Markdown safety.
- Remove excessive whitespace.
- If no title exists, use "ChatGPT Conversation".
-
If messages is empty or missing:
-
Still produce a valid Markdown file.
-
Include the metadata header.
-
Add:
Capture Notice
No conversation messages were detected.
-
-
Include capture errors if present:
-
If capturePayload.error exists, include:
Capture Error
-
-
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.