Skip to main content

Markweave: Markdown to DOCX and PDF

Markweave turns a Markdown file into DOCX, PDF, or both from a small browser interface. It keeps your Word templates and completed jobs on local persistent storage and scans every upload with ClamAV before saving it.

The project is licensed under Apache-2.0. Version 0.3.1 is the current Python package and container image release.

The documentation index provides longer guides organized by role. You do not need to read them before trying the local profile.

Try it locally

You need OpenSSL, flock from util-linux, about 6 GiB of available memory, and either Docker Engine with Compose or rootless Podman with a working podman compose provider. The published Markweave image is Linux/AMD64; native ARM is not supported. Clone the repository so Compose can use the reviewed Chromium seccomp profile, then choose one of these local-evaluation paths.

Path Runtime Command /work isolation
Simple Docker Compose scripts/quickstart-simple.sh up Named volume; no physical cap
Simple Rootless Podman Compose MARKWEAVE_SIMPLE_RUNTIME=podman scripts/quickstart-simple.sh up Named volume; no physical cap
Secure Rootful Docker Compose only scripts/quickstart.sh up Exact 256 MiB ext4 filesystem

The simple path needs no sudo and is the easiest way to try Markweave:

git clone https://github.com/Guillaume-Lombardo/simple-md-to-docx-converter.git
cd simple-md-to-docx-converter
scripts/quickstart-simple.sh up

The helper automatically prefers a working Docker Compose installation and otherwise selects rootless Podman Compose. Set MARKWEAVE_SIMPLE_RUNTIME=docker or MARKWEAVE_SIMPLE_RUNTIME=podman to select one deterministically. It initializes the named workspace for application UID 1001 in a short-lived, network-isolated container; the application itself still starts as UID 1001 without capabilities. The rootless Podman-compatible application image and the simple Podman Compose workflow do not make the secure loop-device helper compatible with Podman. For Podman, the helper starts a private API service configured with the reviewed Chromium seccomp profile because Docker Compose cannot pass that local profile directly to Podman's Docker-compatible API. Podman's automatic Docker-API health metadata is not used; the helper polls ClamAV directly before starting Markweave, then polls Markweave's local readiness endpoint with a bounded timeout.

This uses an ordinary engine-managed named volume for disposable /work data. The application still runs as a non-root user with a read-only root filesystem, no Linux capabilities, loopback-only HTTP, pinned images, and the same memory, CPU, process, upload, and conversion limits. However, the named volume has no physical capacity cap: a failed or hostile document engine could consume host disk until the container engine or host stops it. Use the secure path below when physical disk-exhaustion isolation matters.

The secure path creates an exact 256 MiB ext4 loop filesystem for /work. It additionally requires an AMD64 Linux host, the standard local rootful Docker Engine at unix:///var/run/docker.sock, mkfs.ext4, and losetup; it requests sudo to manage the loop device. Docker Desktop and rootless Docker are unsupported, as are DOCKER_HOST and remote or non-default Docker contexts, non-Linux hosts, and native ARM:

scripts/quickstart.sh up

Both scripts create the administrator password once in a private state directory and reuse it on later starts. They also decode examples/quickstart-template.docx.base64 beside that password. Show the simple-path password without putting it in shell history:

scripts/quickstart-simple.sh password

For the secure path, use the same commands with quickstart.sh instead of quickstart-simple.sh: scripts/quickstart.sh password shows its password and scripts/quickstart.sh down stops it.

Open http://localhost:8080, sign in as admin, and use the password above. The first start can take several minutes while ClamAV downloads and loads its signatures. The simple up command returns only after the selected runtime passes its readiness checks; scripts/quickstart-simple.sh ps shows the containers, and scripts/quickstart-simple.sh logs follows the signature-download progress. The secure helper reports that Markweave is starting; use scripts/quickstart.sh ps or scripts/quickstart.sh logs until both services are healthy.

To make a first conversion:

  1. Open Templates, create a template, and select the generated template at the path printed by the setup script (normally ~/.local/state/markweave-quickstart-simple/quickstart-template.docx for the simple path). In Expected fonts, enter this exact comma-separated list: Aptos, Aptos Display, Calibri, Cambria, Cambria Math, Consolas, Courier New, Times New Roman.
  2. Return to Convert, upload examples/quickstart-source.md, select your active template, and choose DOCX, PDF, or both.
  3. Start the conversion. When the job says it is ready, download the result.

A tiny source file is enough to try the workflow; examples/quickstart-source.md contains:

# My first document

Hello from **Markweave**.

Stop the evaluation with:

scripts/quickstart-simple.sh down

The simple shutdown validates the ordinary work volume's exact project labels, local driver, and empty mount options before removing only that disposable volume. markweave-data, clamav-signatures, the administrator password, and the decoded template remain, so accounts, templates, jobs, results, signatures, and credentials survive normal shutdown. Do not add the --volumes option unless you intentionally want the container engine to remove durable local data.

Completed conversion results remain downloadable for 10 minutes in this evaluation profile. This is a local convenience value, not a recommended production retention policy.

Both paths support repeated up, stopped-stack restart, ps, logs, and down. A stopped restart discards only the disposable work volume and preserves durable data. If Compose fails while starting—for example, because port 8080 is occupied—the selected script removes partial containers and its exact scratch resources while retaining the password, template, application data, and ClamAV signatures. The simple helper rejects concurrent commands that could race over the same private state or Podman service; wait for the active command to finish before running another.

The secure services do not automatically restart with Docker because loop-device numbers are not stable across a reboot. After an abnormal stop or reboot, run scripts/quickstart.sh up; it removes stale scratch metadata, resolves the private backing file independently of old device numbers, reformats disposable work, and restarts safely. Cleanup resolves the current device from the private backing file, never from a stale device number. It refuses a loop device reused for an unrelated file.

What this Compose profile is—and is not

The secure base compose.yaml is a bounded standalone evaluation profile. The simple compose.simple.yaml overlay deliberately replaces only its bounded /work mount with an unbounded named volume. In both paths, one rootless Markweave process runs the API and embedded worker, /data is persistent, the root filesystem is read-only, and the browser port binds only to 127.0.0.1. ClamAV has persistent signatures and no host port. The scanner network is internal, and only ClamAV joins the network used to refresh signatures.

The Compose profile is not a production deployment. Its upload, queue, memory, retention, and timeout values are local evaluation limits reused from the tested final-image workflow. Do not publish port 8080 or place this HTTP setup on an untrusted network. A production deployment needs reviewed limits, TLS, secrets management, backups, network policy, monitoring, and the standalone or distributed topology appropriate to its workload. Start with the container deployment guide, resource policy, storage profiles, and authentication guide.

Both images are pinned by digest. The ClamAV image uses the supported 1.4_base line with its database stored in clamav-signatures; review release notes and validation evidence before changing either digest. ClamAV recommends roughly 4 GiB of RAM for reliable operation and explains the _base image and persistent database pattern in its official Docker documentation.

Use and operate Markweave

How it works

The browser and HTTP API authenticate a local user, validate and scan the upload, and record a durable conversion job. A worker claims that job with a renewable lease, resolves the exact immutable template version, and runs the local Pandoc, Chromium/Mermaid, and LibreOffice engines inside bounded workspaces. Results and traceability metadata are retained for the configured period; document content is not written to logs.

The standalone profile used by Compose keeps SQLite metadata and atomic objects under one /data volume and runs one embedded worker. The distributed profile separates API and worker processes, using PostgreSQL and S3-compatible object storage so workers can scale independently. Both profiles share the same authorization, queue, validation, and retention contracts. See the architecture guide, API guide, and complete configuration reference for the deeper design.

Develop and contribute

Development targets Python 3.14 and uses uv, Ruff, ty, Pytest, and the repository's locked toolchain. Install all groups, then run the canonical checks:

uv sync --all-groups
uv run ruff format --check .
uv run ruff check .
uv run ty check
npm ci --ignore-scripts
npm run test:web
uv run pytest -m "not requires_pandoc and not requires_mermaid and not requires_libreoffice"
uv run pytest

Read CONTRIBUTING.md and the normative product specification before changing behavior. The local-development guide covers the repository layout and deeper setup; the release guide covers protected PyPI and GHCR publication.

Metadata

Release files for markweave 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for markweave 0.3.1
File Size Uploaded
markweave-0.3.1.tar.gz 129.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for markweave 0.3.1
File Interpreter ABI Platform
markweave-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 298.6 kB

Release files / markweave-0.3.1.tar.gz

Download URL markweave-0.3.1.tar.gz
Size 129.5 kB
Tags Source
SHA-256 checksum
How to use checksums
2f0f173f76dc7535b05959e6bc3265f38e57787389821482aaacfc66a1183993
BLAKE2b-256 checksum
How to use checksums
82acc592095258105b6c85ae33457ff207208d14abc1fed09205c0ed61700a44
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.

Transparency log

Release files / markweave-0.3.1-py3-none-any.whl

Download URL markweave-0.3.1-py3-none-any.whl
Size 169.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
33f3faa378453d276d0ce7886f7122f023c267aa391d6c42c42a74877c701e90
BLAKE2b-256 checksum
How to use checksums
e062987cdafd1808e6c77f79da44a625b297ae71b7a9793daaf04bc1fdaebb69
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.

Transparency log

Release history Release notifications | RSS feed

0.7.4

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.4

2 release files

0.6.3

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

This release

0.3.1 This release

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page