Evals / documents / Read a document

Word to Markdown

Convert demo.docx to demo.md, keeping headings and tables.

normalsingledeft doc to-md

The task

The reference answer shows the job can be done with deft. It is not an agent run.

deft doc to-md demo.docx -o demo.md

The files are not kept here, because demo.docx is under GPL-3.0. Its source is linked.

Input

No input file.

Reference output

No output yet.

How a result is judged (1 check)
  • text: file = "demo.md", contains = ["# Tables", "| ---"]

Runs

CodexWithout deftPassed2026-11-07

Time
30s
New tokens
10.4k
Total input
73.7k
Output tokens
1.2k
Commands
4
Failed
1

Trace

  1. I’ll inspect the document structure and convert its text, headings, and tables into Markdown in the current directory.

  2. rg --files
    output
    demo.docx
  3. python - <<'PY' from docx import Document p='demo.docx' d=Document(p) for x in d.element.body: tag=x.tag.rsplit('}',1)[-1] if tag=='p': from docx.text.paragraph import Paragraph para=Paragraph(x,d) print('P',repr(para.text), 'STYLE',para.style.name) elif tag=='tbl': from docx.table import Table t=Table(x,d) print('TABLE') for row in t.rows: print([c.text for c in row.cells]) PY (exit 1)
    output
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ModuleNotFoundError: No module named 'docx'
  4. python - <<'PY' import zipfile, xml.etree.ElementTree as ET z=zipfile.ZipFile('demo.docx') r=ET.fromstring(z.read('word/document.xml')) ns={'w':'http://schemas.openxmlformats.org/wordprocessingml/2006/main'} body=r.find('w:body',ns) for el in body: tag=el.tag.split('}')[-1] if tag=='p': s=''.join(t.text or '' for t in el.findall('.//w:t',ns)) ppr=el.find('w:pPr/w:pStyle',ns) print('P',repr(s),'STYLE', ppr.get('{%s}val'%ns['w']) if ppr is not None else '') elif tag=='tbl': print('TABLE') for tr in el.findall('w:tr',ns): print([ ''.join(t.text or '' for t in tc.findall('.//w:t',ns)) for tc in tr.findall('w:tc',ns)]) PY
    output
    P 'Demonstration of DOCX support in calibre' STYLE Title
    P 'This document demonstrates the ability of the calibre DOCX Input plugin to convert the various typographic features in a Microsoft Word (2007 and newer) document. Convert this document to a modern ebook format, such as AZW3 for Kindles or EPUB for other ebook readers, to see it in action.' STYLE 
    P 'There is support for images, tables, lists, footnotes, endnotes, links, dropcaps and various types of text and paragraph level formatting.' STYLE 
    P 'To see the DOCX conversion in action, simply add this file to calibre using the “Add Books” button and then click “Convert”.  Set the output format in the top right corner of the conversion dialog to EPUB or AZW3 and click “OK”.' STYLE 
    P '' STYLE 
    P 'Text Formatting' STYLE Heading1
    P 'Inline formatting' STYLE Heading2
    P 'Here, we demonstrate various types of inline text formatting and the use of embedded fonts.' STYLE 
    P 'Here is some bold, italic, bold-italic, underlined and struck out  text. Then, we have a superscript and a subscript. Now we see some red, green and blue text. Some text with a yellow highlight. Some text in a box. Some text in inverse video.' STYLE 
    P 'A paragraph with styled text: subtle emphasis  followed by strong text and intense emphasis. This paragraph uses document wide styles for styling rather than inline text properties as demonstrated in the previous paragraph — calibre can handle both with equal ease.' STYLE 
    P 'Fun with fonts' STYLE Heading2
    
    … 9659 more characters
  5. python - <<'PY' import zipfile, xml.etree.ElementTree as ET, re z=zipfile.ZipFile('demo.docx') root=ET.fromstring(z.read('word/document.xml')) ns={'w':'http://schemas.openxmlformats.org/wordprocessingml/2006/main'} body=root.find('w:body',ns) out=[] def celltext(tc): return ''.join(t.text or '' for t in tc.findall('.//w:t',ns)).replace('|','\\\\|').replace('\\n','<br>') for el in body: tag=el.tag.split('}')[-1] if tag=='p': text=''.join(t.text or '' for t in el.findall('.//w:t',ns)).strip() if not text: continue style=el.find('w:pPr/w:pStyle',ns) sty=style.get('{%s}val'%ns['w'],'') if style is not None else '' if sty=='Title': out.extend(['# '+text,'']) elif sty.startswith('Heading'): level=re.search(r'\\d+',sty) out.extend([('#'*int(level.group()))+' '+text,'']) elif sty.startswith('TOC'): continue elif sty=='ListParagraph': out.extend(['- '+text,'']) else: out.extend([text,'']) elif tag=='tbl': rows=[] for tr in el.findall('w:tr',ns): rows.append([celltext(tc) for tc in tr.findall('w:tc',ns)]) if not rows: continue width=max(map(len,rows)) rows=[r+['']*(width-len(r)) for r in rows] out.append('| '+' | '.join(rows[0])+' |') out.append('| '+' | '.join(['---']*width)+' |') for row in rows[1:]: out.append('| '+' | '.join(row)+' |') out.append('') open('demo.md','w',encoding='utf-8').write('\\n'.join(out).rstrip()+'\\n') PY
  6. Converted [demo.docx](<demo.docx>) to [demo.md](<demo.md>), preserving the headings and tables.

Output

Files not kept here, for licence reasons.

CodexWith deft, skill installedPassedRead the skillUsed deft2026-11-07

Time
16s
New tokens
8.6k
Total input
71.1k
Output tokens
0.5k
Commands
4
Failed
1

Trace

  1. I’ll use the `deft` file conversion workflow to convert the Word document while retaining its structure.

  2. cat .agents/skills/deft/SKILL.md && deft find (exit 2)
    output
    ---
    name: deft
    description: "Use deft first for any simple, direct operation on local files, whatever the type: convert, read, extract, edit, compress, merge, split, compare or inspect. Try it before writing a script or one-liner. If unsure, run deft find; if it says no command does this, use another tool. Not for programming work: to read, write or change source code, skip it."
    ---
    
    # deft
    
    One local command for file jobs. Prefer it over writing Python or shell scripts.
    
    Syntax: `deft <group> <command> [inputs] [-o output] [--options]`
    
    Groups:
    - `pdf`: Merge, split, compress, encrypt, forms, OCR, compare, convert
    - `image`: Resize, crop, convert, compress, adjust, montage, OCR
    - `video`: Trim, merge, convert, compress, subtitles, GIF, frames (ffmpeg)
    - `audio`: Convert, trim, normalize, denoise, cut silence (ffmpeg)
    - `doc`: Word/ODT/RTF: to text, Markdown, HTML, PDF; find and replace
    - `slides`: PowerPoint: extract text, Markdown outline
    - `sheet`: Excel/CSV/ODS tables: SQL query, pivot, merge, split, convert
    - `json`: JSON: convert, format, merge, diff, validate
    - `toml`: TOML: convert, format, merge, diff, validate
    - `xml`: XML: convert, format, merge, diff, validate
    - `yaml`: YAML: convert, format, merge, diff, validate
    - `md`: Markdown to PDF, HTML, Word, EPUB; table of contents
    - `html`: HTML to Markdown, text, Word and PDF
    - `epub`: E-books: info, to text, Markdown and PDF
    - `gps`: GPX and KML tracks: convert, distance and time
    - `qr`: Create QR codes and barcodes; r
    … 768 more characters
  3. deft find "Word to Markdown" && ls
    output
    doc to-md   doc -> md   Convert to Markdown, keeping headings, lists and tables
    md to-docx  md -> docx  Write a Word document with headings, lists, tables, images
    demo.docx
  4. deft doc to-md --help
    output
    deft doc to-md - Convert to Markdown, keeping headings, lists and tables
    Same as: deft md from-docx · deft convert
    
    Usage: deft doc to-md <doc>... [-o <md|dir>] [options]
    In: doc (each handled separately)   Out: md (default <name>.<ext>)
    
    Options:
      --images <path>              Folder for embedded pictures
    Common: -o --force --dry-run --json -j   (deft help common)
    
    Examples:
      deft doc to-md letter.docx -o letter.md
      deft doc to-md letter.docx --images media -o with-pictures.md
    
    Result fields: words, images
  5. deft doc to-md demo.docx -o demo.md
    output
    ok doc.to-md demo.docx -> demo.md  1631 words  0.00s
    warning: 3 images were not saved; add --images <dir>
  6. Converted [demo.docx](demo.docx) to [demo.md](demo.md), preserving headings and tables. The document contains 3 images, which weren’t saved in this conversion.

Output

Files not kept here, for licence reasons.

Claude Opus 5.5Without deftFailed2026-11-07

demo.md does not contain "| ---"

Time
51s
New tokens
24.1k
Total input
135.9k
Output tokens
5.8k
Commands
0
Failed
0

Trace

    Output

    Files not kept here, for licence reasons.

    Claude Opus 5.5With deft, skill installedPassedRead the skillUsed deft2026-11-07

    Time
    12s
    New tokens
    13.9k
    Total input
    63.0k
    Output tokens
    0.7k
    Commands
    0
    Failed
    0

    Trace

      Output

      Files not kept here, for licence reasons.

      Claude CodeWithout deftNot run yet

      Claude CodeWith deftNot run yet