markdown-docx 0.2.0__tar.gz → 0.3.1__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 (70) hide show
  1. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/.github/workflows/ci.yml +10 -2
  2. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/AGENTS.md +2 -2
  3. markdown_docx-0.3.1/CHANGELOG.md +31 -0
  4. markdown_docx-0.3.1/PKG-INFO +506 -0
  5. markdown_docx-0.3.1/README.md +474 -0
  6. markdown_docx-0.3.1/docs/public-api-capabilities.md +38 -0
  7. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/docs/skill-management.md +1 -1
  8. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/pyproject.toml +3 -2
  9. markdown_docx-0.3.1/sample/assets/showcase-page-1.png +0 -0
  10. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/sample/showcase.docx +0 -0
  11. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/sample/showcase.md +4 -3
  12. markdown_docx-0.3.1/src/markdown_docx/__init__.py +1 -0
  13. markdown_docx-0.3.1/src/markdown_docx/assets/syntax.json +52 -0
  14. markdown_docx-0.3.1/src/markdown_docx/hyperlinks.py +43 -0
  15. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/src/markdown_docx/markdown_body.py +26 -14
  16. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/src/markdown_docx/models.py +3 -1
  17. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/src/markdown_docx/parser.py +2 -2
  18. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/src/markdown_docx/renderer.py +12 -3
  19. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/src/markdown_docx/skill.py +3 -1
  20. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/src/markdown_docx/styles.py +3 -14
  21. markdown_docx-0.3.1/src/markdown_docx/theme_fonts.py +78 -0
  22. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/test_cli.py +1 -1
  23. markdown_docx-0.3.1/tests/test_font_rendering.py +158 -0
  24. markdown_docx-0.3.1/tests/test_hyperlinks.py +161 -0
  25. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/test_parser.py +2 -1
  26. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/test_public_api_boundary.py +6 -2
  27. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/test_public_api_capabilities.py +21 -3
  28. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/test_renderer_text.py +2 -2
  29. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/test_showcase.py +6 -2
  30. markdown_docx-0.3.1/tests/test_theme_fonts.py +307 -0
  31. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/uv.lock +122 -16
  32. markdown_docx-0.2.0/CHANGELOG.md +0 -16
  33. markdown_docx-0.2.0/PKG-INFO +0 -406
  34. markdown_docx-0.2.0/README.md +0 -374
  35. markdown_docx-0.2.0/docs/public-api-capabilities.md +0 -29
  36. markdown_docx-0.2.0/src/markdown_docx/__init__.py +0 -1
  37. markdown_docx-0.2.0/src/markdown_docx/assets/syntax.json +0 -47
  38. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/.github/workflows/publish-pypi.yml +0 -0
  39. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/.gitignore +0 -0
  40. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/LICENSE +0 -0
  41. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/PLAN.md +0 -0
  42. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/sample/assets/dog-lunch-chase.png +0 -0
  43. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/sample/assets/dog-run-finish.png +0 -0
  44. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/sample/assets/dog-run-start.png +0 -0
  45. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/sample/assets/dog-trio-cameo.png +0 -0
  46. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/sample/assets/dog-trio-inline.png +0 -0
  47. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/sample/assets/dog-wagon-rescue.png +0 -0
  48. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/sample/assets/illustration-prompts.md +0 -0
  49. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/sample/assets/word-icon.png +0 -0
  50. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/sample/assets/word-workflow.png +0 -0
  51. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/scripts/Export-DocxPdf.ps1 +0 -0
  52. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/scripts/build_default_template.py +0 -0
  53. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/scripts/build_qa_templates.py +0 -0
  54. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/scripts/build_showcase_assets.py +0 -0
  55. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/scripts/smoke_skill.py +0 -0
  56. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/src/markdown_docx/assets/default.docx +0 -0
  57. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/src/markdown_docx/assets.py +0 -0
  58. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/src/markdown_docx/cli.py +0 -0
  59. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/src/markdown_docx/errors.py +0 -0
  60. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/src/markdown_docx/images.py +0 -0
  61. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/src/markdown_docx/metadata.py +0 -0
  62. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/src/markdown_docx/template.py +0 -0
  63. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/conftest.py +0 -0
  64. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/test_metadata.py +0 -0
  65. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/test_renderer_images.py +0 -0
  66. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/test_renderer_lists.py +0 -0
  67. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/test_renderer_sections.py +0 -0
  68. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/test_renderer_tables.py +0 -0
  69. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/test_skill.py +0 -0
  70. {markdown_docx-0.2.0 → markdown_docx-0.3.1}/tests/test_template.py +0 -0
@@ -76,12 +76,20 @@ jobs:
76
76
  enable-cache: true
77
77
 
78
78
  - name: Install LibreOffice and Poppler
79
- run: sudo apt-get update && sudo apt-get install -y libreoffice-writer poppler-utils
79
+ run: sudo apt-get update && sudo apt-get install -y libreoffice-writer poppler-utils fonts-liberation
80
+
81
+ - name: Install locked test dependencies
82
+ run: uv sync --locked --all-groups
83
+
84
+ - name: Verify rendered theme fonts and theme changes
85
+ env:
86
+ MARKDOWN_DOCX_FONT_RENDERER: libreoffice
87
+ run: uv run pytest tests/test_font_rendering.py
80
88
 
81
89
  - name: Render showcase DOCX
82
90
  run: |
83
91
  mkdir -p .visual
84
- uvx --from . markdown-docx sample/showcase.md .visual/showcase.docx
92
+ uv run --locked markdown-docx sample/showcase.md .visual/showcase.docx
85
93
 
86
94
  - name: Convert showcase to PDF
87
95
  run: libreoffice --headless --convert-to pdf --outdir .visual .visual/showcase.docx
@@ -10,8 +10,8 @@ This repository contains `markdown-docx`, a strict Python CLI that converts cons
10
10
 
11
11
  ## Core rules
12
12
 
13
- - Use only supported public `python-docx` APIs in production code.
14
- - Never edit OOXML parts directly in production code.
13
+ - Use only supported public `python-docx` APIs in production code, except for the isolated hyperlink helper.
14
+ - Direct OOXML changes are allowed only in `src/markdown_docx/hyperlinks.py` for native hyperlinks. Replace that helper when a supported public API becomes available. Theme font handling must use the public APIs in `ps-python-docx` 1.3.0.
15
15
  - Preserve normal Markdown meaning and keep Word metadata in invisible reserved HTML comments.
16
16
  - Reject unsupported behavior with stable, line-aware diagnostics.
17
17
  - Treat Word sections as layout boundaries. Headings never create sections.
@@ -0,0 +1,31 @@
1
+ # Changelog
2
+
3
+ ## 0.3.1
4
+
5
+ - Use ps-python-docx 1.3.0 public theme APIs. Remove theme-related OOXML access from production code.
6
+ - Apply body and heading font overrides to Word's actual theme fonts. Preserve theme inheritance in mapped styles and linked character styles instead of applying literal fonts to individual headings.
7
+ - Preserve unspecified theme slots and unrelated theme settings. Keep code in its explicit monospace font. Handle missing themes and diagnose malformed themes and conflicting style roles.
8
+ - Add saved-package font cascade tests and layout-engine regression checks that verify PDF fonts before and after changing the theme. Exercise Aptos and Aptos Display with Word and Liberation fonts in visual CI.
9
+
10
+ ## 0.3.0
11
+
12
+ - Convert Markdown links into native, clickable, editable Word hyperlinks in paragraphs, headings, blockquotes, lists, and table cells.
13
+ - Preserve formatted link labels, optional title tooltips, and linked inline images. Support reference links, angle-bracket autolinks, email links, and relative file destinations.
14
+ - Preserve template hyperlink styles and supply a theme-aware default when needed. Keep hyperlink OOXML creation isolated until python-docx provides a public authoring API.
15
+ - Update syntax discovery, managed skill guidance, documentation, and the showcase. Add hyperlink parsing, rendering, relationship, and CLI regression tests.
16
+ - Continue rejecting empty destinations and document-local bookmark links with line-aware diagnostics.
17
+
18
+ ## 0.2.0
19
+
20
+ - Synchronize existing pristine managed skills to the running CLI version during normal commands.
21
+ - Store managed ownership, version, and normalized content hashes in `SKILL.md` front matter. Migrate legacy managed skills and recover invalid version metadata.
22
+ - Add read-only skill status and force installation for managed edits. Preserve custom directory support, removal safety, and JSON output.
23
+ - Skip automatic synchronization for local source and editable builds. Add atomic replacement, concurrent-change checks, and installed-wheel lifecycle smoke tests.
24
+
25
+ ## 0.1.0
26
+
27
+ - Add strict Markdown parsing with invisible YAML directives and line-aware diagnostics.
28
+ - Add editable Word rendering for text, headings, blockquotes, code, mixed nested lists, tables, images, page breaks, and sections.
29
+ - Add blank `.docx` templates, semantic style mapping, font overrides, template inspection, and a packaged default template.
30
+ - Add safe local and remote image handling, JSON automation output, overwrite protection, syntax discovery, and managed agent skill commands.
31
+ - Add a complete test suite, showcase document, CI, package validation, wheel smoke tests, and trusted PyPI publishing.
@@ -0,0 +1,506 @@
1
+ Metadata-Version: 2.5
2
+ Name: markdown-docx
3
+ Version: 0.3.1
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: packaging>=24.0
28
+ Requires-Dist: pillow<13,>=10.0
29
+ Requires-Dist: ps-python-docx==1.3.0
30
+ Requires-Dist: pyyaml<7,>=6.0
31
+ Description-Content-Type: text/markdown
32
+
33
+ # markdown-docx
34
+
35
+ `markdown-docx` turns constrained Markdown into editable Word `.docx` documents built from real Word paragraphs, tables, images, styles, and sections. It is a strict, predictable CLI designed for both people and coding agents.
36
+
37
+ The Markdown stays readable in normal renderers. Word-specific layout and style settings live in invisible reserved HTML comments. Unsupported input produces a stable, line-aware error instead of an approximate document.
38
+
39
+ ## Prerequisite
40
+
41
+ `markdown-docx` is designed to be used with [`uv`](https://docs.astral.sh/uv/getting-started/installation/). Install `uv` before continuing. The documented workflows use `uvx` to run the tool without requiring a global installation.
42
+
43
+ ## Quick start with an agent
44
+
45
+ Install the managed agent skill:
46
+
47
+ ```powershell
48
+ uvx markdown-docx skill install
49
+ ```
50
+
51
+ Then use `$markdown-docx` in Codex, Claude Code, or another agent harness that supports skills:
52
+
53
+ > Use $markdown-docx to create a project brief. Keep the source readable as normal Markdown and save the editable DOCX beside it.
54
+
55
+ The skill teaches the agent how to inspect the format and templates, write valid document Markdown, render the document safely, and handle structured results.
56
+
57
+ ## What it creates
58
+
59
+ Markdown stays readable, while the generated document remains easy to edit in Word.
60
+
61
+ ![Rendered Word document example](sample/assets/showcase-page-1.png)
62
+
63
+ See the [showcase Markdown](sample/showcase.md) and its [editable Word output](sample/showcase.docx) for a complete example.
64
+
65
+ ## Use the CLI directly
66
+
67
+ Render a document without installing the package globally:
68
+
69
+ ```powershell
70
+ uvx markdown-docx document.md document.docx
71
+ ```
72
+
73
+ When the output path is omitted, the tool writes a `.docx` beside the input Markdown file:
74
+
75
+ ```powershell
76
+ uvx markdown-docx document.md
77
+ ```
78
+
79
+ Inspect the supported format or the styles in the default template:
80
+
81
+ ```powershell
82
+ uvx markdown-docx --syntax
83
+ uvx markdown-docx --list-styles
84
+ uvx markdown-docx --list-table-styles
85
+ ```
86
+
87
+ To install the command as a persistent tool instead:
88
+
89
+ ```powershell
90
+ uv tool install markdown-docx
91
+ ```
92
+
93
+ The examples below continue to use `uvx markdown-docx` so they work without a global installation.
94
+
95
+ ## How the format works
96
+
97
+ ![Readable Markdown converted into editable Word](sample/assets/word-workflow.png)
98
+
99
+ The document model has four core rules:
100
+
101
+ 1. Standard Markdown contains the document content.
102
+ 2. Optional document metadata may appear once at the beginning of the file.
103
+ 3. Table, image, page-break, and section directives appear immediately before the content they affect.
104
+ 4. Word templates own detailed formatting such as styles, spacing, colors, borders, and numbering.
105
+
106
+ Headings organize content. They never create Word sections.
107
+
108
+ A minimal document needs no Word metadata:
109
+
110
+ ```markdown
111
+ # Project brief
112
+
113
+ This document was generated from readable Markdown.
114
+
115
+ ## Goals
116
+
117
+ - Make the launch process repeatable
118
+ - Give every deliverable a clear owner
119
+ - Keep the final document editable
120
+
121
+ | Deliverable | Owner | Status |
122
+ | --- | --- | --- |
123
+ | Launch plan | Maya | Ready |
124
+ | Support guide | Jordan | In progress |
125
+ ```
126
+
127
+ Render it with:
128
+
129
+ ```powershell
130
+ uvx markdown-docx project-brief.md project-brief.docx
131
+ ```
132
+
133
+ If no `--template` is provided, the packaged blank template supplies the default styles and document settings.
134
+
135
+ ## Use a Word template
136
+
137
+ A custom template lets an organization control styles, theme data, fonts, numbering definitions, and section defaults while the Markdown remains focused on content. Inspect a template before writing the document, then use only the styles it provides.
138
+
139
+ The template must be a blank `.docx` formatting template. `.dotx` is not supported. Inspect it before writing Markdown that refers to its style names:
140
+
141
+ ```powershell
142
+ uvx markdown-docx --inspect-template --template formatting.docx
143
+ uvx markdown-docx --list-styles --template formatting.docx
144
+ uvx markdown-docx --list-table-styles --template formatting.docx
145
+ ```
146
+
147
+ Then render with the template:
148
+
149
+ ```powershell
150
+ uvx markdown-docx report.md report.docx --template formatting.docx
151
+ ```
152
+
153
+ The template remains unchanged. It must not contain:
154
+
155
+ - Non-whitespace body text
156
+ - Body tables
157
+ - Body images or drawings
158
+ - Nonempty headers or footers
159
+
160
+ Each configured style must exist and 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.
161
+
162
+ ## Customize a document
163
+
164
+ Word-specific settings use reserved `markdown-docx` HTML comments. Normal Markdown renderers hide these comments and continue to display the document content.
165
+
166
+ Document metadata sets document-wide defaults:
167
+
168
+ | Key | Purpose |
169
+ | --- | --- |
170
+ | `page_size` | Select `letter`, `legal`, `a4`, or custom dimensions |
171
+ | `orientation` | Select portrait or landscape orientation |
172
+ | `margins` | Set the top, right, bottom, and left margins |
173
+ | `styles` | Map Markdown constructs to Word style names |
174
+ | `fonts` | Set theme body and heading fonts, plus a fixed monospace font |
175
+
176
+ Content directives control the following block:
177
+
178
+ | Directive | Purpose |
179
+ | --- | --- |
180
+ | `section` | Start a next-page Word section with layout overrides |
181
+ | `table` | Set table style, width, alignment, and column ratios |
182
+ | `image` | Set standalone image width and alignment |
183
+ | `page-break` | Start the next content block on a new page |
184
+
185
+ Only HTML comments beginning with `markdown-docx` are accepted. All other raw HTML and HTML comments are errors. Metadata uses strict YAML. Duplicate keys, unknown keys, invalid types, unitless lengths, and misplaced comments are errors.
186
+
187
+ Run `uvx markdown-docx --syntax` for the complete schema, accepted values, and examples.
188
+
189
+ ### Document settings
190
+
191
+ Document metadata may appear once. It must be the first non-whitespace content:
192
+
193
+ ```markdown
194
+ <!-- markdown-docx
195
+ document:
196
+ page_size: letter
197
+ orientation: portrait
198
+ margins:
199
+ top: 0.75in
200
+ right: 0.75in
201
+ bottom: 0.75in
202
+ left: 0.75in
203
+ fonts:
204
+ body: Aptos
205
+ headings: Aptos Display
206
+ monospace: Consolas
207
+ -->
208
+
209
+ # Project brief
210
+
211
+ This remains ordinary Markdown.
212
+ ```
213
+
214
+ Named page sizes are `letter`, `legal`, and `a4`. Custom page sizes use nominal portrait dimensions. Their width must not exceed their height. Lengths accept `in`, `cm`, `mm`, and `pt`. Margins must leave a positive usable page area.
215
+
216
+ The `styles` mapping assigns Word paragraph and table styles to semantic Markdown constructs. Ordered and unordered list styles are arrays, with one Word style for each supported nesting depth.
217
+
218
+ `fonts.body` and `fonts.headings` set the document theme's Latin body and heading fonts. Word's theme font settings show these choices. Mapped paragraph styles and their linked character styles inherit from the theme, so a later theme font change updates existing text and new paragraphs. Font names are not applied to individual body or heading runs. Body overrides also update the default paragraph style and default run font reference. Omitted body or heading overrides preserve that part of the template theme and its styles.
219
+
220
+ `fonts.monospace` stays explicit for inline code and code blocks because Word has no monospace theme font slot. Templates must use distinct styles for simultaneously overridden body, heading, and code roles. Conflicting mappings report `template_font_style_conflict`. A template without a theme receives the packaged theme when body or heading overrides are requested. A malformed theme reports `template_theme_invalid`.
221
+
222
+ Theme colors, effects, East Asian fonts, complex script fonts, and supplemental script mappings are preserved. These overrides do not embed or install fonts. Word may substitute fonts that are unavailable on the rendering machine.
223
+
224
+ ### Sections and page breaks
225
+
226
+ A section directive starts a next-page Word section before the following content block:
227
+
228
+ ```markdown
229
+ <!-- markdown-docx
230
+ section:
231
+ orientation: landscape
232
+ margins:
233
+ top: 0.75in
234
+ right: 0.75in
235
+ bottom: 0.75in
236
+ left: 0.75in
237
+ -->
238
+
239
+ ## Landscape analysis
240
+ ```
241
+
242
+ 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:
243
+
244
+ ```markdown
245
+ <!-- markdown-docx
246
+ section: default
247
+ -->
248
+ ```
249
+
250
+ To insert a page break without creating a section:
251
+
252
+ ```markdown
253
+ <!-- markdown-docx: page-break -->
254
+
255
+ ## Appendix
256
+ ```
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
+ ### Lists
308
+
309
+ Ordered and unordered lists may be mixed and nested. Each list type maps to one Word paragraph style per nesting depth:
310
+
311
+ ```yaml
312
+ styles:
313
+ ordered_list:
314
+ - List Number
315
+ - List Number 2
316
+ - List Number 3
317
+ unordered_list:
318
+ - List Bullet
319
+ - List Bullet 2
320
+ - List Bullet 3
321
+ ```
322
+
323
+ 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.
324
+
325
+ ## Styles and supported content
326
+
327
+ The packaged template provides these default style mappings. Supplied templates may use different style names.
328
+
329
+ | Content | Default Word style |
330
+ | --- | --- |
331
+ | Paragraph | `Normal` |
332
+ | Headings | `Heading 1` through `Heading 6` |
333
+ | Blockquote | `Quote` |
334
+ | Code block | `Code Block` |
335
+ | Ordered lists | `List Number` through `List Number 3` |
336
+ | Unordered lists | `List Bullet` through `List Bullet 3` |
337
+ | Table | `Table Grid` |
338
+
339
+ The current release supports:
340
+
341
+ - ATX headings from `#` through `######`
342
+ - Paragraphs and standard soft or hard line breaks
343
+ - Emphasis, strong emphasis, and inline backtick code
344
+ - Markdown links with formatted labels and optional titles
345
+ - Fenced code blocks
346
+ - Blockquotes containing paragraphs
347
+ - Ordered and unordered lists, including mixed nesting
348
+ - Pipe tables with inline text formatting
349
+ - Local and remote inline images
350
+ - Standalone images with width and alignment metadata
351
+
352
+ The following syntax is intentionally unsupported:
353
+
354
+ - Raw HTML and non-reserved HTML comments
355
+ - Setext headings and horizontal rules
356
+ - Indented code blocks
357
+ - Task lists and footnotes
358
+ - Multi-paragraph list items
359
+ - Tables, images, code blocks, or blockquotes nested inside list items
360
+ - Images inside table cells or blockquotes
361
+ - Arbitrary Markdown extensions
362
+
363
+ Links such as `[link text](https://example.com)` become native, clickable, editable Word hyperlinks. Labels preserve bold, italic, inline code, and line breaks. Optional Markdown titles become Word tooltips. Links work in paragraphs, headings, blockquotes, lists, and table cells. Reference links, angle-bracket autolinks, email links, relative file links, and linked inline images are supported wherever their content is allowed. Destinations are stored without fetching them. Relative file links are resolved by Word relative to the output document. Bare URLs remain plain text. Empty destinations and document-local links such as `[heading](#heading)` are rejected. Heading bookmarks are not generated.
364
+
365
+ ```markdown
366
+ Read the [**project documentation**](https://example.com/docs "Read the guide").
367
+ Contact [the team](mailto:team@example.com).
368
+ ```
369
+
370
+ The source alt text for images remains meaningful Markdown content, but `ps-python-docx` 1.3.0 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.
371
+
372
+ ## Automation and safety
373
+
374
+ ### Structured results and overwrite safety
375
+
376
+ Use `--json` for one complete machine-readable result:
377
+
378
+ ```powershell
379
+ uvx markdown-docx report.md report.docx --json
380
+ ```
381
+
382
+ 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.
383
+
384
+ The CLI refuses to overwrite an existing output. Add `--force` only when replacement is intended:
385
+
386
+ ```powershell
387
+ uvx markdown-docx report.md report.docx --force --json
388
+ ```
389
+
390
+ ### Remote images and stdin
391
+
392
+ Use `--no-remote-images` for offline builds or untrusted Markdown. Download assets ahead of time and use local paths when reproducible builds matter.
393
+
394
+ For stdin, provide both an output path and a base directory:
395
+
396
+ ```powershell
397
+ Get-Content report.md | uvx markdown-docx --input - --output report.docx --base-dir .
398
+ ```
399
+
400
+ ## Reference
401
+
402
+ Useful discovery and metadata commands:
403
+
404
+ ```powershell
405
+ uvx markdown-docx --help
406
+ uvx markdown-docx --syntax
407
+ uvx markdown-docx --inspect-template --template formatting.docx
408
+ uvx markdown-docx --list-styles --template formatting.docx
409
+ uvx markdown-docx --list-table-styles --template formatting.docx
410
+ uvx markdown-docx --about
411
+ uvx markdown-docx --version
412
+ ```
413
+
414
+ Exit codes:
415
+
416
+ | Code | Meaning |
417
+ | ---: | --- |
418
+ | `0` | Success |
419
+ | `2` | Usage or input error |
420
+ | `3` | Markdown or metadata parse error |
421
+ | `4` | Template or style error |
422
+ | `5` | Image or asset error |
423
+ | `6` | Unsupported Markdown or feature |
424
+ | `7` | DOCX rendering error |
425
+ | `8` | Unexpected internal error |
426
+
427
+ ### Manage the agent skill
428
+
429
+ The standard location is `~/.agents/skills/markdown-docx/SKILL.md`. Inspect the installed skill without changing it:
430
+
431
+ ```powershell
432
+ uvx markdown-docx skill status
433
+ uvx markdown-docx skill status --json
434
+ ```
435
+
436
+ Normal commands synchronize an already-installed managed skill when it is eligible. Synchronization is local. It does not query a package index, refresh uv's cache, or update the CLI. Missing, unmanaged, modified, unverifiable, equal-version, and newer skills are preserved.
437
+
438
+ To replace managed edits intentionally or recover an older managed skill:
439
+
440
+ ```powershell
441
+ uvx markdown-docx skill install --force
442
+ ```
443
+
444
+ Install `--force` still refuses unmanaged content and never downgrades a newer skill. Custom directories require explicit updates:
445
+
446
+ ```powershell
447
+ uvx markdown-docx skill install --skills-dir PATH
448
+ uvx markdown-docx skill status --skills-dir PATH
449
+ uvx --from . markdown-docx skill install
450
+ ```
451
+
452
+ Remove the skill with `uvx markdown-docx skill remove`. Removal refuses unmanaged content and extra files unless `--force` is supplied. All skill commands accept `--skills-dir` and `--json`. Skill commands never trigger automatic synchronization. Maintenance notices go to stderr and leave JSON stdout intact.
453
+
454
+ See [skill lifecycle metadata and decisions](docs/skill-management.md) for the integrity format, version decisions, and recovery rules.
455
+
456
+ ## Examples
457
+
458
+ - [Showcase Markdown source](sample/showcase.md)
459
+ - [Generated editable Word document](sample/showcase.docx)
460
+ - [Rendered first page](sample/assets/showcase-page-1.png)
461
+ - [Workflow illustration](sample/assets/word-workflow.png)
462
+
463
+ The showcase opens with an illustrated three-dog story, then exercises supported text, list, table, image, page-break, and section behavior in a dedicated capability lab.
464
+
465
+ Regenerate it from a repository checkout:
466
+
467
+ ```powershell
468
+ uvx --refresh --from . markdown-docx sample\showcase.md sample\showcase.docx --force
469
+ ```
470
+
471
+ ## Design and compatibility
472
+
473
+ Both development installs and published wheels use `ps-python-docx==1.3.0` from PyPI. It retains the `docx` import package and replaces the upstream `python-docx` distribution. Use `uv sync --locked --all-groups` and `uv run markdown-docx` when working from source. CI and the release workflow test a clean wheel installation from PyPI.
474
+
475
+ Production code uses the public `docx` APIs provided by `ps-python-docx` 1.3.0. Theme fonts, style references, linked styles, and document defaults use public library APIs. The only OOXML exception is `src/markdown_docx/hyperlinks.py` for native hyperlink creation. Replace that helper when a supported creation API becomes available. Tests enforce this boundary and inspect saved theme data, style inheritance, and effective font selection. See [public API capabilities](docs/public-api-capabilities.md) for the decision record.
476
+
477
+ The visual CI job also renders font regression documents through LibreOffice using installed Liberation fonts. It verifies the fonts recorded in the PDF, then changes only the theme and checks that the rendered fonts follow it. To run the same check through installed Microsoft Word with Aptos and Aptos Display on Windows:
478
+
479
+ ```powershell
480
+ $env:MARKDOWN_DOCX_FONT_RENDERER="word"
481
+ uv run pytest tests/test_font_rendering.py
482
+ ```
483
+
484
+ This optional check uses `uvx office-export` and requires the named fonts to be available to Word. A substituted font fails the test.
485
+
486
+ 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.
487
+
488
+ ## Development
489
+
490
+ Install the development environment and run the checks:
491
+
492
+ ```powershell
493
+ $env:UV_LINK_MODE="copy"
494
+ uv sync --locked --all-groups
495
+ uv run pytest
496
+ uv run ruff check .
497
+ uv run ruff format --check .
498
+ uv run mypy
499
+ ```
500
+
501
+ Build and validate distributions:
502
+
503
+ ```powershell
504
+ uv build
505
+ uv run twine check dist/*
506
+ ```