Skill Tracer
Skills › Scientific Agent Skills › markitdown › migration.md

migration.md

368 lines · skills/markitdown/references/migration.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Migration and Release Notes
2
3This skill targets MarkItDown 0.1.8. The timeline below summarizes changes that affect user code and operational guidance.
4

Migration and Release Notes

This skill targets MarkItDown 0.1.8. The timeline below summarizes changes that affect user code and operational guidance.

Raw lines 1 to 4
5## Release Timeline
6

Release Timeline

Raw lines 5 to 6
7### 0.1.0 — March 22, 2025
8
9Major architecture release:
11- Optional dependency feature groups introduced
12- Plugin architecture introduced
13- Conversions moved to in-memory streams; temporary files removed
14- EPUB support added
15- CLI extension, MIME, and charset hints added
16- `--keep-data-uris` added
18Breaking changes:
20- Install `[all]` for behavior comparable to earlier all-in-one installs.
21- `convert_stream()` now requires a binary stream.
22- `DocumentConverter` implementations now receive binary streams plus `StreamInfo`, not file paths.

0.1.0 — March 22, 2025

Major architecture release:

  • Optional dependency feature groups introduced
  • Plugin architecture introduced
  • Conversions moved to in-memory streams; temporary files removed
  • EPUB support added
  • CLI extension, MIME, and charset hints added
  • --keep-data-uris added

Breaking changes:

  • Install [all] for behavior comparable to earlier all-in-one installs.
  • convert_stream() now requires a binary stream.
  • DocumentConverter implementations now receive binary streams plus StreamInfo, not file paths.
Raw lines 7 to 23
24### 0.1.1 — March 25, 2025
26- `convert_url()` renamed to `convert_uri()`.
27- `file:` and `data:` URI handling added.
28- `convert_url()` retained as a compatibility alias.

0.1.1 — March 25, 2025

  • convert_url() renamed to convert_uri().
  • file: and data: URI handling added.
  • convert_url() retained as a compatibility alias.
Raw lines 24 to 29
30### 0.1.2 — May 28, 2025
32- DOCX math-equation rendering
33- Dedicated CSV-to-Markdown conversion
34- XML/OMML parsing switched to `defusedxml`
35- Document Intelligence credential/API-version improvements
36- Streamable HTTP MCP support
37- YouTube transcript fixes
38- Python requirement updated to 3.10+

0.1.2 — May 28, 2025

  • DOCX math-equation rendering
  • Dedicated CSV-to-Markdown conversion
  • XML/OMML parsing switched to defusedxml
  • Document Intelligence credential/API-version improvements
  • Streamable HTTP MCP support
  • YouTube transcript fixes
  • Python requirement updated to 3.10+
Raw lines 30 to 39
Uses an outside tool MCP :36
40### 0.1.3 — August 26, 2025
42- Safer ExifTool handling, requiring version 12.24 or later
43- MCP plugin enablement through `MARKITDOWN_ENABLE_PLUGINS`
44- DOCX linked-image fixes
45- Document Intelligence HTML type handling
46- Custom LLM prompt forwarding fix
47- Additional HTML/PPTX robustness

0.1.3 — August 26, 2025

  • Safer ExifTool handling, requiring version 12.24 or later
  • MCP plugin enablement through MARKITDOWN_ENABLE_PLUGINS
  • DOCX linked-image fixes
  • Document Intelligence HTML type handling
  • Custom LLM prompt forwarding fix
  • Additional HTML/PPTX robustness
Raw lines 40 to 48
Uses an outside tool MCP :43
49### 0.1.4 — December 1, 2025
51Security maintenance release:
53- Mammoth updated to address CVE-2025-11849
54- `pdfminer.six` updated to address GHSA-wf5f-4jwr-ppcp

0.1.4 — December 1, 2025

Security maintenance release:

  • Mammoth updated to address CVE-2025-11849
  • pdfminer.six updated to address GHSA-wf5f-4jwr-ppcp
Raw lines 49 to 55
56### 0.1.5 — February 20, 2026
58- Better aligned and wide PDF tables
59- Partially numbered PDF-list fix
60- `text/markdown` added to the HTTP Accept header
61- Windows ONNX Runtime pin removed

0.1.5 — February 20, 2026

  • Better aligned and wide PDF tables
  • Partially numbered PDF-list fix
  • text/markdown added to the HTTP Accept header
  • Windows ONNX Runtime pin removed
Raw lines 56 to 62
63### 0.1.6 — May 26, 2026
65- Official OCR layer/plugin for embedded images and scanned PDFs
66- PDF page cleanup to fix linear memory growth
67- Deeply nested HTML recursion fix
68- Azure Content Understanding converter
69- Expanded security guidance for broad I/O and MCP binding

0.1.6 — May 26, 2026

  • Official OCR layer/plugin for embedded images and scanned PDFs
  • PDF page cleanup to fix linear memory growth
  • Deeply nested HTML recursion fix
  • Azure Content Understanding converter
  • Expanded security guidance for broad I/O and MCP binding
Raw lines 63 to 70
Uses an outside tool MCP :69
71### 0.1.7 and 0.1.8 — maintenance through September 21, 2026
73- Python supports >=3.10,<3.15.
74- Document Intelligence defers API version selection to its SDK instead of hardcoding the old preview.
75- CU uses the SDK `to_llm_input()` helper and requires `azure-ai-contentunderstanding>=1.2.0b1`; see the preview-default caveat in `cloud_and_ocr.md`.
76- CLI cloud endpoints can come from `MARKITDOWN_DOCINTEL_ENDPOINT` and `MARKITDOWN_CU_ENDPOINT`; stdin is buffered before detection.
77- CSV preserves wider rows and CR-only lines; notebook BOM/headings, RSS/Atom links/content, and duplicate ZIP member handling improved.
78- `markitdown-ocr==0.1.1` uses core Office image hooks and needs core >=0.1.8.
79- `markitdown-mcp==0.0.1a7` uses MCP SDK 2.x.
80- URI schemes are case-insensitive; `file:` rejects UNC/device paths. Local path authorization is still the caller's responsibility.

0.1.7 and 0.1.8 — maintenance through September 21, 2026

  • Python supports >=3.10,<3.15.
  • Document Intelligence defers API version selection to its SDK instead of hardcoding the old preview.
  • CU uses the SDK to_llm_input() helper and requires azure-ai-contentunderstanding>=1.2.0b1; see the preview-default caveat in cloud_and_ocr.md.
  • CLI cloud endpoints can come from MARKITDOWN_DOCINTEL_ENDPOINT and MARKITDOWN_CU_ENDPOINT; stdin is buffered before detection.
  • CSV preserves wider rows and CR-only lines; notebook BOM/headings, RSS/Atom links/content, and duplicate ZIP member handling improved.
  • markitdown-ocr==0.1.1 uses core Office image hooks and needs core >=0.1.8.
  • markitdown-mcp==0.0.1a7 uses MCP SDK 2.x.
  • URI schemes are case-insensitive; file: rejects UNC/device paths. Local path authorization is still the caller's responsibility.
Raw lines 71 to 81
Uses an outside tool MCP :79
82## Upgrade Installation
84Create a clean environment for the comparison:
86```bash
87uv venv --python 3.12 .venv-markitdown
88source .venv-markitdown/bin/activate
89uv pip install "markitdown[all]==0.1.8"
90```
92Do not test a migration in an environment that still contains unknown third-party plugins.

Upgrade Installation

Create a clean environment for the comparison:

uv venv --python 3.12 .venv-markitdown
source .venv-markitdown/bin/activate
uv pip install "markitdown[all]==0.1.8"

Do not test a migration in an environment that still contains unknown third-party plugins.

Raw lines 82 to 93
Runs code bin/activate :88
94## Code Replacements

Code Replacements

Raw lines 94 to 95
96### Result content
98Old/compatibility:
100```python
101content = result.text_content
102```
104Current:
106```python
107content = result.markdown
108```
110`text_content` still works in 0.1.8 but is explicitly documented in source as a soft-deprecated alias.

Result content

Old/compatibility:

content = result.text_content

Current:

content = result.markdown

text_content still works in 0.1.8 but is explicitly documented in source as a soft-deprecated alias.

Raw lines 96 to 111
112### Local conversion
114Broad:
116```python
117result = converter.convert(user_value)
118```
120Narrow local path:
122```python
123result = converter.convert_local(validated_path)
124```
126Use `convert_stream()` for validated uploaded bytes and `convert_response()` after an application-controlled download.

Local conversion

Broad:

result = converter.convert(user_value)

Narrow local path:

result = converter.convert_local(validated_path)

Use convert_stream() for validated uploaded bytes and convert_response() after an application-controlled download.

Raw lines 112 to 127
128### Streams
130Old:
132```python
133from io import StringIO
135result = converter.convert_stream(StringIO("text"))
136```
138Current:
140```python
141from io import BytesIO
143from markitdown import StreamInfo
145result = converter.convert_stream(
146 BytesIO(b"text"),
147 stream_info=StreamInfo(
148 extension=".txt",
149 mimetype="text/plain",
150 charset="utf-8",
151 ),
153```

Streams

Old:

from io import StringIO

result = converter.convert_stream(StringIO("text"))

Current:

from io import BytesIO

from markitdown import StreamInfo

result = converter.convert_stream(
    BytesIO(b"text"),
    stream_info=StreamInfo(
        extension=".txt",
        mimetype="text/plain",
        charset="utf-8",
    ),
)
Raw lines 128 to 154
155### URI API
157Old:
159```python
160result = converter.convert_url(uri)
161```
163Current:
165```python
166result = converter.convert_uri(validated_uri)
167```
169Prefer caller-controlled fetching plus `convert_response()` for HTTP(S).

URI API

Old:

result = converter.convert_url(uri)

Current:

result = converter.convert_uri(validated_uri)

Prefer caller-controlled fetching plus convert_response() for HTTP(S).

Raw lines 155 to 170
171### Hints
173Legacy:
175```python
176result = converter.convert_stream(stream, file_extension=".pdf")
177```
179Current:
181```python
182from markitdown import StreamInfo
184result = converter.convert_stream(
185 stream,
186 stream_info=StreamInfo(
187 extension=".pdf",
188 mimetype="application/pdf",
189 filename="upload.pdf",
190 ),
192```
194The legacy `file_extension`/`url` parameters still exist but are marked for migration in source.

Hints

Legacy:

result = converter.convert_stream(stream, file_extension=".pdf")

Current:

from markitdown import StreamInfo

result = converter.convert_stream(
    stream,
    stream_info=StreamInfo(
        extension=".pdf",
        mimetype="application/pdf",
        filename="upload.pdf",
    ),
)

The legacy file_extension/url parameters still exist but are marked for migration in source.

Raw lines 171 to 195
196## Custom Converter Migration
198Pre-0.1 converter:
200```python
201class OldConverter(DocumentConverter):
202 def convert(self, file_path):
203 ...
204```
2060.1.x converter:
208```python
209from typing import Any, BinaryIO
211from markitdown import DocumentConverter, DocumentConverterResult, StreamInfo
214class CurrentConverter(DocumentConverter):
215 def accepts(
216 self,
217 file_stream: BinaryIO,
218 stream_info: StreamInfo,
219 **kwargs: Any,
220 ) -> bool:
221 ...
223 def convert(
224 self,
225 file_stream: BinaryIO,
226 stream_info: StreamInfo,
227 **kwargs: Any,
228 ) -> DocumentConverterResult:
229 return DocumentConverterResult(markdown="...")
230```
232If `accepts()` peeks at bytes, restore the original stream position before returning.

Custom Converter Migration

Pre-0.1 converter:

class OldConverter(DocumentConverter):
    def convert(self, file_path):
        ...

0.1.x converter:

from typing import Any, BinaryIO

from markitdown import DocumentConverter, DocumentConverterResult, StreamInfo


class CurrentConverter(DocumentConverter):
    def accepts(
        self,
        file_stream: BinaryIO,
        stream_info: StreamInfo,
        **kwargs: Any,
    ) -> bool:
        ...

    def convert(
        self,
        file_stream: BinaryIO,
        stream_info: StreamInfo,
        **kwargs: Any,
    ) -> DocumentConverterResult:
        return DocumentConverterResult(markdown="...")

If accepts() peeks at bytes, restore the original stream position before returning.

Raw lines 196 to 233
234## Plugin Packaging Migration
236Outdated entry-point group:
238```toml
239[project.entry-points."markitdown.plugins"]
240```
242Current group:
244```toml
245[project.entry-points."markitdown.plugin"]
246example = "example_markitdown_plugin"
247```
249The plugin module must export:
251```python
252__plugin_interface_version__ = 1
255def register_converters(markitdown, **kwargs):
256 ...
257```
259Use `pyproject.toml`; old `setup.py`-only examples are no longer the preferred packaging pattern.

Plugin Packaging Migration

Outdated entry-point group:

[project.entry-points."markitdown.plugins"]

Current group:

[project.entry-points."markitdown.plugin"]
example = "example_markitdown_plugin"

The plugin module must export:

__plugin_interface_version__ = 1


def register_converters(markitdown, **kwargs):
    ...

Use pyproject.toml; old setup.py-only examples are no longer the preferred packaging pattern.

Raw lines 234 to 260
261## Installation Guidance Migration
263Outdated:
265```bash
266uv pip install markitdown
267uv pip install "markitdown[all]"
268```
270Repository-standard reproducible install:
272```bash
273uv pip install "markitdown[all]==0.1.8"
274```
276The base package no longer implies every format dependency. Select an extra or `[all]`.

Installation Guidance Migration

Outdated:

uv pip install markitdown
uv pip install "markitdown[all]"

Repository-standard reproducible install:

uv pip install "markitdown[all]==0.1.8"

The base package no longer implies every format dependency. Select an extra or [all].

Raw lines 261 to 277
278## OCR Guidance Migration
280Remove these stale claims:
282- "Built-in PDF conversion uses Tesseract"
283- "All images are OCR'd locally"
284- "GIF and WebP are handled by the built-in image converter"
286Current behavior:
288- Built-in PDF extracts an existing text layer.
289- Built-in JPEG/PNG conversion extracts metadata and optionally requests an LLM description.
290- `markitdown-ocr==0.1.1` uses an external vision-capable client for embedded images and scanned-PDF page fallback.
291- Azure Document Intelligence and Content Understanding provide cloud OCR/extraction.
293The official OCR plugin README's `--llm-client`/`--llm-model` CLI example is not accepted by the 0.1.8 core CLI parser. Configure the plugin in Python.

OCR Guidance Migration

Remove these stale claims:

  • "Built-in PDF conversion uses Tesseract"
  • "All images are OCR'd locally"
  • "GIF and WebP are handled by the built-in image converter"

Current behavior:

  • Built-in PDF extracts an existing text layer.
  • Built-in JPEG/PNG conversion extracts metadata and optionally requests an LLM description.
  • markitdown-ocr==0.1.1 uses an external vision-capable client for embedded images and scanned-PDF page fallback.
  • Azure Document Intelligence and Content Understanding provide cloud OCR/extraction.

The official OCR plugin README's --llm-client/--llm-model CLI example is not accepted by the 0.1.8 core CLI parser. Configure the plugin in Python.

Raw lines 278 to 294
295## Azure Migration
297Current constructors accept explicit credentials:
299```python
300MarkItDown(
301 docintel_endpoint="https://...",
302 docintel_credential=credential,
305MarkItDown(
306 cu_endpoint="https://...",
307 cu_credential=credential,
309```
311Without an explicit credential, the 0.1.8 converters use the named `AZURE_API_KEY` if present and otherwise `DefaultAzureCredential`.
313Do not rely on undocumented variable names such as `AZURE_DOCUMENT_INTELLIGENCE_KEY` for these constructors.
315Content Understanding is new in 0.1.6:
317```python
318from markitdown import MarkItDown
320converter = MarkItDown(
321 cu_endpoint="https://...",
322 cu_analyzer_id="optional-custom-analyzer",
324```

Azure Migration

Current constructors accept explicit credentials:

MarkItDown(
    docintel_endpoint="https://...",
    docintel_credential=credential,
)

MarkItDown(
    cu_endpoint="https://...",
    cu_credential=credential,
)

Without an explicit credential, the 0.1.8 converters use the named AZURE_API_KEY if present and otherwise DefaultAzureCredential.

Do not rely on undocumented variable names such as AZURE_DOCUMENT_INTELLIGENCE_KEY for these constructors.

Content Understanding is new in 0.1.6:

from markitdown import MarkItDown

converter = MarkItDown(
    cu_endpoint="https://...",
    cu_analyzer_id="optional-custom-analyzer",
)
Raw lines 295 to 325
326## Security Migration
328Replace:
330- User-controlled `convert(value)` calls
331- Broad URI access
332- Automatic plugin enablement
333- Undisclosed LLM/cloud fallback
334- Secrets embedded in examples
335- MCP binding to non-local interfaces
337With:
339- Narrow conversion APIs
340- Path and destination allowlists
341- Explicit size/time/resource limits
342- Reviewed, pinned, opt-in plugins
343- User-approved external processing
344- Named credentials through secure provider configuration
345- STDIO or localhost-only MCP in a sandbox

Security Migration

Replace:

  • User-controlled convert(value) calls
  • Broad URI access
  • Automatic plugin enablement
  • Undisclosed LLM/cloud fallback
  • Secrets embedded in examples
  • MCP binding to non-local interfaces

With:

  • Narrow conversion APIs
  • Path and destination allowlists
  • Explicit size/time/resource limits
  • Reviewed, pinned, opt-in plugins
  • User-approved external processing
  • Named credentials through secure provider configuration
  • STDIO or localhost-only MCP in a sandbox
Raw lines 326 to 346
Uses an outside tool MCP :335
347## Regression Checklist
349- [ ] Install 0.1.8 in a clean environment
350- [ ] Replace `.text_content` with `.markdown`
351- [ ] Replace text streams with binary streams
352- [ ] Replace `convert_url()` with `convert_uri()` or controlled fetch
353- [ ] Update custom converter signatures
354- [ ] Update plugin entry-point group
355- [ ] Pin format extras
356- [ ] Test PDF tables and multi-column reading order
357- [ ] Test DOCX math and linked images
358- [ ] Test PPTX grouped shapes and notes
359- [ ] Confirm plugins remain disabled by default
360- [ ] Confirm no conversion unexpectedly calls network/cloud
361- [ ] Compare semantic output on a representative corpus

Regression Checklist

  • [ ] Install 0.1.8 in a clean environment
  • [ ] Replace .text_content with .markdown
  • [ ] Replace text streams with binary streams
  • [ ] Replace convert_url() with convert_uri() or controlled fetch
  • [ ] Update custom converter signatures
  • [ ] Update plugin entry-point group
  • [ ] Pin format extras
  • [ ] Test PDF tables and multi-column reading order
  • [ ] Test DOCX math and linked images
  • [ ] Test PPTX grouped shapes and notes
  • [ ] Confirm plugins remain disabled by default
  • [ ] Confirm no conversion unexpectedly calls network/cloud
  • [ ] Compare semantic output on a representative corpus
Raw lines 347 to 362
363## Sources
365- Releases: https://github.com/microsoft/markitdown/releases
366- 0.1.0 migration notes: https://github.com/microsoft/markitdown/releases/tag/v0.1.0
367- 0.1.6 release: https://github.com/microsoft/markitdown/releases/tag/v0.1.6
368- 0.1.8 release: https://github.com/microsoft/markitdown/releases/tag/v0.1.8

Sources

  • Releases: https://github.com/microsoft/markitdown/releases
  • 0.1.0 migration notes: https://github.com/microsoft/markitdown/releases/tag/v0.1.0
  • 0.1.6 release: https://github.com/microsoft/markitdown/releases/tag/v0.1.6
  • 0.1.8 release: https://github.com/microsoft/markitdown/releases/tag/v0.1.8
Raw lines 363 to 368