markdown-docx 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. markdown_docx-0.1.0/.github/workflows/ci.yml +125 -0
  2. markdown_docx-0.1.0/.github/workflows/publish-pypi.yml +109 -0
  3. markdown_docx-0.1.0/.gitignore +12 -0
  4. markdown_docx-0.1.0/AGENTS.md +41 -0
  5. markdown_docx-0.1.0/CHANGELOG.md +9 -0
  6. markdown_docx-0.1.0/LICENSE +21 -0
  7. markdown_docx-0.1.0/PKG-INFO +372 -0
  8. markdown_docx-0.1.0/PLAN.md +840 -0
  9. markdown_docx-0.1.0/README.md +341 -0
  10. markdown_docx-0.1.0/docs/public-api-capabilities.md +29 -0
  11. markdown_docx-0.1.0/pyproject.toml +72 -0
  12. markdown_docx-0.1.0/sample/assets/dog-lunch-chase.png +0 -0
  13. markdown_docx-0.1.0/sample/assets/dog-run-finish.png +0 -0
  14. markdown_docx-0.1.0/sample/assets/dog-run-start.png +0 -0
  15. markdown_docx-0.1.0/sample/assets/dog-trio-cameo.png +0 -0
  16. markdown_docx-0.1.0/sample/assets/dog-trio-inline.png +0 -0
  17. markdown_docx-0.1.0/sample/assets/dog-wagon-rescue.png +0 -0
  18. markdown_docx-0.1.0/sample/assets/illustration-prompts.md +31 -0
  19. markdown_docx-0.1.0/sample/assets/word-icon.png +0 -0
  20. markdown_docx-0.1.0/sample/assets/word-workflow.png +0 -0
  21. markdown_docx-0.1.0/sample/showcase.docx +0 -0
  22. markdown_docx-0.1.0/sample/showcase.md +310 -0
  23. markdown_docx-0.1.0/scripts/Export-DocxPdf.ps1 +34 -0
  24. markdown_docx-0.1.0/scripts/build_default_template.py +94 -0
  25. markdown_docx-0.1.0/scripts/build_qa_templates.py +38 -0
  26. markdown_docx-0.1.0/scripts/build_showcase_assets.py +60 -0
  27. markdown_docx-0.1.0/src/markdown_docx/__init__.py +1 -0
  28. markdown_docx-0.1.0/src/markdown_docx/assets/default.docx +0 -0
  29. markdown_docx-0.1.0/src/markdown_docx/assets/syntax.json +47 -0
  30. markdown_docx-0.1.0/src/markdown_docx/assets.py +15 -0
  31. markdown_docx-0.1.0/src/markdown_docx/cli.py +318 -0
  32. markdown_docx-0.1.0/src/markdown_docx/errors.py +118 -0
  33. markdown_docx-0.1.0/src/markdown_docx/images.py +161 -0
  34. markdown_docx-0.1.0/src/markdown_docx/markdown_body.py +121 -0
  35. markdown_docx-0.1.0/src/markdown_docx/metadata.py +349 -0
  36. markdown_docx-0.1.0/src/markdown_docx/models.py +180 -0
  37. markdown_docx-0.1.0/src/markdown_docx/parser.py +456 -0
  38. markdown_docx-0.1.0/src/markdown_docx/renderer.py +285 -0
  39. markdown_docx-0.1.0/src/markdown_docx/skill.py +123 -0
  40. markdown_docx-0.1.0/src/markdown_docx/styles.py +50 -0
  41. markdown_docx-0.1.0/src/markdown_docx/template.py +121 -0
  42. markdown_docx-0.1.0/tests/conftest.py +33 -0
  43. markdown_docx-0.1.0/tests/test_cli.py +163 -0
  44. markdown_docx-0.1.0/tests/test_metadata.py +152 -0
  45. markdown_docx-0.1.0/tests/test_parser.py +179 -0
  46. markdown_docx-0.1.0/tests/test_public_api_boundary.py +21 -0
  47. markdown_docx-0.1.0/tests/test_public_api_capabilities.py +82 -0
  48. markdown_docx-0.1.0/tests/test_renderer_images.py +85 -0
  49. markdown_docx-0.1.0/tests/test_renderer_lists.py +39 -0
  50. markdown_docx-0.1.0/tests/test_renderer_sections.py +49 -0
  51. markdown_docx-0.1.0/tests/test_renderer_tables.py +59 -0
  52. markdown_docx-0.1.0/tests/test_renderer_text.py +76 -0
  53. markdown_docx-0.1.0/tests/test_showcase.py +136 -0
  54. markdown_docx-0.1.0/tests/test_template.py +89 -0
  55. markdown_docx-0.1.0/uv.lock +1314 -0
@@ -0,0 +1,125 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ lint:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - name: Check out repository
18
+ uses: actions/checkout@v7.0.1
19
+
20
+ - name: Set up uv
21
+ uses: astral-sh/setup-uv@v10.0.1
22
+ with:
23
+ python-version: "3.13"
24
+ enable-cache: true
25
+
26
+ - name: Install locked dependencies
27
+ run: uv sync --locked --all-groups
28
+
29
+ - name: Lint
30
+ run: uv run ruff check .
31
+
32
+ - name: Check formatting
33
+ run: uv run ruff format --check .
34
+
35
+ - name: Type check
36
+ run: uv run mypy
37
+
38
+ test:
39
+ strategy:
40
+ fail-fast: false
41
+ matrix:
42
+ os: [ubuntu-latest, windows-latest]
43
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
44
+ runs-on: ${{ matrix.os }}
45
+ env:
46
+ UV_LINK_MODE: copy
47
+ steps:
48
+ - name: Check out repository
49
+ uses: actions/checkout@v7.0.1
50
+
51
+ - name: Set up uv
52
+ uses: astral-sh/setup-uv@v10.0.1
53
+ with:
54
+ python-version: ${{ matrix.python-version }}
55
+ enable-cache: true
56
+
57
+ - name: Install locked dependencies
58
+ run: uv sync --locked --all-groups
59
+
60
+ - name: Run tests
61
+ run: uv run pytest
62
+
63
+ visual-smoke:
64
+ runs-on: ubuntu-latest
65
+ steps:
66
+ - name: Check out repository
67
+ uses: actions/checkout@v7.0.1
68
+
69
+ - name: Set up uv
70
+ uses: astral-sh/setup-uv@v10.0.1
71
+ with:
72
+ python-version: "3.13"
73
+ enable-cache: true
74
+
75
+ - name: Install LibreOffice and Poppler
76
+ run: sudo apt-get update && sudo apt-get install -y libreoffice-writer poppler-utils
77
+
78
+ - name: Render showcase DOCX
79
+ run: |
80
+ mkdir -p .visual
81
+ uvx --from . markdown-docx sample/showcase.md .visual/showcase.docx
82
+
83
+ - name: Convert showcase to PDF
84
+ run: libreoffice --headless --convert-to pdf --outdir .visual .visual/showcase.docx
85
+
86
+ - name: Verify rendered PDF
87
+ run: pdfinfo .visual/showcase.pdf
88
+
89
+ package:
90
+ needs: [lint, test, visual-smoke]
91
+ runs-on: ubuntu-latest
92
+ steps:
93
+ - name: Check out repository
94
+ uses: actions/checkout@v7.0.1
95
+
96
+ - name: Set up uv
97
+ uses: astral-sh/setup-uv@v10.0.1
98
+ with:
99
+ python-version: "3.13"
100
+ enable-cache: true
101
+
102
+ - name: Install locked dependencies
103
+ run: uv sync --locked --all-groups
104
+
105
+ - name: Build distributions
106
+ run: uv build
107
+
108
+ - name: Check distribution metadata
109
+ run: uv run twine check dist/*
110
+
111
+ - name: Smoke-test the wheel
112
+ shell: bash
113
+ run: |
114
+ python -m venv .wheel-smoke
115
+ .wheel-smoke/bin/python -m pip install dist/*.whl
116
+ .wheel-smoke/bin/markdown-docx --version
117
+ .wheel-smoke/bin/markdown-docx --syntax --json
118
+ echo '# Wheel smoke test' > smoke.md
119
+ .wheel-smoke/bin/markdown-docx smoke.md smoke.docx
120
+
121
+ - name: Upload distributions
122
+ uses: actions/upload-artifact@v7.0.1
123
+ with:
124
+ name: distributions
125
+ path: dist/
@@ -0,0 +1,109 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types:
6
+ - published
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ quality:
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ os: [ubuntu-latest, windows-latest]
18
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
19
+ runs-on: ${{ matrix.os }}
20
+ env:
21
+ UV_LINK_MODE: copy
22
+ steps:
23
+ - name: Check out repository
24
+ uses: actions/checkout@v7.0.1
25
+
26
+ - name: Set up uv
27
+ uses: astral-sh/setup-uv@v10.0.1
28
+ with:
29
+ python-version: ${{ matrix.python-version }}
30
+ enable-cache: true
31
+
32
+ - name: Install locked dependencies
33
+ run: uv sync --locked --all-groups
34
+
35
+ - name: Lint, format, and type check
36
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
37
+ run: |
38
+ uv run ruff check .
39
+ uv run ruff format --check .
40
+ uv run mypy
41
+
42
+ - name: Run tests
43
+ run: uv run pytest
44
+
45
+ - name: Verify release tag matches package version
46
+ if: github.event_name == 'release' && matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
47
+ shell: bash
48
+ run: |
49
+ version_output="$(uv run markdown-docx --version)"
50
+ package_version="${version_output#markdown-docx }"
51
+ tag_version="${GITHUB_REF_NAME#v}"
52
+ test "$package_version" = "$tag_version" || {
53
+ echo "Package version $package_version does not match release tag $GITHUB_REF_NAME."
54
+ exit 1
55
+ }
56
+
57
+ build:
58
+ needs: quality
59
+ runs-on: ubuntu-latest
60
+ steps:
61
+ - name: Check out repository
62
+ uses: actions/checkout@v7.0.1
63
+
64
+ - name: Set up uv
65
+ uses: astral-sh/setup-uv@v10.0.1
66
+ with:
67
+ python-version: "3.13"
68
+ enable-cache: true
69
+
70
+ - name: Install locked dependencies
71
+ run: uv sync --locked --all-groups
72
+
73
+ - name: Build distributions
74
+ run: uv build
75
+
76
+ - name: Check distribution metadata
77
+ run: uv run twine check dist/*
78
+
79
+ - name: Smoke-test the wheel
80
+ shell: bash
81
+ run: |
82
+ python -m venv .wheel-smoke
83
+ .wheel-smoke/bin/python -m pip install dist/*.whl
84
+ .wheel-smoke/bin/markdown-docx --version
85
+ .wheel-smoke/bin/markdown-docx --inspect-template --json
86
+
87
+ - name: Upload distributions
88
+ uses: actions/upload-artifact@v7.0.1
89
+ with:
90
+ name: distributions
91
+ path: dist/
92
+
93
+ publish:
94
+ needs: build
95
+ runs-on: ubuntu-latest
96
+ environment:
97
+ name: pypi
98
+ url: https://pypi.org/p/markdown-docx
99
+ permissions:
100
+ id-token: write
101
+ steps:
102
+ - name: Download distributions
103
+ uses: actions/download-artifact@v8.0.1
104
+ with:
105
+ name: distributions
106
+ path: dist/
107
+
108
+ - name: Publish to PyPI
109
+ uses: pypa/gh-action-pypi-publish@v1.14.2
@@ -0,0 +1,12 @@
1
+ /.mypy_cache/
2
+ /.qa/
3
+ /.pytest_cache/
4
+ /.pytest-tmp/
5
+ /.ruff_cache/
6
+ /.venv/
7
+ /.wheel-smoke/
8
+ /build/
9
+ /dist/
10
+ /**/__pycache__/
11
+ *.egg-info/
12
+ *.py[cod]
@@ -0,0 +1,41 @@
1
+ # AGENTS.md
2
+
3
+ This repository contains `markdown-docx`, a strict Python CLI that converts constrained Markdown into editable Word `.docx` files.
4
+
5
+ ## Project identity
6
+
7
+ - Published package: `markdown-docx`
8
+ - CLI command: `markdown-docx`
9
+ - Python package: `markdown_docx`
10
+
11
+ ## Core rules
12
+
13
+ - Use only supported public `python-docx` APIs in production code.
14
+ - Never edit OOXML parts directly in production code.
15
+ - Preserve normal Markdown meaning and keep Word metadata in invisible reserved HTML comments.
16
+ - Reject unsupported behavior with stable, line-aware diagnostics.
17
+ - Treat Word sections as layout boundaries. Headings never create sections.
18
+ - Never report a stable page count without a Word-compatible layout engine.
19
+ - Keep parser models independent of `python-docx` objects.
20
+ - Add or update tests whenever behavior changes.
21
+ - Do not use em dashes or semicolons in documentation, messages, or comments.
22
+
23
+ Tests may inspect generated OOXML read-only for precise assertions.
24
+
25
+ ## Commands
26
+
27
+ ```powershell
28
+ $env:UV_LINK_MODE="copy"
29
+ uv sync --locked --all-groups
30
+ uv run pytest
31
+ uv run ruff check .
32
+ uv run ruff format --check .
33
+ uv run mypy
34
+ uv build
35
+ uv run twine check dist/*
36
+ uvx --refresh --from . markdown-docx sample\showcase.md sample\showcase.docx --force
37
+ ```
38
+
39
+ ## Contract files
40
+
41
+ When the input format changes, update the parser, tests, `README.md`, `src/markdown_docx/assets/syntax.json`, the managed skill text, and the showcase together.
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - Add strict Markdown parsing with invisible YAML directives and line-aware diagnostics.
6
+ - Add editable Word rendering for text, headings, blockquotes, code, mixed nested lists, tables, images, page breaks, and sections.
7
+ - Add blank `.docx` templates, semantic style mapping, font overrides, template inspection, and a packaged default template.
8
+ - Add safe local and remote image handling, JSON automation output, overwrite protection, syntax discovery, and managed agent skill commands.
9
+ - Add a complete test suite, showcase document, CI, package validation, wheel smoke tests, and trusted PyPI publishing.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 John Paul Ellis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,372 @@
1
+ Metadata-Version: 2.5
2
+ Name: markdown-docx
3
+ Version: 0.1.0
4
+ Summary: Convert constrained Markdown documents into editable Word files.
5
+ Project-URL: Homepage, https://github.com/pseudosavant/markdown-docx
6
+ Project-URL: Repository, https://github.com/pseudosavant/markdown-docx
7
+ Project-URL: Issues, https://github.com/pseudosavant/markdown-docx/issues
8
+ Project-URL: Releases, https://github.com/pseudosavant/markdown-docx/releases
9
+ Author: John Paul Ellis
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: cli,document,docx,markdown,word
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Office/Business :: Office Suites
22
+ Classifier: Topic :: Software Development :: Documentation
23
+ Classifier: Topic :: Text Processing :: Markup
24
+ Requires-Python: >=3.11
25
+ Requires-Dist: httpx<1,>=0.27
26
+ Requires-Dist: markdown-it-py<5,>=3.0
27
+ Requires-Dist: pillow<13,>=10.0
28
+ Requires-Dist: python-docx==1.2.0
29
+ Requires-Dist: pyyaml<7,>=6.0
30
+ Description-Content-Type: text/markdown
31
+
32
+ # markdown-docx
33
+
34
+ `markdown-docx` turns constrained Markdown into predictable, editable Word `.docx` files. The Markdown stays readable in normal renderers. Word-specific layout and style settings live in invisible HTML comments.
35
+
36
+ The format is strict by design. Unsupported input produces a stable, line-aware error instead of an approximate document.
37
+
38
+ ## Prerequisite
39
+
40
+ The documented workflow uses [`uv`](https://docs.astral.sh/uv/getting-started/installation/). Install `uv` before continuing.
41
+
42
+ ## Quick start with an agent
43
+
44
+ Install the managed agent skill:
45
+
46
+ ```powershell
47
+ uvx markdown-docx skill install
48
+ ```
49
+
50
+ Then ask an agent to create both the Markdown source and the editable Word output:
51
+
52
+ > Use $markdown-docx to create a project brief. Keep the source readable as normal Markdown and save the editable DOCX beside it.
53
+
54
+ The skill teaches the agent how to inspect the format, inspect blank Word templates, render safely, and handle structured results.
55
+
56
+ ## Use the CLI directly
57
+
58
+ ```powershell
59
+ uvx markdown-docx document.md document.docx
60
+ ```
61
+
62
+ When the output path is omitted, the tool writes a `.docx` beside the input Markdown file.
63
+
64
+ ```powershell
65
+ uvx markdown-docx document.md
66
+ ```
67
+
68
+ Inspect the supported syntax:
69
+
70
+ ```powershell
71
+ uvx markdown-docx --syntax
72
+ uvx markdown-docx --syntax --json
73
+ ```
74
+
75
+ ## Supported Markdown
76
+
77
+ Version 0.1.0 supports:
78
+
79
+ - ATX headings from `#` through `######`
80
+ - Paragraphs and standard soft or hard line breaks
81
+ - Emphasis, strong emphasis, and inline backtick code
82
+ - Fenced code blocks
83
+ - Blockquotes containing paragraphs
84
+ - Ordered and unordered lists, including mixed nesting
85
+ - Pipe tables with inline text formatting
86
+ - Local and remote inline images
87
+ - Standalone images with width and alignment metadata
88
+
89
+ Links are rejected in 0.1.0. `python-docx` 1.2.0 can read hyperlinks but has no supported public API for creating them. The source alt text for images remains meaningful Markdown content, but the same library release has no public API for embedding it in a Word drawing. A rendered document containing images reports `image_alt_text_not_embedded` in its warning list.
90
+
91
+ The following syntax is intentionally unsupported:
92
+
93
+ - Raw HTML and non-reserved HTML comments
94
+ - Setext headings and horizontal rules
95
+ - Indented code blocks
96
+ - Task lists and footnotes
97
+ - Multi-paragraph list items
98
+ - Tables, images, code blocks, or blockquotes nested inside list items
99
+ - Images inside table cells or blockquotes
100
+ - Arbitrary Markdown extensions
101
+
102
+ ## Invisible Word metadata
103
+
104
+ Only HTML comments beginning with `markdown-docx` are accepted. All other HTML is an error.
105
+
106
+ Document metadata may appear once. It must be the first non-whitespace content:
107
+
108
+ ```markdown
109
+ <!-- markdown-docx
110
+ document:
111
+ page_size: letter
112
+ orientation: portrait
113
+ margins:
114
+ top: 1in
115
+ right: 1in
116
+ bottom: 1in
117
+ left: 1in
118
+ styles:
119
+ paragraph: Normal
120
+ headings:
121
+ 1: Heading 1
122
+ 2: Heading 2
123
+ 3: Heading 3
124
+ 4: Heading 4
125
+ 5: Heading 5
126
+ 6: Heading 6
127
+ blockquote: Quote
128
+ code_block: Code Block
129
+ ordered_list:
130
+ - List Number
131
+ - List Number 2
132
+ - List Number 3
133
+ unordered_list:
134
+ - List Bullet
135
+ - List Bullet 2
136
+ - List Bullet 3
137
+ table: Table Grid
138
+ fonts:
139
+ body: Calibri
140
+ headings: Calibri
141
+ monospace: Consolas
142
+ -->
143
+
144
+ # Project brief
145
+
146
+ This remains ordinary Markdown.
147
+ ```
148
+
149
+ Metadata uses strict YAML. Duplicate keys, unknown keys, invalid types, unitless lengths, and misplaced comments are errors.
150
+
151
+ ### Page sizes and margins
152
+
153
+ Named page sizes are `letter`, `legal`, and `a4`. Custom page sizes use nominal portrait dimensions. The width must not exceed the height.
154
+
155
+ ```markdown
156
+ <!-- markdown-docx
157
+ document:
158
+ page_size:
159
+ width: 7in
160
+ height: 10in
161
+ orientation: portrait
162
+ margins:
163
+ top: 0.75in
164
+ right: 0.75in
165
+ bottom: 0.75in
166
+ left: 0.75in
167
+ -->
168
+ ```
169
+
170
+ Lengths accept `in`, `cm`, `mm`, and `pt`. Margins must leave a positive usable page area.
171
+
172
+ ### Sections
173
+
174
+ A section directive starts a next-page Word section before the following content block:
175
+
176
+ ```markdown
177
+ <!-- markdown-docx
178
+ section:
179
+ page_size: letter
180
+ orientation: landscape
181
+ margins:
182
+ top: 0.75in
183
+ right: 0.75in
184
+ bottom: 0.75in
185
+ left: 0.75in
186
+ -->
187
+
188
+ ## Landscape analysis
189
+ ```
190
+
191
+ Each section starts from the document defaults and applies its own overrides. It does not inherit omitted values from the preceding section. Reset to the document defaults with:
192
+
193
+ ```markdown
194
+ <!-- markdown-docx
195
+ section: default
196
+ -->
197
+ ```
198
+
199
+ Headings never create sections.
200
+
201
+ ### Page breaks
202
+
203
+ Insert a page break before the next content block:
204
+
205
+ ```markdown
206
+ <!-- markdown-docx: page-break -->
207
+
208
+ ## Appendix
209
+ ```
210
+
211
+ A page break does not create a new section.
212
+
213
+ ## Templates and styles
214
+
215
+ A custom template must be a blank `.docx` formatting template. `.dotx` is not supported. The template may define styles, theme data, fonts, numbering definitions, and section defaults. It must not contain:
216
+
217
+ - Non-whitespace body text
218
+ - Body tables
219
+ - Body images or drawings
220
+ - Nonempty headers or footers
221
+
222
+ Inspect a template before writing Markdown that refers to its style names:
223
+
224
+ ```powershell
225
+ uvx markdown-docx --inspect-template --template formatting.docx
226
+ uvx markdown-docx --list-styles --template formatting.docx
227
+ uvx markdown-docx --list-table-styles --template formatting.docx
228
+ ```
229
+
230
+ Render with the template:
231
+
232
+ ```powershell
233
+ uvx markdown-docx report.md report.docx --template formatting.docx
234
+ ```
235
+
236
+ The template remains unchanged. When no template is supplied, the packaged blank template provides every default style.
237
+
238
+ The Markdown metadata maps semantic constructs to paragraph and table style names. Each configured style must exist and must have the correct Word style type. Body and heading font overrides modify the mapped paragraph styles. The monospace override applies to code blocks and inline code. Sizes, colors, spacing, borders, and other typography remain owned by the template.
239
+
240
+ ## Lists
241
+
242
+ Apply one Word paragraph style per list type and nesting depth:
243
+
244
+ ```yaml
245
+ styles:
246
+ ordered_list:
247
+ - List Number
248
+ - List Number 2
249
+ - List Number 3
250
+ unordered_list:
251
+ - List Bullet
252
+ - List Bullet 2
253
+ - List Bullet 3
254
+ ```
255
+
256
+ Mixed nested lists select ordered or unordered styles independently at every depth. A list deeper than the configured style array is an error. Ordered lists must begin with `1`. Restart controls and arbitrary start values are not supported.
257
+
258
+ ## Tables
259
+
260
+ Standard pipe tables become editable Word tables. Put optional table metadata immediately before the table:
261
+
262
+ ```markdown
263
+ <!-- markdown-docx
264
+ table:
265
+ style: Table Grid
266
+ alignment: center
267
+ width: page
268
+ column_widths: [3, 1, 1]
269
+ -->
270
+
271
+ | Item | Count | Price |
272
+ | --- | ---: | ---: |
273
+ | Widget | 2 | $10 |
274
+ ```
275
+
276
+ The first Markdown row is the semantic header row. Cell alignment follows the Markdown delimiter row. `column_widths` contains positive ratios and must match the column count. `width: page` uses the active section's usable width. `width: auto` lets Word size the table unless ratios are supplied.
277
+
278
+ Merged cells, nested tables, fixed row heights, repeated-header controls, and per-cell border or fill metadata are not supported.
279
+
280
+ ## Images
281
+
282
+ Relative paths resolve from the Markdown file's directory:
283
+
284
+ ```markdown
285
+ Text before ![Status icon](images/status.png) text after.
286
+ ```
287
+
288
+ Put metadata immediately before a standalone image:
289
+
290
+ ```markdown
291
+ <!-- markdown-docx
292
+ image:
293
+ width: 40%
294
+ alignment: center
295
+ -->
296
+ ![Architecture](images/architecture.png)
297
+ ```
298
+
299
+ Widths accept `in`, `cm`, `mm`, `pt`, or a percentage of the active section's usable width. Images preserve aspect ratio. Natural-size images are clamped to the usable width. An explicit physical width that exceeds the usable width is an error.
300
+
301
+ HTTP and HTTPS images use timeouts, a 25 MiB download limit, content-type validation, a 50 megapixel decode limit, and one download per unique URL. Reject remote images for offline builds or untrusted input:
302
+
303
+ ```powershell
304
+ uvx markdown-docx report.md --no-remote-images
305
+ ```
306
+
307
+ ## Automation and safety
308
+
309
+ Use `--json` for one complete machine-readable result:
310
+
311
+ ```powershell
312
+ uvx markdown-docx report.md report.docx --json
313
+ ```
314
+
315
+ A successful result contains the input path, output path, template identifier, section count, and warnings. It does not report a page count. DOCX files do not have a reliable intrinsic page count until a compatible layout engine paginates them.
316
+
317
+ The CLI refuses to overwrite an existing output. Add `--force` only when replacement is intended:
318
+
319
+ ```powershell
320
+ uvx markdown-docx report.md report.docx --force --json
321
+ ```
322
+
323
+ For stdin, provide both an output path and a base directory:
324
+
325
+ ```powershell
326
+ Get-Content report.md | uvx markdown-docx --input - --output report.docx --base-dir .
327
+ ```
328
+
329
+ Exit codes:
330
+
331
+ | Code | Meaning |
332
+ | ---: | --- |
333
+ | `0` | Success |
334
+ | `2` | Usage or input error |
335
+ | `3` | Markdown or metadata parse error |
336
+ | `4` | Template or style error |
337
+ | `5` | Image or asset error |
338
+ | `6` | Unsupported Markdown or feature |
339
+ | `7` | DOCX rendering error |
340
+ | `8` | Unexpected internal error |
341
+
342
+ ## Complete example
343
+
344
+ See [the showcase Markdown](sample/showcase.md). It opens with an illustrated three-dog story, then exercises supported text, list, table, image, page-break, and section behavior in a dedicated capability lab. Regenerate it from a repository checkout:
345
+
346
+ ```powershell
347
+ uvx --refresh --from . markdown-docx sample\showcase.md sample\showcase.docx --force
348
+ ```
349
+
350
+ ## Public API boundary
351
+
352
+ Production code uses only documented public `python-docx` APIs. It does not write OOXML directly and does not call private library members. Tests may inspect generated package XML read-only. The complete capability decision record is in [docs/public-api-capabilities.md](docs/public-api-capabilities.md).
353
+
354
+ Word is the primary compatibility target. LibreOffice Writer is used as a visual smoke-test engine. Differences in pagination or font metrics can occur between layout engines.
355
+
356
+ ## Development
357
+
358
+ ```powershell
359
+ $env:UV_LINK_MODE="copy"
360
+ uv sync --locked --all-groups
361
+ uv run pytest
362
+ uv run ruff check .
363
+ uv run ruff format --check .
364
+ uv run mypy
365
+ ```
366
+
367
+ Build and validate distributions:
368
+
369
+ ```powershell
370
+ uv build
371
+ uv run twine check dist/*
372
+ ```