Skip to content

Converter skills

Look up each converter’s accepted inputs, outputs, options, dependencies, and operational limitations.

The skills in the converters pack, their inputs, outputs, flags, and prerequisites. Each skill is a thin wrapper: the agent invokes a script and reports the result.

SkillDirectionEngine
file-to-markdowndocuments/images → MarkdownDocling / vision pipeline
mermaid-rendererMarkdown → Markdown + imagesMermaid CLI (mmdc)
markdown-to-htmlMarkdown → HTMLmarked + highlight.js
markdown-to-docxMarkdown → branded Word (template-fill)docxtpl
markdown-to-pptxMarkdown → branded PowerPoint (template-fill)python-pptx
markdown-to-xlsxMarkdown → branded Excel (template-fill)openpyxl
msg-to-markdownOutlook .msg → Markdown@nicecode/msg-reader / msgreader

Convert documents and images to Markdown. Two branches, selected by input type.

Source: packs/converters/.apm/skills/file-to-markdown/

BranchExtensionsPath
DocumentPDF, DOCX, PPTX, XLSX, XLSscripts/convert.py (Docling)
ImagePNG, JPG, JPEG, TIFF, BMP, WEBP, GIFscripts/split_image.py + agent vision + scripts/reconcile.py
BranchNeedsInstall
DocumentDocling, Pillowpython -m pip install docling Pillow
ImagePillowpython -m pip install Pillow

The first Docling run downloads ML models (~1–2 min); later runs are fast. Confirm Docling is importable with python -c "import docling" (exit 0 → proceed; non-zero → not installed).

Terminal window
python scripts/convert.py "<input-file>"

Writes <basename>.md next to the input. One file per call — loop for a batch. Stdout markers:

MarkerMeaning
OUTPUT: <path>Path to the written Markdown file
LINES: <n> / WORDS: <n>Counts
WARNING: <msg>Non-fatal (e.g. sparse text); surfaced to the user

A two-pass sliding-window pipeline:

StepCommandOutput
Recommendsplit_image.py recommend --input <image>JSON: source dims, single-pass flag, recommended viewport/stride
Overviewsplit_image.py overview --input <image> --output-dir <dir>/ --max-dim 1200<dir>/overview.png (agent reads it for a structural map)
Detailsplit_image.py detail --input <image> --output-dir <dir>/ --viewport 1200 --stride 800tile_W0_R<row>_C<col>.png + detail_manifest.json
Reconcilereconcile.py --manifest … --extractions … --strategy <name> --title "…" --output-json <dir>/merged.json --output-md <output>.mdmerged JSON + final Markdown

The agent reads each detail tile and writes <dir>/extractions.json, choosing one extraction strategy: architecture, event-storm, process, domain, or conceptual. reconcile.py then translates tile coordinates to global ones, collapses duplicates by (type, normalized_name) and by IoU ≥ 0.5, picks canonical records by confidence then tile-centrality, sorts by the structural map’s layout, and emits Markdown with YAML frontmatter. Reconcile stdout: OUTPUT_JSON, OUTPUT_MD, ELEMENTS, AMBIGUITIES.

SituationBehavior
Image ≤ 1200 px on both dimsSkip overview; run a single detail tile (--viewport/--stride = max dim)
Source > 8000 px on a sideScript auto-prescales before tiling, records the factor in the manifest
Scanned PDFDocling applies OCR automatically; surfaces any WARNING:
Password-protected fileDocument branch fails fast; remove the password first
Detail pass > 100 tilessplit_image.py warns; raise --stride or lower --viewport
Tile read failsSkipped; reconciler reports the gap in ambiguities

Extract ```mermaid fenced blocks from a Markdown file, render each to an image, and write a rewritten Markdown file with each fence replaced by an image reference. The original input is not modified.

Source: packs/converters/.apm/skills/mermaid-renderer/

The Mermaid CLI (mmdc), installed via npm install -g @mermaid-js/mermaid-cli (or a project-local node_modules/ on PATH). No Python deps beyond the standard library. Verify with python scripts/render_mermaid.py --check (exit 0 → ready; exit 2 → not installed).

Terminal window
python scripts/render_mermaid.py --input report.md --output-dir ./rendered [flags]
FlagMeaning
--input PATHSource Markdown file. Required.
--output-dir DIRDirectory for images and the rewritten Markdown. Default: ./mermaid-out.
--format png|svgOutput format. Default: png.
--theme default|forest|dark|neutralMermaid theme. Default: default.
--background white|transparent|#hexBackground color. Default: white.
--prefix NAMEOutput filename prefix. Default: mermaid.
--width NOutput width in px (passes to mmdc -w).
--height NOutput height in px (passes to mmdc -H).
--checkVerify mmdc is on PATH; exit 0 or 2.
--verboseDebug logging.
  • <output-dir>/<prefix>-1.<ext>, <prefix>-2.<ext>, … — one image per block, numbered in document order.
  • <output-dir>/<input-basename>.md — rewritten copy with each fence replaced by a Markdown image reference.

Stdout: OUTPUT_DIR, REWRITTEN, DIAGRAMS.

SituationBehavior
No Mermaid blocksDIAGRAMS: 0, input copied through unchanged, exit 0
A block fails to renderWrites mermaid-N.error.txt, leaves the fence intact, keeps going, exits non-zero with a failure count
Unknown thememmdc exits with the valid choices; surfaced
mmdc not on PATH--check exits 2 with the install command

Convert a Markdown file to a self-contained, styled HTML page (sticky header, sidebar nav, syntax-highlighted code, callout boxes, Mermaid diagrams, print-ready). For documents, not slides.

Source: packs/converters/.apm/skills/markdown-to-html/

Node.js with marked and highlight.js (pinned in the skill’s package.json). Verify from the skill directory with node -e "require.resolve('marked'); require.resolve('highlight.js')" (exit 0 → ready; non-zero → run npm install once). Add the skill’s node_modules/ to .gitignore if the skill lives in a tracked directory.

Terminal window
node scripts/render.js <input.md> [flags]
FlagMeaning
--output FILEOutput path. Default: input with .html extension.
--title TEXTPage title. Default: first H1, then filename.
--subtitle TEXTHeader subtitle (small grey text).
--theme navy|green|teal|amber|roseAccent color. Default: navy.
--no-mermaidSkip the Mermaid CDN script.

Writes the HTML file and prints three stdout lines:

MarkerMeaning
OUTPUT: <path>Path to the written HTML file
SECTIONS: <n>Number of h2/h3 anchors built
MERMAID: yes|noWhether Mermaid handling was emitted
  • Headings get stable id attributes for sidebar links and the print TOC.
  • Code blocks are syntax-highlighted; ```mermaid fences pass through as <div class="mermaid"> for the runtime CDN renderer.
  • Tables are wrapped in <div class="table-wrap"> for horizontal scroll.
  • Paragraphs beginning with **Note:**, **Tip:**, **Warning:**, **Important:**, or **Stop:** become styled callout boxes.
  • Every output includes an @media print block; Ctrl+P → Save as PDF works out of the box.
SituationBehavior
Missing dependenciesrender.js exits 1 with an install hint
No headingsSidebar shows (no sections); output still works
Unknown themeExits with the list of valid choices
Offline output wanted with Mermaid presentPass --no-mermaid; the block falls back to a plain <pre>

Fill a branded Word template from a Markdown artifact. Template-fill via docxtpl — the designer’s cover page, styles, headers, and logo survive; the skill never converts Markdown into a fresh document.

Source: packs/converters/.apm/skills/markdown-to-docx/

Tier-1 on docxtpl (exact canonical PyPI package). Install with python -m pip install 'docxtpl>=0.16.0' (the floor clears a version where get_undeclared_template_variables() was broken). The library installs into your environment, outside the repo’s SCA. Verify with python scripts/render.py --check (exit 0 → ready; exit 2 → not installed).

Terminal window
python scripts/render.py --check
python scripts/render.py inspect <template.docx>
python scripts/render.py render <markdown> --template <template.docx> [--output <path>]
VerbPurpose
--checkImport-probe docxtpl; exit 0/2.
inspect <template>List the template’s declared Jinja variables.
render <markdown> --template <tpl>Fill the template and write a .docx. Default output: <basename>.docx in CWD.

A .docx has no fill-points until you add Jinja tags: {{ var }} (scalar), {%p for it in items %}…{%p endfor %} (paragraph loop), {%tr for r in rows %}…{%tr endfor %} (table-row loop). Mapping: front-matter key: value{{ key }}; the first list → items; the first Markdown table → rows (list of {column: value} dicts). Author each tag in one uniform run or Word’s run-splitting will hide it.

Stdout: OUTPUT:, FILLED:, WARNING:, and GUIDANCE: (emitted instead of OUTPUT: when the template has no tags). Renders with autoescape=True, so user content with </&/{{ is XML-escaped, not interpolated. A user-supplied template is trusted-author input — a malicious template author could embed SSTI; that (and XXE / zip-bomb) is an accepted, out-of-scope risk. The output write is confined under the working directory. Omit --template only on the user’s explicit opt-out — the skill then writes an unbranded .docx via python-docx (with a WARNING:).


Fill a branded PowerPoint template from a Markdown artifact. Template-fill via python-pptx — the slide master, theme, fonts, and placed logo survive.

Source: packs/converters/.apm/skills/markdown-to-pptx/

Tier-1 on python-pptx. Install with python -m pip install 'python-pptx>=1.0.0'. Installs outside the repo’s SCA. Verify with python scripts/render.py --check.

Terminal window
python scripts/render.py --check
python scripts/render.py inspect <template.pptx>
python scripts/render.py render <markdown> --template <template.pptx> [--output <path>]
VerbPurpose
--checkImport-probe python-pptx; exit 0/2.
inspect <template>List the layout placeholders (layout/idx/type/name).
render <markdown> --template <tpl>Fill the deck and write a .pptx. Default output: <basename>.pptx in CWD.

PowerPoint layouts already carry placeholders, keyed by their stable idx — so every .pptx is fillable (no “untagged template” case). Mapping: front-matter title/subtitle → the title slide; each #/## heading → one slide; list items → bullet rows; a Markdown table → a TABLE placeholder if the layout has one, else a table added to the slide.

Stdout: OUTPUT:, FILLED:, WARNING:. python-pptx evaluates no template content as code, so there is no SSTI surface; XXE / zip-bomb on a crafted archive is an accepted, out-of-scope risk. The output write is confined under the working directory. Omit --template only on the user’s explicit opt-out (renders with the python-pptx default master; unbranded).


Fill a branded Excel template from a Markdown artifact. Template-fill via openpyxl — writes into named ranges and Excel Tables only, so formatting, formulas, and charts survive.

Source: packs/converters/.apm/skills/markdown-to-xlsx/

Tier-1 on openpyxl. Install with python -m pip install 'openpyxl>=3.1.0'. Installs outside the repo’s SCA. Verify with python scripts/render.py --check.

Terminal window
python scripts/render.py --check
python scripts/render.py inspect <template.xlsx>
python scripts/render.py render <markdown> --template <template.xlsx> [--output <path>]
VerbPurpose
--checkImport-probe openpyxl; exit 0/2.
inspect <template>List named ranges + Excel Tables (kind/name/ref).
render <markdown> --template <tpl>Fill the data ranges and write a .xlsx. Default output: <basename>.xlsx in CWD.

A workbook needs named ranges (for scalars) and/or Excel Tables (for tabular data) defined beforehand. Mapping: front-matter key: value → the single-cell named range called key; the first Markdown table → the first Excel Table’s data region (columns aligned by header, else by position).

Stdout: OUTPUT:, FILLED:, WARNING:, and GUIDANCE: (when the workbook has no fill-points). The script writes only into data cells and never resizes a range, so a chart reading it keeps working; a Markdown table longer than the Excel Table is truncated with a WARNING:, never expanded. openpyxl preserves charts/images it can parse on round-trip, but its tutorial warns shapes it cannot read are lost — re-open and verify for complex templates. The output write is confined under the working directory. Omit --template only on the user’s explicit opt-out — the skill then writes an unbranded .xlsx via a bare openpyxl workbook (with a WARNING:).


Convert Outlook .msg email files to Markdown, preserving headers (From, To, CC, Date), body content, and attachment metadata.

Source: packs/converters/.apm/skills/msg-to-markdown/

Node.js with one of @nicecode/msg-reader (preferred) or msgreader; scripts/convert.js uses whichever is installed. Install with npm install @nicecode/msg-reader. Verify from the skill directory:

Terminal window
node -e "try{require.resolve('@nicecode/msg-reader')}catch{require.resolve('msgreader')}"
CommandPurpose
node scripts/convert.js "<file>.msg"Convert one .msg to Markdown
node scripts/extract-attachments.js "<file>.msg"Extract attachments to a folder

For a glob like emails/*.msg, loop over each file individually.

Structured Markdown with a header table (From/To/CC/Date), the body, and attachment metadata. HTML bodies are converted (complex CSS or conditional Outlook markup may be simplified).

SituationBehavior
RTF-only bodyFlagged; re-save as HTML in Outlook or install an RTF parser
Winmail.dat / TNEFMay not parse; node-tnef suggested
Inline images (cid:)Stored as attachments; broken refs until extracted
Reply chainsQuoted replies preserved as nested blockquotes
Unusual encodingRe-read as UTF-8 / UTF-16LE / Windows-1252
Calendar .ics attachmentOffered for parsing into a structured section
Sensitivity labelsIncluded in the metadata table when present

For task recipes, see the how-to guides. Installing and upgrading the pack live in ../../_shared/.