# brewdoc

> Fast, deterministic document-to-Markdown conversion for agent systems. Easy to install. No model weights, OCR or external services.

Local conversion after installation is offline and downloads no runtime components.
Supported formats and readable-file constraints are defined in FORMATS.md.
Version 0.4.1 added [selected ZIP/XML reader budgets](https://github.com/kochetkov-ma/brewdoc/blob/v0.7.1/FORMATS.md#zipxml-reader-limits)
for DOCX/PPTX and workbook metadata/artifacts, with refusal before output writes.
Native workbook values and total process memory are outside those bounds.

Version 0.5.0 added ODT/ODP text and tables, selected MIME email bodies and exact UTF-8
MD/TXT pass-through. It preserved workbook Unicode and exposed datetime precision and used
qualified DOCX Fallback-only selection. Selected PDF caption/table/math-spacing fixes and
textless-page facts were included.
Version 0.6.0 writes cleaner Markdown with minimal escaping, adds --body-only, accepts
documents through --url, decodes legacy HTML charsets and falls back to the whole page in
article mode. Version 0.7.0 added --render-js auto and HTML --no-links, refuses captcha,
login and JavaScript shell pages with a plain reason, reports HTTP status, redirects and
charset in URL receipts, decodes mislabelled HTML charsets by fallback and writes code and
image links as standard Markdown links. Version 0.7.1 checks --url TLS against the
operating system trust store, converts embedded title, description, JSON-LD and noscript
text of some JavaScript shell pages as a partial result and names AWS WAF challenges.
FORMATS.md owns the limits.

- [Installation](https://github.com/kochetkov-ma/brewdoc/blob/v0.7.1/INSTALL.md): pip, uv/uvx, pipx, native downloads, PATH, update and removal.
- [CLI/API and receipts](https://github.com/kochetkov-ma/brewdoc/blob/v0.7.1/README.md): deterministic Markdown and machine-readable results, including article mode introduced in 0.4.0.
- [Format limits](https://github.com/kochetkov-ma/brewdoc/blob/v0.7.1/FORMATS.md): supported/refused inputs, omissions, resource budgets and package compatibility evidence.
- [Latest release](https://github.com/kochetkov-ma/brewdoc/releases/latest): concise features, actual assets and channel availability.
- Installation examples select 0.7.1. Use a channel listed as available in [that release](https://github.com/kochetkov-ma/brewdoc/releases/tag/v0.7.1). npm targets Linux x64/glibc and macOS ARM64; Windows uses GitHub native or Python.
- When listed as available in the release, `kochetkov-ma/brew/brewdoc` installs the complete bundle on macOS 15+ ARM64 or Linux x64/system glibc 2.35+; see installation for lifecycle commands.

## CLI and API

```sh
brewdoc file.pdf --out file.md
brewdoc --body-only paper.pdf --out paper.md
brewdoc book.xlsx --sheet Calc --sheet Inputs --out book.md
brewdoc --self-check
```

Conversion prints a JSON receipt first; without --out, Markdown follows on stdout.
Paths resolve against the caller's directory; --out creates parents. --sheet and
--artifact are repeatable and workbook-only. Parsed documents use brewdoc.markdown/2;
UTF-8 MD/TXT use brewdoc.markdown/passthrough/1 with exact bytes, no envelope and zero units.
--body-only (API body_only=True) drops the title, metadata, omissions, contents and unit
anchors; unit headings stay only for several units and the receipt is unchanged.
Local receipts are brewdoc.receipt/1, URL receipts brewdoc.receipt/2.
Exit 0 means conversion, 1 refusal and 2 invalid usage. Success does not prove fidelity.

```python
import brewdoc
code, receipt, markdown = brewdoc.run("book.epub", out="book.md")
markdown, tally = brewdoc.render_html("page.html")
```

Local run/render APIs and self-check never acquire URLs.

## Deliberate HTTP acquisition

```sh
brewdoc --url https://example.com --render-js --timeout 30 --out page.md
brewdoc --url https://arxiv.org/pdf/1706.03762 --out attention.md
brewdoc --url https://example.com --render-js auto --no-links --out page.md
```

--url deliberately fetches a public HTTP(S) page or supported document; Content-Type and
magic bytes pick the route. DNS, destinations, redirects,
TLS, requests and byte budgets are validated. The default waiting budget is 30
seconds. JS uses installed/bundled components and may preserve valid partial
content on timing-only expiry; hard failures refuse. Ordinary requests use GET;
only the narrow credential-free HN Algolia XHR POST exception is admitted.
Bare --render-js means always; --render-js auto runs JS only on a JavaScript shell page.
Prefer --render-js auto for unknown pages: always runs JS on every page and can hit
an engine quota on a page that static mode reads. Pages that need more than the
bounded engine refuse, such as crates.io. A shell page whose static HTML embeds at
least 200 characters of JSON-LD or noscript text converts it as a partial result with a
javascript_required error. Captcha, bot challenge, login and other shell pages refuse at
stage challenge or javascript_required with a plain reason; the receipt names the challenge
and HTTP status.
--no-links (HTML only) keeps link text and discloses omitted destinations in the receipt.
See the format limits for supported JS runtimes and prerequisite refusals.

## Article mode

Introduced in 0.4.0; use a channel listed as available in the release. Python JS capture
needs `brewdoc[render-js]==0.7.1`; supported standalone bundles include its prerequisites.

```sh
brewdoc page.html --article --out article.md
brewdoc --url https://example.com/article --article --out article.md
brewdoc --url https://example.com/article --render-js --article --out article.md
```

Python: `run(path, article=True)` or `render_html(path, article=True)`. Local APIs stay offline.
Roots are visible main elements or role=main, or outer article elements when no main exists;
articles outside a main are dropped when one exists. role=article and class names do not select.
Hidden and page-chrome landmark subtrees are skipped; a header inside an article or a nav inside
main stays.
Peer articles and multiple mains render in DOM order; nested articles stay inside their outer
article. With no rendered candidate, the whole clean page renders and the receipt adds
`article_fallback: true`; selection never refuses for page structure. No text scoring, title
replacement or inferred author/date metadata. When content is selected, receipt `not_carried`
and Markdown Known omissions include
`body content outside the selected article or main subtree; complete page coverage is not claimed`.
See [the article contract](https://github.com/kochetkov-ma/brewdoc/blob/v0.7.1/FORMATS.md#article-selection).

[Earlier source-package CI](https://github.com/kochetkov-ma/brewdoc/actions/runs/38431645006) passed on
Ubuntu 22.04 x64/glibc with CPython 3.13.15, macOS 15 ARM64 and Windows Server 2025 x64
with CPython 3.14.7. Each passed four independent wheel/sdist base/optional installs;
optional JS executed on Unix and refused before requests on Windows. These are selected
tested patches. CPython 3.12.14 retains local macOS full-suite and existing CI smoke evidence.
These results predate the 0.5.0 changes.
Source-package checks are separate from standalone binaries; other OS/minor combinations,
free-threaded CPython and other architectures remain untested here.
See [package compatibility](https://github.com/kochetkov-ma/brewdoc/blob/v0.7.1/FORMATS.md#python-package-compatibility).

## Related projects

- [BrewPage](https://brewpage.app): free hosting for HTML, Markdown, JSON and files; each upload returns a shareable HTTPS link.
- [BrewPage MCP server](https://github.com/kochetkov-ma/brewpage-openapi/tree/main/mcp-server): npm package brewpage-mcp for publishing to BrewPage from MCP clients.
- [claude-brewcode](https://github.com/kochetkov-ma/claude-brewcode): plugin suite for Claude Code. Its brewdoc plugin is a different tool from this brewdoc CLI.
- [claude-brewcode documentation](https://doc-claude.brewcode.app): installation and skill reference for that suite.
- [brewcode.app](https://brewcode.app): home site of the Brew projects.

This is a readable entry point, without a promise of automatic client discovery.
