Read .docx files with ~90% fewer LLM tokens. Same text, zero dependencies.
Google Drive agent skills (read_file / download_file / export_file)
are token-expensive for non-native .docx files: a 227 KB document becomes
~310K chars of base64 ≈ ~77K tokens when passed raw to an LLM.
docs-reader downloads the bytes outside the LLM context, parses them
locally into clean Markdown, and feeds only the text in — about ~7.6K
tokens for the same document.
No install. Python 3 only, stdlib only (zipfile + xml).
git clone https://github.com/dstwn/docs-reader.git
cd docs-reader
# Full extract
python3 skills/drive-docx-reader/scripts/extract.py "document.docx" -o /tmp/out.md
# One section only (saves even more)
python3 skills/drive-docx-reader/scripts/extract.py "document.docx" --section 6 -o /tmp/section6.mdToken estimate is printed to stderr on every run:
-- chars=30585 est_tokens~7646 blocks=72
Quick rule of thumb: tokens ≈ chars / 4.
The skill is self-contained (SKILL.md + scripts/), so drop the folder
in and restart Cursor (or start a new Agent session):
# Global — available in every project
git clone https://github.com/dstwn/docs-reader.git /tmp/docs-reader
mkdir -p ~/.cursor/skills
cp -r /tmp/docs-reader/skills/drive-docx-reader ~/.cursor/skills/
# ...or project-only
cp -r /tmp/docs-reader/skills/drive-docx-reader ./.cursor/skills/Verify: Settings → Rules → Agent Decides shows drive-docx-reader.
Trigger it automatically (agent decides from the description) or manually
by typing /drive-docx-reader in Agent chat.
python3 extract.py [-h] [-o OUT] [--section SECTION] docx
| Flag | Effect |
|---|---|
-o / --out |
Write Markdown file (default: stdout) |
--section N |
Keep only the numbered heading starting with N (e.g. --section 6) |
Lossless text — only overhead is removed:
Stripped (not content, safe to drop):
- XML metadata: author, revisions, fonts, style IDs
- Image binaries and drawing anchors
- Empty paragraphs, double spaces → single,
\n{3,}→\n\n - Duplicated per-section headers/footers (kept once)
Preserved (content stays identical):
- Order, numbered sections, requirement IDs
- Tables → compact Markdown (
| a | b |instead of verbose XML) - List / bullet nesting levels
read_file fails on .docx (binary, not a native Google Doc) and
download_file / export_file burn tens of thousands of tokens on base64.
Use this pattern instead:
- Skip
searchwhen the file ID is already in the user's pasted URL. - Call
get_file_metadata(id)first — report title/size/mimeType only. Do not callread_file/export_fileyet. - If
mimeType = ...wordprocessingml.document(.docx):- Do NOT
read_file(fails/binary). - Do NOT send
export_file/download_fileoutput to the LLM. - Download bytes to
/tmpvia local tooling and run:python3 extract.py /tmp/file.docx -o /tmp/file.md
- Do NOT
- Read
/tmp/file.mdper section, not the whole file. - Don't
list_comments/ export PDF unless explicitly asked.
Packaged as an agent skill for one-click install:
skills/drive-docx-reader/SKILL.md
(Cursor / Opencode / Claude compatible).
Real run on a 232,916-byte BRD document:
| Path | Into the LLM | Est. tokens |
|---|---|---|
download_file raw base64 |
~310,556 chars | ~77,639 |
extract.py Markdown (72 blocks) |
30,585 chars | ~7,646 |
| Saved | ~90.2% |
Section filtering (--section 9 → 2,040 chars ≈ 510 tokens) saves another
60–80% on top when only one part is needed.
Issues and PRs welcome. Keep it stdlib-only so the tool stays copy-paste usable anywhere.