A Python CLI tool that compiles MkDocs-flavoured Markdown into native Confluence storage XHTML and publishes it directly to Confluence Cloud. It is a compiler/transpiler, not an HTML converter — every construct maps to its native Confluence equivalent, so pages look and behave like hand-authored Confluence content.
It also bridges the gap between Confluence reviewers and developers: the sync-comments command turns open Confluence page comments into GitHub pull request review threads, and auto-resolves them in Confluence when the PR is merged.
Zensical compatible — Zensical is the modern successor to MkDocs + Material for MkDocs. Since it uses the same
mkdocs.ymlformat and Python Markdown extensions, your Zensical project works with mk2conf today with no changes required.
Requires Python 3.12+. The PyPI package is mkdocs2confluence; the CLI command is mk2conf.
pip install mkdocs2confluence
# or, for an isolated install:
pipx install mkdocs2confluenceFrom source (see Setup.md):
git clone https://github.com/jeckyl2010/mkdocs2confluence.git
cd mkdocs2confluence && uv syncPublish docs automatically on every push — no local install needed:
- name: Publish docs to Confluence
uses: jeckyl2010/mkdocs2confluence@v1
with:
token: ${{ secrets.CONFLUENCE_API_TOKEN }}Full workflow — triggers on changes to docs/ or mkdocs.yml:
name: Publish docs
on:
push:
branches: [main]
paths: ['docs/**', 'mkdocs.yml']
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: jeckyl2010/mkdocs2confluence@v1
with:
token: ${{ secrets.CONFLUENCE_API_TOKEN }}
prune: 'true'Available inputs: token (required), config, version, dry-run, section, page, prune, quiet. See docs/commands.md for details.
# Preview a page locally (no Confluence API calls)
mk2conf preview --page index.md --watch
# Dry-run: see what would be published
mk2conf publish --dry-run
# Publish all nav pages
mk2conf publish
# Export a section to PDF
mk2conf pdf --section Guide --out guide.pdf
# Sync Confluence comments to GitHub PR review threads
mk2conf sync-commentsAdd a confluence: block to your mkdocs.yml:
confluence:
base_url: https://yourorg.atlassian.net
space_key: TECH
email: user@example.com
token: !ENV CONFLUENCE_API_TOKEN # never hardcode the token
parent_page_id: "123456" # optional root page
mermaid_render: kroki # "kroki" (default) | "kroki:https://your-kroki" | "none"
full_width: true # default: trueThe confluence: block is also accepted under extra: for MkDocs strict-mode compatibility. The API token is read from token: in mkdocs.yml, then CONFLUENCE_API_TOKEN, then MK2CONF_TOKEN.
Your first publish:
export CONFLUENCE_API_TOKEN=your_api_token_here
mk2conf preview --page docs/index.md --watch # verify output locally
mk2conf publish --dry-run # check the plan
mk2conf publish # go live| docs/commands.md | Full flag reference for all four commands |
| docs/features.md | Supported Markdown / Material features and known limitations |
| Setup.md | Development environment setup |
Pipeline stages: loader → preprocess → IR → transforms → emitter → publisher.
The publisher is split into two phases:
planner.pybuilds a nav-ordered publish plan, compiles pages, and makes the read-side API calls needed to decide create vs update vs skip.executor.pyapplies that plan, performs the write-side API calls, uploads attachments, and wires parent/child relationships in nav order so parent pages always exist before their children.
publisher/pipeline.py remains a compatibility facade that re-exports the public publish surface used by the CLI and tests.
uv run pytest -q
uv run ruff check src tests
uv run mypy src
uv run vulture src --min-confidence 80